diff --git a/package.json b/package.json index eca4a07..7468df3 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "framer-motion": "^10.16.4", "graphql": "^16.8.1", "mdi-react": "^9.3.0", - "next": "^14.1.3", + "next": "^14.2.3", "polished": "^4.2.2", "prop-types": "^15.8.1", "rc-notification": "^5.3.0", diff --git a/src/app/(auth)/login/_components/LogInForm.tsx b/src/app/(auth)/login/_components/LogInForm.tsx index 6b936f4..ea89e11 100644 --- a/src/app/(auth)/login/_components/LogInForm.tsx +++ b/src/app/(auth)/login/_components/LogInForm.tsx @@ -95,7 +95,7 @@ const LogInForm = ({ onSubmit, error = '' }: LogInFormProps) => { defaultValue="" /> - Forgot a password? + Forgot a password? diff --git a/src/app/(auth)/resetpasswor/_components/form.test.tsx b/src/app/(auth)/resetpasswor/_components/form.test.tsx new file mode 100644 index 0000000..54fa3c9 --- /dev/null +++ b/src/app/(auth)/resetpasswor/_components/form.test.tsx @@ -0,0 +1,142 @@ +import { act } from 'react-dom/test-utils'; +import { screen, render, fireEvent } from '@testing-library/react'; +import { MemoryRouter as Router } from 'react-router-dom'; +import ResetPasswordForm from './form'; + +interface PasswordFieldProps { + input: { + name: string; + value: string; + onChange: (event: React.ChangeEvent) => void; + }; + meta: { + touched: boolean; + error?: string; + }; + placeholder: string; + keyIcon: boolean; +} + +jest.mock('@/shared/components/form/Password', () => { + const PasswordFieldMock: React.FC = ({ + input, + meta, + placeholder, + keyIcon, + }) => ( +
+ + + {meta.touched && meta.error && {meta.error}} +
Mocked Eye Icon
+
+ ); + + return { + __esModule: true, + default: PasswordFieldMock, + }; +}); + +describe('ResetPasswordForm', () => { + const mockOnSuccess = jest.fn(); + + it('should render the form and show password fields', () => { + render( + + + + ); + + const passwordInput = screen.getByPlaceholderText('Password'); + const confirmPasswordInput = screen.getByPlaceholderText('Confirm Password'); + + expect(passwordInput).toBeInTheDocument(); + expect(confirmPasswordInput).toBeInTheDocument(); + }); + + it('should allow user to enter and confirm password', async () => { + render( + + + + ); + + const passwordInput = screen.getByPlaceholderText('Password'); + const confirmPasswordInput = screen.getByPlaceholderText('Confirm Password'); + + fireEvent.change(passwordInput, { target: { value: 'Password@123' } }); + fireEvent.change(confirmPasswordInput, { target: { value: 'Password@123' } }); + + expect(passwordInput).toHaveValue('Password@123'); + expect(confirmPasswordInput).toHaveValue('Password@123'); + }); + + it('should show error if passwords do not match', async () => { + render( + + + + ); + + const passwordInput = screen.getByPlaceholderText('Password'); + const confirmPasswordInput = screen.getByPlaceholderText('Confirm Password'); + const submitButton = screen.getByRole('button', { name: 'Submit' }); + + await act(async () => { + fireEvent.change(passwordInput, { target: { value: 'Password@123' } }); + fireEvent.change(confirmPasswordInput, { target: { value: 'DifferentPassword@123' } }); + fireEvent.click(submitButton); + }); + + const alert = screen.queryByText(/Passwords must match/i); + expect(alert).toBeInTheDocument(); + }); + + it('should not call onSuccess if the passwords do not match', async () => { + render( + + + + ); + + const passwordInput = screen.getByPlaceholderText('Password'); + const confirmPasswordInput = screen.getByPlaceholderText('Confirm Password'); + const submitButton = screen.getByRole('button', { name: 'Submit' }); + + await act(async () => { + fireEvent.change(passwordInput, { target: { value: 'Password@123' } }); + fireEvent.change(confirmPasswordInput, { target: { value: 'DifferentPassword@123' } }); + fireEvent.click(submitButton); + }); + + expect(mockOnSuccess).not.toHaveBeenCalled(); + }); + + it('should call onSuccess if the passwords match', async () => { + render( + + + + ); + + const passwordInput = screen.getByPlaceholderText('Password'); + const confirmPasswordInput = screen.getByPlaceholderText('Confirm Password'); + const submitButton = screen.getByRole('button', { name: 'Submit' }); + + await act(async () => { + fireEvent.change(passwordInput, { target: { value: 'Password@123' } }); + fireEvent.change(confirmPasswordInput, { target: { value: 'Password@123' } }); + fireEvent.click(submitButton); + }); + + expect(mockOnSuccess).toHaveBeenCalled(); + }); +}); diff --git a/src/app/(auth)/resetpasswor/_components/form.tsx b/src/app/(auth)/resetpasswor/_components/form.tsx new file mode 100644 index 0000000..1f3ed3e --- /dev/null +++ b/src/app/(auth)/resetpasswor/_components/form.tsx @@ -0,0 +1,103 @@ +import { passwordPatten } from '@/shared/utils/helpers'; +import PasswordField from '@/shared/components/form/Password'; +import { useForm, Controller, SubmitHandler } from 'react-hook-form'; +import { FormGroup, FormGroupField, FormGroupLabel } from '@/shared/components/form/FormElements'; +import { AccountButton } from '@/shared/components/account/AccountElements'; +import Link from 'next/link'; + +interface FormValues { + password: string; + confirmPassword: string; +} + +interface ResetPasswordFormProps { + onSuccess: () => void; +} + +const ResetPasswordForm: React.FC = ({ onSuccess }) => { + const { handleSubmit, control, watch } = useForm({ + mode: 'onSubmit', + }); + + const onSubmit: SubmitHandler = (data) => { + if (data.password !== data.confirmPassword) { + alert('Passwords do not match.'); + return; + } + onSuccess(); + }; + + return ( +
+ + Password + + ( + + )} + defaultValue="" + /> + + + + Confirm Password + + { + const { password } = watch(); + return password === value || 'Passwords must match'; + }, + }, + }} + render={({ field, fieldState }) => ( + + )} + defaultValue="" + /> + + + + Submit + + + Back to Login + +
+ ); +}; + +export default ResetPasswordForm; diff --git a/src/app/(auth)/resetpasswor/_components/success.test.tsx b/src/app/(auth)/resetpasswor/_components/success.test.tsx new file mode 100644 index 0000000..4cfbae4 --- /dev/null +++ b/src/app/(auth)/resetpasswor/_components/success.test.tsx @@ -0,0 +1,34 @@ +import { render, screen } from '@testing-library/react'; +import ResetPasswordSuccess from '../_components/success'; +import React, { ReactNode } from 'react'; + +jest.mock('styled-theming', () => ({ + theme: jest.fn().mockImplementation((_, values) => values.mode), +})); + +jest.mock('@/shared/components/account/AccountElements', () => ({ + AccountContent: ({ children }: { children: ReactNode }) =>
{children}
, + AccountHead: ({ children }: { children: ReactNode }) =>
{children}
, + AccountLogo: ({ children }: { children: ReactNode }) =>
{children}
, + AccountLogoAccent: ({ children }: { children: ReactNode }) => ( +
{children}
+ ), + AccountTitle: ({ children }: { children: ReactNode }) =>
{children}
, + AccountButton: ({ children, ...props }: { children: ReactNode }) => ( + + ), +})); + +jest.mock('next/link', () => { + return ({ children, ...props }: { children: ReactNode }) => {children}; +}); + +describe('PasswordResetSuccess', () => { + it('navigates back to login on button click', () => { + render(); + + // Find the link by text and check its href attribute + const backButtonLink = screen.getByRole('link', { name: /back to login/i }); + expect(backButtonLink).toHaveAttribute('href', '/login'); + }); +}); diff --git a/src/app/(auth)/resetpasswor/_components/success.tsx b/src/app/(auth)/resetpasswor/_components/success.tsx new file mode 100644 index 0000000..d1fda14 --- /dev/null +++ b/src/app/(auth)/resetpasswor/_components/success.tsx @@ -0,0 +1,36 @@ +import { + AccountContent, + AccountHead, + AccountLogo, + AccountLogoAccent, + AccountTitle, + AccountButton, +} from '@/shared/components/account/AccountElements'; +import successImage from '@/shared/img/success.png'; +import Link from 'next/link'; + +const ResetPasswordSuccess = () => { + return ( +
+ Success +
+ + + + + Cool! + +
+ Your password has been reset +
+
+
+ + + Back to Login + +
+ ); +}; + +export default ResetPasswordSuccess; diff --git a/src/app/(auth)/resetpasswor/page.test.tsx b/src/app/(auth)/resetpasswor/page.test.tsx new file mode 100644 index 0000000..0267e48 --- /dev/null +++ b/src/app/(auth)/resetpasswor/page.test.tsx @@ -0,0 +1,116 @@ +import { act } from 'react-dom/test-utils'; +import { screen, render, fireEvent } from '@testing-library/react'; +import { BrowserRouter as Router } from 'react-router-dom'; +import ResetPasswordInitiationPage from './page'; + +interface IconProps { + className?: string; +} + +jest.mock('mdi-react/TrendingUpIcon', () => { + return { + __esModule: true, + default: ({ className }: IconProps) =>
Mocked Trending Up Icon
, + }; +}); + +jest.mock('mdi-react/TrendingDownIcon', () => { + return { + __esModule: true, + default: ({ className }: IconProps) => ( +
Mocked Trending Down Icon
+ ), + }; +}); + +jest.mock('mdi-react/AccountOutlineIcon', () => { + return { + __esModule: true, + default: () =>
Mocked Account Outline Icon
, + }; +}); + +jest.mock('./_components/form', () => ({ + __esModule: true, + default: ({ onSuccess }: { onSuccess: () => void }) => ( +
+ Mocked Reset Password Form + +
+ ), +})); + +jest.mock('./_components/success', () => ({ + __esModule: true, + default: () =>
Mocked Reset Password Success
, +})); + +describe('ResetPasswordInitiationPage', () => { + it('should render the page and show the correct title', async () => { + render( + + + + ); + + const title = screen.getByText(/Enter Your Email/i); + expect(title).toBeInTheDocument(); + }); + + it('should allow user to enter email', async () => { + render( + + + + ); + const input = screen.getByPlaceholderText('Email'); + + await act(async () => { + fireEvent.change(input, { target: { value: 'user@example.com' } }); + }); + expect(screen.getByDisplayValue('user@example.com')).toBeInTheDocument(); + }); + + it('should navigate to the reset password form page on submit', async () => { + render( + + + + ); + + const input = screen.getByPlaceholderText('Email'); + const button = screen.getByRole('button', { name: 'Submit' }); + + await act(async () => { + fireEvent.change(input, { target: { value: 'user@example.com' } }); + fireEvent.click(button); + }); + + const form = screen.getByText('Mocked Reset Password Form'); + expect(form).toBeInTheDocument(); + }); + + it('should navigate to the success page after form submission', async () => { + render( + + + + ); + + const input = screen.getByPlaceholderText('Email'); + const button = screen.getByRole('button', { name: 'Submit' }); + + await act(async () => { + fireEvent.change(input, { target: { value: 'user@example.com' } }); + fireEvent.click(button); + }); + + const formButton = screen.getByText('Mock Submit'); + await act(async () => { + fireEvent.click(formButton); + }); + + const successMessage = screen.getByText('Mocked Reset Password Success'); + expect(successMessage).toBeInTheDocument(); + }); +}); diff --git a/src/app/(auth)/resetpasswor/page.tsx b/src/app/(auth)/resetpasswor/page.tsx new file mode 100644 index 0000000..25362ed --- /dev/null +++ b/src/app/(auth)/resetpasswor/page.tsx @@ -0,0 +1,119 @@ +'use client'; + +import { useState, Suspense } from 'react'; +import { + AccountWrap, + AccountContent, + AccountCard, + AccountHead, + AccountLogo, + AccountLogoAccent, + AccountTitle, + AccountButton, +} from '@/shared/components/account/AccountElements'; +import { + FormGroup, + FormGroupField, + FormGroupIcon, + FormGroupLabel, +} from '@/shared/components/form/FormElements'; +import AccountOutlineIcon from 'mdi-react/AccountOutlineIcon'; +import FormField from '@/shared/components/form/FormHookField'; +import { useForm } from 'react-hook-form'; +import { emailPattern } from '@/shared/utils/helpers'; +import { EMAIL } from '@/shared/constants/storage'; +import Link from 'next/link'; +import dynamic from 'next/dynamic'; + +const ResetPasswordForm = dynamic(() => import('./_components/form'), { ssr: false }); +const ResetPasswordSuccess = dynamic(() => import('./_components/success'), { ssr: false }); + +interface FormData { + email: string; +} + +const ResetPasswordInitiationPage = () => { + const [showEmailHint, setShowEmailHint] = useState(false); + const [step, setStep] = useState('init'); // 使用状态控制显示的步骤 + const { + control, + formState: { errors }, + handleSubmit, + } = useForm(); + + const onSubmit = (data: FormData) => { + setStep('form'); + }; + + return ( + + + + {step !== 'success' && ( + + + {step === 'init' ? 'Enter Your Email' : 'Reset Password'} +
+ + BeeQuant + AI + +
+

Trading smart, trading with BeeQuant AI

+
+ )} + {step === 'init' ? ( +
+ + Email + + + + + setShowEmailHint(true)} + onBlur={() => setShowEmailHint(false)} + /> + {showEmailHint && ( +
Please enter a valid email address.
+ )} +
+
+ + Submit + + + + Back to Login + +
+ ) : step === 'form' ? ( + Loading...}> + setStep('success')} /> + + ) : ( + Loading...}> + + + )} +
+
+
+ ); +}; + +export default ResetPasswordInitiationPage; diff --git a/src/graphql/auth.ts b/src/graphql/auth.ts index d874837..a67147d 100644 --- a/src/graphql/auth.ts +++ b/src/graphql/auth.ts @@ -19,3 +19,13 @@ export const USER_REGISTER = gql` } } `; + +export const USER_RESETPASSWOR = gql` + mutation Resetpasswor($input: CreateUserInput!) { + resetpasswor(input: $input) { + code + message + data + } + } +`; diff --git a/src/routes/routeConfig.ts b/src/routes/routeConfig.ts index 11968d1..e947641 100644 --- a/src/routes/routeConfig.ts +++ b/src/routes/routeConfig.ts @@ -13,6 +13,9 @@ import ExchangeDetails from 'app/(protected)/crypto/exchange/details/page'; import PriceDetails from 'app/(protected)/crypto/price/details/page'; import BotDetail from 'app/(protected)/bot/details/page'; import BotCreate from 'app/(protected)/bot/create/page'; +import ResetPassword from 'app/(auth)/resetpasswor/page'; +import ResetPasswordForm from 'app/(auth)/resetpasswor/_components/form'; +import PasswordResetSuccess from 'app/(auth)/resetpasswor/_components/success'; interface IRoute { path: string; @@ -30,6 +33,9 @@ export const ROUTE_KEY = { LOGIN: 'login', REGISTER: 'register', SETTINGS: 'settings', + RESET_PASSWORD: 'resetpasswor', + RESET_PASSWORD_FORM: 'reset_password_form', + PASSWORD_RESET_SUCCESS: 'password_reset_success', BOT_DASHBOARD: 'bot_dashboard', BOT_MANAGEMENT: 'bot_management', BOT_CREATE: 'bot_create', @@ -53,6 +59,28 @@ export const PUBLIC_ROUTE_CONFIG: Record = { title: 'Register - BeeQuant', component: Register, }, + + [ROUTE_KEY.RESET_PASSWORD]: { + path: '/resetpasswor', + name: 'resetpasswor', + title: 'Register - BeeQuant', + component: ResetPassword, + }, + + [ROUTE_KEY.RESET_PASSWORD_FORM]: { + path: '/resetpasswor/form', + name: 'Reset Password Form', + title: 'Enter New Password - BeeQuant', + component: ResetPasswordForm, + }, + + [ROUTE_KEY.PASSWORD_RESET_SUCCESS]: { + path: '/resetpasswor/success', + name: 'Password Reset Success', + title: 'Password Reset Success - BeeQuant', + component: PasswordResetSuccess, + }, + [ROUTE_KEY.PAGE_404]: { path: '/404', name: '404', diff --git a/yarn.lock b/yarn.lock index 94ee1b9..5036730 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1170,10 +1170,10 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@next/env@14.1.3": - version "14.1.3" - resolved "https://registry.npmjs.org/@next/env/-/env-14.1.3.tgz" - integrity sha512-VhgXTvrgeBRxNPjyfBsDIMvgsKDxjlpw4IAUsHCX8Gjl1vtHUYRT3+xfQ/wwvLPDd/6kqfLqk9Pt4+7gysuCKQ== +"@next/env@14.2.3": + version "14.2.3" + resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.3.tgz#d6def29d1c763c0afb397343a15a82e7d92353a0" + integrity sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA== "@next/eslint-plugin-next@14.1.3": version "14.1.3" @@ -1182,50 +1182,50 @@ dependencies: glob "10.3.10" -"@next/swc-darwin-arm64@14.1.3": - version "14.1.3" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.3.tgz#b4c218fdb49275972d91e9a9a0ccadba243b6739" - integrity sha512-LALu0yIBPRiG9ANrD5ncB3pjpO0Gli9ZLhxdOu6ZUNf3x1r3ea1rd9Q+4xxUkGrUXLqKVK9/lDkpYIJaCJ6AHQ== - -"@next/swc-darwin-x64@14.1.3": - version "14.1.3" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.3.tgz#aa0d4357179d68daaa6f400708b76666708ffec9" - integrity sha512-E/9WQeXxkqw2dfcn5UcjApFgUq73jqNKaE5bysDm58hEUdUGedVrnRhblhJM7HbCZNhtVl0j+6TXsK0PuzXTCg== - -"@next/swc-linux-arm64-gnu@14.1.3": - version "14.1.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.3.tgz#1ba8df39c04368ede185f268c3a817a8f4290e4c" - integrity sha512-USArX9B+3rZSXYLFvgy0NVWQgqh6LHWDmMt38O4lmiJNQcwazeI6xRvSsliDLKt+78KChVacNiwvOMbl6g6BBw== - -"@next/swc-linux-arm64-musl@14.1.3": - version "14.1.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.3.tgz#2fa8fe435862eb186aca6d6068c8aef2126ab11e" - integrity sha512-esk1RkRBLSIEp1qaQXv1+s6ZdYzuVCnDAZySpa62iFTMGTisCyNQmqyCTL9P+cLJ4N9FKCI3ojtSfsyPHJDQNw== - -"@next/swc-linux-x64-gnu@14.1.3": - version "14.1.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.3.tgz#57a687b44337af219e07a79ecc8c63a3c1b2d020" - integrity sha512-8uOgRlYEYiKo0L8YGeS+3TudHVDWDjPVDUcST+z+dUzgBbTEwSSIaSgF/vkcC1T/iwl4QX9iuUyUdQEl0Kxalg== - -"@next/swc-linux-x64-musl@14.1.3": - version "14.1.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.3.tgz#8c057f8f7fb9679915df25eda6ab0ea1b7af85ff" - integrity sha512-DX2zqz05ziElLoxskgHasaJBREC5Y9TJcbR2LYqu4r7naff25B4iXkfXWfcp69uD75/0URmmoSgT8JclJtrBoQ== - -"@next/swc-win32-arm64-msvc@14.1.3": - version "14.1.3" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.3.tgz#5367333e701f722009592013502aa8e735bee782" - integrity sha512-HjssFsCdsD4GHstXSQxsi2l70F/5FsRTRQp8xNgmQs15SxUfUJRvSI9qKny/jLkY3gLgiCR3+6A7wzzK0DBlfA== - -"@next/swc-win32-ia32-msvc@14.1.3": - version "14.1.3" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.3.tgz#dc455021fee85e037f6fb4134e85895dce5a0495" - integrity sha512-DRuxD5axfDM1/Ue4VahwSxl1O5rn61hX8/sF0HY8y0iCbpqdxw3rB3QasdHn/LJ6Wb2y5DoWzXcz3L1Cr+Thrw== - -"@next/swc-win32-x64-msvc@14.1.3": - version "14.1.3" - resolved "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.3.tgz" - integrity sha512-uC2DaDoWH7h1P/aJ4Fok3Xiw6P0Lo4ez7NbowW2VGNXw/Xv6tOuLUcxhBYZxsSUJtpeknCi8/fvnSpyCFp4Rcg== +"@next/swc-darwin-arm64@14.2.3": + version "14.2.3" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.3.tgz#db1a05eb88c0224089b815ad10ac128ec79c2cdb" + integrity sha512-3pEYo/RaGqPP0YzwnlmPN2puaF2WMLM3apt5jLW2fFdXD9+pqcoTzRk+iZsf8ta7+quAe4Q6Ms0nR0SFGFdS1A== + +"@next/swc-darwin-x64@14.2.3": + version "14.2.3" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.3.tgz#a3f8af05b5f9a52ac3082e66ac29e125ab1d7b9c" + integrity sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA== + +"@next/swc-linux-arm64-gnu@14.2.3": + version "14.2.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.3.tgz#4e63f43879285b52554bfd39e6e0cc78a9b27bbf" + integrity sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA== + +"@next/swc-linux-arm64-musl@14.2.3": + version "14.2.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.3.tgz#ebdaed26214448b1e6f2c3e8b3cd29bfba387990" + integrity sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw== + +"@next/swc-linux-x64-gnu@14.2.3": + version "14.2.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.3.tgz#19e3bcc137c3b582a1ab867106817e5c90a20593" + integrity sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w== + +"@next/swc-linux-x64-musl@14.2.3": + version "14.2.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.3.tgz#794a539b98e064169cf0ff7741b2a4fb16adec7d" + integrity sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ== + +"@next/swc-win32-arm64-msvc@14.2.3": + version "14.2.3" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.3.tgz#eda9fa0fbf1ff9113e87ac2668ee67ce9e5add5a" + integrity sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A== + +"@next/swc-win32-ia32-msvc@14.2.3": + version "14.2.3" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.3.tgz#7c1190e3f640ab16580c6bdbd7d0e766b9920457" + integrity sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw== + +"@next/swc-win32-x64-msvc@14.2.3": + version "14.2.3" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.3.tgz#2be4e39ee25bfbd85be78eea17c0e7751dc4323c" + integrity sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1372,11 +1372,17 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@swc/helpers@0.5.2": - version "0.5.2" - resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz" - integrity sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw== +"@swc/counter@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + +"@swc/helpers@0.5.5": + version "0.5.5" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.5.tgz#12689df71bfc9b21c4f4ca00ae55f2f16c8b77c0" + integrity sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A== dependencies: + "@swc/counter" "^0.1.3" tslib "^2.4.0" "@swc/helpers@^0.5.0": @@ -5550,28 +5556,28 @@ negotiator@0.6.3, negotiator@^0.6.3: resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -next@^14.1.3: - version "14.1.3" - resolved "https://registry.npmjs.org/next/-/next-14.1.3.tgz" - integrity sha512-oexgMV2MapI0UIWiXKkixF8J8ORxpy64OuJ/J9oVUmIthXOUCcuVEZX+dtpgq7wIfIqtBwQsKEDXejcjTsan9g== +next@^14.2.3: + version "14.2.3" + resolved "https://registry.yarnpkg.com/next/-/next-14.2.3.tgz#f117dd5d5f20c307e7b8e4f9c1c97d961008925d" + integrity sha512-dowFkFTR8v79NPJO4QsBUtxv0g9BrS/phluVpMAt2ku7H+cbcBJlopXjkWlwxrk/xGqMemr7JkGPGemPrLLX7A== dependencies: - "@next/env" "14.1.3" - "@swc/helpers" "0.5.2" + "@next/env" "14.2.3" + "@swc/helpers" "0.5.5" busboy "1.6.0" caniuse-lite "^1.0.30001579" graceful-fs "^4.2.11" postcss "8.4.31" styled-jsx "5.1.1" optionalDependencies: - "@next/swc-darwin-arm64" "14.1.3" - "@next/swc-darwin-x64" "14.1.3" - "@next/swc-linux-arm64-gnu" "14.1.3" - "@next/swc-linux-arm64-musl" "14.1.3" - "@next/swc-linux-x64-gnu" "14.1.3" - "@next/swc-linux-x64-musl" "14.1.3" - "@next/swc-win32-arm64-msvc" "14.1.3" - "@next/swc-win32-ia32-msvc" "14.1.3" - "@next/swc-win32-x64-msvc" "14.1.3" + "@next/swc-darwin-arm64" "14.2.3" + "@next/swc-darwin-x64" "14.2.3" + "@next/swc-linux-arm64-gnu" "14.2.3" + "@next/swc-linux-arm64-musl" "14.2.3" + "@next/swc-linux-x64-gnu" "14.2.3" + "@next/swc-linux-x64-musl" "14.2.3" + "@next/swc-win32-arm64-msvc" "14.2.3" + "@next/swc-win32-ia32-msvc" "14.2.3" + "@next/swc-win32-x64-msvc" "14.2.3" node-abort-controller@^3.1.1: version "3.1.1"