[frontend]: add eslint
This commit is contained in:
parent
75930d105e
commit
a6cef0298d
@ -1,19 +1,121 @@
|
||||
import { dirname } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { FlatCompat } from "@eslint/eslintrc";
|
||||
import config from 'eslint-config-ksv741';
|
||||
import nextPlugin from '@next/eslint-plugin-next'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const {flatConfig} = nextPlugin;
|
||||
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
});
|
||||
export default [
|
||||
...config,
|
||||
flatConfig.coreWebVitals,
|
||||
{
|
||||
name: 'my-rules',
|
||||
files: [
|
||||
'**/*.js',
|
||||
'**/*.ts',
|
||||
'**/*.tsx',
|
||||
],
|
||||
rules: {
|
||||
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
|
||||
'import/order': [
|
||||
'error', {
|
||||
pathGroups: [
|
||||
{
|
||||
pattern: '__spec__/**',
|
||||
group: 'builtin',
|
||||
position: 'before',
|
||||
},
|
||||
{
|
||||
pattern: 'apps/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: 'pages/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: 'widgets/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: 'features/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: 'entities/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: 'shared/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
],
|
||||
distinctGroup: true,
|
||||
groups: [
|
||||
'builtin',
|
||||
'external',
|
||||
'internal',
|
||||
'parent',
|
||||
'sibling',
|
||||
'object',
|
||||
'index',
|
||||
'type',
|
||||
],
|
||||
'newlines-between': 'always',
|
||||
alphabetize: {
|
||||
order: 'asc',
|
||||
caseInsensitive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
'no-await-in-loop': 'off',
|
||||
'no-void': ['error', { allowAsStatement: true }],
|
||||
// "@typescript-eslint/no-extraneous-class": ['error', {allowEmpty: true}],
|
||||
// "@typescript-eslint/parameter-properties": ['error', { "allow": ["private readonly"] }],
|
||||
'@typescript-eslint/max-params': 'off',
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
// todo fixme
|
||||
'import/max-dependencies': 'off',
|
||||
'@typescript-eslint/no-unsafe-type-assertion': 'off',
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'import/no-cycle': 'off',
|
||||
'@typescript-eslint/strict-boolean-expressions': 'off',
|
||||
'import/extensions': 'off',
|
||||
'@typescript-eslint/no-unnecessary-condition': 'off',
|
||||
'max-classes-per-file': 'off',
|
||||
'@typescript-eslint/no-unsafe-return': 'off',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||
'@typescript-eslint/no-unsafe-argument': 'off',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unnecessary-type-conversion': 'off',
|
||||
'@typescript-eslint/consistent-return': 'off',
|
||||
'@typescript-eslint/class-methods-use-this': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/member-ordering': 'off',
|
||||
'no-undefined': 'off',
|
||||
'@typescript-eslint/no-misused-spread': 'off',
|
||||
'@typescript-eslint/require-await': 'off',
|
||||
'@typescript-eslint/parameter-properties': 'off',
|
||||
'@typescript-eslint/no-extraneous-class': 'off',
|
||||
'@stylistic/max-len': 'off',
|
||||
'@typescript-eslint/no-unnecessary-type-parameters': 'off',
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
|
||||
const eslintConfig = [
|
||||
...compat.extends("next/core-web-vitals", "next/typescript"),
|
||||
'react/destructuring-assignment': ['off', 'never', { ignoreClassFields: true, destructureInSignature: 'always' }],
|
||||
"@typescript-eslint/no-misused-promises": ["error", {
|
||||
"checksVoidReturn": false
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ['src/graphql/generated']
|
||||
}
|
||||
];
|
||||
|
||||
export default eslintConfig;
|
||||
|
||||
@ -35,11 +35,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "3.3.1",
|
||||
"@next/eslint-plugin-next": "15.4.5",
|
||||
"@tailwindcss/postcss": "4.1.11",
|
||||
"@types/node": "22.17.0",
|
||||
"@types/react": "19.1.9",
|
||||
"@types/react-dom": "19.1.7",
|
||||
"eslint": "9.32.0",
|
||||
"eslint-config-ksv741": "0.2.0",
|
||||
"eslint-config-next": "15.4.4",
|
||||
"tailwindcss": "4.1.11",
|
||||
"tw-animate-css": "1.3.6",
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import CreateAccountForm from '@/components/features/auth/forms/CreateAccountForm';
|
||||
import { Metadata } from 'next';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import React from 'react';
|
||||
|
||||
import CreateAccountForm from '@/components/features/auth/forms/CreateAccountForm';
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
const t = await getTranslations('auth.register');
|
||||
|
||||
return {
|
||||
title: t('heading')
|
||||
}
|
||||
title: t('heading'),
|
||||
};
|
||||
}
|
||||
|
||||
const CreateAccountPage = () => {
|
||||
return (
|
||||
<CreateAccountForm/>
|
||||
);
|
||||
};
|
||||
const CreateAccountPage = () => (
|
||||
<CreateAccountForm />
|
||||
);
|
||||
|
||||
export default CreateAccountPage;
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import LoginAccountForm from '@/components/features/auth/forms/LoginAccountForm';
|
||||
import { Metadata } from 'next';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import React from 'react';
|
||||
|
||||
import LoginAccountForm from '@/components/features/auth/forms/LoginAccountForm';
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
const t = await getTranslations('auth.login');
|
||||
|
||||
return {
|
||||
title: t('heading')
|
||||
}
|
||||
title: t('heading'),
|
||||
};
|
||||
}
|
||||
|
||||
const LoginAccountPage = () => {
|
||||
return (
|
||||
<LoginAccountForm/>
|
||||
);
|
||||
};
|
||||
const LoginAccountPage = () => (
|
||||
<LoginAccountForm />
|
||||
);
|
||||
|
||||
export default LoginAccountPage;
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import { NewPasswordForm } from '@/components/features/auth/forms/NewPasswordForm';
|
||||
import { Metadata } from 'next';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import React from 'react';
|
||||
|
||||
import { NewPasswordForm } from '@/components/features/auth/forms/NewPasswordForm';
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
const t = await getTranslations('auth.newPassword');
|
||||
|
||||
return {
|
||||
title: t('heading')
|
||||
}
|
||||
title: t('heading'),
|
||||
};
|
||||
}
|
||||
|
||||
const NewPasswordPage = () => {
|
||||
return (
|
||||
<NewPasswordForm/>
|
||||
);
|
||||
};
|
||||
const NewPasswordPage = () => (
|
||||
<NewPasswordForm />
|
||||
);
|
||||
|
||||
export default NewPasswordPage;
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import { ResetPasswordForm } from '@/components/features/auth/forms/ResetPasswordForm';
|
||||
import { Metadata } from 'next';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import React from 'react';
|
||||
|
||||
import { ResetPasswordForm } from '@/components/features/auth/forms/ResetPasswordForm';
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
const t = await getTranslations('auth.resetPassword');
|
||||
|
||||
return {
|
||||
title: t('heading')
|
||||
}
|
||||
title: t('heading'),
|
||||
};
|
||||
}
|
||||
|
||||
const ResetPasswordPage = () => {
|
||||
return (
|
||||
<ResetPasswordForm/>
|
||||
);
|
||||
};
|
||||
const ResetPasswordPage = () => (
|
||||
<ResetPasswordForm />
|
||||
);
|
||||
|
||||
export default ResetPasswordPage;
|
||||
|
||||
@ -1,27 +1,28 @@
|
||||
import { VerifyAccountForm } from '@/components/features/auth/forms/VerifyAccoiuntForm';
|
||||
import { Metadata } from 'next';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import React from 'react';
|
||||
|
||||
import { VerifyAccountForm } from '@/components/features/auth/forms/VerifyAccoiuntForm';
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
const t = await getTranslations('auth.verify');
|
||||
|
||||
return {
|
||||
title: t('heading')
|
||||
}
|
||||
title: t('heading'),
|
||||
};
|
||||
}
|
||||
|
||||
type VerifyAccountPageProps = {
|
||||
searchParams: Promise<{token: string}>
|
||||
}
|
||||
searchParams: Promise<{ token: string }>;
|
||||
};
|
||||
|
||||
const VerifyAccountPage = async (props: VerifyAccountPageProps) => {
|
||||
const {token} = await props.searchParams;
|
||||
const { token } = await props.searchParams;
|
||||
|
||||
if (!token) {
|
||||
return redirect('/account/create')
|
||||
return redirect('/account/create');
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@ -1,42 +1,46 @@
|
||||
import { Geist } from 'next/font/google';
|
||||
import { NextIntlClientProvider } from 'next-intl';
|
||||
import { getLocale, getMessages } from 'next-intl/server';
|
||||
|
||||
import ApolloClientProvider from '@/providers/ApolloClientProvider';
|
||||
import { ThemeProvider } from '@/providers/ThemeProvider';
|
||||
import { ToastProvider } from '@/providers/ToastProvider';
|
||||
import type { Metadata } from "next";
|
||||
import { NextIntlClientProvider } from 'next-intl';
|
||||
import { getLocale, getMessages } from 'next-intl/server';
|
||||
import { Geist } from "next/font/google";
|
||||
import "../styles/globals.css";
|
||||
|
||||
import '../styles/globals.css';
|
||||
import type { Metadata } from 'next';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
variable: '--font-geist-sans',
|
||||
subsets: ['latin'],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
title: 'Create Next App',
|
||||
description: 'Generated by create next app',
|
||||
};
|
||||
|
||||
export default async function RootLayout({
|
||||
const RootLayout = async ({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
const locale = await getLocale()
|
||||
const messages = await getMessages()
|
||||
children: ReactNode;
|
||||
}>) => {
|
||||
const locale = await getLocale();
|
||||
const messages = await getMessages();
|
||||
|
||||
return (
|
||||
<html lang={locale} suppressHydrationWarning>
|
||||
<html suppressHydrationWarning lang={locale}>
|
||||
<body className={geistSans.variable}>
|
||||
<ApolloClientProvider>
|
||||
<NextIntlClientProvider messages={messages}>
|
||||
<ThemeProvider
|
||||
disableTransitionOnChange
|
||||
enableSystem
|
||||
attribute="class"
|
||||
defaultTheme="dark"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<ToastProvider/>
|
||||
<ToastProvider />
|
||||
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</NextIntlClientProvider>
|
||||
@ -44,4 +48,6 @@ export default async function RootLayout({
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default RootLayout;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
|
||||
@ -1,34 +1,50 @@
|
||||
import Link from 'next/link';
|
||||
import React from 'react';
|
||||
|
||||
import { LogoImage } from '@/components/images/LogoImage';
|
||||
import { Button } from '@/components/ui/common/Button';
|
||||
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/common/Card';
|
||||
import Link from 'next/link';
|
||||
import React, { FC, ReactNode } from 'react';
|
||||
import {
|
||||
Card, CardContent, CardFooter, CardHeader, CardTitle,
|
||||
} from '@/components/ui/common/Card';
|
||||
|
||||
import type { FC, ReactNode } from 'react';
|
||||
|
||||
type AuthWrapperProps = {
|
||||
heading: string
|
||||
backButtonLabel?: string
|
||||
backButtonHref?: string
|
||||
children: ReactNode
|
||||
}
|
||||
heading: string;
|
||||
backButtonLabel?: string;
|
||||
backButtonHref?: string;
|
||||
children: ReactNode;
|
||||
};
|
||||
const AuthWrapper: FC<AuthWrapperProps> = (props) => {
|
||||
const { children, backButtonHref, backButtonLabel, heading } = props;
|
||||
const {
|
||||
children, backButtonHref, backButtonLabel, heading,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div className='flex h-full items-center justify-center'>
|
||||
<Card className='w-[450px]'>
|
||||
<CardHeader className='flex-row items-center justify-center gap-x-4'>
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<Card className="w-[450px]">
|
||||
<CardHeader className="flex-row items-center justify-center gap-x-4">
|
||||
<LogoImage />
|
||||
<CardTitle>{heading}</CardTitle>
|
||||
|
||||
<CardTitle>
|
||||
{heading}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>{children}</CardContent>
|
||||
<CardFooter className='-mt-2'>
|
||||
{backButtonLabel && backButtonHref && (
|
||||
<Link href={backButtonHref} className='w-full'>
|
||||
<Button variant='ghost' className='w-full'>
|
||||
|
||||
<CardContent>
|
||||
{children}
|
||||
</CardContent>
|
||||
|
||||
<CardFooter className="-mt-2">
|
||||
{backButtonLabel && backButtonHref
|
||||
? (
|
||||
<Link className="w-full" href={backButtonHref}>
|
||||
<Button className="w-full" variant="ghost">
|
||||
{backButtonLabel}
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
)
|
||||
: null}
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@ -1,127 +1,153 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { Button } from '@/components/ui/common/Button';
|
||||
import { createAccountSchema, TypeCreateAccountSchema } from '@/schemas/auth/create-account.schema';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { CircleCheck } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import React, { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
import AuthWrapper from '../AuthWrapper';
|
||||
import React, { useState } from 'react';
|
||||
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel } from '@/components/ui/common/Form';
|
||||
import { Input } from '@/components/ui/common/Input';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/common/Alert';
|
||||
import { useCreateUserMutation } from '@/graphql/generated/output';
|
||||
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/common/Alert';
|
||||
import { Button } from '@/components/ui/common/Button';
|
||||
import {
|
||||
Form, FormControl, FormDescription, FormField, FormItem, FormLabel,
|
||||
} from '@/components/ui/common/Form';
|
||||
import { Input } from '@/components/ui/common/Input';
|
||||
import { useCreateUserMutation } from '@/graphql/generated/output';
|
||||
import { createAccountSchema } from '@/schemas/auth/create-account.schema';
|
||||
|
||||
import AuthWrapper from '../AuthWrapper';
|
||||
|
||||
import type { TypeCreateAccountSchema } from '@/schemas/auth/create-account.schema';
|
||||
|
||||
const CreateAccountForm = () => {
|
||||
const [isSuccess, setIsSuccess] = useState(false)
|
||||
const t = useTranslations('auth.register')
|
||||
const [isSuccess, setIsSuccess] = useState(false);
|
||||
const t = useTranslations('auth.register');
|
||||
|
||||
const form = useForm<TypeCreateAccountSchema>({
|
||||
resolver: zodResolver(createAccountSchema),
|
||||
defaultValues: {
|
||||
name: '',
|
||||
email: '',
|
||||
password: ''
|
||||
}
|
||||
})
|
||||
const { isValid } = form.formState
|
||||
password: '',
|
||||
},
|
||||
});
|
||||
const { isValid } = form.formState;
|
||||
|
||||
const [create, { loading: isLoadingCreate }] = useCreateUserMutation({
|
||||
onCompleted() {
|
||||
setIsSuccess(true)
|
||||
setIsSuccess(true);
|
||||
},
|
||||
onError() {
|
||||
toast.error(t('errorMessage'))
|
||||
}
|
||||
})
|
||||
toast.error(t('errorMessage'));
|
||||
},
|
||||
});
|
||||
|
||||
function onSubmit(data: TypeCreateAccountSchema) {
|
||||
create({ variables: { data } })
|
||||
void create({ variables: { data } });
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthWrapper
|
||||
heading={t('heading')}
|
||||
backButtonHref="/account/login"
|
||||
backButtonLabel={t('backButtonLabel')}
|
||||
backButtonHref='/account/login'
|
||||
heading={t('heading')}
|
||||
>
|
||||
{isSuccess ? (
|
||||
{isSuccess
|
||||
? (
|
||||
<Alert>
|
||||
<CircleCheck className='size-4' />
|
||||
<AlertTitle>{t('successAlertTitle')}</AlertTitle>
|
||||
<CircleCheck className="size-4" />
|
||||
|
||||
<AlertTitle>
|
||||
{t('successAlertTitle')}
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
{t('successAlertDescription')}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : (
|
||||
)
|
||||
: (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className="grid gap-y-3"
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className='grid gap-y-3'
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='name'
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('usernameLabel')}</FormLabel>
|
||||
<FormLabel>
|
||||
{t('usernameLabel')}
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder='johndoe'
|
||||
disabled={isLoadingCreate}
|
||||
placeholder="johndoe"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
{t('usernameDescription')}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='email'
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('emailLabel')}</FormLabel>
|
||||
<FormLabel>
|
||||
{t('emailLabel')}
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder='john.doe@example.com'
|
||||
disabled={isLoadingCreate}
|
||||
placeholder="john.doe@example.com"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
{t('emailDescription')}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='password'
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('passwordLabel')}</FormLabel>
|
||||
<FormLabel>
|
||||
{t('passwordLabel')}
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder='********'
|
||||
type='password'
|
||||
disabled={isLoadingCreate}
|
||||
placeholder="********"
|
||||
type="password"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
{t('passwordDescription')}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
className='mt-2 w-full'
|
||||
className="mt-2 w-full"
|
||||
disabled={!isValid || isLoadingCreate}
|
||||
>
|
||||
{t('submitButton')}
|
||||
|
||||
@ -1,24 +1,29 @@
|
||||
'use client'
|
||||
|
||||
import { Button } from '@/components/ui/common/Button';
|
||||
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel } from '@/components/ui/common/Form';
|
||||
import { Input } from '@/components/ui/common/Input';
|
||||
import { useLoginUserMutation } from '@/graphql/generated/output';
|
||||
import { loginSchema, TypeLoginSchema } from '@/schemas/auth/login.schema';
|
||||
import { useTranslations } from 'next-intl';
|
||||
'use client';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import React, { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
import AuthWrapper from '../AuthWrapper';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
|
||||
import { Button } from '@/components/ui/common/Button';
|
||||
import {
|
||||
Form, FormControl, FormDescription, FormField, FormItem, FormLabel,
|
||||
} from '@/components/ui/common/Form';
|
||||
import { Input } from '@/components/ui/common/Input';
|
||||
import { InputOTP, InputOTPGroup, InputOTPSlot } from '@/components/ui/common/InputOTP';
|
||||
import { useLoginUserMutation } from '@/graphql/generated/output';
|
||||
import { loginSchema } from '@/schemas/auth/login.schema';
|
||||
|
||||
import AuthWrapper from '../AuthWrapper';
|
||||
|
||||
import type { TypeLoginSchema } from '@/schemas/auth/login.schema';
|
||||
|
||||
const LoginAccountForm = () => {
|
||||
const t = useTranslations('auth.login')
|
||||
const [isShowTwoFactor, setIsShowTwoFactor] = useState(false)
|
||||
const t = useTranslations('auth.login');
|
||||
const [isShowTwoFactor, setIsShowTwoFactor] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
const form = useForm<TypeLoginSchema>({
|
||||
@ -26,109 +31,128 @@ const LoginAccountForm = () => {
|
||||
defaultValues: {
|
||||
login: '',
|
||||
password: '',
|
||||
}
|
||||
})
|
||||
const { isValid } = form.formState
|
||||
},
|
||||
});
|
||||
const { isValid } = form.formState;
|
||||
|
||||
const [login, {loading: isLoadingLogin}] = useLoginUserMutation({
|
||||
const [login, { loading: isLoadingLogin }] = useLoginUserMutation({
|
||||
onCompleted(data) {
|
||||
if (data.loginUser.message) {
|
||||
setIsShowTwoFactor(true)
|
||||
setIsShowTwoFactor(true);
|
||||
} else {
|
||||
toast.success(t('successMessage'))
|
||||
router.push('/dashboard/settings')
|
||||
toast.success(t('successMessage'));
|
||||
router.push('/dashboard/settings');
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(t('errorMessage'))
|
||||
}
|
||||
})
|
||||
toast.error(t('errorMessage'));
|
||||
},
|
||||
});
|
||||
|
||||
function onSubmit(data: TypeLoginSchema) {
|
||||
void login({variables: {data}})
|
||||
void login({ variables: { data } });
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthWrapper
|
||||
heading={t('heading')}
|
||||
backButtonHref="/account/create"
|
||||
backButtonLabel={t('backButtonLabel')}
|
||||
backButtonHref='/account/create'
|
||||
heading={t('heading')}
|
||||
>
|
||||
<Form {...form}>
|
||||
<form
|
||||
className="grid gap-y-3"
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className='grid gap-y-3'
|
||||
>
|
||||
{isShowTwoFactor ? (
|
||||
{isShowTwoFactor
|
||||
? (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='pin'
|
||||
name="pin"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('pinLabel')}</FormLabel>
|
||||
<FormLabel>
|
||||
{t('pinLabel')}
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<InputOTP maxLength={6} {...field}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
|
||||
<InputOTPSlot index={1} />
|
||||
|
||||
<InputOTPSlot index={2} />
|
||||
|
||||
<InputOTPSlot index={3} />
|
||||
|
||||
<InputOTPSlot index={4} />
|
||||
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
{t('pinDescription')}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
)
|
||||
: (
|
||||
<>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='login'
|
||||
name="login"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('loginLabel')}</FormLabel>
|
||||
<FormLabel>
|
||||
{t('loginLabel')}
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder='johndoe'
|
||||
disabled={isLoadingLogin}
|
||||
placeholder="johndoe"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
{t('loginDescription')}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='password'
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<div className='flex items-center justify-between'>
|
||||
<div className="flex items-center justify-between">
|
||||
<FormLabel>
|
||||
{t('passwordLabel')}
|
||||
</FormLabel>
|
||||
|
||||
<Link
|
||||
href='/account/recovery'
|
||||
className='ml-auto inline-block text-sm'
|
||||
className="ml-auto inline-block text-sm"
|
||||
href="/account/recovery"
|
||||
>
|
||||
{t('forgotPassword')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder='********'
|
||||
type='password'
|
||||
disabled={isLoadingLogin}
|
||||
placeholder="********"
|
||||
type="password"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
{t('passwordDescription')}
|
||||
</FormDescription>
|
||||
@ -137,8 +161,9 @@ const LoginAccountForm = () => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Button
|
||||
className='mt-2 w-full'
|
||||
className="mt-2 w-full"
|
||||
disabled={!isValid || isLoadingLogin}
|
||||
>
|
||||
{t('submitButton')}
|
||||
|
||||
@ -1,113 +1,121 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { useTranslations } from 'next-intl'
|
||||
import { useParams, useRouter } from 'next/navigation'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { toast } from 'sonner'
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import { Button } from '@/components/ui/common/Button'
|
||||
import { Button } from '@/components/ui/common/Button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel
|
||||
} from '@/components/ui/common/Form'
|
||||
import { Input } from '@/components/ui/common/Input'
|
||||
FormLabel,
|
||||
} from '@/components/ui/common/Form';
|
||||
import { Input } from '@/components/ui/common/Input';
|
||||
import { useNewPasswordMutation } from '@/graphql/generated/output';
|
||||
import { newPasswordSchema } from '@/schemas/auth/new-password.schema';
|
||||
|
||||
import { useNewPasswordMutation } from '@/graphql/generated/output'
|
||||
import AuthWrapper from '../AuthWrapper';
|
||||
|
||||
import type { TypeNewPasswordSchema } from '@/schemas/auth/new-password.schema';
|
||||
|
||||
import AuthWrapper from '../AuthWrapper'
|
||||
import { newPasswordSchema, TypeNewPasswordSchema } from '@/schemas/auth/new-password.schema'
|
||||
export const NewPasswordForm = () => {
|
||||
const t = useTranslations('auth.newPassword');
|
||||
|
||||
export function NewPasswordForm() {
|
||||
const t = useTranslations('auth.newPassword')
|
||||
|
||||
const router = useRouter()
|
||||
const params = useParams<{ token: string }>()
|
||||
const router = useRouter();
|
||||
const params = useParams<{ token: string }>();
|
||||
|
||||
const form = useForm<TypeNewPasswordSchema>({
|
||||
resolver: zodResolver(newPasswordSchema),
|
||||
defaultValues: {
|
||||
password: '',
|
||||
passwordRepeat: ''
|
||||
}
|
||||
})
|
||||
passwordRepeat: '',
|
||||
},
|
||||
});
|
||||
|
||||
const [newPassword, { loading: isLoadingNew }] = useNewPasswordMutation({
|
||||
onCompleted(data) {
|
||||
toast.success(t('successMessage'))
|
||||
router.push('/account/login')
|
||||
toast.success(t('successMessage'));
|
||||
router.push('/account/login');
|
||||
},
|
||||
onError() {
|
||||
toast.error(t('errorMessage'))
|
||||
}
|
||||
})
|
||||
toast.error(t('errorMessage'));
|
||||
},
|
||||
});
|
||||
|
||||
const { isValid } = form.formState
|
||||
const { isValid } = form.formState;
|
||||
|
||||
function onSubmit(data: TypeNewPasswordSchema) {
|
||||
newPassword({ variables: { data: { ...data, token: params.token } } })
|
||||
void newPassword({ variables: { data: { ...data, token: params.token } } });
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthWrapper
|
||||
heading={t('heading')}
|
||||
backButtonHref="/account/login"
|
||||
backButtonLabel={t('backButtonLabel')}
|
||||
backButtonHref='/account/login'
|
||||
heading={t('heading')}
|
||||
>
|
||||
<Form {...form}>
|
||||
<form
|
||||
className="grid gap-y-3"
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className='grid gap-y-3'
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='password'
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('passwordLabel')}</FormLabel>
|
||||
<FormLabel>
|
||||
{t('passwordLabel')}
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder='********'
|
||||
type='password'
|
||||
disabled={isLoadingNew}
|
||||
placeholder="********"
|
||||
type="password"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
{t('passwordDescription')}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='passwordRepeat'
|
||||
name="passwordRepeat"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t('passwordRepeatLabel')}
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder='********'
|
||||
type='password'
|
||||
disabled={isLoadingNew}
|
||||
placeholder="********"
|
||||
type="password"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
{t('passwordRepeatDescription')}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
className='mt-2 w-full'
|
||||
className="mt-2 w-full"
|
||||
disabled={!isValid || isLoadingNew}
|
||||
>
|
||||
{t('submitButton')}
|
||||
@ -115,5 +123,5 @@ export function NewPasswordForm() {
|
||||
</form>
|
||||
</Form>
|
||||
</AuthWrapper>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,106 +1,116 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { CircleCheck } from 'lucide-react'
|
||||
import { useTranslations } from 'next-intl'
|
||||
import { useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { toast } from 'sonner'
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { CircleCheck } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import {
|
||||
Alert,
|
||||
AlertDescription,
|
||||
AlertTitle
|
||||
} from '@/components/ui/common/Alert'
|
||||
import { Button } from '@/components/ui/common/Button'
|
||||
AlertTitle,
|
||||
} from '@/components/ui/common/Alert';
|
||||
import { Button } from '@/components/ui/common/Button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel
|
||||
} from '@/components/ui/common/Form'
|
||||
import { Input } from '@/components/ui/common/Input'
|
||||
|
||||
import { useResetPasswordMutation } from '@/graphql/generated/output'
|
||||
|
||||
FormLabel,
|
||||
} from '@/components/ui/common/Form';
|
||||
import { Input } from '@/components/ui/common/Input';
|
||||
import { useResetPasswordMutation } from '@/graphql/generated/output';
|
||||
import {
|
||||
type TypeResetPasswordSchema,
|
||||
resetPasswordSchema
|
||||
} from '@/schemas/auth/reset-password.schema'
|
||||
resetPasswordSchema,
|
||||
} from '@/schemas/auth/reset-password.schema';
|
||||
|
||||
import AuthWrapper from '../AuthWrapper'
|
||||
import AuthWrapper from '../AuthWrapper';
|
||||
|
||||
export function ResetPasswordForm() {
|
||||
const t = useTranslations('auth.resetPassword')
|
||||
export const ResetPasswordForm = () => {
|
||||
const t = useTranslations('auth.resetPassword');
|
||||
|
||||
const [isSuccess, setIsSuccess] = useState(false)
|
||||
const [isSuccess, setIsSuccess] = useState(false);
|
||||
|
||||
const form = useForm<TypeResetPasswordSchema>({
|
||||
resolver: zodResolver(resetPasswordSchema),
|
||||
defaultValues: {
|
||||
email: ''
|
||||
}
|
||||
})
|
||||
email: '',
|
||||
},
|
||||
});
|
||||
|
||||
const [resetPassword, { loading: isLoadingReset }] =
|
||||
useResetPasswordMutation({
|
||||
const [resetPassword, { loading: isLoadingReset }] = useResetPasswordMutation({
|
||||
onCompleted() {
|
||||
setIsSuccess(true)
|
||||
setIsSuccess(true);
|
||||
},
|
||||
onError() {
|
||||
toast.error(t('errorMessage'))
|
||||
}
|
||||
})
|
||||
toast.error(t('errorMessage'));
|
||||
},
|
||||
});
|
||||
|
||||
const { isValid } = form.formState
|
||||
const { isValid } = form.formState;
|
||||
|
||||
function onSubmit(data: TypeResetPasswordSchema) {
|
||||
void resetPassword({ variables: { data } })
|
||||
void resetPassword({ variables: { data } });
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthWrapper
|
||||
heading={t('heading')}
|
||||
backButtonHref="/account/login"
|
||||
backButtonLabel={t('backButtonLabel')}
|
||||
backButtonHref='/account/login'
|
||||
heading={t('heading')}
|
||||
>
|
||||
{isSuccess ? (
|
||||
{isSuccess
|
||||
? (
|
||||
<Alert>
|
||||
<CircleCheck className='size-4' />
|
||||
<AlertTitle>{t('successAlertTitle')}</AlertTitle>
|
||||
<CircleCheck className="size-4" />
|
||||
|
||||
<AlertTitle>
|
||||
{t('successAlertTitle')}
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
{t('successAlertDescription')}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : (
|
||||
)
|
||||
: (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className='grid gap-y-3'
|
||||
className="grid gap-y-3"
|
||||
onSubmit={() => {
|
||||
form.handleSubmit(onSubmit);
|
||||
}}
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='email'
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('emailLabel')}</FormLabel>
|
||||
<FormLabel>
|
||||
{t('emailLabel')}
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder='john.doe@example.com'
|
||||
disabled={isLoadingReset}
|
||||
placeholder="john.doe@example.com"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
{t('emailDescription')}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
className='mt-2 w-full'
|
||||
className="mt-2 w-full"
|
||||
disabled={!isValid || isLoadingReset}
|
||||
>
|
||||
{t('submitButton')}
|
||||
@ -109,5 +119,5 @@ export function ResetPasswordForm() {
|
||||
</Form>
|
||||
)}
|
||||
</AuthWrapper>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,46 +1,47 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { Loader } from 'lucide-react'
|
||||
import { useTranslations } from 'next-intl'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useEffect } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
import { Loader } from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useEffect } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import { useVerifyAccountMutation } from '@/graphql/generated/output'
|
||||
import { useVerifyAccountMutation } from '@/graphql/generated/output';
|
||||
|
||||
import AuthWrapper from '../AuthWrapper';
|
||||
|
||||
import AuthWrapper from '../AuthWrapper'
|
||||
type VerifyAccountFormProps = {
|
||||
token: string
|
||||
}
|
||||
export function VerifyAccountForm(props: VerifyAccountFormProps) {
|
||||
token: string;
|
||||
};
|
||||
export const VerifyAccountForm = (props: VerifyAccountFormProps) => {
|
||||
const { token } = props;
|
||||
const t = useTranslations('auth.verify')
|
||||
const t = useTranslations('auth.verify');
|
||||
|
||||
const router = useRouter()
|
||||
const router = useRouter();
|
||||
|
||||
const [verify] = useVerifyAccountMutation({
|
||||
onCompleted() {
|
||||
toast.success(t('successMessage'))
|
||||
router.push('/dashboard/settings')
|
||||
toast.success(t('successMessage'));
|
||||
router.push('/dashboard/settings');
|
||||
},
|
||||
onError() {
|
||||
toast.error(t('errorMessage'))
|
||||
}
|
||||
})
|
||||
toast.error(t('errorMessage'));
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
void verify({
|
||||
variables: {
|
||||
data: { token }
|
||||
}
|
||||
})
|
||||
}, [token, verify])
|
||||
data: { token },
|
||||
},
|
||||
});
|
||||
}, [token, verify]);
|
||||
|
||||
return (
|
||||
<AuthWrapper heading={t('heading')}>
|
||||
<div className='flex justify-center'>
|
||||
<Loader className='size-8 animate-spin' />
|
||||
<div className="flex justify-center">
|
||||
<Loader className="size-8 animate-spin" />
|
||||
</div>
|
||||
</AuthWrapper>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,43 +1,44 @@
|
||||
export function LogoImage() {
|
||||
return (
|
||||
export const LogoImage = () => (
|
||||
<svg
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
xmlnsXlink='http://www.w3.org/1999/xlink'
|
||||
viewBox='0 0 2400 2800'
|
||||
xmlSpace='preserve'
|
||||
width={42}
|
||||
height={42}
|
||||
viewBox="0 0 2400 2800"
|
||||
width={42}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
xmlSpace="preserve"
|
||||
>
|
||||
<title>Logo</title>
|
||||
|
||||
<g>
|
||||
<polygon
|
||||
className='fill-white'
|
||||
points='2200,1300 1800,1700 1400,1700 1050,2050 1050,1700 600,1700 600,200 2200,200 '
|
||||
className="fill-white"
|
||||
points="2200,1300 1800,1700 1400,1700 1050,2050 1050,1700 600,1700 600,200 2200,200"
|
||||
/>
|
||||
|
||||
<g>
|
||||
<g id='Layer_1-2'>
|
||||
<g id="Layer_1-2">
|
||||
<path
|
||||
className='fill-primary'
|
||||
d='M500,0L0,500v1800h600v500l500-500h400l900-900V0H500z M2200,1300l-400,400h-400l-350,350v-350H600V200h1600
|
||||
V1300z'
|
||||
className="fill-primary"
|
||||
d="M500,0L0,500v1800h600v500l500-500h400l900-900V0H500z M2200,1300l-400,400h-400l-350,350v-350H600V200h1600 V1300z"
|
||||
/>
|
||||
|
||||
<rect
|
||||
x='1700'
|
||||
y='550'
|
||||
className='fill-primary'
|
||||
width='200'
|
||||
height='600'
|
||||
className="fill-primary"
|
||||
height="600"
|
||||
width="200"
|
||||
x="1700"
|
||||
y="550"
|
||||
/>
|
||||
|
||||
<rect
|
||||
x='1150'
|
||||
y='550'
|
||||
className='fill-primary'
|
||||
width='200'
|
||||
height='600'
|
||||
className="fill-primary"
|
||||
height="600"
|
||||
width="200"
|
||||
x="1150"
|
||||
y="550"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { cn } from '@/utils/twMerge'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
import { type HTMLAttributes, forwardRef } from 'react'
|
||||
import { type VariantProps, cva } from 'class-variance-authority';
|
||||
import { type HTMLAttributes, forwardRef } from 'react';
|
||||
|
||||
import { cn } from '@/utils/twMerge';
|
||||
|
||||
const alertVariants = cva(
|
||||
'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground',
|
||||
@ -10,14 +10,14 @@ const alertVariants = cva(
|
||||
variant: {
|
||||
default: 'bg-background text-foreground',
|
||||
destructive:
|
||||
'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive'
|
||||
}
|
||||
'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default'
|
||||
}
|
||||
}
|
||||
)
|
||||
variant: 'default',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const Alert = forwardRef<
|
||||
HTMLDivElement,
|
||||
@ -25,24 +25,25 @@ const Alert = forwardRef<
|
||||
>(({ className, variant, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
role='alert'
|
||||
className={cn(alertVariants({ variant }), className)}
|
||||
role="alert"
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Alert.displayName = 'Alert'
|
||||
));
|
||||
Alert.displayName = 'Alert';
|
||||
|
||||
const AlertTitle = forwardRef<
|
||||
HTMLParagraphElement,
|
||||
HTMLAttributes<HTMLHeadingElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
// eslint-disable-next-line jsx-a11y/heading-has-content
|
||||
<h5
|
||||
ref={ref}
|
||||
className={cn('mb-1 font-medium leading-none tracking-wide', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertTitle.displayName = 'AlertTitle'
|
||||
));
|
||||
AlertTitle.displayName = 'AlertTitle';
|
||||
|
||||
const AlertDescription = forwardRef<
|
||||
HTMLParagraphElement,
|
||||
@ -52,11 +53,11 @@ const AlertDescription = forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'mt-2 text-sm text-muted-foreground [&_p]:leading-relaxed',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertDescription.displayName = 'AlertDescription'
|
||||
));
|
||||
AlertDescription.displayName = 'AlertDescription';
|
||||
|
||||
export { Alert, AlertDescription, AlertTitle }
|
||||
export { Alert, AlertDescription, AlertTitle };
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { cn } from '@/utils/twMerge'
|
||||
import { Slot } from '@radix-ui/react-slot'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
import { type ButtonHTMLAttributes, forwardRef } from 'react'
|
||||
import { Slot } from '@radix-ui/react-slot';
|
||||
import { type VariantProps, cva } from 'class-variance-authority';
|
||||
import { type ButtonHTMLAttributes, forwardRef } from 'react';
|
||||
|
||||
import { cn } from '@/utils/twMerge';
|
||||
|
||||
const buttonVariants = cva(
|
||||
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
@ -12,39 +12,40 @@ const buttonVariants = cva(
|
||||
default: 'bg-primary text-primary-foreground',
|
||||
outline: 'border border-border bg-background',
|
||||
secondary: 'bg-secondary text-secondary-foreground',
|
||||
ghost: 'text-accent-foreground hover:bg-accent hover:text-accent-foreground'
|
||||
ghost: 'text-accent-foreground hover:bg-accent hover:text-accent-foreground',
|
||||
},
|
||||
size: {
|
||||
default: 'h-10 px-5 py-2 rounded-full',
|
||||
icon: 'size-8 rounded-full',
|
||||
lgIcon: 'size-10 rounded-full'
|
||||
}
|
||||
lgIcon: 'size-10 rounded-full',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default'
|
||||
}
|
||||
}
|
||||
)
|
||||
size: 'default',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
}
|
||||
export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof buttonVariants> & {
|
||||
asChild?: boolean;
|
||||
};
|
||||
|
||||
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : 'button'
|
||||
({
|
||||
className, variant, size, asChild = false, ...props
|
||||
}, ref) => {
|
||||
const Comp = asChild ? Slot : 'button';
|
||||
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = 'Button'
|
||||
);
|
||||
},
|
||||
);
|
||||
Button.displayName = 'Button';
|
||||
|
||||
export { Button, buttonVariants }
|
||||
export { Button, buttonVariants };
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { cn } from '@/utils/twMerge';
|
||||
import { type HTMLAttributes, forwardRef } from 'react'
|
||||
import { type HTMLAttributes, forwardRef } from 'react';
|
||||
|
||||
import { cn } from '@/utils/twMerge';
|
||||
|
||||
const Card = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
@ -8,13 +8,13 @@ const Card = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'bg-card text-card-foreground border-border rounded-lg border shadow-sm',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
Card.displayName = 'Card'
|
||||
),
|
||||
);
|
||||
Card.displayName = 'Card';
|
||||
|
||||
const CardHeader = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
@ -23,9 +23,9 @@ const CardHeader = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
className={cn('flex flex-col space-y-1.5 p-6', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
CardHeader.displayName = 'CardHeader'
|
||||
),
|
||||
);
|
||||
CardHeader.displayName = 'CardHeader';
|
||||
|
||||
const CardTitle = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
@ -33,13 +33,13 @@ const CardTitle = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'text-2xl font-semibold leading-none tracking-wide',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
CardTitle.displayName = 'CardTitle'
|
||||
),
|
||||
);
|
||||
CardTitle.displayName = 'CardTitle';
|
||||
|
||||
const CardDescription = forwardRef<
|
||||
HTMLDivElement,
|
||||
@ -50,15 +50,15 @@ const CardDescription = forwardRef<
|
||||
className={cn('text-muted-foreground text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CardDescription.displayName = 'CardDescription'
|
||||
));
|
||||
CardDescription.displayName = 'CardDescription';
|
||||
|
||||
const CardContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
|
||||
)
|
||||
)
|
||||
CardContent.displayName = 'CardContent'
|
||||
),
|
||||
);
|
||||
CardContent.displayName = 'CardContent';
|
||||
|
||||
const CardFooter = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
@ -67,8 +67,10 @@ const CardFooter = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
className={cn('flex items-center p-6 pt-0', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
CardFooter.displayName = 'CardFooter'
|
||||
),
|
||||
);
|
||||
CardFooter.displayName = 'CardFooter';
|
||||
|
||||
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle }
|
||||
export {
|
||||
Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,
|
||||
};
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { cn } from '@/utils/twMerge';
|
||||
import * as LabelPrimitive from '@radix-ui/react-label'
|
||||
import { Slot } from '@radix-ui/react-slot'
|
||||
import { Slot } from '@radix-ui/react-slot';
|
||||
import {
|
||||
type ComponentPropsWithoutRef,
|
||||
type ComponentRef,
|
||||
@ -10,82 +8,62 @@ import {
|
||||
createContext,
|
||||
forwardRef,
|
||||
useContext,
|
||||
useId
|
||||
} from 'react'
|
||||
useId,
|
||||
} from 'react';
|
||||
import {
|
||||
Controller,
|
||||
type ControllerProps,
|
||||
type FieldPath,
|
||||
type FieldValues,
|
||||
FormProvider,
|
||||
useFormContext
|
||||
} from 'react-hook-form'
|
||||
useFormContext,
|
||||
} from 'react-hook-form';
|
||||
|
||||
import { cn } from '@/utils/twMerge';
|
||||
|
||||
import { Label } from './Label'
|
||||
import { Label } from './Label';
|
||||
|
||||
const Form = FormProvider
|
||||
import type * as LabelPrimitive from '@radix-ui/react-label';
|
||||
|
||||
const Form = FormProvider;
|
||||
|
||||
type FormFieldContextValue<
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||
> = {
|
||||
name: TName
|
||||
}
|
||||
name: TName;
|
||||
};
|
||||
|
||||
const FormFieldContext = createContext<FormFieldContextValue>(
|
||||
{} as FormFieldContextValue
|
||||
)
|
||||
{} as FormFieldContextValue,
|
||||
);
|
||||
|
||||
const FormField = <
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||
>({
|
||||
...props
|
||||
}: ControllerProps<TFieldValues, TName>) => {
|
||||
return (
|
||||
}: ControllerProps<TFieldValues, TName>) => (
|
||||
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
||||
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||
<Controller {...props} />
|
||||
</FormFieldContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
const useFormField = () => {
|
||||
const fieldContext = useContext(FormFieldContext)
|
||||
const itemContext = useContext(FormItemContext)
|
||||
const { getFieldState, formState } = useFormContext()
|
||||
|
||||
const fieldState = getFieldState(fieldContext.name, formState)
|
||||
|
||||
if (!fieldContext) {
|
||||
throw new Error('useFormField should be used within <FormField>')
|
||||
}
|
||||
|
||||
const { id } = itemContext
|
||||
|
||||
return {
|
||||
id,
|
||||
name: fieldContext.name,
|
||||
formItemId: `${id}-form-item`,
|
||||
formDescriptionId: `${id}-form-item-description`,
|
||||
formMessageId: `${id}-form-item-message`,
|
||||
...fieldState
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
type FormItemContextValue = {
|
||||
id: string
|
||||
}
|
||||
id: string;
|
||||
};
|
||||
|
||||
const FormItemContext = createContext<FormItemContextValue>(
|
||||
{} as FormItemContextValue
|
||||
)
|
||||
{} as FormItemContextValue,
|
||||
);
|
||||
|
||||
const FormItem = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => {
|
||||
const id = useId()
|
||||
const id = useId();
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
||||
<FormItemContext.Provider value={{ id }}>
|
||||
<div
|
||||
ref={ref}
|
||||
@ -93,16 +71,38 @@ const FormItem = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
{...props}
|
||||
/>
|
||||
</FormItemContext.Provider>
|
||||
)
|
||||
}
|
||||
)
|
||||
FormItem.displayName = 'FormItem'
|
||||
);
|
||||
},
|
||||
);
|
||||
FormItem.displayName = 'FormItem';
|
||||
|
||||
const useFormField = () => {
|
||||
const fieldContext = useContext(FormFieldContext);
|
||||
const itemContext = useContext(FormItemContext);
|
||||
const { getFieldState, formState } = useFormContext();
|
||||
|
||||
const fieldState = getFieldState(fieldContext.name, formState);
|
||||
|
||||
if (!fieldContext) {
|
||||
throw new Error('useFormField should be used within <FormField>');
|
||||
}
|
||||
|
||||
const { id } = itemContext;
|
||||
|
||||
return {
|
||||
id,
|
||||
name: fieldContext.name,
|
||||
formItemId: `${id}-form-item`,
|
||||
formDescriptionId: `${id}-form-item-description`,
|
||||
formMessageId: `${id}-form-item-message`,
|
||||
...fieldState,
|
||||
};
|
||||
};
|
||||
const FormLabel = forwardRef<
|
||||
ComponentRef<typeof LabelPrimitive.Root>,
|
||||
ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { error, formItemId } = useFormField()
|
||||
const { error, formItemId } = useFormField();
|
||||
|
||||
return (
|
||||
<Label
|
||||
@ -111,73 +111,74 @@ const FormLabel = forwardRef<
|
||||
htmlFor={formItemId}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormLabel.displayName = 'FormLabel'
|
||||
);
|
||||
});
|
||||
FormLabel.displayName = 'FormLabel';
|
||||
|
||||
const FormControl = forwardRef<
|
||||
ComponentRef<typeof Slot>,
|
||||
ComponentPropsWithoutRef<typeof Slot>
|
||||
>(({ ...props }, ref) => {
|
||||
const { error, formItemId, formDescriptionId, formMessageId } =
|
||||
useFormField()
|
||||
const {
|
||||
error, formItemId, formDescriptionId, formMessageId,
|
||||
} = useFormField();
|
||||
|
||||
return (
|
||||
<Slot
|
||||
ref={ref}
|
||||
id={formItemId}
|
||||
aria-describedby={
|
||||
!error
|
||||
? `${formDescriptionId}`
|
||||
? formDescriptionId
|
||||
: `${formDescriptionId} ${formMessageId}`
|
||||
}
|
||||
aria-invalid={!!error}
|
||||
id={formItemId}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormControl.displayName = 'FormControl'
|
||||
);
|
||||
});
|
||||
FormControl.displayName = 'FormControl';
|
||||
|
||||
const FormDescription = forwardRef<
|
||||
HTMLParagraphElement,
|
||||
HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { formDescriptionId } = useFormField()
|
||||
const { formDescriptionId } = useFormField();
|
||||
|
||||
return (
|
||||
<p
|
||||
ref={ref}
|
||||
id={formDescriptionId}
|
||||
className={cn('text-sm text-muted-foreground', className)}
|
||||
id={formDescriptionId}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormDescription.displayName = 'FormDescription'
|
||||
);
|
||||
});
|
||||
FormDescription.displayName = 'FormDescription';
|
||||
|
||||
const FormMessage = forwardRef<
|
||||
HTMLParagraphElement,
|
||||
HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, children, ...props }, ref) => {
|
||||
const { error, formMessageId } = useFormField()
|
||||
const body = error ? String(error?.message) : children
|
||||
const { error, formMessageId } = useFormField();
|
||||
const body = error ? String(error?.message) : children;
|
||||
|
||||
if (!body) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<p
|
||||
ref={ref}
|
||||
id={formMessageId}
|
||||
className={cn('text-sm font-medium text-destructive', className)}
|
||||
id={formMessageId}
|
||||
{...props}
|
||||
>
|
||||
{body}
|
||||
</p>
|
||||
)
|
||||
})
|
||||
FormMessage.displayName = 'FormMessage'
|
||||
);
|
||||
});
|
||||
FormMessage.displayName = 'FormMessage';
|
||||
|
||||
export {
|
||||
Form,
|
||||
@ -187,5 +188,5 @@ export {
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
useFormField
|
||||
}
|
||||
useFormField,
|
||||
};
|
||||
|
||||
@ -1,22 +1,20 @@
|
||||
import { cn } from '@/utils/twMerge';
|
||||
import { type ComponentProps, forwardRef } from 'react'
|
||||
import { type ComponentProps, forwardRef } from 'react';
|
||||
|
||||
import { cn } from '@/utils/twMerge';
|
||||
|
||||
const Input = forwardRef<HTMLInputElement, ComponentProps<'input'>>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
({ className, type, ...props }, ref) => (
|
||||
<input
|
||||
type={type}
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex h-10 w-full rounded-md border border-border bg-input px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus:border-primary focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
type={type}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Input.displayName = 'Input'
|
||||
),
|
||||
);
|
||||
Input.displayName = 'Input';
|
||||
|
||||
export { Input }
|
||||
export { Input };
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { cn } from '@/utils/twMerge';
|
||||
import { OTPInput, OTPInputContext } from 'input-otp'
|
||||
import { Dot } from 'lucide-react'
|
||||
import { OTPInput, OTPInputContext } from 'input-otp';
|
||||
import { Dot } from 'lucide-react';
|
||||
import {
|
||||
type ComponentPropsWithoutRef,
|
||||
type ComponentRef,
|
||||
forwardRef,
|
||||
useContext
|
||||
} from 'react'
|
||||
useContext,
|
||||
} from 'react';
|
||||
|
||||
import { cn } from '@/utils/twMerge';
|
||||
|
||||
const InputOTP = forwardRef<
|
||||
ComponentRef<typeof OTPInput>,
|
||||
@ -17,15 +17,15 @@ const InputOTP = forwardRef<
|
||||
>(({ className, containerClassName, ...props }, ref) => (
|
||||
<OTPInput
|
||||
ref={ref}
|
||||
className={cn('disabled:cursor-not-allowed', className)}
|
||||
containerClassName={cn(
|
||||
'flex items-center gap-2 has-disabled:opacity-50',
|
||||
containerClassName
|
||||
containerClassName,
|
||||
)}
|
||||
className={cn('disabled:cursor-not-allowed', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
InputOTP.displayName = 'InputOTP'
|
||||
));
|
||||
InputOTP.displayName = 'InputOTP';
|
||||
|
||||
const InputOTPGroup = forwardRef<
|
||||
ComponentRef<'div'>,
|
||||
@ -36,15 +36,15 @@ const InputOTPGroup = forwardRef<
|
||||
className={cn('flex items-center gap-x-3', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
InputOTPGroup.displayName = 'InputOTPGroup'
|
||||
));
|
||||
InputOTPGroup.displayName = 'InputOTPGroup';
|
||||
|
||||
const InputOTPSlot = forwardRef<
|
||||
ComponentRef<'div'>,
|
||||
ComponentPropsWithoutRef<'div'> & { index: number }
|
||||
>(({ index, className, ...props }, ref) => {
|
||||
const inputOTPContext = useContext(OTPInputContext)
|
||||
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]
|
||||
const inputOTPContext = useContext(OTPInputContext);
|
||||
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -52,29 +52,34 @@ const InputOTPSlot = forwardRef<
|
||||
className={cn(
|
||||
'relative flex h-10 w-14 items-center justify-center rounded-md border border-border text-sm transition-all',
|
||||
isActive && 'z-10 ring-2 ring-primary ring-offset-background',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{char}
|
||||
{hasFakeCaret && (
|
||||
<div className='pointer-events-none absolute inset-0 flex items-center justify-center'>
|
||||
<div className='animate-caret-blink h-4 w-px bg-foreground duration-1000' />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{hasFakeCaret
|
||||
? (
|
||||
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
||||
<div className="animate-caret-blink h-4 w-px bg-foreground duration-1000" />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
InputOTPSlot.displayName = 'InputOTPSlot'
|
||||
: null}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
InputOTPSlot.displayName = 'InputOTPSlot';
|
||||
|
||||
const InputOTPSeparator = forwardRef<
|
||||
ComponentRef<'div'>,
|
||||
ComponentPropsWithoutRef<'div'>
|
||||
>(({ ...props }, ref) => (
|
||||
<div ref={ref} role='separator' {...props}>
|
||||
<div ref={ref} role="separator" {...props}>
|
||||
<Dot />
|
||||
</div>
|
||||
))
|
||||
InputOTPSeparator.displayName = 'InputOTPSeparator'
|
||||
));
|
||||
InputOTPSeparator.displayName = 'InputOTPSeparator';
|
||||
|
||||
export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot }
|
||||
export {
|
||||
InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot,
|
||||
};
|
||||
|
||||
@ -1,30 +1,30 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { cn } from '@/utils/twMerge'
|
||||
import * as LabelPrimitive from '@radix-ui/react-label'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
import * as LabelPrimitive from '@radix-ui/react-label';
|
||||
import { type VariantProps, cva } from 'class-variance-authority';
|
||||
import {
|
||||
type ComponentPropsWithoutRef,
|
||||
type ComponentRef,
|
||||
forwardRef
|
||||
} from 'react'
|
||||
forwardRef,
|
||||
} from 'react';
|
||||
|
||||
import { cn } from '@/utils/twMerge';
|
||||
|
||||
const labelVariants = cva(
|
||||
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
|
||||
)
|
||||
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
||||
);
|
||||
|
||||
const Label = forwardRef<
|
||||
ComponentRef<typeof LabelPrimitive.Root>,
|
||||
ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
||||
VariantProps<typeof labelVariants>
|
||||
ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||
& VariantProps<typeof labelVariants>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<LabelPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(labelVariants(), className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Label.displayName = LabelPrimitive.Root.displayName
|
||||
));
|
||||
Label.displayName = LabelPrimitive.Root.displayName;
|
||||
|
||||
export { Label }
|
||||
export { Label };
|
||||
|
||||
@ -1,25 +1,27 @@
|
||||
"use client"
|
||||
'use client';
|
||||
|
||||
import { useTheme } from "next-themes"
|
||||
import { Toaster as Sonner, ToasterProps } from "sonner"
|
||||
import { useTheme } from 'next-themes';
|
||||
import { Toaster as Sonner } from 'sonner';
|
||||
|
||||
import type { ToasterProps } from 'sonner';
|
||||
|
||||
const Toaster = ({ ...props }: ToasterProps) => {
|
||||
const { theme = "system" } = useTheme()
|
||||
const { theme = 'system' } = useTheme();
|
||||
|
||||
return (
|
||||
<Sonner
|
||||
theme={theme as ToasterProps["theme"]}
|
||||
className="toaster group"
|
||||
style={
|
||||
{
|
||||
"--normal-bg": "var(--popover)",
|
||||
"--normal-text": "var(--popover-foreground)",
|
||||
"--normal-border": "var(--border)",
|
||||
'--normal-bg': 'var(--popover)',
|
||||
'--normal-text': 'var(--popover-foreground)',
|
||||
'--normal-border': 'var(--border)',
|
||||
} as React.CSSProperties
|
||||
}
|
||||
theme={theme as ToasterProps['theme']}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export { Toaster }
|
||||
export { Toaster };
|
||||
|
||||
6
frontend/src/global.d.ts
vendored
6
frontend/src/global.d.ts
vendored
@ -1,10 +1,10 @@
|
||||
import messages from '../public/languages/ru.json';
|
||||
import type messages from '../public/languages/ru.json';
|
||||
|
||||
const locales = ['ru', 'en'] as const;
|
||||
|
||||
declare module 'next-intl' {
|
||||
interface AppConfig {
|
||||
type AppConfig = {
|
||||
Locale: (typeof locales)[number];
|
||||
Messages: typeof messages;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -2,10 +2,10 @@ import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client';
|
||||
|
||||
const httpLink = createHttpLink({
|
||||
uri: process.env.NEXT_PUBLIC_SERVER_URL,
|
||||
credentials: 'include'
|
||||
})
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
export const client = new ApolloClient({
|
||||
link: httpLink,
|
||||
cache: new InMemoryCache()
|
||||
})
|
||||
cache: new InMemoryCache(),
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export const COOKIE_NAME = 'language'
|
||||
export const languages = ['ru', 'en'] as const
|
||||
export const COOKIE_NAME = 'language';
|
||||
export const languages = ['ru', 'en'] as const;
|
||||
export const defaultLanguages: Language = 'ru';
|
||||
|
||||
export type Language = (typeof languages)[number]
|
||||
export type Language = (typeof languages)[number];
|
||||
|
||||
@ -1,14 +1,19 @@
|
||||
'use server'
|
||||
'use server';
|
||||
|
||||
import { cookies } from "next/headers";
|
||||
import { COOKIE_NAME, defaultLanguages, Language } from "./config";
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
import { COOKIE_NAME, defaultLanguages } from './config';
|
||||
|
||||
import type { Language } from './config';
|
||||
|
||||
export async function getCurrentLanguage() {
|
||||
const cookieStore = await cookies();
|
||||
return <Language>cookieStore.get(COOKIE_NAME)?.value ?? defaultLanguages;
|
||||
|
||||
return cookieStore.get(COOKIE_NAME)?.value as Language ?? defaultLanguages;
|
||||
}
|
||||
|
||||
export async function setCurrentLanguage(lang: Language) {
|
||||
const cookieStore = await cookies();
|
||||
|
||||
return cookieStore.set(COOKIE_NAME, lang);
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { getRequestConfig } from 'next-intl/server';
|
||||
import { getCurrentLanguage } from "./language"
|
||||
|
||||
import { getCurrentLanguage } from './language';
|
||||
|
||||
export default getRequestConfig(async () => {
|
||||
const locale = await getCurrentLanguage();
|
||||
@ -8,5 +9,5 @@ export default getRequestConfig(async () => {
|
||||
return {
|
||||
locale,
|
||||
messages,
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { ApolloProvider } from '@apollo/client';
|
||||
import React from 'react';
|
||||
|
||||
import { client } from '@/libs/apollo-client';
|
||||
import { ApolloProvider } from '@apollo/client';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
|
||||
import type { PropsWithChildren } from 'react';
|
||||
|
||||
const ApolloClientProvider = (props: PropsWithChildren) => {
|
||||
const {children} = props;
|
||||
const { children } = props;
|
||||
|
||||
return (
|
||||
<ApolloProvider client={client}>
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
"use client";
|
||||
'use client';
|
||||
|
||||
import * as React from "react";
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||
import { ThemeProvider as NextThemesProvider } from 'next-themes';
|
||||
import * as React from 'react';
|
||||
|
||||
export function ThemeProvider({children,
|
||||
export const ThemeProvider = ({
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NextThemesProvider>) {
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
|
||||
}
|
||||
}: React.ComponentProps<typeof NextThemesProvider>) => (
|
||||
<NextThemesProvider {...props}>
|
||||
{children}
|
||||
</NextThemesProvider>
|
||||
);
|
||||
|
||||
@ -1,25 +1,26 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { useTheme } from 'next-themes'
|
||||
import type { ComponentProps } from 'react'
|
||||
import { Toaster as Sonner } from 'sonner'
|
||||
import { useTheme } from 'next-themes';
|
||||
import { Toaster as Sonner } from 'sonner';
|
||||
|
||||
type ToasterProps = ComponentProps<typeof Sonner>
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
export function ToastProvider({ ...props }: ToasterProps) {
|
||||
const { theme = 'system' } = useTheme()
|
||||
type ToasterProps = ComponentProps<typeof Sonner>;
|
||||
|
||||
export const ToastProvider = ({ ...props }: ToasterProps) => {
|
||||
const { theme = 'system' } = useTheme();
|
||||
|
||||
return (
|
||||
<Sonner
|
||||
className="toaster group"
|
||||
theme={theme as ToasterProps['theme']}
|
||||
className='toaster group'
|
||||
toastOptions={{
|
||||
classNames: {
|
||||
toast: 'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
|
||||
description: 'text-muted-foreground'
|
||||
}
|
||||
description: 'text-muted-foreground',
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { z } from 'zod'
|
||||
import { z } from 'zod';
|
||||
|
||||
export const createAccountSchema = z.object({
|
||||
name: z
|
||||
.string()
|
||||
.min(1)
|
||||
.regex(/^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*$/),
|
||||
email: z.string().email({ pattern: z.regexes.html5Email }).min(3),
|
||||
password: z.string().min(8)
|
||||
})
|
||||
email: z.email({ pattern: z.regexes.html5Email }).min(3),
|
||||
password: z.string().min(8),
|
||||
});
|
||||
|
||||
export type TypeCreateAccountSchema = z.infer<typeof createAccountSchema>
|
||||
export type TypeCreateAccountSchema = z.infer<typeof createAccountSchema>;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { z } from 'zod'
|
||||
import { z } from 'zod';
|
||||
|
||||
export const loginSchema = z.object({
|
||||
login: z.string().min(1),
|
||||
password: z.string().min(8),
|
||||
pin: z.string().optional()
|
||||
})
|
||||
pin: z.string().optional(),
|
||||
});
|
||||
|
||||
export type TypeLoginSchema = z.infer<typeof loginSchema>
|
||||
export type TypeLoginSchema = z.infer<typeof loginSchema>;
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { z } from 'zod'
|
||||
import { z } from 'zod';
|
||||
|
||||
export const newPasswordSchema = z
|
||||
.object({
|
||||
password: z.string().min(8),
|
||||
passwordRepeat: z.string().min(8)
|
||||
})
|
||||
.refine(data => data.password === data.passwordRepeat, {
|
||||
path: ['passwordRepeat']
|
||||
passwordRepeat: z.string().min(8),
|
||||
})
|
||||
.refine((data) => data.password === data.passwordRepeat, {
|
||||
path: ['passwordRepeat'],
|
||||
});
|
||||
|
||||
export type TypeNewPasswordSchema = z.infer<typeof newPasswordSchema>
|
||||
export type TypeNewPasswordSchema = z.infer<typeof newPasswordSchema>;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { z } from 'zod'
|
||||
import { z } from 'zod';
|
||||
|
||||
export const resetPasswordSchema = z.object({
|
||||
email: z.string().email()
|
||||
})
|
||||
email: z.email(),
|
||||
});
|
||||
|
||||
export type TypeResetPasswordSchema = z.infer<typeof resetPasswordSchema>
|
||||
export type TypeResetPasswordSchema = z.infer<typeof resetPasswordSchema>;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
import { clsx, type ClassValue } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
@ -451,7 +451,7 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.27.1"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.26.10":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.16.3", "@babel/runtime@^7.26.10":
|
||||
version "7.28.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.2.tgz#2ae5a9d51cc583bd1f5673b3bb70d6d819682473"
|
||||
integrity sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==
|
||||
@ -1399,6 +1399,13 @@
|
||||
dependencies:
|
||||
fast-glob "3.3.1"
|
||||
|
||||
"@next/eslint-plugin-next@15.4.5":
|
||||
version "15.4.5"
|
||||
resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-15.4.5.tgz#fa46b04406c0b0aea22413b336f32595cd7613b6"
|
||||
integrity sha512-YhbrlbEt0m4jJnXHMY/cCUDBAWgd5SaTa5mJjzOt82QwflAFfW/h3+COp2TfVSzhmscIZ5sg2WXt3MLziqCSCw==
|
||||
dependencies:
|
||||
fast-glob "3.3.1"
|
||||
|
||||
"@next/swc-darwin-arm64@15.4.5":
|
||||
version "15.4.5"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.5.tgz#a716f1b8baf6dac0ac4cad9670350f637991f89e"
|
||||
@ -1516,6 +1523,18 @@
|
||||
resolved "https://registry.yarnpkg.com/@standard-schema/utils/-/utils-0.3.0.tgz#3d5e608f16c2390c10528e98e59aef6bf73cae7b"
|
||||
integrity sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==
|
||||
|
||||
"@stylistic/eslint-plugin@5.2.0":
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin/-/eslint-plugin-5.2.0.tgz#fd664d2c81544cbe12c35d4af6d79b42814fc57f"
|
||||
integrity sha512-RCEdbREv9EBiToUBQTlRhVYKG093I6ZnnQ990j08eJ6uRZh71DXkOnoxtTLfDQ6utVCVQzrhZFHZP0zfrfOIjA==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.7.0"
|
||||
"@typescript-eslint/types" "^8.37.0"
|
||||
eslint-visitor-keys "^4.2.1"
|
||||
espree "^10.4.0"
|
||||
estraverse "^5.3.0"
|
||||
picomatch "^4.0.3"
|
||||
|
||||
"@swc/helpers@0.5.15":
|
||||
version "0.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.15.tgz#79efab344c5819ecf83a43f3f9f811fc84b516d7"
|
||||
@ -1712,6 +1731,21 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz#332392883f936137cd6252c8eb236d298e514e70"
|
||||
integrity sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==
|
||||
dependencies:
|
||||
"@eslint-community/regexpp" "^4.10.0"
|
||||
"@typescript-eslint/scope-manager" "8.37.0"
|
||||
"@typescript-eslint/type-utils" "8.37.0"
|
||||
"@typescript-eslint/utils" "8.37.0"
|
||||
"@typescript-eslint/visitor-keys" "8.37.0"
|
||||
graphemer "^1.4.0"
|
||||
ignore "^7.0.0"
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^2.1.0"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0":
|
||||
version "8.38.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz#6e5220d16f2691ab6d983c1737dd5b36e17641b7"
|
||||
@ -1727,6 +1761,17 @@
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^2.1.0"
|
||||
|
||||
"@typescript-eslint/parser@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.37.0.tgz#b87f6b61e25ad5cc5bbf8baf809b8da889c89804"
|
||||
integrity sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "8.37.0"
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
"@typescript-eslint/typescript-estree" "8.37.0"
|
||||
"@typescript-eslint/visitor-keys" "8.37.0"
|
||||
debug "^4.3.4"
|
||||
|
||||
"@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0":
|
||||
version "8.38.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.38.0.tgz#6723a5ea881e1777956b1045cba30be5ea838293"
|
||||
@ -1738,6 +1783,15 @@
|
||||
"@typescript-eslint/visitor-keys" "8.38.0"
|
||||
debug "^4.3.4"
|
||||
|
||||
"@typescript-eslint/project-service@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.37.0.tgz#0594352e32a4ac9258591b88af77b5653800cdfe"
|
||||
integrity sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==
|
||||
dependencies:
|
||||
"@typescript-eslint/tsconfig-utils" "^8.37.0"
|
||||
"@typescript-eslint/types" "^8.37.0"
|
||||
debug "^4.3.4"
|
||||
|
||||
"@typescript-eslint/project-service@8.38.0":
|
||||
version "8.38.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.38.0.tgz#4900771f943163027fd7d2020a062892056b5e2f"
|
||||
@ -1747,7 +1801,15 @@
|
||||
"@typescript-eslint/types" "^8.38.0"
|
||||
debug "^4.3.4"
|
||||
|
||||
"@typescript-eslint/scope-manager@8.38.0":
|
||||
"@typescript-eslint/scope-manager@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz#a31a3c80ca2ef4ed58de13742debb692e7d4c0a4"
|
||||
integrity sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
"@typescript-eslint/visitor-keys" "8.37.0"
|
||||
|
||||
"@typescript-eslint/scope-manager@8.38.0", "@typescript-eslint/scope-manager@^8.15.0":
|
||||
version "8.38.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz#5a0efcb5c9cf6e4121b58f87972f567c69529226"
|
||||
integrity sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==
|
||||
@ -1755,11 +1817,27 @@
|
||||
"@typescript-eslint/types" "8.38.0"
|
||||
"@typescript-eslint/visitor-keys" "8.38.0"
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@8.38.0", "@typescript-eslint/tsconfig-utils@^8.38.0":
|
||||
"@typescript-eslint/tsconfig-utils@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz#47a2760d265c6125f8e7864bc5c8537cad2bd053"
|
||||
integrity sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@8.38.0", "@typescript-eslint/tsconfig-utils@^8.37.0", "@typescript-eslint/tsconfig-utils@^8.38.0":
|
||||
version "8.38.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz#6de4ce224a779601a8df667db56527255c42c4d0"
|
||||
integrity sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==
|
||||
|
||||
"@typescript-eslint/type-utils@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz#2a682e4c6ff5886712dad57e9787b5e417124507"
|
||||
integrity sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
"@typescript-eslint/typescript-estree" "8.37.0"
|
||||
"@typescript-eslint/utils" "8.37.0"
|
||||
debug "^4.3.4"
|
||||
ts-api-utils "^2.1.0"
|
||||
|
||||
"@typescript-eslint/type-utils@8.38.0":
|
||||
version "8.38.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz#a56cd84765fa6ec135fe252b5db61e304403a85b"
|
||||
@ -1771,11 +1849,32 @@
|
||||
debug "^4.3.4"
|
||||
ts-api-utils "^2.1.0"
|
||||
|
||||
"@typescript-eslint/types@8.38.0", "@typescript-eslint/types@^8.38.0":
|
||||
"@typescript-eslint/types@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.37.0.tgz#09517aa9625eb3c68941dde3ac8835740587b6ff"
|
||||
integrity sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==
|
||||
|
||||
"@typescript-eslint/types@8.38.0", "@typescript-eslint/types@^8.37.0", "@typescript-eslint/types@^8.38.0":
|
||||
version "8.38.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.38.0.tgz#297351c994976b93c82ac0f0e206c8143aa82529"
|
||||
integrity sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==
|
||||
|
||||
"@typescript-eslint/typescript-estree@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz#a07e4574d8e6e4355a558f61323730c987f5fcbc"
|
||||
integrity sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==
|
||||
dependencies:
|
||||
"@typescript-eslint/project-service" "8.37.0"
|
||||
"@typescript-eslint/tsconfig-utils" "8.37.0"
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
"@typescript-eslint/visitor-keys" "8.37.0"
|
||||
debug "^4.3.4"
|
||||
fast-glob "^3.3.2"
|
||||
is-glob "^4.0.3"
|
||||
minimatch "^9.0.4"
|
||||
semver "^7.6.0"
|
||||
ts-api-utils "^2.1.0"
|
||||
|
||||
"@typescript-eslint/typescript-estree@8.38.0":
|
||||
version "8.38.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz#82262199eb6778bba28a319e25ad05b1158957df"
|
||||
@ -1792,7 +1891,17 @@
|
||||
semver "^7.6.0"
|
||||
ts-api-utils "^2.1.0"
|
||||
|
||||
"@typescript-eslint/utils@8.38.0":
|
||||
"@typescript-eslint/utils@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.37.0.tgz#189ea59b2709f5d898614611f091a776751ee335"
|
||||
integrity sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.7.0"
|
||||
"@typescript-eslint/scope-manager" "8.37.0"
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
"@typescript-eslint/typescript-estree" "8.37.0"
|
||||
|
||||
"@typescript-eslint/utils@8.38.0", "@typescript-eslint/utils@^8.0.0", "@typescript-eslint/utils@^8.15.0":
|
||||
version "8.38.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.38.0.tgz#5f10159899d30eb92ba70e642ca6f754bddbf15a"
|
||||
integrity sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==
|
||||
@ -1802,6 +1911,14 @@
|
||||
"@typescript-eslint/types" "8.38.0"
|
||||
"@typescript-eslint/typescript-estree" "8.38.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz#cdb6a6bd3e8d6dd69bd70c1bdda36e2d18737455"
|
||||
integrity sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.37.0"
|
||||
eslint-visitor-keys "^4.2.1"
|
||||
|
||||
"@typescript-eslint/visitor-keys@8.38.0":
|
||||
version "8.38.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz#a9765a527b082cb8fc60fd8a16e47c7ad5b60ea5"
|
||||
@ -2594,7 +2711,7 @@ debounce@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
|
||||
integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
|
||||
|
||||
debug@4, debug@4.4.1, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0:
|
||||
debug@4, debug@4.4.1, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0, debug@^4.4.1:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
|
||||
integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
|
||||
@ -2874,6 +2991,25 @@ escape-string-regexp@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||
|
||||
eslint-config-ksv741@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-ksv741/-/eslint-config-ksv741-0.2.0.tgz#07adf285648823dad3b37821bd63eb598d6e4c9a"
|
||||
integrity sha512-cGEY1VE79RuFrndqGEWeYow34W9ogi8JOuLOmL9QuPR66a07Evwu41dIlcBcXWcU493w/DXb9iQabJBmCMhYzQ==
|
||||
dependencies:
|
||||
"@eslint/eslintrc" "3.3.1"
|
||||
"@stylistic/eslint-plugin" "5.2.0"
|
||||
eslint-import-resolver-typescript "4.4.4"
|
||||
eslint-plugin-import "2.32.0"
|
||||
eslint-plugin-jest "29.0.1"
|
||||
eslint-plugin-jest-dom "5.5.0"
|
||||
eslint-plugin-jest-formatting "3.1.0"
|
||||
eslint-plugin-jsx-a11y "6.10.2"
|
||||
eslint-plugin-react "7.37.5"
|
||||
eslint-plugin-react-hooks "5.2.0"
|
||||
eslint-plugin-testing-library "7.6.0"
|
||||
globals "16.3.0"
|
||||
typescript-eslint "8.37.0"
|
||||
|
||||
eslint-config-next@15.4.4:
|
||||
version "15.4.4"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-15.4.4.tgz#df20632c342b2b48e8450d0028b8fd15edb10a60"
|
||||
@ -2890,6 +3026,14 @@ eslint-config-next@15.4.4:
|
||||
eslint-plugin-react "^7.37.0"
|
||||
eslint-plugin-react-hooks "^5.0.0"
|
||||
|
||||
eslint-import-context@^0.1.8:
|
||||
version "0.1.9"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-context/-/eslint-import-context-0.1.9.tgz#967b0b2f0a90ef4b689125e088f790f0b7756dbe"
|
||||
integrity sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==
|
||||
dependencies:
|
||||
get-tsconfig "^4.10.1"
|
||||
stable-hash-x "^0.2.0"
|
||||
|
||||
eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9:
|
||||
version "0.3.9"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac"
|
||||
@ -2899,6 +3043,19 @@ eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9:
|
||||
is-core-module "^2.13.0"
|
||||
resolve "^1.22.4"
|
||||
|
||||
eslint-import-resolver-typescript@4.4.4:
|
||||
version "4.4.4"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz#3e83a9c25f4a053fe20e1b07b47e04e8519a8720"
|
||||
integrity sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==
|
||||
dependencies:
|
||||
debug "^4.4.1"
|
||||
eslint-import-context "^0.1.8"
|
||||
get-tsconfig "^4.10.1"
|
||||
is-bun-module "^2.0.0"
|
||||
stable-hash-x "^0.2.0"
|
||||
tinyglobby "^0.2.14"
|
||||
unrs-resolver "^1.7.11"
|
||||
|
||||
eslint-import-resolver-typescript@^3.5.2:
|
||||
version "3.10.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz#23dac32efa86a88e2b8232eb244ac499ad636db2"
|
||||
@ -2919,7 +3076,7 @@ eslint-module-utils@^2.12.1:
|
||||
dependencies:
|
||||
debug "^3.2.7"
|
||||
|
||||
eslint-plugin-import@^2.31.0:
|
||||
eslint-plugin-import@2.32.0, eslint-plugin-import@^2.31.0:
|
||||
version "2.32.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz#602b55faa6e4caeaa5e970c198b5c00a37708980"
|
||||
integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==
|
||||
@ -2944,7 +3101,27 @@ eslint-plugin-import@^2.31.0:
|
||||
string.prototype.trimend "^1.0.9"
|
||||
tsconfig-paths "^3.15.0"
|
||||
|
||||
eslint-plugin-jsx-a11y@^6.10.0:
|
||||
eslint-plugin-jest-dom@5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.5.0.tgz#3ccdfe197eddb4108f390db583057a5dacccd4a0"
|
||||
integrity sha512-CRlXfchTr7EgC3tDI7MGHY6QjdJU5Vv2RPaeeGtkXUHnKZf04kgzMPIJUXt4qKCvYWVVIEo9ut9Oq1vgXAykEA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.16.3"
|
||||
requireindex "^1.2.0"
|
||||
|
||||
eslint-plugin-jest-formatting@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jest-formatting/-/eslint-plugin-jest-formatting-3.1.0.tgz#b26dd5a40f432b642dcc880021a771bb1c93dcd2"
|
||||
integrity sha512-XyysraZ1JSgGbLSDxjj5HzKKh0glgWf+7CkqxbTqb7zEhW7X2WHo5SBQ8cGhnszKN+2Lj3/oevBlHNbHezoc/A==
|
||||
|
||||
eslint-plugin-jest@29.0.1:
|
||||
version "29.0.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-29.0.1.tgz#0f72a81349409d20742208260c9a6cb9efed4df5"
|
||||
integrity sha512-EE44T0OSMCeXhDrrdsbKAhprobKkPtJTbQz5yEktysNpHeDZTAL1SfDTNKmcFfJkY6yrQLtTKZALrD3j/Gpmiw==
|
||||
dependencies:
|
||||
"@typescript-eslint/utils" "^8.0.0"
|
||||
|
||||
eslint-plugin-jsx-a11y@6.10.2, eslint-plugin-jsx-a11y@^6.10.0:
|
||||
version "6.10.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz#d2812bb23bf1ab4665f1718ea442e8372e638483"
|
||||
integrity sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==
|
||||
@ -2965,12 +3142,12 @@ eslint-plugin-jsx-a11y@^6.10.0:
|
||||
safe-regex-test "^1.0.3"
|
||||
string.prototype.includes "^2.0.1"
|
||||
|
||||
eslint-plugin-react-hooks@^5.0.0:
|
||||
eslint-plugin-react-hooks@5.2.0, eslint-plugin-react-hooks@^5.0.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3"
|
||||
integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==
|
||||
|
||||
eslint-plugin-react@^7.37.0:
|
||||
eslint-plugin-react@7.37.5, eslint-plugin-react@^7.37.0:
|
||||
version "7.37.5"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065"
|
||||
integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==
|
||||
@ -2994,6 +3171,14 @@ eslint-plugin-react@^7.37.0:
|
||||
string.prototype.matchall "^4.0.12"
|
||||
string.prototype.repeat "^1.0.0"
|
||||
|
||||
eslint-plugin-testing-library@7.6.0:
|
||||
version "7.6.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-7.6.0.tgz#ac6ab335c19d3da2a2456379c21a12a8e042783c"
|
||||
integrity sha512-rxCz4VQFb45kDeFLnQcjGpeb72r4HmCh6v49d+DhrD2HVpnJuwK/GOnPjezWS7CytkNjQjpXcPopxLN++FlXxw==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "^8.15.0"
|
||||
"@typescript-eslint/utils" "^8.15.0"
|
||||
|
||||
eslint-scope@^8.4.0:
|
||||
version "8.4.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82"
|
||||
@ -3311,7 +3496,7 @@ get-symbol-description@^1.1.0:
|
||||
es-errors "^1.3.0"
|
||||
get-intrinsic "^1.2.6"
|
||||
|
||||
get-tsconfig@^4.10.0:
|
||||
get-tsconfig@^4.10.0, get-tsconfig@^4.10.1:
|
||||
version "4.10.1"
|
||||
resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.10.1.tgz#d34c1c01f47d65a606c37aa7a177bc3e56ab4b2e"
|
||||
integrity sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==
|
||||
@ -3344,6 +3529,11 @@ glob@^7.1.1:
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
globals@16.3.0:
|
||||
version "16.3.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-16.3.0.tgz#66118e765ddaf9e2d880f7e17658543f93f1f667"
|
||||
integrity sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==
|
||||
|
||||
globals@^14.0.0:
|
||||
version "14.0.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
|
||||
@ -4633,7 +4823,7 @@ picomatch@^2.3.1:
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
picomatch@^4.0.2:
|
||||
picomatch@^4.0.2, picomatch@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042"
|
||||
integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==
|
||||
@ -4788,6 +4978,11 @@ require-main-filename@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
|
||||
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
|
||||
|
||||
requireindex@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef"
|
||||
integrity sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==
|
||||
|
||||
resolve-from@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
|
||||
@ -5120,6 +5315,11 @@ sponge-case@^1.0.1:
|
||||
dependencies:
|
||||
tslib "^2.0.3"
|
||||
|
||||
stable-hash-x@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/stable-hash-x/-/stable-hash-x-0.2.0.tgz#dfd76bfa5d839a7470125c6a6b3c8b22061793e9"
|
||||
integrity sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==
|
||||
|
||||
stable-hash@^0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/stable-hash/-/stable-hash-0.0.5.tgz#94e8837aaeac5b4d0f631d2972adef2924b40269"
|
||||
@ -5316,7 +5516,7 @@ timeout-signal@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/timeout-signal/-/timeout-signal-2.0.0.tgz#23207ea448d50258bb0defe3beea4a467643abba"
|
||||
integrity sha512-YBGpG4bWsHoPvofT6y/5iqulfXIiIErl5B0LdtHT1mGXDFTAhhRrbUpTvBgYbovr+3cKblya2WAOcpoy90XguA==
|
||||
|
||||
tinyglobby@^0.2.13:
|
||||
tinyglobby@^0.2.13, tinyglobby@^0.2.14:
|
||||
version "0.2.14"
|
||||
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d"
|
||||
integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==
|
||||
@ -5454,6 +5654,16 @@ typed-array-length@^1.0.7:
|
||||
possible-typed-array-names "^1.0.0"
|
||||
reflect.getprototypeof "^1.0.6"
|
||||
|
||||
typescript-eslint@8.37.0:
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.37.0.tgz#2235ddfa40cdbdadb1afb05f8bda688a2294b4c2"
|
||||
integrity sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin" "8.37.0"
|
||||
"@typescript-eslint/parser" "8.37.0"
|
||||
"@typescript-eslint/typescript-estree" "8.37.0"
|
||||
"@typescript-eslint/utils" "8.37.0"
|
||||
|
||||
typescript@5.8.3:
|
||||
version "5.8.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
|
||||
@ -5496,7 +5706,7 @@ unixify@^1.0.0:
|
||||
dependencies:
|
||||
normalize-path "^2.1.1"
|
||||
|
||||
unrs-resolver@^1.6.2:
|
||||
unrs-resolver@^1.6.2, unrs-resolver@^1.7.11:
|
||||
version "1.11.1"
|
||||
resolved "https://registry.yarnpkg.com/unrs-resolver/-/unrs-resolver-1.11.1.tgz#be9cd8686c99ef53ecb96df2a473c64d304048a9"
|
||||
integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user