diff --git a/.dockerignore b/.dockerignore index 944a2ec..e50c8dd 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,7 @@ node_modules .next .git -.env* +.env.local +.env.development +external-code/ + diff --git a/.env b/.env new file mode 100644 index 0000000..182e378 --- /dev/null +++ b/.env @@ -0,0 +1,9 @@ +SMTP_HOST=smtp.gmail.com +SMTP_PORT=587 +SMTP_SECURE=false +RECIPIENT_EMAIL=mark@finlion.com +GOOGLE_EMAIL=system@deafgain.org +GOOGLE_APP_PASSWORD=ojvlysraxwjriwzy +UPSTASH_REDIS_REST_URL=https://gusc1-resolved-jaybird-30779.upstash.io +UPSTASH_REDIS_REST_TOKEN=AXg7ASQgNDMzMDE0MTYtNWE0Ni00OTc3LThhYjktM2IxMzMxNGMyMzMxNWRiNGMyOGU2MjE0NGUyNTkwMTQyNmUxZTU2NzE4NDI= + diff --git a/.gitignore b/.gitignore index 1c34e5b..284d90c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ node_modules/ .next/ -.env* +.env.* .DS_Store *.pem npm-debug.log* diff --git a/ROADMAP b/ROADMAP index e1442d8..abe1688 100644 --- a/ROADMAP +++ b/ROADMAP @@ -1,144 +1,82 @@ -This is a portfolio website for a person named Mark Apodaca, MBA, PRP. He is a solo person who provide different services related to finances and consulting on nonprofit organizations. +# Contact Form Implementation Guide -Those are his services: +## Directory Structure +/src + /lib + - email.ts + - rate-limit.ts + /components + /shared + - ContactModal.tsx + - Toast.tsx + /providers + - notification-provider.tsx + /app + /api + /contact + - route.ts - Accounting and bookkeeping services using QuickBooks and Xero. - Income tax services - Financial statement analysis - Financial budgeting and estimating - Financial planning and analysis - Financial modeling - Business plans - Business models - Business analysis - Strategic planning - Small business consulting - Nonprofit organization consulting +## Step-by-Step Implementation +### 1. Create Directory Structure + mkdir -p src/lib + mkdir -p src/components/shared + mkdir -p src/components/providers + mkdir -p src/app/api/contact -I want to use this following as the frontend for the website: +### 2. Install Dependencies + npm install nodemailer @upstash/redis framer-motion lucide-react -Next.js 14 -TypeScript -Tailwind CSS -Lucide Icons +### 3. Environment Variables +Create .env file with: -There are no expected administration management or any database server needed for this website. + SMTP_HOST=smtp.gmail.com + SMTP_PORT=465 + SMTP_SECURE=true + GOOGLE_EMAIL=your-email@gmail.com + GOOGLE_APP_PASSWORD=your-app-password + RECIPIENT_EMAIL=recipient@example.com + UPSTASH_REDIS_REST_URL=your-redis-url + UPSTASH_REDIS_REST_TOKEN=your-redis-token -There are two images that will be used for this website. +### 4. Integration Steps +1. Copy all required files from source project +2. Update layout.tsx to include NotificationProvider +3. Configure email settings +4. Set up Redis connection +5. Test implementation -First image is a photo of Mark as mark.jpg. Here is the description of the image and suggested idea for the website design: +### 5. Testing Checklist +- Email Sending + - Test with valid email credentials + - Verify email receipt + - Check HTML formatting -Subject Description: The image features a professional man, seated at a desk, with an approachable and confident demeanor. He is middle-aged with a balding head, gray and dark hair on the sides, and a neatly trimmed beard and mustache. He wears rectangular black-framed glasses, which contribute to a professional and studious appearance. He has a friendly smile and rests his hands lightly clasped on the desk in front of him. +- Rate Limiting + - Test multiple submissions + - Verify Redis connection + - Check rate limit messages -Clothing and Accessories: He is dressed in a pale blue dress shirt with a bright red tie that has a subtle pattern, giving him a polished and formal look. Around his neck is a lanyard that appears to have the words "SCHOOL FOR" written on it, likely representing an affiliation or prior role. On his left hand, he wears a prominent gold ring with intricate detailing, suggesting achievement or membership, such as a class ring or a professional association. His wristwatch on the left hand is dark with a clean, understated design. +- Form Validation + - Test all form fields + - Verify error messages + - Check input sanitization -Background and Environment: The setting is an office with a professional but cozy atmosphere. Behind him are organized office shelves with binders, some labeled and standing upright. These folders add to the impression of a well-organized and methodical work ethic. The desk in front of him has a polished wood surface with a few visible items: a white and red document or calendar, adding a functional element, and part of a phone on the left edge of the image. +- Notifications + - Test success messages + - Test error messages + - Verify toast timing -Lighting and Composition: The room is well-lit, with soft natural light coming from a window with horizontal white blinds visible in the background. The lighting casts no harsh shadows, creating an inviting and professional tone. The subject is centered in the frame, with the focus clearly on him and his upper body. +### 6. Debugging Guide +- Check environment variables are properly set +- Verify Redis connection in logs +- Test email credentials separately +- Monitor Network tab in browser dev tools +- Check server logs for errors +- Verify CORS settings if needed -Tone and Impression: The overall tone of the image is warm, approachable, and professional, reflecting a balance of trustworthiness and competence. This impression aligns well with the services of financial consulting and supporting nonprofit organizations, as it suggests reliability, experience, and attention to detail. - -Second image is a logo of Mark's business and here is the visual description: - -Text and Typography: The logo prominently features the word "FINLION" in bold, capitalized serif letters. The font style is classic and professional, with slight serifs on the edges of each letter, giving it a formal and authoritative look. The letters are evenly spaced, making the text easily readable. - -Color Scheme: The entire logo is rendered in a deep, rich blue color. This color conveys trustworthiness, professionalism, and stability, traits often associated with financial services. - -Graphic Element: Integrated within the word "FINLION" is a stylized depiction of a lion’s head, replacing the "O" in "LION." The lion's face is symmetrical, with sharp, clean lines. The eyes are small and almond-shaped, giving the lion a focused and determined expression. The nose is angular, and the mouth is minimalistic, further emphasizing the lion's confident and bold demeanor. Surrounding the face is a flowing mane, stylized with sharp, dynamic strokes that radiate outward, creating a sense of movement and energy. The mane adds a modern and powerful touch to the logo. - -Trademark Symbol: To the lower right of the "N," a small ® (registered trademark symbol) is visible, indicating that this logo is legally trademarked. - -Overall Design: The combination of the bold, serif text and the strong, dynamic lion graphic conveys a message of strength, leadership, and reliability. The lion, a universal symbol of courage and power, is fitting for a brand associated with financial consulting and nonprofit services, as it implies trust and guidance. - -For a website designed for Mark Apodaca’s services, consider integrating these elements: - -1. Color Palette: Build around the deep blue of the logo, pairing it with neutral tones like white and light gray for backgrounds and accents or accents of red or gold to mirror his tie and ring. -2. Typography: Use a serif font similar to the logo for headings to maintain brand consistency, paired with a clean sans-serif font for body text. -3. Iconography: Use lion-inspired imagery or subtle mane-like patterns for decorative elements to echo the logo's theme. -4. Imagery Style: Include warm, welcoming photos and emphasize neat organization, reflecting the details in the office environment. -4. Emphasis: Highlight the lion's strength and elegance in the design to reflect the brand’s values of leadership and reliability. -5. Navigation and Layout: Keep the design structured and easy to navigate, with sections that highlight his expertise, services, and contact information. Use soft contrasts to ensure accessibility. - -Here is a third image that will not be on the website but is to provide information about the previous website that is a screenshot. Here is the visual description: - -Layout Overview: - -The screenshot displays a relatively simple and traditional website layout with a fixed-width design. It features a two-column structure: - - Left Column: Contains navigation and a welcome text. - Right Column: Includes a header with the company logo and a tagline, along with an image of professionals in a collaborative setting. - -Header Section: - - Logo: - The top-right corner of the website prominently displays the FINLION logo in blue, as described earlier. - Below the logo is a tagline in smaller, italicized font: - "A business & financial consulting firm since 1978." - This adds credibility by emphasizing the firm's longstanding history. - - Background Bar: - A thin horizontal gray bar runs beneath the header, creating separation between the logo/tagline and the main body of the webpage. - -Navigation Menu: - -The left column contains a vertical navigation menu, styled as a series of blue buttons with white text. The menu includes the following links: - - Overview - Services - Benefits - Articles - Contact - -The blue-and-white color combination maintains a professional appearance and aligns with the branding established by the logo. -Main Content Area: - -The right column is divided into text and an image section: - - Welcome Text: - A heading in bold blue text reads: - "Welcome to FINLION!" - Below the heading is a paragraph in black text that provides an introduction to the firm: - - FINLION has been serving the needs of individuals and small businesses since 1978. Originally formed as an income tax practice in Los Angeles, California, the firm specializes in business startups, accounting and income taxes, financial management, and personal financial planning. Feel welcome to explore this website and if you have any questions or would like to utilize FINLION’s services, feel free to contact us. - - Bullet Point Links: - - Beneath the paragraph, there are four clickable text links in gold: - What Makes Great Organizations? - Focus - Proficiency - The Power of Planning - - These links appear to direct users to additional resources or articles. - -Image Section: - -To the right of the welcome text, there is a photo of three professionals working together: - - The setting is an office environment with a bright, neutral background. - Two women and one man are gathered around a laptop, appearing engaged in discussion. This imagery reinforces themes of collaboration and professionalism. - -Footer: - -At the bottom of the page, in small black text, there is a copyright notice: - - "© 1999-2010, FINLION. All rights reserved." - Below this, there is a credit to the website producer: - "Produced by Design Actually, LLC." - The text "Design Actually, LLC" is a clickable link, suggesting a reference to the original web design firm. - -Design Notes: - - The overall color scheme uses blue, white, gray, and gold, consistent with the logo's professional aesthetic. - The website feels clean but slightly outdated, as it follows a late-1990s to early-2000s design approach with a heavy focus on text and simple structure. - The layout is functional but not responsive, likely designed for desktop viewing rather than mobile devices. - -Suggestions for Modernizing: - - Responsive Design: Ensure the website is optimized for both desktop and mobile platforms with a flexible layout. - Typography Update: Use more modern fonts with better readability and a mix of sans-serif for headings and body text. - Improved Visuals: Replace static professional imagery with dynamic, authentic visuals that represent Mark’s services. - Streamlined Navigation: Simplify the navigation menu for user-friendly access, such as dropdowns or a sticky top menu. - Call to Action (CTA): Add prominent buttons for quick contact or consultation requests on the homepage. - Brand Consistency: Retain the blue, white, and gold color scheme but integrate it with contemporary UI elements like gradients or subtle animations. \ No newline at end of file +### 7. Security Considerations +- Input sanitization is implemented +- Rate limiting prevents spam +- Email credentials are secured +- Form validation prevents injection \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 10d099f..00b43a8 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -13,4 +13,10 @@ services: - /app/.next environment: - NODE_ENV=development + - SMTP_HOST=smtp.gmail.com + - SMTP_PORT=587 + - SMTP_SECURE=false + - GOOGLE_EMAIL=${GOOGLE_EMAIL} + - GOOGLE_APP_PASSWORD=${GOOGLE_APP_PASSWORD} + - RECIPIENT_EMAIL=${RECIPIENT_EMAIL} command: pnpm dev diff --git a/docker-compose.yml b/docker-compose.yml index c24ac7e..084bc6d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,14 +8,14 @@ services: pull_policy: build ports: - "805:805" - networks: - - caddy_network +# networks: +# - caddy_network environment: - NODE_ENV=production - PORT=805 - VERSION=1.2 restart: unless-stopped -networks: - caddy_network: - external: true +#networks: +# caddy_network: +# external: true diff --git a/package.json b/package.json index 6322b20..3993d0e 100644 --- a/package.json +++ b/package.json @@ -12,24 +12,27 @@ "dependencies": { "@emotion/is-prop-valid": "^1.3.1", "@headlessui/react": "^2.2.0", - "framer-motion": "11.12.0", - "lucide-react": "^0.462.0", - "next": "15.0.3", - "react": "18.3.1", - "react-dom": "18.3.1", - "react-icons": "^5.3.0" + "@types/nodemailer": "^6.4.17", + "@upstash/redis": "^1.34.3", + "framer-motion": "11.13.3", + "lucide-react": "^0.468.0", + "next": "15.0.4", + "nodemailer": "^6.9.16", + "react": "19.0.0", + "react-dom": "19.0.0", + "react-icons": "^5.4.0" }, "devDependencies": { "@types/node": "^22.10.1", - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@typescript-eslint/parser": "^8.16.0", + "@types/react": "^19.0.1", + "@types/react-dom": "^19.0.2", + "@typescript-eslint/parser": "^8.18.0", "autoprefixer": "^10.4.20", "eslint": "^9.16.0", - "eslint-config-next": "15.0.3", + "eslint-config-next": "15.0.4", "eslint-plugin-import": "^2.31.0", "postcss": "^8.4.49", - "tailwindcss": "^3.4.15", + "tailwindcss": "^3.4.16", "typescript": "^5.7.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 84787b6..af8e215 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,38 +13,47 @@ importers: version: 1.3.1 '@headlessui/react': specifier: ^2.2.0 - version: 2.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@types/nodemailer': + specifier: ^6.4.17 + version: 6.4.17 + '@upstash/redis': + specifier: ^1.34.3 + version: 1.34.3 framer-motion: - specifier: 11.12.0 - version: 11.12.0(@emotion/is-prop-valid@1.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 11.13.3 + version: 11.13.3(@emotion/is-prop-valid@1.3.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) lucide-react: - specifier: ^0.462.0 - version: 0.462.0(react@18.3.1) + specifier: ^0.468.0 + version: 0.468.0(react@19.0.0) next: - specifier: 15.0.3 - version: 15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 15.0.4 + version: 15.0.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + nodemailer: + specifier: ^6.9.16 + version: 6.9.16 react: - specifier: 18.3.1 - version: 18.3.1 + specifier: 19.0.0 + version: 19.0.0 react-dom: - specifier: 18.3.1 - version: 18.3.1(react@18.3.1) + specifier: 19.0.0 + version: 19.0.0(react@19.0.0) react-icons: - specifier: ^5.3.0 - version: 5.3.0(react@18.3.1) + specifier: ^5.4.0 + version: 5.4.0(react@19.0.0) devDependencies: '@types/node': specifier: ^22.10.1 version: 22.10.1 '@types/react': - specifier: ^18.3.12 - version: 18.3.12 + specifier: ^19.0.1 + version: 19.0.1 '@types/react-dom': - specifier: ^18.3.1 - version: 18.3.1 + specifier: ^19.0.2 + version: 19.0.2(@types/react@19.0.1) '@typescript-eslint/parser': - specifier: ^8.16.0 - version: 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + specifier: ^8.18.0 + version: 8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.49) @@ -52,17 +61,17 @@ importers: specifier: ^9.16.0 version: 9.16.0(jiti@1.21.6) eslint-config-next: - specifier: 15.0.3 - version: 15.0.3(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + specifier: 15.0.4 + version: 15.0.4(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) eslint-plugin-import: specifier: ^2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) + version: 2.31.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@9.16.0(jiti@1.21.6)) postcss: specifier: ^8.4.49 version: 8.4.49 tailwindcss: - specifier: ^3.4.15 - version: 3.4.15 + specifier: ^3.4.16 + version: 3.4.16 typescript: specifier: ^5.7.2 version: 5.7.2 @@ -92,12 +101,12 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.19.0': - resolution: {integrity: sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==} + '@eslint/config-array@0.19.1': + resolution: {integrity: sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.9.0': - resolution: {integrity: sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==} + '@eslint/core@0.9.1': + resolution: {integrity: sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/eslintrc@3.2.0': @@ -108,12 +117,12 @@ packages: resolution: {integrity: sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/object-schema@2.1.4': - resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} + '@eslint/object-schema@2.1.5': + resolution: {integrity: sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.2.3': - resolution: {integrity: sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==} + '@eslint/plugin-kit@0.2.4': + resolution: {integrity: sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@floating-ui/core@1.6.8': @@ -291,56 +300,56 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@next/env@15.0.3': - resolution: {integrity: sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==} + '@next/env@15.0.4': + resolution: {integrity: sha512-WNRvtgnRVDD4oM8gbUcRc27IAhaL4eXQ/2ovGbgLnPGUvdyDr8UdXP4Q/IBDdAdojnD2eScryIDirv0YUCjUVw==} - '@next/eslint-plugin-next@15.0.3': - resolution: {integrity: sha512-3Ln/nHq2V+v8uIaxCR6YfYo7ceRgZNXfTd3yW1ukTaFbO+/I8jNakrjYWODvG9BuR2v5kgVtH/C8r0i11quOgw==} + '@next/eslint-plugin-next@15.0.4': + resolution: {integrity: sha512-rbsF17XGzHtR7SDWzWpavSfum3/UdnF8bAaisnKwP//si3KWPTedVUsflAdjyK1zW3rweBjbALfKcavFneLGvg==} - '@next/swc-darwin-arm64@15.0.3': - resolution: {integrity: sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==} + '@next/swc-darwin-arm64@15.0.4': + resolution: {integrity: sha512-QecQXPD0yRHxSXWL5Ff80nD+A56sUXZG9koUsjWJwA2Z0ZgVQfuy7gd0/otjxoOovPVHR2eVEvPMHbtZP+pf9w==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.0.3': - resolution: {integrity: sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==} + '@next/swc-darwin-x64@15.0.4': + resolution: {integrity: sha512-pb7Bye3y1Og3PlCtnz2oO4z+/b3pH2/HSYkLbL0hbVuTGil7fPen8/3pyyLjdiTLcFJ+ymeU3bck5hd4IPFFCA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.0.3': - resolution: {integrity: sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==} + '@next/swc-linux-arm64-gnu@15.0.4': + resolution: {integrity: sha512-12oSaBFjGpB227VHzoXF3gJoK2SlVGmFJMaBJSu5rbpaoT5OjP5OuCLuR9/jnyBF1BAWMs/boa6mLMoJPRriMA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.0.3': - resolution: {integrity: sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==} + '@next/swc-linux-arm64-musl@15.0.4': + resolution: {integrity: sha512-QARO88fR/a+wg+OFC3dGytJVVviiYFEyjc/Zzkjn/HevUuJ7qGUUAUYy5PGVWY1YgTzeRYz78akQrVQ8r+sMjw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.0.3': - resolution: {integrity: sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==} + '@next/swc-linux-x64-gnu@15.0.4': + resolution: {integrity: sha512-Z50b0gvYiUU1vLzfAMiChV8Y+6u/T2mdfpXPHraqpypP7yIT2UV9YBBhcwYkxujmCvGEcRTVWOj3EP7XW/wUnw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.0.3': - resolution: {integrity: sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==} + '@next/swc-linux-x64-musl@15.0.4': + resolution: {integrity: sha512-7H9C4FAsrTAbA/ENzvFWsVytqRYhaJYKa2B3fyQcv96TkOGVMcvyS6s+sj4jZlacxxTcn7ygaMXUPkEk7b78zw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.0.3': - resolution: {integrity: sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==} + '@next/swc-win32-arm64-msvc@15.0.4': + resolution: {integrity: sha512-Z/v3WV5xRaeWlgJzN9r4PydWD8sXV35ywc28W63i37G2jnUgScA4OOgS8hQdiXLxE3gqfSuHTicUhr7931OXPQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.0.3': - resolution: {integrity: sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==} + '@next/swc-win32-x64-msvc@15.0.4': + resolution: {integrity: sha512-NGLchGruagh8lQpDr98bHLyWJXOBSmkEAfK980OiNBa7vNm6PsNoPvzTfstT78WyOeMRQphEQ455rggd7Eo+Dw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -411,11 +420,11 @@ packages: '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@tanstack/react-virtual@3.10.9': - resolution: {integrity: sha512-OXO2uBjFqA4Ibr2O3y0YMnkrRWGVNqcvHQXmGvMu6IK8chZl3PrDxFXdGZ2iZkSrKh3/qUYoFqYe+Rx23RoU0g==} + '@tanstack/react-virtual@3.11.1': + resolution: {integrity: sha512-orn2QNe5tF6SqjucHJ6cKTKcRDe3GG7bcYqPNn72Yejj7noECdzgAyRfGt2pGDPemhYim3d1HIR/dgruCnLfUA==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@tanstack/virtual-core@3.10.9': resolution: {integrity: sha512-kBknKOKzmeR7lN+vSadaKWXaLS0SZZG+oqpQ/k80Q6g9REn6zRHS/ZYdrIzHnpHgy/eWs00SujveUN/GJT2qTw==} @@ -432,77 +441,67 @@ packages: '@types/node@22.10.1': resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==} - '@types/prop-types@15.7.13': - resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} + '@types/nodemailer@6.4.17': + resolution: {integrity: sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==} - '@types/react-dom@18.3.1': - resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==} + '@types/react-dom@19.0.2': + resolution: {integrity: sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==} + peerDependencies: + '@types/react': ^19.0.0 - '@types/react@18.3.12': - resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==} + '@types/react@19.0.1': + resolution: {integrity: sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==} - '@typescript-eslint/eslint-plugin@8.16.0': - resolution: {integrity: sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==} + '@typescript-eslint/eslint-plugin@8.18.0': + resolution: {integrity: sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/parser@8.16.0': - resolution: {integrity: sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w==} + '@typescript-eslint/parser@8.18.0': + resolution: {integrity: sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/scope-manager@8.16.0': - resolution: {integrity: sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg==} + '@typescript-eslint/scope-manager@8.18.0': + resolution: {integrity: sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.16.0': - resolution: {integrity: sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg==} + '@typescript-eslint/type-utils@8.18.0': + resolution: {integrity: sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/types@8.16.0': - resolution: {integrity: sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==} + '@typescript-eslint/types@8.18.0': + resolution: {integrity: sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.16.0': - resolution: {integrity: sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==} + '@typescript-eslint/typescript-estree@8.18.0': + resolution: {integrity: sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/utils@8.16.0': - resolution: {integrity: sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==} + '@typescript-eslint/utils@8.18.0': + resolution: {integrity: sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/visitor-keys@8.16.0': - resolution: {integrity: sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==} + '@typescript-eslint/visitor-keys@8.18.0': + resolution: {integrity: sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@upstash/redis@1.34.3': + resolution: {integrity: sha512-VT25TyODGy/8ljl7GADnJoMmtmJ1F8d84UXfGonRRF8fWYJz7+2J6GzW+a6ETGtk4OyuRTt7FRSvFG5GvrfSdQ==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -629,8 +628,12 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} - call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} engines: {node: '>= 0.4'} callsites@3.1.0: @@ -641,8 +644,8 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - caniuse-lite@1.0.30001685: - resolution: {integrity: sha512-e/kJN1EMyHQzgcMEEgoo+YTCO1NGCmIYHk5Qk8jT6AazWemS5QFKJ5ShCJlH3GZrNIdZofcNCEwZqbMjjKzmnA==} + caniuse-lite@1.0.30001687: + resolution: {integrity: sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -684,6 +687,9 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -715,8 +721,8 @@ packages: supports-color: optional: true - debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -749,11 +755,15 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} + dunder-proto@1.0.0: + resolution: {integrity: sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==} + engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - electron-to-chromium@1.5.67: - resolution: {integrity: sha512-nz88NNBsD7kQSAGGJyp8hS6xSPtWwqNogA0mjtc2nUYeEf3nURK9qpV18TuBdDmEDgVWotS8Wkzf+V52dSQ/LQ==} + electron-to-chromium@1.5.72: + resolution: {integrity: sha512-ZpSAUOZ2Izby7qnZluSrAlGgGQzucmFbN0n64dYzocYxnxV5ufurpj3VgEe4cUp7ir9LmeLxNYo8bVnlM8bQHw==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -769,8 +779,8 @@ packages: resolution: {integrity: sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==} engines: {node: '>= 0.4'} - es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} es-errors@1.3.0: @@ -804,8 +814,8 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-config-next@15.0.3: - resolution: {integrity: sha512-IGP2DdQQrgjcr4mwFPve4DrCqo7CVVez1WoYY47XwKSrYO4hC0Dlb+iJA60i0YfICOzgNADIb8r28BpQ5Zs0wg==} + eslint-config-next@15.0.4: + resolution: {integrity: sha512-97mLaAhbJKVQYXUBBrenRtEUAA6bNDPxWfaFEd6mEhKfpajP4wJrW4l7BUlHuYWxR8oQa9W014qBJpumpJQwWA==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 typescript: '>=3.3.1' @@ -816,8 +826,8 @@ packages: eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - eslint-import-resolver-typescript@3.6.3: - resolution: {integrity: sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==} + eslint-import-resolver-typescript@3.7.0: + resolution: {integrity: sha512-Vrwyi8HHxY97K5ebydMtffsWAn1SCR9eol49eCd5fJS4O1WV7PaAjbcjmbfJJSMz/t4Mal212Uz/fQZrOB8mow==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -866,8 +876,8 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - eslint-plugin-react-hooks@5.0.0: - resolution: {integrity: sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==} + eslint-plugin-react-hooks@5.1.0: + resolution: {integrity: sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 @@ -969,8 +979,8 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - framer-motion@11.12.0: - resolution: {integrity: sha512-gZaZeqFM6pX9kMVti60hYAa75jGpSsGYWAHbBfIkuHN7DkVHVkxSxeNYnrGmHuM0zPkWTzQx10ZT+fDjn7N4SA==} + framer-motion@11.13.3: + resolution: {integrity: sha512-3ZSNuYpDFeNxqVKUyYipOm5A1fXSbMje1XIfEWxKTJ4ughl5FEjvkp6gKmFHLjzwijCVU/PjsMNlTMVCmi+Twg==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 @@ -998,8 +1008,8 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + get-intrinsic@1.2.5: + resolution: {integrity: sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==} engines: {node: '>= 0.4'} get-symbol-description@1.0.2: @@ -1029,8 +1039,8 @@ packages: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} - gopd@1.1.0: - resolution: {integrity: sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} graceful-fs@4.2.11: @@ -1049,12 +1059,12 @@ packages: has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - has-proto@1.1.0: - resolution: {integrity: sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q==} + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} engines: {node: '>= 0.4'} - has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} has-tostringtag@1.0.2: @@ -1092,8 +1102,9 @@ packages: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} engines: {node: '>= 0.4'} - is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} @@ -1174,8 +1185,8 @@ packages: resolution: {integrity: sha512-PlfzajuF9vSo5wErv3MJAKD/nqf9ngAs1NFQYm16nUYFO2IzxJ2hcm+IOCg+EEopdykNNUhVq5cz35cAUxU8+g==} engines: {node: '>= 0.4'} - is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + is-symbol@1.1.0: + resolution: {integrity: sha512-qS8KkNNXUZ/I+nX6QT8ZS1/Yx0A444yhzdTKxCzKkNjQ9sHErBxJnJAgh+f5YhusYECEcjo4XcyH87hn6+ks0A==} engines: {node: '>= 0.4'} is-typed-array@1.1.13: @@ -1248,12 +1259,8 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - - lilconfig@3.1.2: - resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} lines-and-columns@1.2.4: @@ -1273,8 +1280,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lucide-react@0.462.0: - resolution: {integrity: sha512-NTL7EbAao9IFtuSivSZgrAh4fZd09Lr+6MTkqIxuHaH2nnYiYIzXPo06cOxHg9wKLdj6LL8TByG4qpePqwgx/g==} + lucide-react@0.468.0: + resolution: {integrity: sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc @@ -1300,6 +1307,12 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + motion-dom@11.13.0: + resolution: {integrity: sha512-Oc1MLGJQ6nrvXccXA89lXtOqFyBmvHtaDcTRGT66o8Czl7nuA8BeHAd9MQV1pQKX0d2RHFBFaw5g3k23hQJt0w==} + + motion-utils@11.13.0: + resolution: {integrity: sha512-lq6TzXkH5c/ysJQBxgLXgM01qwBH1b4goTPh57VvZWJbVJZF/0SB31UWEn4EIqbVPf3au88n2rvK17SpDTja1A==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1314,16 +1327,16 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@15.0.3: - resolution: {integrity: sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw==} + next@15.0.4: + resolution: {integrity: sha512-nuy8FH6M1FG0lktGotamQDCXhh5hZ19Vo0ht1AOIQWrYJLP598TIUagKtvJrfJ5AGwB/WmDqkKaKhMpVifvGPA==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 '@playwright/test': ^1.41.2 babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-66855b96-20241106 - react-dom: ^18.2.0 || 19.0.0-rc-66855b96-20241106 + react: ^18.2.0 || 19.0.0-rc-66855b96-20241106 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-66855b96-20241106 || ^19.0.0 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': @@ -1335,8 +1348,12 @@ packages: sass: optional: true - node-releases@2.0.18: - resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + nodemailer@6.9.16: + resolution: {integrity: sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==} + engines: {node: '>=6.0.0'} normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -1494,21 +1511,21 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + react-dom@19.0.0: + resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} peerDependencies: - react: ^18.3.1 + react: ^19.0.0 - react-icons@5.3.0: - resolution: {integrity: sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==} + react-icons@5.4.0: + resolution: {integrity: sha512-7eltJxgVt7X64oHh6wSWNwwbKTCtMfK35hcjvJS0yxEAhPM8oUKdS3+kqaW1vicIltw+kR2unHaa12S9pPALoQ==} peerDependencies: react: '*' react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + react@19.0.0: + resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} read-cache@1.0.0: @@ -1518,8 +1535,8 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - reflect.getprototypeof@1.0.7: - resolution: {integrity: sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==} + reflect.getprototypeof@1.0.8: + resolution: {integrity: sha512-B5dj6usc5dkk8uFliwjwDHM8To5/QwdKz9JcBZ8Ic4G1f0YmeeJTtE/ZTdgRFPAfxZFiUaPhZ1Jcs4qeagItGQ==} engines: {node: '>= 0.4'} regexp.prototype.flags@1.5.3: @@ -1556,8 +1573,8 @@ packages: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + scheduler@0.25.0: + resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} @@ -1603,6 +1620,9 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + stable-hash@0.0.4: + resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} + streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -1682,8 +1702,8 @@ packages: tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} - tailwindcss@3.4.15: - resolution: {integrity: sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==} + tailwindcss@3.4.16: + resolution: {integrity: sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==} engines: {node: '>=14.0.0'} hasBin: true @@ -1760,8 +1780,9 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + which-boxed-primitive@1.1.0: + resolution: {integrity: sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng==} + engines: {node: '>= 0.4'} which-builtin-type@1.2.0: resolution: {integrity: sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==} @@ -1823,20 +1844,22 @@ snapshots: '@eslint-community/regexpp@4.12.1': {} - '@eslint/config-array@0.19.0': + '@eslint/config-array@0.19.1': dependencies: - '@eslint/object-schema': 2.1.4 - debug: 4.3.7 + '@eslint/object-schema': 2.1.5 + debug: 4.4.0 minimatch: 3.1.2 transitivePeerDependencies: - supports-color - '@eslint/core@0.9.0': {} + '@eslint/core@0.9.1': + dependencies: + '@types/json-schema': 7.0.15 '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 - debug: 4.3.7 + debug: 4.4.0 espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -1849,9 +1872,9 @@ snapshots: '@eslint/js@9.16.0': {} - '@eslint/object-schema@2.1.4': {} + '@eslint/object-schema@2.1.5': {} - '@eslint/plugin-kit@0.2.3': + '@eslint/plugin-kit@0.2.4': dependencies: levn: 0.4.1 @@ -1864,30 +1887,30 @@ snapshots: '@floating-ui/core': 1.6.8 '@floating-ui/utils': 0.2.8 - '@floating-ui/react-dom@2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react-dom@2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@floating-ui/dom': 1.6.12 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) - '@floating-ui/react@0.26.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react@0.26.28(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@floating-ui/utils': 0.2.8 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) tabbable: 6.2.0 '@floating-ui/utils@0.2.8': {} - '@headlessui/react@2.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@headlessui/react@2.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@floating-ui/react': 0.26.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-aria/focus': 3.19.0(react@18.3.1) - '@react-aria/interactions': 3.22.5(react@18.3.1) - '@tanstack/react-virtual': 3.10.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@floating-ui/react': 0.26.28(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@react-aria/focus': 3.19.0(react@19.0.0) + '@react-aria/interactions': 3.22.5(react@19.0.0) + '@tanstack/react-virtual': 3.11.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) '@humanfs/core@0.19.1': {} @@ -2003,34 +2026,34 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@next/env@15.0.3': {} + '@next/env@15.0.4': {} - '@next/eslint-plugin-next@15.0.3': + '@next/eslint-plugin-next@15.0.4': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.0.3': + '@next/swc-darwin-arm64@15.0.4': optional: true - '@next/swc-darwin-x64@15.0.3': + '@next/swc-darwin-x64@15.0.4': optional: true - '@next/swc-linux-arm64-gnu@15.0.3': + '@next/swc-linux-arm64-gnu@15.0.4': optional: true - '@next/swc-linux-arm64-musl@15.0.3': + '@next/swc-linux-arm64-musl@15.0.4': optional: true - '@next/swc-linux-x64-gnu@15.0.3': + '@next/swc-linux-x64-gnu@15.0.4': optional: true - '@next/swc-linux-x64-musl@15.0.3': + '@next/swc-linux-x64-musl@15.0.4': optional: true - '@next/swc-win32-arm64-msvc@15.0.3': + '@next/swc-win32-arm64-msvc@15.0.4': optional: true - '@next/swc-win32-x64-msvc@15.0.3': + '@next/swc-win32-x64-msvc@15.0.4': optional: true '@nodelib/fs.scandir@2.1.5': @@ -2050,45 +2073,45 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@react-aria/focus@3.19.0(react@18.3.1)': + '@react-aria/focus@3.19.0(react@19.0.0)': dependencies: - '@react-aria/interactions': 3.22.5(react@18.3.1) - '@react-aria/utils': 3.26.0(react@18.3.1) - '@react-types/shared': 3.26.0(react@18.3.1) + '@react-aria/interactions': 3.22.5(react@19.0.0) + '@react-aria/utils': 3.26.0(react@19.0.0) + '@react-types/shared': 3.26.0(react@19.0.0) '@swc/helpers': 0.5.15 clsx: 2.1.1 - react: 18.3.1 + react: 19.0.0 - '@react-aria/interactions@3.22.5(react@18.3.1)': + '@react-aria/interactions@3.22.5(react@19.0.0)': dependencies: - '@react-aria/ssr': 3.9.7(react@18.3.1) - '@react-aria/utils': 3.26.0(react@18.3.1) - '@react-types/shared': 3.26.0(react@18.3.1) + '@react-aria/ssr': 3.9.7(react@19.0.0) + '@react-aria/utils': 3.26.0(react@19.0.0) + '@react-types/shared': 3.26.0(react@19.0.0) '@swc/helpers': 0.5.15 - react: 18.3.1 + react: 19.0.0 - '@react-aria/ssr@3.9.7(react@18.3.1)': + '@react-aria/ssr@3.9.7(react@19.0.0)': dependencies: '@swc/helpers': 0.5.15 - react: 18.3.1 + react: 19.0.0 - '@react-aria/utils@3.26.0(react@18.3.1)': + '@react-aria/utils@3.26.0(react@19.0.0)': dependencies: - '@react-aria/ssr': 3.9.7(react@18.3.1) - '@react-stately/utils': 3.10.5(react@18.3.1) - '@react-types/shared': 3.26.0(react@18.3.1) + '@react-aria/ssr': 3.9.7(react@19.0.0) + '@react-stately/utils': 3.10.5(react@19.0.0) + '@react-types/shared': 3.26.0(react@19.0.0) '@swc/helpers': 0.5.15 clsx: 2.1.1 - react: 18.3.1 + react: 19.0.0 - '@react-stately/utils@3.10.5(react@18.3.1)': + '@react-stately/utils@3.10.5(react@19.0.0)': dependencies: '@swc/helpers': 0.5.15 - react: 18.3.1 + react: 19.0.0 - '@react-types/shared@3.26.0(react@18.3.1)': + '@react-types/shared@3.26.0(react@19.0.0)': dependencies: - react: 18.3.1 + react: 19.0.0 '@rtsao/scc@1.1.0': {} @@ -2104,11 +2127,11 @@ snapshots: dependencies: tslib: 2.8.1 - '@tanstack/react-virtual@3.10.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tanstack/react-virtual@3.11.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@tanstack/virtual-core': 3.10.9 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) '@tanstack/virtual-core@3.10.9': {} @@ -2122,99 +2145,99 @@ snapshots: dependencies: undici-types: 6.20.0 - '@types/prop-types@15.7.13': {} - - '@types/react-dom@18.3.1': + '@types/nodemailer@6.4.17': dependencies: - '@types/react': 18.3.12 + '@types/node': 22.10.1 - '@types/react@18.3.12': + '@types/react-dom@19.0.2(@types/react@19.0.1)': + dependencies: + '@types/react': 19.0.1 + + '@types/react@19.0.1': dependencies: - '@types/prop-types': 15.7.13 csstype: 3.1.3 - '@typescript-eslint/eslint-plugin@8.16.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)': + '@typescript-eslint/eslint-plugin@8.18.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) - '@typescript-eslint/scope-manager': 8.16.0 - '@typescript-eslint/type-utils': 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) - '@typescript-eslint/utils': 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) - '@typescript-eslint/visitor-keys': 8.16.0 + '@typescript-eslint/parser': 8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.18.0 + '@typescript-eslint/type-utils': 8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.18.0 eslint: 9.16.0(jiti@1.21.6) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 ts-api-utils: 1.4.3(typescript@5.7.2) - optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)': + '@typescript-eslint/parser@8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)': dependencies: - '@typescript-eslint/scope-manager': 8.16.0 - '@typescript-eslint/types': 8.16.0 - '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.7.2) - '@typescript-eslint/visitor-keys': 8.16.0 - debug: 4.3.7 + '@typescript-eslint/scope-manager': 8.18.0 + '@typescript-eslint/types': 8.18.0 + '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.18.0 + debug: 4.4.0 eslint: 9.16.0(jiti@1.21.6) - optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.16.0': + '@typescript-eslint/scope-manager@8.18.0': dependencies: - '@typescript-eslint/types': 8.16.0 - '@typescript-eslint/visitor-keys': 8.16.0 + '@typescript-eslint/types': 8.18.0 + '@typescript-eslint/visitor-keys': 8.18.0 - '@typescript-eslint/type-utils@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)': + '@typescript-eslint/type-utils@8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)': dependencies: - '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.7.2) - '@typescript-eslint/utils': 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) - debug: 4.3.7 + '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + debug: 4.4.0 eslint: 9.16.0(jiti@1.21.6) ts-api-utils: 1.4.3(typescript@5.7.2) - optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.16.0': {} + '@typescript-eslint/types@8.18.0': {} - '@typescript-eslint/typescript-estree@8.16.0(typescript@5.7.2)': + '@typescript-eslint/typescript-estree@8.18.0(typescript@5.7.2)': dependencies: - '@typescript-eslint/types': 8.16.0 - '@typescript-eslint/visitor-keys': 8.16.0 - debug: 4.3.7 + '@typescript-eslint/types': 8.18.0 + '@typescript-eslint/visitor-keys': 8.18.0 + debug: 4.4.0 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 ts-api-utils: 1.4.3(typescript@5.7.2) - optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)': + '@typescript-eslint/utils@8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2)': dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@9.16.0(jiti@1.21.6)) - '@typescript-eslint/scope-manager': 8.16.0 - '@typescript-eslint/types': 8.16.0 - '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.18.0 + '@typescript-eslint/types': 8.18.0 + '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) eslint: 9.16.0(jiti@1.21.6) - optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.16.0': + '@typescript-eslint/visitor-keys@8.18.0': dependencies: - '@typescript-eslint/types': 8.16.0 + '@typescript-eslint/types': 8.18.0 eslint-visitor-keys: 4.2.0 + '@upstash/redis@1.34.3': + dependencies: + crypto-js: 4.2.0 + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 @@ -2253,21 +2276,21 @@ snapshots: array-buffer-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-array-buffer: 3.0.4 array-includes@3.1.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.5 is-string: 1.1.0 array.prototype.findlast@1.2.5: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 es-errors: 1.3.0 @@ -2276,7 +2299,7 @@ snapshots: array.prototype.findlastindex@1.2.5: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 es-errors: 1.3.0 @@ -2285,21 +2308,21 @@ snapshots: array.prototype.flat@1.3.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 es-shim-unscopables: 1.0.2 array.prototype.flatmap@1.3.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 es-shim-unscopables: 1.0.2 array.prototype.tosorted@1.1.4: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 es-errors: 1.3.0 @@ -2308,11 +2331,11 @@ snapshots: arraybuffer.prototype.slice@1.0.3: dependencies: array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.5 is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 @@ -2321,7 +2344,7 @@ snapshots: autoprefixer@10.4.20(postcss@8.4.49): dependencies: browserslist: 4.24.2 - caniuse-lite: 1.0.30001685 + caniuse-lite: 1.0.30001687 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -2355,28 +2378,32 @@ snapshots: browserslist@4.24.2: dependencies: - caniuse-lite: 1.0.30001685 - electron-to-chromium: 1.5.67 - node-releases: 2.0.18 + caniuse-lite: 1.0.30001687 + electron-to-chromium: 1.5.72 + node-releases: 2.0.19 update-browserslist-db: 1.1.1(browserslist@4.24.2) busboy@1.6.0: dependencies: streamsearch: 1.1.0 - call-bind@1.0.7: + call-bind-apply-helpers@1.0.1: dependencies: - es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.5 set-function-length: 1.2.2 callsites@3.1.0: {} camelcase-css@2.0.1: {} - caniuse-lite@1.0.30001685: {} + caniuse-lite@1.0.30001687: {} chalk@4.1.2: dependencies: @@ -2427,6 +2454,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + crypto-js@4.2.0: {} + cssesc@3.0.0: {} csstype@3.1.3: {} @@ -2435,19 +2464,19 @@ snapshots: data-view-buffer@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 data-view-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 data-view-byte-offset@1.0.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 @@ -2455,7 +2484,7 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.3.7: + debug@4.4.0: dependencies: ms: 2.1.3 @@ -2463,9 +2492,9 @@ snapshots: define-data-property@1.1.4: dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 - gopd: 1.1.0 + gopd: 1.2.0 define-properties@1.2.1: dependencies: @@ -2484,9 +2513,15 @@ snapshots: dependencies: esutils: 2.0.3 + dunder-proto@1.0.0: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + eastasianwidth@0.2.0: {} - electron-to-chromium@1.5.67: {} + electron-to-chromium@1.5.72: {} emoji-regex@8.0.0: {} @@ -2502,23 +2537,23 @@ snapshots: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 data-view-buffer: 1.0.1 data-view-byte-length: 1.0.1 data-view-byte-offset: 1.0.0 - es-define-property: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-set-tostringtag: 2.0.3 es-to-primitive: 1.3.0 function.prototype.name: 1.1.6 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.5 get-symbol-description: 1.0.2 globalthis: 1.0.4 - gopd: 1.1.0 + gopd: 1.2.0 has-property-descriptors: 1.0.2 - has-proto: 1.1.0 - has-symbols: 1.0.3 + has-proto: 1.2.0 + has-symbols: 1.1.0 hasown: 2.0.2 internal-slot: 1.0.7 is-array-buffer: 3.0.4 @@ -2546,26 +2581,24 @@ snapshots: unbox-primitive: 1.0.2 which-typed-array: 1.1.16 - es-define-property@1.0.0: - dependencies: - get-intrinsic: 1.2.4 + es-define-property@1.0.1: {} es-errors@1.3.0: {} es-iterator-helpers@1.2.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 es-errors: 1.3.0 es-set-tostringtag: 2.0.3 function-bind: 1.1.2 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.5 globalthis: 1.0.4 - gopd: 1.1.0 + gopd: 1.2.0 has-property-descriptors: 1.0.2 - has-proto: 1.1.0 - has-symbols: 1.0.3 + has-proto: 1.2.0 + has-symbols: 1.1.0 internal-slot: 1.0.7 iterator.prototype: 1.1.3 safe-array-concat: 1.1.2 @@ -2576,7 +2609,7 @@ snapshots: es-set-tostringtag@2.0.3: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.5 has-tostringtag: 1.0.2 hasown: 2.0.2 @@ -2588,25 +2621,25 @@ snapshots: dependencies: is-callable: 1.2.7 is-date-object: 1.0.5 - is-symbol: 1.0.4 + is-symbol: 1.1.0 escalade@3.2.0: {} escape-string-regexp@4.0.0: {} - eslint-config-next@15.0.3(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2): + eslint-config-next@15.0.4(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2): dependencies: - '@next/eslint-plugin-next': 15.0.3 + '@next/eslint-plugin-next': 15.0.4 '@rushstack/eslint-patch': 1.10.4 - '@typescript-eslint/eslint-plugin': 8.16.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) - '@typescript-eslint/parser': 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + '@typescript-eslint/eslint-plugin': 8.18.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + '@typescript-eslint/parser': 8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) eslint: 9.16.0(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@9.16.0(jiti@1.21.6)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.16.0(jiti@1.21.6)) eslint-plugin-react: 7.37.2(eslint@9.16.0(jiti@1.21.6)) - eslint-plugin-react-hooks: 5.0.0(eslint@9.16.0(jiti@1.21.6)) + eslint-plugin-react-hooks: 5.1.0(eslint@9.16.0(jiti@1.21.6)) optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: @@ -2622,37 +2655,34 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)): + eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)): dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.3.7 + debug: 4.4.0 enhanced-resolve: 5.17.1 eslint: 9.16.0(jiti@1.21.6) - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.3.0 is-glob: 4.0.3 + stable-hash: 0.0.4 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@9.16.0(jiti@1.21.6)) transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-node - - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.16.0(jiti@1.21.6)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + '@typescript-eslint/parser': 8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) eslint: 9.16.0(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@1.21.6)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@9.16.0(jiti@1.21.6)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -2663,7 +2693,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.16.0(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.16.0(jiti@1.21.6)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.16.0(jiti@1.21.6)) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -2675,7 +2705,7 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.16.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + '@typescript-eslint/parser': 8.18.0(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -2700,7 +2730,7 @@ snapshots: safe-regex-test: 1.0.3 string.prototype.includes: 2.0.1 - eslint-plugin-react-hooks@5.0.0(eslint@9.16.0(jiti@1.21.6)): + eslint-plugin-react-hooks@5.1.0(eslint@9.16.0(jiti@1.21.6)): dependencies: eslint: 9.16.0(jiti@1.21.6) @@ -2739,11 +2769,11 @@ snapshots: dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@9.16.0(jiti@1.21.6)) '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.19.0 - '@eslint/core': 0.9.0 + '@eslint/config-array': 0.19.1 + '@eslint/core': 0.9.1 '@eslint/eslintrc': 3.2.0 '@eslint/js': 9.16.0 - '@eslint/plugin-kit': 0.2.3 + '@eslint/plugin-kit': 0.2.4 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.1 @@ -2752,7 +2782,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.3.7 + debug: 4.4.0 escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 eslint-visitor-keys: 4.2.0 @@ -2851,13 +2881,15 @@ snapshots: fraction.js@4.3.7: {} - framer-motion@11.12.0(@emotion/is-prop-valid@1.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + framer-motion@11.13.3(@emotion/is-prop-valid@1.3.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: + motion-dom: 11.13.0 + motion-utils: 11.13.0 tslib: 2.8.1 optionalDependencies: '@emotion/is-prop-valid': 1.3.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) fsevents@2.3.3: optional: true @@ -2866,26 +2898,29 @@ snapshots: function.prototype.name@1.1.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 functions-have-names: 1.2.3 functions-have-names@1.2.3: {} - get-intrinsic@1.2.4: + get-intrinsic@1.2.5: dependencies: + call-bind-apply-helpers: 1.0.1 + dunder-proto: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 function-bind: 1.1.2 - has-proto: 1.1.0 - has-symbols: 1.0.3 + gopd: 1.2.0 + has-symbols: 1.1.0 hasown: 2.0.2 get-symbol-description@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.5 get-tsconfig@4.8.1: dependencies: @@ -2913,11 +2948,9 @@ snapshots: globalthis@1.0.4: dependencies: define-properties: 1.2.1 - gopd: 1.1.0 + gopd: 1.2.0 - gopd@1.1.0: - dependencies: - get-intrinsic: 1.2.4 + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -2929,17 +2962,17 @@ snapshots: has-property-descriptors@1.0.2: dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 - has-proto@1.1.0: + has-proto@1.2.0: dependencies: - call-bind: 1.0.7 + dunder-proto: 1.0.0 - has-symbols@1.0.3: {} + has-symbols@1.1.0: {} has-tostringtag@1.0.2: dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 hasown@2.0.2: dependencies: @@ -2962,8 +2995,8 @@ snapshots: is-array-buffer@3.0.4: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bind: 1.0.8 + get-intrinsic: 1.2.5 is-arrayish@0.3.2: optional: true @@ -2972,7 +3005,7 @@ snapshots: dependencies: has-tostringtag: 1.0.2 - is-bigint@1.0.4: + is-bigint@1.1.0: dependencies: has-bigints: 1.0.2 @@ -2982,7 +3015,7 @@ snapshots: is-boolean-object@1.2.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-tostringtag: 1.0.2 is-bun-module@1.3.0: @@ -3007,7 +3040,7 @@ snapshots: is-finalizationregistry@1.1.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-fullwidth-code-point@3.0.0: {} @@ -3025,15 +3058,15 @@ snapshots: is-number-object@1.1.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-tostringtag: 1.0.2 is-number@7.0.0: {} is-regex@1.2.0: dependencies: - call-bind: 1.0.7 - gopd: 1.1.0 + call-bind: 1.0.8 + gopd: 1.2.0 has-tostringtag: 1.0.2 hasown: 2.0.2 @@ -3041,16 +3074,18 @@ snapshots: is-shared-array-buffer@1.0.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-string@1.1.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-tostringtag: 1.0.2 - is-symbol@1.0.4: + is-symbol@1.1.0: dependencies: - has-symbols: 1.0.3 + call-bind: 1.0.8 + has-symbols: 1.1.0 + safe-regex-test: 1.0.3 is-typed-array@1.1.13: dependencies: @@ -3060,12 +3095,12 @@ snapshots: is-weakref@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-weakset@2.0.3: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bind: 1.0.8 + get-intrinsic: 1.2.5 isarray@2.0.5: {} @@ -3074,9 +3109,9 @@ snapshots: iterator.prototype@1.1.3: dependencies: define-properties: 1.2.1 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.7 + get-intrinsic: 1.2.5 + has-symbols: 1.1.0 + reflect.getprototypeof: 1.0.8 set-function-name: 2.0.2 jackspeak@3.4.3: @@ -3125,9 +3160,7 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lilconfig@2.1.0: {} - - lilconfig@3.1.2: {} + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -3143,9 +3176,9 @@ snapshots: lru-cache@10.4.3: {} - lucide-react@0.462.0(react@18.3.1): + lucide-react@0.468.0(react@19.0.0): dependencies: - react: 18.3.1 + react: 19.0.0 merge2@1.4.1: {} @@ -3166,6 +3199,10 @@ snapshots: minipass@7.1.2: {} + motion-dom@11.13.0: {} + + motion-utils@11.13.0: {} + ms@2.1.3: {} mz@2.7.0: @@ -3178,32 +3215,34 @@ snapshots: natural-compare@1.4.0: {} - next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@15.0.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: - '@next/env': 15.0.3 + '@next/env': 15.0.4 '@swc/counter': 0.1.3 '@swc/helpers': 0.5.13 busboy: 1.6.0 - caniuse-lite: 1.0.30001685 + caniuse-lite: 1.0.30001687 postcss: 8.4.31 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.6(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + styled-jsx: 5.1.6(react@19.0.0) optionalDependencies: - '@next/swc-darwin-arm64': 15.0.3 - '@next/swc-darwin-x64': 15.0.3 - '@next/swc-linux-arm64-gnu': 15.0.3 - '@next/swc-linux-arm64-musl': 15.0.3 - '@next/swc-linux-x64-gnu': 15.0.3 - '@next/swc-linux-x64-musl': 15.0.3 - '@next/swc-win32-arm64-msvc': 15.0.3 - '@next/swc-win32-x64-msvc': 15.0.3 + '@next/swc-darwin-arm64': 15.0.4 + '@next/swc-darwin-x64': 15.0.4 + '@next/swc-linux-arm64-gnu': 15.0.4 + '@next/swc-linux-arm64-musl': 15.0.4 + '@next/swc-linux-x64-gnu': 15.0.4 + '@next/swc-linux-x64-musl': 15.0.4 + '@next/swc-win32-arm64-msvc': 15.0.4 + '@next/swc-win32-x64-msvc': 15.0.4 sharp: 0.33.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - node-releases@2.0.18: {} + node-releases@2.0.19: {} + + nodemailer@6.9.16: {} normalize-path@3.0.0: {} @@ -3219,33 +3258,33 @@ snapshots: object.assign@4.1.5: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - has-symbols: 1.0.3 + has-symbols: 1.1.0 object-keys: 1.1.1 object.entries@1.1.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-object-atoms: 1.0.0 object.fromentries@2.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 es-object-atoms: 1.0.0 object.groupby@1.0.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 object.values@1.2.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-object-atoms: 1.0.0 @@ -3307,7 +3346,7 @@ snapshots: postcss-load-config@4.0.2(postcss@8.4.49): dependencies: - lilconfig: 3.1.2 + lilconfig: 3.1.3 yaml: 2.6.1 optionalDependencies: postcss: 8.4.49 @@ -3348,21 +3387,18 @@ snapshots: queue-microtask@1.2.3: {} - react-dom@18.3.1(react@18.3.1): + react-dom@19.0.0(react@19.0.0): dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 + react: 19.0.0 + scheduler: 0.25.0 - react-icons@5.3.0(react@18.3.1): + react-icons@5.4.0(react@19.0.0): dependencies: - react: 18.3.1 + react: 19.0.0 react-is@16.13.1: {} - react@18.3.1: - dependencies: - loose-envify: 1.4.0 + react@19.0.0: {} read-cache@1.0.0: dependencies: @@ -3372,19 +3408,20 @@ snapshots: dependencies: picomatch: 2.3.1 - reflect.getprototypeof@1.0.7: + reflect.getprototypeof@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 + dunder-proto: 1.0.0 es-abstract: 1.23.5 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - gopd: 1.1.0 + get-intrinsic: 1.2.5 + gopd: 1.2.0 which-builtin-type: 1.2.0 regexp.prototype.flags@1.5.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 @@ -3413,20 +3450,18 @@ snapshots: safe-array-concat@1.1.2: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 + call-bind: 1.0.8 + get-intrinsic: 1.2.5 + has-symbols: 1.1.0 isarray: 2.0.5 safe-regex-test@1.0.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-regex: 1.2.0 - scheduler@0.23.2: - dependencies: - loose-envify: 1.4.0 + scheduler@0.25.0: {} semver@6.3.1: {} @@ -3437,8 +3472,8 @@ snapshots: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.1.0 + get-intrinsic: 1.2.5 + gopd: 1.2.0 has-property-descriptors: 1.0.2 set-function-name@2.0.2: @@ -3483,9 +3518,9 @@ snapshots: side-channel@1.0.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.5 object-inspect: 1.13.3 signal-exit@4.1.0: {} @@ -3497,6 +3532,8 @@ snapshots: source-map-js@1.2.1: {} + stable-hash@0.0.4: {} + streamsearch@1.1.0: {} string-width@4.2.3: @@ -3513,20 +3550,20 @@ snapshots: string.prototype.includes@2.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 string.prototype.matchall@4.0.11: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 es-errors: 1.3.0 es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 - gopd: 1.1.0 - has-symbols: 1.0.3 + get-intrinsic: 1.2.5 + gopd: 1.2.0 + has-symbols: 1.1.0 internal-slot: 1.0.7 regexp.prototype.flags: 1.5.3 set-function-name: 2.0.2 @@ -3539,20 +3576,20 @@ snapshots: string.prototype.trim@1.2.9: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.5 es-object-atoms: 1.0.0 string.prototype.trimend@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-object-atoms: 1.0.0 string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-object-atoms: 1.0.0 @@ -3568,10 +3605,10 @@ snapshots: strip-json-comments@3.1.1: {} - styled-jsx@5.1.6(react@18.3.1): + styled-jsx@5.1.6(react@19.0.0): dependencies: client-only: 0.0.1 - react: 18.3.1 + react: 19.0.0 sucrase@3.35.0: dependencies: @@ -3591,7 +3628,7 @@ snapshots: tabbable@6.2.0: {} - tailwindcss@3.4.15: + tailwindcss@3.4.16: dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -3602,7 +3639,7 @@ snapshots: glob-parent: 6.0.2 is-glob: 4.0.3 jiti: 1.21.6 - lilconfig: 2.1.0 + lilconfig: 3.1.3 micromatch: 4.0.8 normalize-path: 3.0.0 object-hash: 3.0.0 @@ -3653,45 +3690,45 @@ snapshots: typed-array-buffer@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-typed-array: 1.1.13 typed-array-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.1.0 - has-proto: 1.1.0 + gopd: 1.2.0 + has-proto: 1.2.0 is-typed-array: 1.1.13 typed-array-byte-offset@1.0.3: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.1.0 - has-proto: 1.1.0 + gopd: 1.2.0 + has-proto: 1.2.0 is-typed-array: 1.1.13 - reflect.getprototypeof: 1.0.7 + reflect.getprototypeof: 1.0.8 typed-array-length@1.0.7: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.1.0 + gopd: 1.2.0 is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - reflect.getprototypeof: 1.0.7 + reflect.getprototypeof: 1.0.8 typescript@5.7.2: {} unbox-primitive@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.0 undici-types@6.20.0: {} @@ -3707,17 +3744,17 @@ snapshots: util-deprecate@1.0.2: {} - which-boxed-primitive@1.0.2: + which-boxed-primitive@1.1.0: dependencies: - is-bigint: 1.0.4 + is-bigint: 1.1.0 is-boolean-object: 1.2.0 is-number-object: 1.1.0 is-string: 1.1.0 - is-symbol: 1.0.4 + is-symbol: 1.1.0 which-builtin-type@1.2.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 function.prototype.name: 1.1.6 has-tostringtag: 1.0.2 is-async-function: 2.0.0 @@ -3727,7 +3764,7 @@ snapshots: is-regex: 1.2.0 is-weakref: 1.0.2 isarray: 2.0.5 - which-boxed-primitive: 1.0.2 + which-boxed-primitive: 1.1.0 which-collection: 1.0.2 which-typed-array: 1.1.16 @@ -3741,9 +3778,9 @@ snapshots: which-typed-array@1.1.16: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.1.0 + gopd: 1.2.0 has-tostringtag: 1.0.2 which@2.0.2: diff --git a/src/app/api/contact/route.ts b/src/app/api/contact/route.ts new file mode 100644 index 0000000..404cda8 --- /dev/null +++ b/src/app/api/contact/route.ts @@ -0,0 +1,119 @@ +import { NextResponse } from 'next/server' +import nodemailer from 'nodemailer' +import { rateLimit } from '@/lib/rate-limit' + +interface FormData { + name: string + email: string + service: string + message: string +} + +const validateEmail = (email: string): boolean => { + const pattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ + return pattern.test(email) +} + +const validateInput = (data: FormData): { isValid: boolean; error?: string } => { + if (!data.name || data.name.length < 2 || data.name.length > 50) { + return { isValid: false, error: 'Invalid name length' } + } + + if (!data.email || !validateEmail(data.email)) { + return { isValid: false, error: 'Invalid email format' } + } + + if (!data.service) { + return { isValid: false, error: 'Service selection required' } + } + + if (!data.message || data.message.length < 10 || data.message.length > 1000) { + return { isValid: false, error: 'Invalid message length' } + } + + return { isValid: true } +} + +const sanitizeInput = (input: string): string => { + return input + .trim() + .replace(/[<>]/g, '') // Basic XSS prevention + .slice(0, 1000) // Length limitation +} + +export async function POST(req: Request) { + try { + // Rate limiting check + const rateLimitResult = await rateLimit() + if (!rateLimitResult.success) { + return NextResponse.json( + { success: false, message: 'Too many requests. Please try again later.' }, + { status: 429 } + ) + } + + const data: FormData = await req.json() + + // Input validation + const validation = validateInput(data) + if (!validation.isValid) { + return NextResponse.json( + { success: false, message: validation.error }, + { status: 400 } + ) + } + + // Sanitize inputs + const sanitizedData = { + name: sanitizeInput(data.name), + email: sanitizeInput(data.email), + service: sanitizeInput(data.service), + message: sanitizeInput(data.message) + } + + const transporter = nodemailer.createTransport({ + host: process.env.SMTP_HOST, + port: Number(process.env.SMTP_PORT), + secure: process.env.SMTP_SECURE === 'true', + auth: { + user: process.env.GOOGLE_EMAIL, + pass: process.env.GOOGLE_APP_PASSWORD, + }, + }) + + const mailOptions = { + from: { + name: 'NO REPLY', + address: process.env.GOOGLE_EMAIL! + }, + to: process.env.RECIPIENT_EMAIL!, + subject: `New Contact Form Submission - ${sanitizedData.service}`, + html: ` +
+

New Contact Form Submission

+
+

Name: ${sanitizedData.name}

+

Email: ${sanitizedData.email}

+

Service: ${sanitizedData.service}

+

Message:

+

${sanitizedData.message}

+
+
+ `, + } + + await transporter.sendMail(mailOptions) + + return NextResponse.json({ + success: true, + message: 'Email sent successfully' + }) + + } catch (error) { + console.error('Error sending email:', error) + return NextResponse.json( + { success: false, message: 'Failed to send email' }, + { status: 500 } + ) + } +} diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx index 1899ecb..bd2e8be 100644 --- a/src/app/contact/page.tsx +++ b/src/app/contact/page.tsx @@ -1,4 +1,106 @@ +'use client' + +import { useState, useEffect } from 'react' +import { useNotification } from '@/components/providers/notification-provider' + export default function ContactPage() { + const { showNotification } = useNotification() + const [mounted, setMounted] = useState(false) + const [isSubmitting, setIsSubmitting] = useState(false) + const [formData, setFormData] = useState({ + name: '', + email: '', + service: '', + message: '' + }) + + const [errors, setErrors] = useState({ + name: '', + email: '', + service: '', + message: '' + }) + + useEffect(() => { + setMounted(true) + }, []) + + const validateField = (name: string, value: string) => { + switch (name) { + case 'name': + return value.length < 2 || value.length > 50 + ? 'Name must be between 2 and 50 characters' + : '' + case 'email': + return !/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value) + ? 'Please enter a valid email address' + : '' + case 'service': + return !value ? 'Please select a service' : '' + case 'message': + return value.length < 10 + ? 'Message must be at least 10 characters long' + : value.length > 1000 + ? 'Message must not exceed 1000 characters' + : '' + default: + return '' + } + } + + const handleChange = ( + e: React.ChangeEvent + ) => { + const { name, value } = e.target + setFormData(prev => ({ ...prev, [name]: value })) + setErrors(prev => ({ ...prev, [name]: validateField(name, value) })) + } + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + + const newErrors = { + name: validateField('name', formData.name), + email: validateField('email', formData.email), + service: validateField('service', formData.service), + message: validateField('message', formData.message) + } + + setErrors(newErrors) + + if (Object.values(newErrors).some(error => error)) { + showNotification('Please correct the errors before submitting.', 'error') + return + } + + setIsSubmitting(true) + + try { + const response = await fetch('/api/contact', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(formData) + }) + + const data = await response.json() + + if (data.success) { + showNotification('Message sent successfully!', 'success') + setFormData({ name: '', email: '', service: '', message: '' }) + } else { + showNotification(data.message || 'Failed to send message.', 'error') + } + } catch (error) { + showNotification('An error occurred. Please try again.', 'error') + } finally { + setIsSubmitting(false) + } + } + + if (!mounted) { + return null + } + return (
@@ -12,7 +114,7 @@ export default function ContactPage() {
-
+
+
+ +
+ + + {errors.service && ( +

{errors.service}

+ )} +
+
+
@@ -64,5 +218,5 @@ export default function ContactPage() {
- ); + ) } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b589c19..db0e326 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next"; import { Playfair_Display, Inter } from "next/font/google"; import Header from '../components/layout/Header'; import Footer from '../components/layout/Footer'; +import { NotificationProvider } from '../components/providers/notification-provider'; import '../styles/globals.css'; const playfair = Playfair_Display({ @@ -40,12 +41,14 @@ export default function RootLayout({ return ( -
-
- {children} -
-