[frontend]: add eslint
This commit is contained in:
parent
75930d105e
commit
a6cef0298d
@ -1,19 +1,121 @@
|
|||||||
import { dirname } from "path";
|
import config from 'eslint-config-ksv741';
|
||||||
import { fileURLToPath } from "url";
|
import nextPlugin from '@next/eslint-plugin-next'
|
||||||
import { FlatCompat } from "@eslint/eslintrc";
|
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const {flatConfig} = nextPlugin;
|
||||||
const __dirname = dirname(__filename);
|
|
||||||
|
|
||||||
const compat = new FlatCompat({
|
export default [
|
||||||
baseDirectory: __dirname,
|
...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 = [
|
'react/destructuring-assignment': ['off', 'never', { ignoreClassFields: true, destructureInSignature: 'always' }],
|
||||||
...compat.extends("next/core-web-vitals", "next/typescript"),
|
"@typescript-eslint/no-misused-promises": ["error", {
|
||||||
|
"checksVoidReturn": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ignores: ['src/graphql/generated']
|
ignores: ['src/graphql/generated']
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export default eslintConfig;
|
|
||||||
|
|||||||
@ -35,11 +35,13 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "3.3.1",
|
"@eslint/eslintrc": "3.3.1",
|
||||||
|
"@next/eslint-plugin-next": "15.4.5",
|
||||||
"@tailwindcss/postcss": "4.1.11",
|
"@tailwindcss/postcss": "4.1.11",
|
||||||
"@types/node": "22.17.0",
|
"@types/node": "22.17.0",
|
||||||
"@types/react": "19.1.9",
|
"@types/react": "19.1.9",
|
||||||
"@types/react-dom": "19.1.7",
|
"@types/react-dom": "19.1.7",
|
||||||
"eslint": "9.32.0",
|
"eslint": "9.32.0",
|
||||||
|
"eslint-config-ksv741": "0.2.0",
|
||||||
"eslint-config-next": "15.4.4",
|
"eslint-config-next": "15.4.4",
|
||||||
"tailwindcss": "4.1.11",
|
"tailwindcss": "4.1.11",
|
||||||
"tw-animate-css": "1.3.6",
|
"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 { getTranslations } from 'next-intl/server';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import CreateAccountForm from '@/components/features/auth/forms/CreateAccountForm';
|
||||||
|
|
||||||
|
import type { Metadata } from 'next';
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const t = await getTranslations('auth.register');
|
const t = await getTranslations('auth.register');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: t('heading')
|
title: t('heading'),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreateAccountPage = () => {
|
const CreateAccountPage = () => (
|
||||||
return (
|
|
||||||
<CreateAccountForm />
|
<CreateAccountForm />
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
export default CreateAccountPage;
|
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 { getTranslations } from 'next-intl/server';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import LoginAccountForm from '@/components/features/auth/forms/LoginAccountForm';
|
||||||
|
|
||||||
|
import type { Metadata } from 'next';
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const t = await getTranslations('auth.login');
|
const t = await getTranslations('auth.login');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: t('heading')
|
title: t('heading'),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const LoginAccountPage = () => {
|
const LoginAccountPage = () => (
|
||||||
return (
|
|
||||||
<LoginAccountForm />
|
<LoginAccountForm />
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
export default LoginAccountPage;
|
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 { getTranslations } from 'next-intl/server';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { NewPasswordForm } from '@/components/features/auth/forms/NewPasswordForm';
|
||||||
|
|
||||||
|
import type { Metadata } from 'next';
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const t = await getTranslations('auth.newPassword');
|
const t = await getTranslations('auth.newPassword');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: t('heading')
|
title: t('heading'),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const NewPasswordPage = () => {
|
const NewPasswordPage = () => (
|
||||||
return (
|
|
||||||
<NewPasswordForm />
|
<NewPasswordForm />
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
export default NewPasswordPage;
|
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 { getTranslations } from 'next-intl/server';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { ResetPasswordForm } from '@/components/features/auth/forms/ResetPasswordForm';
|
||||||
|
|
||||||
|
import type { Metadata } from 'next';
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const t = await getTranslations('auth.resetPassword');
|
const t = await getTranslations('auth.resetPassword');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: t('heading')
|
title: t('heading'),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const ResetPasswordPage = () => {
|
const ResetPasswordPage = () => (
|
||||||
return (
|
|
||||||
<ResetPasswordForm />
|
<ResetPasswordForm />
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
export default ResetPasswordPage;
|
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 { redirect } from 'next/navigation';
|
||||||
|
import { getTranslations } from 'next-intl/server';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { VerifyAccountForm } from '@/components/features/auth/forms/VerifyAccoiuntForm';
|
||||||
|
|
||||||
|
import type { Metadata } from 'next';
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const t = await getTranslations('auth.verify');
|
const t = await getTranslations('auth.verify');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: t('heading')
|
title: t('heading'),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type VerifyAccountPageProps = {
|
type VerifyAccountPageProps = {
|
||||||
searchParams: Promise<{token: string}>
|
searchParams: Promise<{ token: string }>;
|
||||||
}
|
};
|
||||||
|
|
||||||
const VerifyAccountPage = async (props: VerifyAccountPageProps) => {
|
const VerifyAccountPage = async (props: VerifyAccountPageProps) => {
|
||||||
const { token } = await props.searchParams;
|
const { token } = await props.searchParams;
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return redirect('/account/create')
|
return redirect('/account/create');
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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 ApolloClientProvider from '@/providers/ApolloClientProvider';
|
||||||
import { ThemeProvider } from '@/providers/ThemeProvider';
|
import { ThemeProvider } from '@/providers/ThemeProvider';
|
||||||
import { ToastProvider } from '@/providers/ToastProvider';
|
import { ToastProvider } from '@/providers/ToastProvider';
|
||||||
import type { Metadata } from "next";
|
|
||||||
import { NextIntlClientProvider } from 'next-intl';
|
import '../styles/globals.css';
|
||||||
import { getLocale, getMessages } from 'next-intl/server';
|
import type { Metadata } from 'next';
|
||||||
import { Geist } from "next/font/google";
|
import type { ReactNode } from 'react';
|
||||||
import "../styles/globals.css";
|
|
||||||
|
|
||||||
const geistSans = Geist({
|
const geistSans = Geist({
|
||||||
variable: "--font-geist-sans",
|
variable: '--font-geist-sans',
|
||||||
subsets: ["latin"],
|
subsets: ['latin'],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Create Next App",
|
title: 'Create Next App',
|
||||||
description: "Generated by create next app",
|
description: 'Generated by create next app',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function RootLayout({
|
const RootLayout = async ({
|
||||||
children,
|
children,
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
children: React.ReactNode;
|
children: ReactNode;
|
||||||
}>) {
|
}>) => {
|
||||||
const locale = await getLocale()
|
const locale = await getLocale();
|
||||||
const messages = await getMessages()
|
const messages = await getMessages();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang={locale} suppressHydrationWarning>
|
<html suppressHydrationWarning lang={locale}>
|
||||||
<body className={geistSans.variable}>
|
<body className={geistSans.variable}>
|
||||||
<ApolloClientProvider>
|
<ApolloClientProvider>
|
||||||
<NextIntlClientProvider messages={messages}>
|
<NextIntlClientProvider messages={messages}>
|
||||||
<ThemeProvider
|
<ThemeProvider
|
||||||
|
disableTransitionOnChange
|
||||||
|
enableSystem
|
||||||
attribute="class"
|
attribute="class"
|
||||||
defaultTheme="dark"
|
defaultTheme="dark"
|
||||||
enableSystem
|
|
||||||
disableTransitionOnChange
|
|
||||||
>
|
>
|
||||||
<ToastProvider />
|
<ToastProvider />
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</NextIntlClientProvider>
|
</NextIntlClientProvider>
|
||||||
@ -44,4 +48,6 @@ export default async function RootLayout({
|
|||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default RootLayout;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
'use client'
|
'use client';
|
||||||
|
|
||||||
import { redirect } from 'next/navigation';
|
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 { LogoImage } from '@/components/images/LogoImage';
|
||||||
import { Button } from '@/components/ui/common/Button';
|
import { Button } from '@/components/ui/common/Button';
|
||||||
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/common/Card';
|
import {
|
||||||
import Link from 'next/link';
|
Card, CardContent, CardFooter, CardHeader, CardTitle,
|
||||||
import React, { FC, ReactNode } from 'react';
|
} from '@/components/ui/common/Card';
|
||||||
|
|
||||||
|
import type { FC, ReactNode } from 'react';
|
||||||
|
|
||||||
type AuthWrapperProps = {
|
type AuthWrapperProps = {
|
||||||
heading: string
|
heading: string;
|
||||||
backButtonLabel?: string
|
backButtonLabel?: string;
|
||||||
backButtonHref?: string
|
backButtonHref?: string;
|
||||||
children: ReactNode
|
children: ReactNode;
|
||||||
}
|
};
|
||||||
const AuthWrapper: FC<AuthWrapperProps> = (props) => {
|
const AuthWrapper: FC<AuthWrapperProps> = (props) => {
|
||||||
const { children, backButtonHref, backButtonLabel, heading } = props;
|
const {
|
||||||
|
children, backButtonHref, backButtonLabel, heading,
|
||||||
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex h-full items-center justify-center'>
|
<div className="flex h-full items-center justify-center">
|
||||||
<Card className='w-[450px]'>
|
<Card className="w-[450px]">
|
||||||
<CardHeader className='flex-row items-center justify-center gap-x-4'>
|
<CardHeader className="flex-row items-center justify-center gap-x-4">
|
||||||
<LogoImage />
|
<LogoImage />
|
||||||
<CardTitle>{heading}</CardTitle>
|
|
||||||
|
<CardTitle>
|
||||||
|
{heading}
|
||||||
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>{children}</CardContent>
|
|
||||||
<CardFooter className='-mt-2'>
|
<CardContent>
|
||||||
{backButtonLabel && backButtonHref && (
|
{children}
|
||||||
<Link href={backButtonHref} className='w-full'>
|
</CardContent>
|
||||||
<Button variant='ghost' className='w-full'>
|
|
||||||
|
<CardFooter className="-mt-2">
|
||||||
|
{backButtonLabel && backButtonHref
|
||||||
|
? (
|
||||||
|
<Link className="w-full" href={backButtonHref}>
|
||||||
|
<Button className="w-full" variant="ghost">
|
||||||
{backButtonLabel}
|
{backButtonLabel}
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)
|
||||||
|
: null}
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</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 { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { CircleCheck } from 'lucide-react';
|
import { CircleCheck } from 'lucide-react';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
import React, { useState } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { toast } from 'sonner';
|
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 CreateAccountForm = () => {
|
||||||
const [isSuccess, setIsSuccess] = useState(false)
|
const [isSuccess, setIsSuccess] = useState(false);
|
||||||
const t = useTranslations('auth.register')
|
const t = useTranslations('auth.register');
|
||||||
|
|
||||||
const form = useForm<TypeCreateAccountSchema>({
|
const form = useForm<TypeCreateAccountSchema>({
|
||||||
resolver: zodResolver(createAccountSchema),
|
resolver: zodResolver(createAccountSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: '',
|
name: '',
|
||||||
email: '',
|
email: '',
|
||||||
password: ''
|
password: '',
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
const { isValid } = form.formState
|
const { isValid } = form.formState;
|
||||||
|
|
||||||
const [create, { loading: isLoadingCreate }] = useCreateUserMutation({
|
const [create, { loading: isLoadingCreate }] = useCreateUserMutation({
|
||||||
onCompleted() {
|
onCompleted() {
|
||||||
setIsSuccess(true)
|
setIsSuccess(true);
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
toast.error(t('errorMessage'))
|
toast.error(t('errorMessage'));
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
function onSubmit(data: TypeCreateAccountSchema) {
|
function onSubmit(data: TypeCreateAccountSchema) {
|
||||||
create({ variables: { data } })
|
void create({ variables: { data } });
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthWrapper
|
<AuthWrapper
|
||||||
heading={t('heading')}
|
backButtonHref="/account/login"
|
||||||
backButtonLabel={t('backButtonLabel')}
|
backButtonLabel={t('backButtonLabel')}
|
||||||
backButtonHref='/account/login'
|
heading={t('heading')}
|
||||||
>
|
>
|
||||||
{isSuccess ? (
|
{isSuccess
|
||||||
|
? (
|
||||||
<Alert>
|
<Alert>
|
||||||
<CircleCheck className='size-4' />
|
<CircleCheck className="size-4" />
|
||||||
<AlertTitle>{t('successAlertTitle')}</AlertTitle>
|
|
||||||
|
<AlertTitle>
|
||||||
|
{t('successAlertTitle')}
|
||||||
|
</AlertTitle>
|
||||||
|
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
{t('successAlertDescription')}
|
{t('successAlertDescription')}
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
) : (
|
)
|
||||||
|
: (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
|
className="grid gap-y-3"
|
||||||
onSubmit={form.handleSubmit(onSubmit)}
|
onSubmit={form.handleSubmit(onSubmit)}
|
||||||
className='grid gap-y-3'
|
|
||||||
>
|
>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='name'
|
name="name"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('usernameLabel')}</FormLabel>
|
<FormLabel>
|
||||||
|
{t('usernameLabel')}
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder='johndoe'
|
|
||||||
disabled={isLoadingCreate}
|
disabled={isLoadingCreate}
|
||||||
|
placeholder="johndoe"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t('usernameDescription')}
|
{t('usernameDescription')}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='email'
|
name="email"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('emailLabel')}</FormLabel>
|
<FormLabel>
|
||||||
|
{t('emailLabel')}
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder='john.doe@example.com'
|
|
||||||
disabled={isLoadingCreate}
|
disabled={isLoadingCreate}
|
||||||
|
placeholder="john.doe@example.com"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t('emailDescription')}
|
{t('emailDescription')}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='password'
|
name="password"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('passwordLabel')}</FormLabel>
|
<FormLabel>
|
||||||
|
{t('passwordLabel')}
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder='********'
|
|
||||||
type='password'
|
|
||||||
disabled={isLoadingCreate}
|
disabled={isLoadingCreate}
|
||||||
|
placeholder="********"
|
||||||
|
type="password"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t('passwordDescription')}
|
{t('passwordDescription')}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className='mt-2 w-full'
|
className="mt-2 w-full"
|
||||||
disabled={!isValid || isLoadingCreate}
|
disabled={!isValid || isLoadingCreate}
|
||||||
>
|
>
|
||||||
{t('submitButton')}
|
{t('submitButton')}
|
||||||
|
|||||||
@ -1,24 +1,29 @@
|
|||||||
'use client'
|
'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';
|
|
||||||
|
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { useTranslations } from 'next-intl';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { toast } from 'sonner';
|
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 { 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 LoginAccountForm = () => {
|
||||||
const t = useTranslations('auth.login')
|
const t = useTranslations('auth.login');
|
||||||
const [isShowTwoFactor, setIsShowTwoFactor] = useState(false)
|
const [isShowTwoFactor, setIsShowTwoFactor] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const form = useForm<TypeLoginSchema>({
|
const form = useForm<TypeLoginSchema>({
|
||||||
@ -26,109 +31,128 @@ const LoginAccountForm = () => {
|
|||||||
defaultValues: {
|
defaultValues: {
|
||||||
login: '',
|
login: '',
|
||||||
password: '',
|
password: '',
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
const { isValid } = form.formState
|
const { isValid } = form.formState;
|
||||||
|
|
||||||
const [login, { loading: isLoadingLogin }] = useLoginUserMutation({
|
const [login, { loading: isLoadingLogin }] = useLoginUserMutation({
|
||||||
onCompleted(data) {
|
onCompleted(data) {
|
||||||
if (data.loginUser.message) {
|
if (data.loginUser.message) {
|
||||||
setIsShowTwoFactor(true)
|
setIsShowTwoFactor(true);
|
||||||
} else {
|
} else {
|
||||||
toast.success(t('successMessage'))
|
toast.success(t('successMessage'));
|
||||||
router.push('/dashboard/settings')
|
router.push('/dashboard/settings');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
toast.error(t('errorMessage'))
|
toast.error(t('errorMessage'));
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
function onSubmit(data: TypeLoginSchema) {
|
function onSubmit(data: TypeLoginSchema) {
|
||||||
void login({variables: {data}})
|
void login({ variables: { data } });
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthWrapper
|
<AuthWrapper
|
||||||
heading={t('heading')}
|
backButtonHref="/account/create"
|
||||||
backButtonLabel={t('backButtonLabel')}
|
backButtonLabel={t('backButtonLabel')}
|
||||||
backButtonHref='/account/create'
|
heading={t('heading')}
|
||||||
>
|
>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
|
className="grid gap-y-3"
|
||||||
onSubmit={form.handleSubmit(onSubmit)}
|
onSubmit={form.handleSubmit(onSubmit)}
|
||||||
className='grid gap-y-3'
|
|
||||||
>
|
>
|
||||||
{isShowTwoFactor ? (
|
{isShowTwoFactor
|
||||||
|
? (
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='pin'
|
name="pin"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('pinLabel')}</FormLabel>
|
<FormLabel>
|
||||||
|
{t('pinLabel')}
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<InputOTP maxLength={6} {...field}>
|
<InputOTP maxLength={6} {...field}>
|
||||||
<InputOTPGroup>
|
<InputOTPGroup>
|
||||||
<InputOTPSlot index={0} />
|
<InputOTPSlot index={0} />
|
||||||
|
|
||||||
<InputOTPSlot index={1} />
|
<InputOTPSlot index={1} />
|
||||||
|
|
||||||
<InputOTPSlot index={2} />
|
<InputOTPSlot index={2} />
|
||||||
|
|
||||||
<InputOTPSlot index={3} />
|
<InputOTPSlot index={3} />
|
||||||
|
|
||||||
<InputOTPSlot index={4} />
|
<InputOTPSlot index={4} />
|
||||||
|
|
||||||
<InputOTPSlot index={5} />
|
<InputOTPSlot index={5} />
|
||||||
</InputOTPGroup>
|
</InputOTPGroup>
|
||||||
</InputOTP>
|
</InputOTP>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t('pinDescription')}
|
{t('pinDescription')}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
) : (
|
)
|
||||||
|
: (
|
||||||
<>
|
<>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='login'
|
name="login"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('loginLabel')}</FormLabel>
|
<FormLabel>
|
||||||
|
{t('loginLabel')}
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder='johndoe'
|
|
||||||
disabled={isLoadingLogin}
|
disabled={isLoadingLogin}
|
||||||
|
placeholder="johndoe"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t('loginDescription')}
|
{t('loginDescription')}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='password'
|
name="password"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<div className='flex items-center justify-between'>
|
<div className="flex items-center justify-between">
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{t('passwordLabel')}
|
{t('passwordLabel')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href='/account/recovery'
|
className="ml-auto inline-block text-sm"
|
||||||
className='ml-auto inline-block text-sm'
|
href="/account/recovery"
|
||||||
>
|
>
|
||||||
{t('forgotPassword')}
|
{t('forgotPassword')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder='********'
|
|
||||||
type='password'
|
|
||||||
disabled={isLoadingLogin}
|
disabled={isLoadingLogin}
|
||||||
|
placeholder="********"
|
||||||
|
type="password"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t('passwordDescription')}
|
{t('passwordDescription')}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
@ -137,8 +161,9 @@ const LoginAccountForm = () => {
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className='mt-2 w-full'
|
className="mt-2 w-full"
|
||||||
disabled={!isValid || isLoadingLogin}
|
disabled={!isValid || isLoadingLogin}
|
||||||
>
|
>
|
||||||
{t('submitButton')}
|
{t('submitButton')}
|
||||||
|
|||||||
@ -1,113 +1,121 @@
|
|||||||
'use client'
|
'use client';
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod'
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useTranslations } from 'next-intl'
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
import { useParams, useRouter } from 'next/navigation'
|
import { useTranslations } from 'next-intl';
|
||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form';
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
import { Button } from '@/components/ui/common/Button'
|
import { Button } from '@/components/ui/common/Button';
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
FormDescription,
|
FormDescription,
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel
|
FormLabel,
|
||||||
} from '@/components/ui/common/Form'
|
} from '@/components/ui/common/Form';
|
||||||
import { Input } from '@/components/ui/common/Input'
|
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'
|
export const NewPasswordForm = () => {
|
||||||
import { newPasswordSchema, TypeNewPasswordSchema } from '@/schemas/auth/new-password.schema'
|
const t = useTranslations('auth.newPassword');
|
||||||
|
|
||||||
export function NewPasswordForm() {
|
const router = useRouter();
|
||||||
const t = useTranslations('auth.newPassword')
|
const params = useParams<{ token: string }>();
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const params = useParams<{ token: string }>()
|
|
||||||
|
|
||||||
const form = useForm<TypeNewPasswordSchema>({
|
const form = useForm<TypeNewPasswordSchema>({
|
||||||
resolver: zodResolver(newPasswordSchema),
|
resolver: zodResolver(newPasswordSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
password: '',
|
password: '',
|
||||||
passwordRepeat: ''
|
passwordRepeat: '',
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const [newPassword, { loading: isLoadingNew }] = useNewPasswordMutation({
|
const [newPassword, { loading: isLoadingNew }] = useNewPasswordMutation({
|
||||||
onCompleted(data) {
|
onCompleted(data) {
|
||||||
toast.success(t('successMessage'))
|
toast.success(t('successMessage'));
|
||||||
router.push('/account/login')
|
router.push('/account/login');
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
toast.error(t('errorMessage'))
|
toast.error(t('errorMessage'));
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const { isValid } = form.formState
|
const { isValid } = form.formState;
|
||||||
|
|
||||||
function onSubmit(data: TypeNewPasswordSchema) {
|
function onSubmit(data: TypeNewPasswordSchema) {
|
||||||
newPassword({ variables: { data: { ...data, token: params.token } } })
|
void newPassword({ variables: { data: { ...data, token: params.token } } });
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthWrapper
|
<AuthWrapper
|
||||||
heading={t('heading')}
|
backButtonHref="/account/login"
|
||||||
backButtonLabel={t('backButtonLabel')}
|
backButtonLabel={t('backButtonLabel')}
|
||||||
backButtonHref='/account/login'
|
heading={t('heading')}
|
||||||
>
|
>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
|
className="grid gap-y-3"
|
||||||
onSubmit={form.handleSubmit(onSubmit)}
|
onSubmit={form.handleSubmit(onSubmit)}
|
||||||
className='grid gap-y-3'
|
|
||||||
>
|
>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='password'
|
name="password"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('passwordLabel')}</FormLabel>
|
<FormLabel>
|
||||||
|
{t('passwordLabel')}
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder='********'
|
|
||||||
type='password'
|
|
||||||
disabled={isLoadingNew}
|
disabled={isLoadingNew}
|
||||||
|
placeholder="********"
|
||||||
|
type="password"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t('passwordDescription')}
|
{t('passwordDescription')}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='passwordRepeat'
|
name="passwordRepeat"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{t('passwordRepeatLabel')}
|
{t('passwordRepeatLabel')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder='********'
|
|
||||||
type='password'
|
|
||||||
disabled={isLoadingNew}
|
disabled={isLoadingNew}
|
||||||
|
placeholder="********"
|
||||||
|
type="password"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t('passwordRepeatDescription')}
|
{t('passwordRepeatDescription')}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className='mt-2 w-full'
|
className="mt-2 w-full"
|
||||||
disabled={!isValid || isLoadingNew}
|
disabled={!isValid || isLoadingNew}
|
||||||
>
|
>
|
||||||
{t('submitButton')}
|
{t('submitButton')}
|
||||||
@ -115,5 +123,5 @@ export function NewPasswordForm() {
|
|||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
</AuthWrapper>
|
</AuthWrapper>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,106 +1,116 @@
|
|||||||
'use client'
|
'use client';
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod'
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { CircleCheck } from 'lucide-react'
|
import { CircleCheck } from 'lucide-react';
|
||||||
import { useTranslations } from 'next-intl'
|
import { useTranslations } from 'next-intl';
|
||||||
import { useState } from 'react'
|
import { useState } from 'react';
|
||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form';
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
AlertDescription,
|
AlertDescription,
|
||||||
AlertTitle
|
AlertTitle,
|
||||||
} from '@/components/ui/common/Alert'
|
} from '@/components/ui/common/Alert';
|
||||||
import { Button } from '@/components/ui/common/Button'
|
import { Button } from '@/components/ui/common/Button';
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
FormDescription,
|
FormDescription,
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel
|
FormLabel,
|
||||||
} from '@/components/ui/common/Form'
|
} from '@/components/ui/common/Form';
|
||||||
import { Input } from '@/components/ui/common/Input'
|
import { Input } from '@/components/ui/common/Input';
|
||||||
|
import { useResetPasswordMutation } from '@/graphql/generated/output';
|
||||||
import { useResetPasswordMutation } from '@/graphql/generated/output'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type TypeResetPasswordSchema,
|
type TypeResetPasswordSchema,
|
||||||
resetPasswordSchema
|
resetPasswordSchema,
|
||||||
} from '@/schemas/auth/reset-password.schema'
|
} from '@/schemas/auth/reset-password.schema';
|
||||||
|
|
||||||
import AuthWrapper from '../AuthWrapper'
|
import AuthWrapper from '../AuthWrapper';
|
||||||
|
|
||||||
export function ResetPasswordForm() {
|
export const ResetPasswordForm = () => {
|
||||||
const t = useTranslations('auth.resetPassword')
|
const t = useTranslations('auth.resetPassword');
|
||||||
|
|
||||||
const [isSuccess, setIsSuccess] = useState(false)
|
const [isSuccess, setIsSuccess] = useState(false);
|
||||||
|
|
||||||
const form = useForm<TypeResetPasswordSchema>({
|
const form = useForm<TypeResetPasswordSchema>({
|
||||||
resolver: zodResolver(resetPasswordSchema),
|
resolver: zodResolver(resetPasswordSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
email: ''
|
email: '',
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const [resetPassword, { loading: isLoadingReset }] =
|
const [resetPassword, { loading: isLoadingReset }] = useResetPasswordMutation({
|
||||||
useResetPasswordMutation({
|
|
||||||
onCompleted() {
|
onCompleted() {
|
||||||
setIsSuccess(true)
|
setIsSuccess(true);
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
toast.error(t('errorMessage'))
|
toast.error(t('errorMessage'));
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const { isValid } = form.formState
|
const { isValid } = form.formState;
|
||||||
|
|
||||||
function onSubmit(data: TypeResetPasswordSchema) {
|
function onSubmit(data: TypeResetPasswordSchema) {
|
||||||
void resetPassword({ variables: { data } })
|
void resetPassword({ variables: { data } });
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthWrapper
|
<AuthWrapper
|
||||||
heading={t('heading')}
|
backButtonHref="/account/login"
|
||||||
backButtonLabel={t('backButtonLabel')}
|
backButtonLabel={t('backButtonLabel')}
|
||||||
backButtonHref='/account/login'
|
heading={t('heading')}
|
||||||
>
|
>
|
||||||
{isSuccess ? (
|
{isSuccess
|
||||||
|
? (
|
||||||
<Alert>
|
<Alert>
|
||||||
<CircleCheck className='size-4' />
|
<CircleCheck className="size-4" />
|
||||||
<AlertTitle>{t('successAlertTitle')}</AlertTitle>
|
|
||||||
|
<AlertTitle>
|
||||||
|
{t('successAlertTitle')}
|
||||||
|
</AlertTitle>
|
||||||
|
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
{t('successAlertDescription')}
|
{t('successAlertDescription')}
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
) : (
|
)
|
||||||
|
: (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
onSubmit={form.handleSubmit(onSubmit)}
|
className="grid gap-y-3"
|
||||||
className='grid gap-y-3'
|
onSubmit={() => {
|
||||||
|
form.handleSubmit(onSubmit);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='email'
|
name="email"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('emailLabel')}</FormLabel>
|
<FormLabel>
|
||||||
|
{t('emailLabel')}
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder='john.doe@example.com'
|
|
||||||
disabled={isLoadingReset}
|
disabled={isLoadingReset}
|
||||||
|
placeholder="john.doe@example.com"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t('emailDescription')}
|
{t('emailDescription')}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className='mt-2 w-full'
|
className="mt-2 w-full"
|
||||||
disabled={!isValid || isLoadingReset}
|
disabled={!isValid || isLoadingReset}
|
||||||
>
|
>
|
||||||
{t('submitButton')}
|
{t('submitButton')}
|
||||||
@ -109,5 +119,5 @@ export function ResetPasswordForm() {
|
|||||||
</Form>
|
</Form>
|
||||||
)}
|
)}
|
||||||
</AuthWrapper>
|
</AuthWrapper>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,46 +1,47 @@
|
|||||||
'use client'
|
'use client';
|
||||||
|
|
||||||
import { Loader } from 'lucide-react'
|
import { Loader } from 'lucide-react';
|
||||||
import { useTranslations } from 'next-intl'
|
import { useRouter } from 'next/navigation';
|
||||||
import { useRouter } from 'next/navigation'
|
import { useTranslations } from 'next-intl';
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react';
|
||||||
import { toast } from 'sonner'
|
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 = {
|
type VerifyAccountFormProps = {
|
||||||
token: string
|
token: string;
|
||||||
}
|
};
|
||||||
export function VerifyAccountForm(props: VerifyAccountFormProps) {
|
export const VerifyAccountForm = (props: VerifyAccountFormProps) => {
|
||||||
const { token } = props;
|
const { token } = props;
|
||||||
const t = useTranslations('auth.verify')
|
const t = useTranslations('auth.verify');
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
|
|
||||||
const [verify] = useVerifyAccountMutation({
|
const [verify] = useVerifyAccountMutation({
|
||||||
onCompleted() {
|
onCompleted() {
|
||||||
toast.success(t('successMessage'))
|
toast.success(t('successMessage'));
|
||||||
router.push('/dashboard/settings')
|
router.push('/dashboard/settings');
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
toast.error(t('errorMessage'))
|
toast.error(t('errorMessage'));
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void verify({
|
void verify({
|
||||||
variables: {
|
variables: {
|
||||||
data: { token }
|
data: { token },
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}, [token, verify])
|
}, [token, verify]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthWrapper heading={t('heading')}>
|
<AuthWrapper heading={t('heading')}>
|
||||||
<div className='flex justify-center'>
|
<div className="flex justify-center">
|
||||||
<Loader className='size-8 animate-spin' />
|
<Loader className="size-8 animate-spin" />
|
||||||
</div>
|
</div>
|
||||||
</AuthWrapper>
|
</AuthWrapper>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,43 +1,44 @@
|
|||||||
export function LogoImage() {
|
export const LogoImage = () => (
|
||||||
return (
|
|
||||||
<svg
|
<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}
|
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>
|
<title>Logo</title>
|
||||||
|
|
||||||
<g>
|
<g>
|
||||||
<polygon
|
<polygon
|
||||||
className='fill-white'
|
className="fill-white"
|
||||||
points='2200,1300 1800,1700 1400,1700 1050,2050 1050,1700 600,1700 600,200 2200,200 '
|
points="2200,1300 1800,1700 1400,1700 1050,2050 1050,1700 600,1700 600,200 2200,200"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<g>
|
<g>
|
||||||
<g id='Layer_1-2'>
|
<g id="Layer_1-2">
|
||||||
<path
|
<path
|
||||||
className='fill-primary'
|
className="fill-primary"
|
||||||
d='M500,0L0,500v1800h600v500l500-500h400l900-900V0H500z M2200,1300l-400,400h-400l-350,350v-350H600V200h1600
|
d="M500,0L0,500v1800h600v500l500-500h400l900-900V0H500z M2200,1300l-400,400h-400l-350,350v-350H600V200h1600 V1300z"
|
||||||
V1300z'
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<rect
|
<rect
|
||||||
x='1700'
|
className="fill-primary"
|
||||||
y='550'
|
height="600"
|
||||||
className='fill-primary'
|
width="200"
|
||||||
width='200'
|
x="1700"
|
||||||
height='600'
|
y="550"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<rect
|
<rect
|
||||||
x='1150'
|
className="fill-primary"
|
||||||
y='550'
|
height="600"
|
||||||
className='fill-primary'
|
width="200"
|
||||||
width='200'
|
x="1150"
|
||||||
height='600'
|
y="550"
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
);
|
||||||
}
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { cn } from '@/utils/twMerge'
|
import { type VariantProps, cva } from 'class-variance-authority';
|
||||||
import { type VariantProps, cva } from 'class-variance-authority'
|
import { type HTMLAttributes, forwardRef } from 'react';
|
||||||
import { type HTMLAttributes, forwardRef } from 'react'
|
|
||||||
|
|
||||||
|
import { cn } from '@/utils/twMerge';
|
||||||
|
|
||||||
const alertVariants = cva(
|
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',
|
'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: {
|
variant: {
|
||||||
default: 'bg-background text-foreground',
|
default: 'bg-background text-foreground',
|
||||||
destructive:
|
destructive:
|
||||||
'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive'
|
'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: 'default'
|
variant: 'default',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
const Alert = forwardRef<
|
const Alert = forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
@ -25,24 +25,25 @@ const Alert = forwardRef<
|
|||||||
>(({ className, variant, ...props }, ref) => (
|
>(({ className, variant, ...props }, ref) => (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
role='alert'
|
|
||||||
className={cn(alertVariants({ variant }), className)}
|
className={cn(alertVariants({ variant }), className)}
|
||||||
|
role="alert"
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
Alert.displayName = 'Alert'
|
Alert.displayName = 'Alert';
|
||||||
|
|
||||||
const AlertTitle = forwardRef<
|
const AlertTitle = forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
HTMLAttributes<HTMLHeadingElement>
|
HTMLAttributes<HTMLHeadingElement>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
|
// eslint-disable-next-line jsx-a11y/heading-has-content
|
||||||
<h5
|
<h5
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn('mb-1 font-medium leading-none tracking-wide', className)}
|
className={cn('mb-1 font-medium leading-none tracking-wide', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
AlertTitle.displayName = 'AlertTitle'
|
AlertTitle.displayName = 'AlertTitle';
|
||||||
|
|
||||||
const AlertDescription = forwardRef<
|
const AlertDescription = forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
@ -52,11 +53,11 @@ const AlertDescription = forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'mt-2 text-sm text-muted-foreground [&_p]:leading-relaxed',
|
'mt-2 text-sm text-muted-foreground [&_p]:leading-relaxed',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...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 { Slot } from '@radix-ui/react-slot'
|
import { type VariantProps, cva } from 'class-variance-authority';
|
||||||
import { type VariantProps, cva } from 'class-variance-authority'
|
import { type ButtonHTMLAttributes, forwardRef } from 'react';
|
||||||
import { type ButtonHTMLAttributes, forwardRef } from 'react'
|
|
||||||
|
|
||||||
|
import { cn } from '@/utils/twMerge';
|
||||||
|
|
||||||
const buttonVariants = cva(
|
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',
|
'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',
|
default: 'bg-primary text-primary-foreground',
|
||||||
outline: 'border border-border bg-background',
|
outline: 'border border-border bg-background',
|
||||||
secondary: 'bg-secondary text-secondary-foreground',
|
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: {
|
size: {
|
||||||
default: 'h-10 px-5 py-2 rounded-full',
|
default: 'h-10 px-5 py-2 rounded-full',
|
||||||
icon: 'size-8 rounded-full',
|
icon: 'size-8 rounded-full',
|
||||||
lgIcon: 'size-10 rounded-full'
|
lgIcon: 'size-10 rounded-full',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: 'default',
|
variant: 'default',
|
||||||
size: 'default'
|
size: 'default',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
export interface ButtonProps
|
export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof buttonVariants> & {
|
||||||
extends ButtonHTMLAttributes<HTMLButtonElement>,
|
asChild?: boolean;
|
||||||
VariantProps<typeof buttonVariants> {
|
};
|
||||||
asChild?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
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 (
|
return (
|
||||||
<Comp
|
<Comp
|
||||||
className={cn(buttonVariants({ variant, size, className }))}
|
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
{...props}
|
{...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>>(
|
const Card = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||||
({ className, ...props }, ref) => (
|
({ className, ...props }, ref) => (
|
||||||
@ -8,13 +8,13 @@ const Card = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-card text-card-foreground border-border rounded-lg border shadow-sm',
|
'bg-card text-card-foreground border-border rounded-lg border shadow-sm',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
),
|
||||||
)
|
);
|
||||||
Card.displayName = 'Card'
|
Card.displayName = 'Card';
|
||||||
|
|
||||||
const CardHeader = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
const CardHeader = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||||
({ className, ...props }, ref) => (
|
({ 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)}
|
className={cn('flex flex-col space-y-1.5 p-6', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
),
|
||||||
)
|
);
|
||||||
CardHeader.displayName = 'CardHeader'
|
CardHeader.displayName = 'CardHeader';
|
||||||
|
|
||||||
const CardTitle = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
const CardTitle = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||||
({ className, ...props }, ref) => (
|
({ className, ...props }, ref) => (
|
||||||
@ -33,13 +33,13 @@ const CardTitle = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'text-2xl font-semibold leading-none tracking-wide',
|
'text-2xl font-semibold leading-none tracking-wide',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
),
|
||||||
)
|
);
|
||||||
CardTitle.displayName = 'CardTitle'
|
CardTitle.displayName = 'CardTitle';
|
||||||
|
|
||||||
const CardDescription = forwardRef<
|
const CardDescription = forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
@ -50,15 +50,15 @@ const CardDescription = forwardRef<
|
|||||||
className={cn('text-muted-foreground text-sm', className)}
|
className={cn('text-muted-foreground text-sm', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
CardDescription.displayName = 'CardDescription'
|
CardDescription.displayName = 'CardDescription';
|
||||||
|
|
||||||
const CardContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
const CardContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||||
({ className, ...props }, ref) => (
|
({ className, ...props }, ref) => (
|
||||||
<div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
|
<div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
|
||||||
)
|
),
|
||||||
)
|
);
|
||||||
CardContent.displayName = 'CardContent'
|
CardContent.displayName = 'CardContent';
|
||||||
|
|
||||||
const CardFooter = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
const CardFooter = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||||
({ className, ...props }, ref) => (
|
({ className, ...props }, ref) => (
|
||||||
@ -67,8 +67,10 @@ const CardFooter = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|||||||
className={cn('flex items-center p-6 pt-0', className)}
|
className={cn('flex items-center p-6 pt-0', className)}
|
||||||
{...props}
|
{...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 { Slot } from '@radix-ui/react-slot';
|
||||||
import * as LabelPrimitive from '@radix-ui/react-label'
|
|
||||||
import { Slot } from '@radix-ui/react-slot'
|
|
||||||
import {
|
import {
|
||||||
type ComponentPropsWithoutRef,
|
type ComponentPropsWithoutRef,
|
||||||
type ComponentRef,
|
type ComponentRef,
|
||||||
@ -10,82 +8,62 @@ import {
|
|||||||
createContext,
|
createContext,
|
||||||
forwardRef,
|
forwardRef,
|
||||||
useContext,
|
useContext,
|
||||||
useId
|
useId,
|
||||||
} from 'react'
|
} from 'react';
|
||||||
import {
|
import {
|
||||||
Controller,
|
Controller,
|
||||||
type ControllerProps,
|
type ControllerProps,
|
||||||
type FieldPath,
|
type FieldPath,
|
||||||
type FieldValues,
|
type FieldValues,
|
||||||
FormProvider,
|
FormProvider,
|
||||||
useFormContext
|
useFormContext,
|
||||||
} from 'react-hook-form'
|
} 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<
|
type FormFieldContextValue<
|
||||||
TFieldValues extends FieldValues = FieldValues,
|
TFieldValues extends FieldValues = FieldValues,
|
||||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||||
> = {
|
> = {
|
||||||
name: TName
|
name: TName;
|
||||||
}
|
};
|
||||||
|
|
||||||
const FormFieldContext = createContext<FormFieldContextValue>(
|
const FormFieldContext = createContext<FormFieldContextValue>(
|
||||||
{} as FormFieldContextValue
|
{} as FormFieldContextValue,
|
||||||
)
|
);
|
||||||
|
|
||||||
const FormField = <
|
const FormField = <
|
||||||
TFieldValues extends FieldValues = FieldValues,
|
TFieldValues extends FieldValues = FieldValues,
|
||||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||||
>({
|
>({
|
||||||
...props
|
...props
|
||||||
}: ControllerProps<TFieldValues, TName>) => {
|
}: ControllerProps<TFieldValues, TName>) => (
|
||||||
return (
|
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
||||||
<FormFieldContext.Provider value={{ name: props.name }}>
|
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||||
<Controller {...props} />
|
<Controller {...props} />
|
||||||
</FormFieldContext.Provider>
|
</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 = {
|
type FormItemContextValue = {
|
||||||
id: string
|
id: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const FormItemContext = createContext<FormItemContextValue>(
|
const FormItemContext = createContext<FormItemContextValue>(
|
||||||
{} as FormItemContextValue
|
{} as FormItemContextValue,
|
||||||
)
|
);
|
||||||
|
|
||||||
const FormItem = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
const FormItem = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||||
({ className, ...props }, ref) => {
|
({ className, ...props }, ref) => {
|
||||||
const id = useId()
|
const id = useId();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
||||||
<FormItemContext.Provider value={{ id }}>
|
<FormItemContext.Provider value={{ id }}>
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@ -93,16 +71,38 @@ const FormItem = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</FormItemContext.Provider>
|
</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<
|
const FormLabel = forwardRef<
|
||||||
ComponentRef<typeof LabelPrimitive.Root>,
|
ComponentRef<typeof LabelPrimitive.Root>,
|
||||||
ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
const { error, formItemId } = useFormField()
|
const { error, formItemId } = useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Label
|
<Label
|
||||||
@ -111,73 +111,74 @@ const FormLabel = forwardRef<
|
|||||||
htmlFor={formItemId}
|
htmlFor={formItemId}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormLabel.displayName = 'FormLabel'
|
FormLabel.displayName = 'FormLabel';
|
||||||
|
|
||||||
const FormControl = forwardRef<
|
const FormControl = forwardRef<
|
||||||
ComponentRef<typeof Slot>,
|
ComponentRef<typeof Slot>,
|
||||||
ComponentPropsWithoutRef<typeof Slot>
|
ComponentPropsWithoutRef<typeof Slot>
|
||||||
>(({ ...props }, ref) => {
|
>(({ ...props }, ref) => {
|
||||||
const { error, formItemId, formDescriptionId, formMessageId } =
|
const {
|
||||||
useFormField()
|
error, formItemId, formDescriptionId, formMessageId,
|
||||||
|
} = useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slot
|
<Slot
|
||||||
ref={ref}
|
ref={ref}
|
||||||
id={formItemId}
|
|
||||||
aria-describedby={
|
aria-describedby={
|
||||||
!error
|
!error
|
||||||
? `${formDescriptionId}`
|
? formDescriptionId
|
||||||
: `${formDescriptionId} ${formMessageId}`
|
: `${formDescriptionId} ${formMessageId}`
|
||||||
}
|
}
|
||||||
aria-invalid={!!error}
|
aria-invalid={!!error}
|
||||||
|
id={formItemId}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormControl.displayName = 'FormControl'
|
FormControl.displayName = 'FormControl';
|
||||||
|
|
||||||
const FormDescription = forwardRef<
|
const FormDescription = forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
HTMLAttributes<HTMLParagraphElement>
|
HTMLAttributes<HTMLParagraphElement>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
const { formDescriptionId } = useFormField()
|
const { formDescriptionId } = useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p
|
<p
|
||||||
ref={ref}
|
ref={ref}
|
||||||
id={formDescriptionId}
|
|
||||||
className={cn('text-sm text-muted-foreground', className)}
|
className={cn('text-sm text-muted-foreground', className)}
|
||||||
|
id={formDescriptionId}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormDescription.displayName = 'FormDescription'
|
FormDescription.displayName = 'FormDescription';
|
||||||
|
|
||||||
const FormMessage = forwardRef<
|
const FormMessage = forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
HTMLAttributes<HTMLParagraphElement>
|
HTMLAttributes<HTMLParagraphElement>
|
||||||
>(({ className, children, ...props }, ref) => {
|
>(({ className, children, ...props }, ref) => {
|
||||||
const { error, formMessageId } = useFormField()
|
const { error, formMessageId } = useFormField();
|
||||||
const body = error ? String(error?.message) : children
|
const body = error ? String(error?.message) : children;
|
||||||
|
|
||||||
if (!body) {
|
if (!body) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p
|
<p
|
||||||
ref={ref}
|
ref={ref}
|
||||||
id={formMessageId}
|
|
||||||
className={cn('text-sm font-medium text-destructive', className)}
|
className={cn('text-sm font-medium text-destructive', className)}
|
||||||
|
id={formMessageId}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{body}
|
{body}
|
||||||
</p>
|
</p>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormMessage.displayName = 'FormMessage'
|
FormMessage.displayName = 'FormMessage';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Form,
|
Form,
|
||||||
@ -187,5 +188,5 @@ export {
|
|||||||
FormItem,
|
FormItem,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
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'>>(
|
const Input = forwardRef<HTMLInputElement, ComponentProps<'input'>>(
|
||||||
({ className, type, ...props }, ref) => {
|
({ className, type, ...props }, ref) => (
|
||||||
return (
|
|
||||||
<input
|
<input
|
||||||
type={type}
|
ref={ref}
|
||||||
className={cn(
|
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',
|
'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}
|
{...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 { OTPInput, OTPInputContext } from 'input-otp'
|
import { Dot } from 'lucide-react';
|
||||||
import { Dot } from 'lucide-react'
|
|
||||||
import {
|
import {
|
||||||
type ComponentPropsWithoutRef,
|
type ComponentPropsWithoutRef,
|
||||||
type ComponentRef,
|
type ComponentRef,
|
||||||
forwardRef,
|
forwardRef,
|
||||||
useContext
|
useContext,
|
||||||
} from 'react'
|
} from 'react';
|
||||||
|
|
||||||
|
import { cn } from '@/utils/twMerge';
|
||||||
|
|
||||||
const InputOTP = forwardRef<
|
const InputOTP = forwardRef<
|
||||||
ComponentRef<typeof OTPInput>,
|
ComponentRef<typeof OTPInput>,
|
||||||
@ -17,15 +17,15 @@ const InputOTP = forwardRef<
|
|||||||
>(({ className, containerClassName, ...props }, ref) => (
|
>(({ className, containerClassName, ...props }, ref) => (
|
||||||
<OTPInput
|
<OTPInput
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
className={cn('disabled:cursor-not-allowed', className)}
|
||||||
containerClassName={cn(
|
containerClassName={cn(
|
||||||
'flex items-center gap-2 has-disabled:opacity-50',
|
'flex items-center gap-2 has-disabled:opacity-50',
|
||||||
containerClassName
|
containerClassName,
|
||||||
)}
|
)}
|
||||||
className={cn('disabled:cursor-not-allowed', className)}
|
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
InputOTP.displayName = 'InputOTP'
|
InputOTP.displayName = 'InputOTP';
|
||||||
|
|
||||||
const InputOTPGroup = forwardRef<
|
const InputOTPGroup = forwardRef<
|
||||||
ComponentRef<'div'>,
|
ComponentRef<'div'>,
|
||||||
@ -36,15 +36,15 @@ const InputOTPGroup = forwardRef<
|
|||||||
className={cn('flex items-center gap-x-3', className)}
|
className={cn('flex items-center gap-x-3', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
InputOTPGroup.displayName = 'InputOTPGroup'
|
InputOTPGroup.displayName = 'InputOTPGroup';
|
||||||
|
|
||||||
const InputOTPSlot = forwardRef<
|
const InputOTPSlot = forwardRef<
|
||||||
ComponentRef<'div'>,
|
ComponentRef<'div'>,
|
||||||
ComponentPropsWithoutRef<'div'> & { index: number }
|
ComponentPropsWithoutRef<'div'> & { index: number }
|
||||||
>(({ index, className, ...props }, ref) => {
|
>(({ index, className, ...props }, ref) => {
|
||||||
const inputOTPContext = useContext(OTPInputContext)
|
const inputOTPContext = useContext(OTPInputContext);
|
||||||
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]
|
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -52,29 +52,34 @@ const InputOTPSlot = forwardRef<
|
|||||||
className={cn(
|
className={cn(
|
||||||
'relative flex h-10 w-14 items-center justify-center rounded-md border border-border text-sm transition-all',
|
'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',
|
isActive && 'z-10 ring-2 ring-primary ring-offset-background',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{char}
|
{char}
|
||||||
{hasFakeCaret && (
|
|
||||||
<div className='pointer-events-none absolute inset-0 flex items-center justify-center'>
|
{hasFakeCaret
|
||||||
<div className='animate-caret-blink h-4 w-px bg-foreground duration-1000' />
|
? (
|
||||||
</div>
|
<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>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
: null}
|
||||||
InputOTPSlot.displayName = 'InputOTPSlot'
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
InputOTPSlot.displayName = 'InputOTPSlot';
|
||||||
|
|
||||||
const InputOTPSeparator = forwardRef<
|
const InputOTPSeparator = forwardRef<
|
||||||
ComponentRef<'div'>,
|
ComponentRef<'div'>,
|
||||||
ComponentPropsWithoutRef<'div'>
|
ComponentPropsWithoutRef<'div'>
|
||||||
>(({ ...props }, ref) => (
|
>(({ ...props }, ref) => (
|
||||||
<div ref={ref} role='separator' {...props}>
|
<div ref={ref} role="separator" {...props}>
|
||||||
<Dot />
|
<Dot />
|
||||||
</div>
|
</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 * as LabelPrimitive from '@radix-ui/react-label'
|
import { type VariantProps, cva } from 'class-variance-authority';
|
||||||
import { type VariantProps, cva } from 'class-variance-authority'
|
|
||||||
import {
|
import {
|
||||||
type ComponentPropsWithoutRef,
|
type ComponentPropsWithoutRef,
|
||||||
type ComponentRef,
|
type ComponentRef,
|
||||||
forwardRef
|
forwardRef,
|
||||||
} from 'react'
|
} from 'react';
|
||||||
|
|
||||||
|
import { cn } from '@/utils/twMerge';
|
||||||
|
|
||||||
const labelVariants = cva(
|
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<
|
const Label = forwardRef<
|
||||||
ComponentRef<typeof LabelPrimitive.Root>,
|
ComponentRef<typeof LabelPrimitive.Root>,
|
||||||
ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||||
VariantProps<typeof labelVariants>
|
& VariantProps<typeof labelVariants>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<LabelPrimitive.Root
|
<LabelPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(labelVariants(), className)}
|
className={cn(labelVariants(), className)}
|
||||||
{...props}
|
{...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 { useTheme } from 'next-themes';
|
||||||
import { Toaster as Sonner, ToasterProps } from "sonner"
|
import { Toaster as Sonner } from 'sonner';
|
||||||
|
|
||||||
|
import type { ToasterProps } from 'sonner';
|
||||||
|
|
||||||
const Toaster = ({ ...props }: ToasterProps) => {
|
const Toaster = ({ ...props }: ToasterProps) => {
|
||||||
const { theme = "system" } = useTheme()
|
const { theme = 'system' } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sonner
|
<Sonner
|
||||||
theme={theme as ToasterProps["theme"]}
|
|
||||||
className="toaster group"
|
className="toaster group"
|
||||||
style={
|
style={
|
||||||
{
|
{
|
||||||
"--normal-bg": "var(--popover)",
|
'--normal-bg': 'var(--popover)',
|
||||||
"--normal-text": "var(--popover-foreground)",
|
'--normal-text': 'var(--popover-foreground)',
|
||||||
"--normal-border": "var(--border)",
|
'--normal-border': 'var(--border)',
|
||||||
} as React.CSSProperties
|
} as React.CSSProperties
|
||||||
}
|
}
|
||||||
|
theme={theme as ToasterProps['theme']}
|
||||||
{...props}
|
{...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;
|
const locales = ['ru', 'en'] as const;
|
||||||
|
|
||||||
declare module 'next-intl' {
|
declare module 'next-intl' {
|
||||||
interface AppConfig {
|
type AppConfig = {
|
||||||
Locale: (typeof locales)[number];
|
Locale: (typeof locales)[number];
|
||||||
Messages: typeof messages;
|
Messages: typeof messages;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,10 @@ import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client';
|
|||||||
|
|
||||||
const httpLink = createHttpLink({
|
const httpLink = createHttpLink({
|
||||||
uri: process.env.NEXT_PUBLIC_SERVER_URL,
|
uri: process.env.NEXT_PUBLIC_SERVER_URL,
|
||||||
credentials: 'include'
|
credentials: 'include',
|
||||||
})
|
});
|
||||||
|
|
||||||
export const client = new ApolloClient({
|
export const client = new ApolloClient({
|
||||||
link: httpLink,
|
link: httpLink,
|
||||||
cache: new InMemoryCache()
|
cache: new InMemoryCache(),
|
||||||
})
|
});
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export const COOKIE_NAME = 'language'
|
export const COOKIE_NAME = 'language';
|
||||||
export const languages = ['ru', 'en'] as const
|
export const languages = ['ru', 'en'] as const;
|
||||||
export const defaultLanguages: Language = 'ru';
|
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 { cookies } from 'next/headers';
|
||||||
import { COOKIE_NAME, defaultLanguages, Language } from "./config";
|
|
||||||
|
import { COOKIE_NAME, defaultLanguages } from './config';
|
||||||
|
|
||||||
|
import type { Language } from './config';
|
||||||
|
|
||||||
export async function getCurrentLanguage() {
|
export async function getCurrentLanguage() {
|
||||||
const cookieStore = await cookies();
|
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) {
|
export async function setCurrentLanguage(lang: Language) {
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
|
|
||||||
return cookieStore.set(COOKIE_NAME, lang);
|
return cookieStore.set(COOKIE_NAME, lang);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { getRequestConfig } from 'next-intl/server';
|
import { getRequestConfig } from 'next-intl/server';
|
||||||
import { getCurrentLanguage } from "./language"
|
|
||||||
|
import { getCurrentLanguage } from './language';
|
||||||
|
|
||||||
export default getRequestConfig(async () => {
|
export default getRequestConfig(async () => {
|
||||||
const locale = await getCurrentLanguage();
|
const locale = await getCurrentLanguage();
|
||||||
@ -8,5 +9,5 @@ export default getRequestConfig(async () => {
|
|||||||
return {
|
return {
|
||||||
locale,
|
locale,
|
||||||
messages,
|
messages,
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
'use client'
|
'use client';
|
||||||
|
|
||||||
|
import { ApolloProvider } from '@apollo/client';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
import { client } from '@/libs/apollo-client';
|
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 ApolloClientProvider = (props: PropsWithChildren) => {
|
||||||
const { children } = props;
|
const { children } = props;
|
||||||
|
|||||||
@ -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
|
...props
|
||||||
}: React.ComponentProps<typeof NextThemesProvider>) {
|
}: React.ComponentProps<typeof NextThemesProvider>) => (
|
||||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
|
<NextThemesProvider {...props}>
|
||||||
}
|
{children}
|
||||||
|
</NextThemesProvider>
|
||||||
|
);
|
||||||
|
|||||||
@ -1,25 +1,26 @@
|
|||||||
'use client'
|
'use client';
|
||||||
|
|
||||||
import { useTheme } from 'next-themes'
|
import { useTheme } from 'next-themes';
|
||||||
import type { ComponentProps } from 'react'
|
import { Toaster as Sonner } from 'sonner';
|
||||||
import { Toaster as Sonner } from 'sonner'
|
|
||||||
|
|
||||||
type ToasterProps = ComponentProps<typeof Sonner>
|
import type { ComponentProps } from 'react';
|
||||||
|
|
||||||
export function ToastProvider({ ...props }: ToasterProps) {
|
type ToasterProps = ComponentProps<typeof Sonner>;
|
||||||
const { theme = 'system' } = useTheme()
|
|
||||||
|
export const ToastProvider = ({ ...props }: ToasterProps) => {
|
||||||
|
const { theme = 'system' } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sonner
|
<Sonner
|
||||||
|
className="toaster group"
|
||||||
theme={theme as ToasterProps['theme']}
|
theme={theme as ToasterProps['theme']}
|
||||||
className='toaster group'
|
|
||||||
toastOptions={{
|
toastOptions={{
|
||||||
classNames: {
|
classNames: {
|
||||||
toast: 'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
|
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}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { z } from 'zod'
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const createAccountSchema = z.object({
|
export const createAccountSchema = z.object({
|
||||||
name: z
|
name: z
|
||||||
.string()
|
.string()
|
||||||
.min(1)
|
.min(1)
|
||||||
.regex(/^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*$/),
|
.regex(/^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*$/),
|
||||||
email: z.string().email({ pattern: z.regexes.html5Email }).min(3),
|
email: z.email({ pattern: z.regexes.html5Email }).min(3),
|
||||||
password: z.string().min(8)
|
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({
|
export const loginSchema = z.object({
|
||||||
login: z.string().min(1),
|
login: z.string().min(1),
|
||||||
password: z.string().min(8),
|
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
|
export const newPasswordSchema = z
|
||||||
.object({
|
.object({
|
||||||
password: z.string().min(8),
|
password: z.string().min(8),
|
||||||
passwordRepeat: z.string().min(8)
|
passwordRepeat: z.string().min(8),
|
||||||
})
|
|
||||||
.refine(data => data.password === data.passwordRepeat, {
|
|
||||||
path: ['passwordRepeat']
|
|
||||||
})
|
})
|
||||||
|
.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({
|
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 { clsx, type ClassValue } from 'clsx';
|
||||||
import { twMerge } from "tailwind-merge"
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -451,7 +451,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.27.1"
|
"@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"
|
version "7.28.2"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.2.tgz#2ae5a9d51cc583bd1f5673b3bb70d6d819682473"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.2.tgz#2ae5a9d51cc583bd1f5673b3bb70d6d819682473"
|
||||||
integrity sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==
|
integrity sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==
|
||||||
@ -1399,6 +1399,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
fast-glob "3.3.1"
|
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":
|
"@next/swc-darwin-arm64@15.4.5":
|
||||||
version "15.4.5"
|
version "15.4.5"
|
||||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.5.tgz#a716f1b8baf6dac0ac4cad9670350f637991f89e"
|
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"
|
resolved "https://registry.yarnpkg.com/@standard-schema/utils/-/utils-0.3.0.tgz#3d5e608f16c2390c10528e98e59aef6bf73cae7b"
|
||||||
integrity sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==
|
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":
|
"@swc/helpers@0.5.15":
|
||||||
version "0.5.15"
|
version "0.5.15"
|
||||||
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.15.tgz#79efab344c5819ecf83a43f3f9f811fc84b516d7"
|
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.15.tgz#79efab344c5819ecf83a43f3f9f811fc84b516d7"
|
||||||
@ -1712,6 +1731,21 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@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":
|
"@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0":
|
||||||
version "8.38.0"
|
version "8.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz#6e5220d16f2691ab6d983c1737dd5b36e17641b7"
|
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"
|
natural-compare "^1.4.0"
|
||||||
ts-api-utils "^2.1.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":
|
"@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0":
|
||||||
version "8.38.0"
|
version "8.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.38.0.tgz#6723a5ea881e1777956b1045cba30be5ea838293"
|
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"
|
"@typescript-eslint/visitor-keys" "8.38.0"
|
||||||
debug "^4.3.4"
|
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":
|
"@typescript-eslint/project-service@8.38.0":
|
||||||
version "8.38.0"
|
version "8.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.38.0.tgz#4900771f943163027fd7d2020a062892056b5e2f"
|
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"
|
"@typescript-eslint/types" "^8.38.0"
|
||||||
debug "^4.3.4"
|
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"
|
version "8.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz#5a0efcb5c9cf6e4121b58f87972f567c69529226"
|
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==
|
integrity sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==
|
||||||
@ -1755,11 +1817,27 @@
|
|||||||
"@typescript-eslint/types" "8.38.0"
|
"@typescript-eslint/types" "8.38.0"
|
||||||
"@typescript-eslint/visitor-keys" "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"
|
version "8.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz#6de4ce224a779601a8df667db56527255c42c4d0"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz#6de4ce224a779601a8df667db56527255c42c4d0"
|
||||||
integrity sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==
|
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":
|
"@typescript-eslint/type-utils@8.38.0":
|
||||||
version "8.38.0"
|
version "8.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz#a56cd84765fa6ec135fe252b5db61e304403a85b"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz#a56cd84765fa6ec135fe252b5db61e304403a85b"
|
||||||
@ -1771,11 +1849,32 @@
|
|||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
ts-api-utils "^2.1.0"
|
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"
|
version "8.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.38.0.tgz#297351c994976b93c82ac0f0e206c8143aa82529"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.38.0.tgz#297351c994976b93c82ac0f0e206c8143aa82529"
|
||||||
integrity sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==
|
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":
|
"@typescript-eslint/typescript-estree@8.38.0":
|
||||||
version "8.38.0"
|
version "8.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz#82262199eb6778bba28a319e25ad05b1158957df"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz#82262199eb6778bba28a319e25ad05b1158957df"
|
||||||
@ -1792,7 +1891,17 @@
|
|||||||
semver "^7.6.0"
|
semver "^7.6.0"
|
||||||
ts-api-utils "^2.1.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"
|
version "8.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.38.0.tgz#5f10159899d30eb92ba70e642ca6f754bddbf15a"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.38.0.tgz#5f10159899d30eb92ba70e642ca6f754bddbf15a"
|
||||||
integrity sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==
|
integrity sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==
|
||||||
@ -1802,6 +1911,14 @@
|
|||||||
"@typescript-eslint/types" "8.38.0"
|
"@typescript-eslint/types" "8.38.0"
|
||||||
"@typescript-eslint/typescript-estree" "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":
|
"@typescript-eslint/visitor-keys@8.38.0":
|
||||||
version "8.38.0"
|
version "8.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz#a9765a527b082cb8fc60fd8a16e47c7ad5b60ea5"
|
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"
|
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
|
||||||
integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
|
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"
|
version "4.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
|
||||||
integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
|
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"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
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:
|
eslint-config-next@15.4.4:
|
||||||
version "15.4.4"
|
version "15.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-15.4.4.tgz#df20632c342b2b48e8450d0028b8fd15edb10a60"
|
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 "^7.37.0"
|
||||||
eslint-plugin-react-hooks "^5.0.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:
|
eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9:
|
||||||
version "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"
|
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"
|
is-core-module "^2.13.0"
|
||||||
resolve "^1.22.4"
|
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:
|
eslint-import-resolver-typescript@^3.5.2:
|
||||||
version "3.10.1"
|
version "3.10.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz#23dac32efa86a88e2b8232eb244ac499ad636db2"
|
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:
|
dependencies:
|
||||||
debug "^3.2.7"
|
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"
|
version "2.32.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz#602b55faa6e4caeaa5e970c198b5c00a37708980"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz#602b55faa6e4caeaa5e970c198b5c00a37708980"
|
||||||
integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==
|
integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==
|
||||||
@ -2944,7 +3101,27 @@ eslint-plugin-import@^2.31.0:
|
|||||||
string.prototype.trimend "^1.0.9"
|
string.prototype.trimend "^1.0.9"
|
||||||
tsconfig-paths "^3.15.0"
|
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"
|
version "6.10.2"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz#d2812bb23bf1ab4665f1718ea442e8372e638483"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz#d2812bb23bf1ab4665f1718ea442e8372e638483"
|
||||||
integrity sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==
|
integrity sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==
|
||||||
@ -2965,12 +3142,12 @@ eslint-plugin-jsx-a11y@^6.10.0:
|
|||||||
safe-regex-test "^1.0.3"
|
safe-regex-test "^1.0.3"
|
||||||
string.prototype.includes "^2.0.1"
|
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"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3"
|
||||||
integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==
|
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"
|
version "7.37.5"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065"
|
||||||
integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==
|
integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==
|
||||||
@ -2994,6 +3171,14 @@ eslint-plugin-react@^7.37.0:
|
|||||||
string.prototype.matchall "^4.0.12"
|
string.prototype.matchall "^4.0.12"
|
||||||
string.prototype.repeat "^1.0.0"
|
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:
|
eslint-scope@^8.4.0:
|
||||||
version "8.4.0"
|
version "8.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82"
|
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"
|
es-errors "^1.3.0"
|
||||||
get-intrinsic "^1.2.6"
|
get-intrinsic "^1.2.6"
|
||||||
|
|
||||||
get-tsconfig@^4.10.0:
|
get-tsconfig@^4.10.0, get-tsconfig@^4.10.1:
|
||||||
version "4.10.1"
|
version "4.10.1"
|
||||||
resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.10.1.tgz#d34c1c01f47d65a606c37aa7a177bc3e56ab4b2e"
|
resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.10.1.tgz#d34c1c01f47d65a606c37aa7a177bc3e56ab4b2e"
|
||||||
integrity sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==
|
integrity sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==
|
||||||
@ -3344,6 +3529,11 @@ glob@^7.1.1:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
path-is-absolute "^1.0.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:
|
globals@^14.0.0:
|
||||||
version "14.0.0"
|
version "14.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
|
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"
|
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||||
|
|
||||||
picomatch@^4.0.2:
|
picomatch@^4.0.2, picomatch@^4.0.3:
|
||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042"
|
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042"
|
||||||
integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==
|
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"
|
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
|
||||||
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
|
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:
|
resolve-from@5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
|
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
|
||||||
@ -5120,6 +5315,11 @@ sponge-case@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.0.3"
|
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:
|
stable-hash@^0.0.5:
|
||||||
version "0.0.5"
|
version "0.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/stable-hash/-/stable-hash-0.0.5.tgz#94e8837aaeac5b4d0f631d2972adef2924b40269"
|
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"
|
resolved "https://registry.yarnpkg.com/timeout-signal/-/timeout-signal-2.0.0.tgz#23207ea448d50258bb0defe3beea4a467643abba"
|
||||||
integrity sha512-YBGpG4bWsHoPvofT6y/5iqulfXIiIErl5B0LdtHT1mGXDFTAhhRrbUpTvBgYbovr+3cKblya2WAOcpoy90XguA==
|
integrity sha512-YBGpG4bWsHoPvofT6y/5iqulfXIiIErl5B0LdtHT1mGXDFTAhhRrbUpTvBgYbovr+3cKblya2WAOcpoy90XguA==
|
||||||
|
|
||||||
tinyglobby@^0.2.13:
|
tinyglobby@^0.2.13, tinyglobby@^0.2.14:
|
||||||
version "0.2.14"
|
version "0.2.14"
|
||||||
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d"
|
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d"
|
||||||
integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==
|
integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==
|
||||||
@ -5454,6 +5654,16 @@ typed-array-length@^1.0.7:
|
|||||||
possible-typed-array-names "^1.0.0"
|
possible-typed-array-names "^1.0.0"
|
||||||
reflect.getprototypeof "^1.0.6"
|
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:
|
typescript@5.8.3:
|
||||||
version "5.8.3"
|
version "5.8.3"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
|
||||||
@ -5496,7 +5706,7 @@ unixify@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
normalize-path "^2.1.1"
|
normalize-path "^2.1.1"
|
||||||
|
|
||||||
unrs-resolver@^1.6.2:
|
unrs-resolver@^1.6.2, unrs-resolver@^1.7.11:
|
||||||
version "1.11.1"
|
version "1.11.1"
|
||||||
resolved "https://registry.yarnpkg.com/unrs-resolver/-/unrs-resolver-1.11.1.tgz#be9cd8686c99ef53ecb96df2a473c64d304048a9"
|
resolved "https://registry.yarnpkg.com/unrs-resolver/-/unrs-resolver-1.11.1.tgz#be9cd8686c99ef53ecb96df2a473c64d304048a9"
|
||||||
integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==
|
integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user