Refactor auth methods, remove i18n, and update UI
This commit covers a variety of actions that includes the refactoring of the authentication components to accept paths and invite tokens as props instead of a singular callback prop, thereby improving the component's flexibility. This refactor process removes 'withI18n' calls as i18n functionalities are no longer used. The commit also contains several adjustments to the UI components, including the authorization layout, pricing table, and sign-up page. It also includes minor changes to error messages, specifically those related to password resetting. Lastly, several peer dependencies are removed in the 'package.json' files and changes made to the 'browser.client.ts' file providing a significant code cleanup.
This commit is contained in:
@@ -1,5 +1,3 @@
|
|||||||
import { GlobalLoader } from '@kit/ui/global-loader';
|
import { GlobalLoader } from '@kit/ui/global-loader';
|
||||||
|
|
||||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
export default GlobalLoader;
|
||||||
|
|
||||||
export default withI18n(GlobalLoader);
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { GlobalLoader } from '@kit/ui/global-loader';
|
import { GlobalLoader } from '@kit/ui/global-loader';
|
||||||
|
|
||||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
export default GlobalLoader;
|
||||||
|
|
||||||
export default withI18n(GlobalLoader);
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { GlobalLoader } from '@kit/ui/global-loader';
|
import { GlobalLoader } from '@kit/ui/global-loader';
|
||||||
|
|
||||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
export default GlobalLoader;
|
||||||
|
|
||||||
export default withI18n(GlobalLoader);
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
import { GlobalLoader } from '@kit/ui/global-loader';
|
|
||||||
|
|
||||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
|
||||||
|
|
||||||
export default withI18n(GlobalLoader);
|
|
||||||
@@ -18,6 +18,8 @@ export const generateMetadata = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function PasswordResetPage() {
|
function PasswordResetPage() {
|
||||||
|
const redirectPath = `${pathsConfig.auth.callback}?next=${pathsConfig.auth.passwordUpdate}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Heading level={5}>
|
<Heading level={5}>
|
||||||
@@ -25,9 +27,7 @@ function PasswordResetPage() {
|
|||||||
</Heading>
|
</Heading>
|
||||||
|
|
||||||
<div className={'flex flex-col space-y-4'}>
|
<div className={'flex flex-col space-y-4'}>
|
||||||
<PasswordResetRequestContainer
|
<PasswordResetRequestContainer redirectPath={redirectPath} />
|
||||||
redirectTo={pathsConfig.auth.passwordUpdate}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className={'flex justify-center text-xs'}>
|
<div className={'flex justify-center text-xs'}>
|
||||||
<Link href={pathsConfig.auth.signIn}>
|
<Link href={pathsConfig.auth.signIn}>
|
||||||
|
|||||||
@@ -18,7 +18,15 @@ export const generateMetadata = async () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function SignUpPage() {
|
interface Props {
|
||||||
|
searchParams: {
|
||||||
|
invite_token?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function SignUpPage({ searchParams }: Props) {
|
||||||
|
const inviteToken = searchParams.invite_token;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Heading level={5}>
|
<Heading level={5}>
|
||||||
@@ -27,7 +35,10 @@ function SignUpPage() {
|
|||||||
|
|
||||||
<SignUpMethodsContainer
|
<SignUpMethodsContainer
|
||||||
providers={authConfig.providers}
|
providers={authConfig.providers}
|
||||||
callbackPath={pathsConfig.auth.callback}
|
paths={{
|
||||||
|
callback: pathsConfig.auth.callback,
|
||||||
|
}}
|
||||||
|
inviteToken={inviteToken}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={'justify-centers flex'}>
|
<div className={'justify-centers flex'}>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { GlobalLoader } from '@kit/ui/global-loader';
|
import { GlobalLoader } from '@kit/ui/global-loader';
|
||||||
|
|
||||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
export default GlobalLoader;
|
||||||
|
|
||||||
export default withI18n(GlobalLoader);
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { redirect } from 'next/navigation';
|
|||||||
|
|
||||||
import { PasswordResetForm } from '@kit/auth/password-reset';
|
import { PasswordResetForm } from '@kit/auth/password-reset';
|
||||||
import { AuthLayoutShell } from '@kit/auth/shared';
|
import { AuthLayoutShell } from '@kit/auth/shared';
|
||||||
|
import { requireAuth } from '@kit/supabase/require-auth';
|
||||||
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
||||||
|
|
||||||
import { AppLogo } from '~/components/app-logo';
|
import { AppLogo } from '~/components/app-logo';
|
||||||
@@ -10,18 +11,16 @@ import { withI18n } from '~/lib/i18n/with-i18n';
|
|||||||
|
|
||||||
async function PasswordResetPage() {
|
async function PasswordResetPage() {
|
||||||
const client = getSupabaseServerComponentClient();
|
const client = getSupabaseServerComponentClient();
|
||||||
const user = await client.auth.getUser();
|
const auth = await requireAuth(client);
|
||||||
|
|
||||||
// we require the user to be logged in to access this page
|
// we require the user to be logged in to access this page
|
||||||
if (!user.data) {
|
if (auth.error) {
|
||||||
redirect(pathsConfig.auth.passwordReset);
|
redirect(auth.redirectTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
const redirectTo = `/${pathsConfig.auth.callback}?next=${pathsConfig.app.home}`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthLayoutShell Logo={AppLogo}>
|
<AuthLayoutShell Logo={AppLogo}>
|
||||||
<PasswordResetForm redirectTo={redirectTo} />
|
<PasswordResetForm redirectTo={pathsConfig.app.home} />
|
||||||
</AuthLayoutShell>
|
</AuthLayoutShell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ const AuthConfigSchema = z.object({
|
|||||||
providers: z.object({
|
providers: z.object({
|
||||||
password: z.boolean(),
|
password: z.boolean(),
|
||||||
magicLink: z.boolean(),
|
magicLink: z.boolean(),
|
||||||
otp: z.boolean(),
|
|
||||||
oAuth: providers.array(),
|
oAuth: providers.array(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -17,9 +16,8 @@ const authConfig = AuthConfigSchema.parse({
|
|||||||
// NB: Enable the providers below in the Supabase Console
|
// NB: Enable the providers below in the Supabase Console
|
||||||
// in your production project
|
// in your production project
|
||||||
providers: {
|
providers: {
|
||||||
password: true,
|
password: false,
|
||||||
magicLink: false,
|
magicLink: true,
|
||||||
otp: false,
|
|
||||||
oAuth: ['google'],
|
oAuth: ['google'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const pathsConfig = PathsSchema.parse({
|
|||||||
verifyMfa: '/auth/verify',
|
verifyMfa: '/auth/verify',
|
||||||
callback: '/auth/callback',
|
callback: '/auth/callback',
|
||||||
passwordReset: '/auth/password-reset',
|
passwordReset: '/auth/password-reset',
|
||||||
passwordUpdate: '/password-reset',
|
passwordUpdate: '/update-password',
|
||||||
},
|
},
|
||||||
app: {
|
app: {
|
||||||
home: '/home',
|
home: '/home',
|
||||||
|
|||||||
@@ -38,7 +38,8 @@
|
|||||||
"passwordLengthError": "Please provide a password with at least 6 characters",
|
"passwordLengthError": "Please provide a password with at least 6 characters",
|
||||||
"sendEmailLink": "Send Email Link",
|
"sendEmailLink": "Send Email Link",
|
||||||
"sendingEmailLink": "Sending Email Link...",
|
"sendingEmailLink": "Sending Email Link...",
|
||||||
"sendLinkSuccess": "We sent you a link to your email! Follow the link to sign in.",
|
"sendLinkSuccessDescription": "Check your email, we just sent you a link. Follow the link to sign in.",
|
||||||
|
"sendLinkSuccess": "We send you a link.",
|
||||||
"sendLinkSuccessToast": "Link successfully sent",
|
"sendLinkSuccessToast": "Link successfully sent",
|
||||||
"getNewLink": "Get a new link",
|
"getNewLink": "Get a new link",
|
||||||
"verificationCode": "Verification Code",
|
"verificationCode": "Verification Code",
|
||||||
|
|||||||
@@ -14,8 +14,6 @@
|
|||||||
"./components": "./src/components/index.ts"
|
"./components": "./src/components/index.ts"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"zod": "^3.22.4",
|
"zod": "^3.22.4",
|
||||||
"@kit/ui": "0.1.0",
|
"@kit/ui": "0.1.0",
|
||||||
"@kit/stripe": "0.1.0",
|
"@kit/stripe": "0.1.0",
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
"./schema": "./src/schema/index.ts"
|
"./schema": "./src/schema/index.ts"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"zod": "^3.22.4",
|
"zod": "^3.22.4",
|
||||||
"@kit/ui": "0.1.0",
|
"@kit/ui": "0.1.0",
|
||||||
"@kit/supabase": "0.1.0",
|
"@kit/supabase": "0.1.0",
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export function PricingTable({
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'flex flex-col items-start space-y-6 lg:space-y-0' +
|
'flex flex-col items-start space-y-6 lg:space-y-0' +
|
||||||
' justify-center lg:flex-row lg:space-x-4'
|
' justify-center space-x-2 lg:flex-row'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{config.products.map((product) => {
|
{config.products.map((product) => {
|
||||||
@@ -107,6 +107,7 @@ function PricingItem(
|
|||||||
|
|
||||||
product: {
|
product: {
|
||||||
name: string;
|
name: string;
|
||||||
|
currency: string;
|
||||||
description: string;
|
description: string;
|
||||||
badge?: string;
|
badge?: string;
|
||||||
highlighted?: boolean;
|
highlighted?: boolean;
|
||||||
@@ -122,12 +123,8 @@ function PricingItem(
|
|||||||
className={cn(
|
className={cn(
|
||||||
`
|
`
|
||||||
relative flex w-full flex-col justify-between space-y-6 rounded-lg
|
relative flex w-full flex-col justify-between space-y-6 rounded-lg
|
||||||
p-6 lg:w-4/12 xl:max-w-xs xl:p-8 2xl:w-3/12
|
border p-6 lg:w-4/12 xl:max-w-xs xl:p-8 2xl:w-3/12
|
||||||
`,
|
`,
|
||||||
{
|
|
||||||
['dark:border-dark-900 border border-gray-100']: !highlighted,
|
|
||||||
['border-primary border-2']: highlighted,
|
|
||||||
},
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className={'flex flex-col space-y-2.5'}>
|
<div className={'flex flex-col space-y-2.5'}>
|
||||||
@@ -142,7 +139,7 @@ function PricingItem(
|
|||||||
`flex space-x-1 rounded-md px-2 py-1 text-xs font-medium`,
|
`flex space-x-1 rounded-md px-2 py-1 text-xs font-medium`,
|
||||||
{
|
{
|
||||||
['text-primary-foreground bg-primary']: highlighted,
|
['text-primary-foreground bg-primary']: highlighted,
|
||||||
['bg-gray-50 text-gray-500 dark:text-gray-800']: !highlighted,
|
['text-muted-foreground bg-gray-50']: !highlighted,
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -161,7 +158,10 @@ function PricingItem(
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={'flex items-center space-x-1'}>
|
<div className={'flex items-center space-x-1'}>
|
||||||
<Price>{props.plan.price}</Price>
|
<Price>
|
||||||
|
<span className={'text-base'}>{props.product.currency}</span>
|
||||||
|
{props.plan.price}
|
||||||
|
</Price>
|
||||||
|
|
||||||
<If condition={props.plan.name}>
|
<If condition={props.plan.name}>
|
||||||
<span className={cn(`text-muted-foreground text-base lowercase`)}>
|
<span className={cn(`text-muted-foreground text-base lowercase`)}>
|
||||||
@@ -223,10 +223,12 @@ function Price({ children }: React.PropsWithChildren) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={key}
|
key={key}
|
||||||
className={`animate-in slide-in-from-left-4 fade-in duration-500`}
|
className={`animate-in slide-in-from-left-4 fade-in items-center duration-500`}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={'text-2xl font-bold lg:text-3xl xl:text-4xl 2xl:text-5xl'}
|
className={
|
||||||
|
'flex items-center text-2xl font-bold lg:text-3xl xl:text-4xl 2xl:text-5xl'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -21,8 +21,6 @@
|
|||||||
"@kit/tsconfig": "0.1.0"
|
"@kit/tsconfig": "0.1.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"@kit/supabase": "0.1.0",
|
"@kit/supabase": "0.1.0",
|
||||||
"@kit/ui": "0.1.0",
|
"@kit/ui": "0.1.0",
|
||||||
"@kit/shared": "0.1.0",
|
"@kit/shared": "0.1.0",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export function AuthLayoutShell({
|
|||||||
className={
|
className={
|
||||||
'flex h-screen flex-col items-center justify-center space-y-4' +
|
'flex h-screen flex-col items-center justify-center space-y-4' +
|
||||||
' dark:lg:bg-background md:space-y-8 lg:space-y-12 lg:bg-gray-50' +
|
' dark:lg:bg-background md:space-y-8 lg:space-y-12 lg:bg-gray-50' +
|
||||||
' animate-in fade-in slide-in-from-top-8 duration-1000'
|
' animate-in fade-in slide-in-from-top-8 zoom-in-95 duration-1000'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{Logo && <Logo />}
|
{Logo && <Logo />}
|
||||||
|
|||||||
@@ -1,98 +1,132 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import type { FormEventHandler } from 'react';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useCallback } from 'react';
|
import { CheckIcon } from '@radix-ui/react-icons';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { useSignInWithOtp } from '@kit/supabase/hooks/use-sign-in-with-otp';
|
import { useSignInWithOtp } from '@kit/supabase/hooks/use-sign-in-with-otp';
|
||||||
import { Alert, AlertDescription } from '@kit/ui/alert';
|
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
||||||
import { Button } from '@kit/ui/button';
|
import { Button } from '@kit/ui/button';
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from '@kit/ui/form';
|
||||||
import { If } from '@kit/ui/if';
|
import { If } from '@kit/ui/if';
|
||||||
import { Input } from '@kit/ui/input';
|
import { Input } from '@kit/ui/input';
|
||||||
import { Label } from '@kit/ui/label';
|
|
||||||
import { Trans } from '@kit/ui/trans';
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
|
||||||
export function MagicLinkAuthContainer({
|
export function MagicLinkAuthContainer({
|
||||||
inviteCode,
|
inviteToken,
|
||||||
redirectUrl,
|
redirectUrl,
|
||||||
}: {
|
}: {
|
||||||
inviteCode?: string;
|
inviteToken?: string;
|
||||||
redirectUrl: string;
|
redirectUrl: string;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const signInWithOtpMutation = useSignInWithOtp();
|
const signInWithOtpMutation = useSignInWithOtp();
|
||||||
|
|
||||||
const onSubmit: FormEventHandler<HTMLFormElement> = useCallback(
|
const form = useForm({
|
||||||
(event) => {
|
resolver: zodResolver(
|
||||||
event.preventDefault();
|
z.object({
|
||||||
|
email: z.string().email(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
defaultValues: {
|
||||||
|
email: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const target = event.currentTarget;
|
const onSubmit = ({ email }: { email: string }) => {
|
||||||
const data = new FormData(target);
|
const queryParams = inviteToken ? `?invite_token=${inviteToken}` : '';
|
||||||
const email = data.get('email') as string;
|
const emailRedirectTo = [redirectUrl, queryParams].join('');
|
||||||
const queryParams = inviteCode ? `?inviteCode=${inviteCode}` : '';
|
|
||||||
|
|
||||||
const emailRedirectTo = [redirectUrl, queryParams].join('');
|
const promise = () =>
|
||||||
|
signInWithOtpMutation.mutateAsync({
|
||||||
const promise = signInWithOtpMutation.mutateAsync({
|
|
||||||
email,
|
email,
|
||||||
options: {
|
options: {
|
||||||
emailRedirectTo,
|
emailRedirectTo,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
toast.promise(promise, {
|
toast.promise(promise, {
|
||||||
loading: t('auth:sendingEmailLink'),
|
loading: t('auth:sendingEmailLink'),
|
||||||
success: t(`auth:sendLinkSuccessToast`),
|
success: t(`auth:sendLinkSuccessToast`),
|
||||||
error: t(`auth:errors.link`),
|
error: t(`auth:errors.link`),
|
||||||
});
|
});
|
||||||
},
|
};
|
||||||
[inviteCode, redirectUrl, signInWithOtpMutation, t],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (signInWithOtpMutation.data) {
|
if (signInWithOtpMutation.data) {
|
||||||
return (
|
return (
|
||||||
<Alert variant={'success'}>
|
<Alert variant={'success'}>
|
||||||
<AlertDescription>
|
<CheckIcon className={'h-4'} />
|
||||||
|
|
||||||
|
<AlertTitle>
|
||||||
<Trans i18nKey={'auth:sendLinkSuccess'} />
|
<Trans i18nKey={'auth:sendLinkSuccess'} />
|
||||||
|
</AlertTitle>
|
||||||
|
|
||||||
|
<AlertDescription>
|
||||||
|
<Trans i18nKey={'auth:sendLinkSuccessDescription'} />
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={'w-full'} onSubmit={onSubmit}>
|
<Form {...form}>
|
||||||
<If condition={signInWithOtpMutation.error}>
|
<form className={'w-full'} onSubmit={form.handleSubmit(onSubmit)}>
|
||||||
<Alert variant={'destructive'}>
|
<If condition={signInWithOtpMutation.error}>
|
||||||
<AlertDescription>
|
<Alert variant={'destructive'}>
|
||||||
<Trans i18nKey={'auth:errors.link'} />
|
<AlertTitle>
|
||||||
</AlertDescription>
|
<Trans i18nKey={'auth:errors.generic'} />
|
||||||
</Alert>
|
</AlertTitle>
|
||||||
</If>
|
|
||||||
|
|
||||||
<div className={'flex flex-col space-y-4'}>
|
<AlertDescription>
|
||||||
<Label>
|
<Trans i18nKey={'auth:errors.link'} />
|
||||||
<Trans i18nKey={'common:emailAddress'} />
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
</If>
|
||||||
|
|
||||||
<Input
|
<div className={'flex flex-col space-y-4'}>
|
||||||
data-test={'email-input'}
|
<FormField
|
||||||
required
|
render={({ field }) => (
|
||||||
type="email"
|
<FormItem>
|
||||||
placeholder={t('auth:emailPlaceholder')}
|
<FormLabel>
|
||||||
|
<Trans i18nKey={'common:emailAddress'} />
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
data-test={'email-input'}
|
||||||
|
required
|
||||||
|
type="email"
|
||||||
|
placeholder={t('auth:emailPlaceholder')}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
name={'email'}
|
name={'email'}
|
||||||
/>
|
/>
|
||||||
</Label>
|
|
||||||
|
|
||||||
<Button disabled={signInWithOtpMutation.isPending}>
|
<Button disabled={signInWithOtpMutation.isPending}>
|
||||||
<If
|
<If
|
||||||
condition={signInWithOtpMutation.isPending}
|
condition={signInWithOtpMutation.isPending}
|
||||||
fallback={<Trans i18nKey={'auth:sendEmailLink'} />}
|
fallback={<Trans i18nKey={'auth:sendEmailLink'} />}
|
||||||
>
|
>
|
||||||
<Trans i18nKey={'auth:sendingEmailLink'} />
|
<Trans i18nKey={'auth:sendingEmailLink'} />
|
||||||
</If>
|
</If>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</Form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,13 @@ import { AuthErrorAlert } from './auth-error-alert';
|
|||||||
import { AuthProviderButton } from './auth-provider-button';
|
import { AuthProviderButton } from './auth-provider-button';
|
||||||
|
|
||||||
export const OauthProviders: React.FC<{
|
export const OauthProviders: React.FC<{
|
||||||
returnUrl?: string;
|
inviteToken?: string;
|
||||||
inviteCode?: string;
|
|
||||||
enabledProviders: Provider[];
|
enabledProviders: Provider[];
|
||||||
redirectUrl: string;
|
|
||||||
|
paths: {
|
||||||
|
callback: string;
|
||||||
|
returnPath: string;
|
||||||
|
};
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
const signInWithProviderMutation = useSignInWithProvider();
|
const signInWithProviderMutation = useSignInWithProvider();
|
||||||
|
|
||||||
@@ -57,16 +60,16 @@ export const OauthProviders: React.FC<{
|
|||||||
const origin = window.location.origin;
|
const origin = window.location.origin;
|
||||||
const queryParams = new URLSearchParams();
|
const queryParams = new URLSearchParams();
|
||||||
|
|
||||||
if (props.returnUrl) {
|
if (props.paths.returnPath) {
|
||||||
queryParams.set('next', props.returnUrl);
|
queryParams.set('next', props.paths.returnPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.inviteCode) {
|
if (props.inviteToken) {
|
||||||
queryParams.set('inviteCode', props.inviteCode);
|
queryParams.set('invite_token', props.inviteToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
const redirectPath = [
|
const redirectPath = [
|
||||||
props.redirectUrl,
|
props.paths.callback,
|
||||||
queryParams.toString(),
|
queryParams.toString(),
|
||||||
].join('?');
|
].join('?');
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,11 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import {
|
||||||
|
ArrowLeftIcon,
|
||||||
|
CheckIcon,
|
||||||
|
ExclamationTriangleIcon,
|
||||||
|
} from '@radix-ui/react-icons';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import type { z } from 'zod';
|
import type { z } from 'zod';
|
||||||
|
|
||||||
@@ -112,7 +117,9 @@ export function PasswordResetForm(params: { redirectTo: string }) {
|
|||||||
function SuccessState() {
|
function SuccessState() {
|
||||||
return (
|
return (
|
||||||
<div className={'flex flex-col space-y-4'}>
|
<div className={'flex flex-col space-y-4'}>
|
||||||
<Alert variant={'destructive'}>
|
<Alert variant={'success'}>
|
||||||
|
<CheckIcon className={'s-6'} />
|
||||||
|
|
||||||
<AlertTitle>
|
<AlertTitle>
|
||||||
<Trans i18nKey={'account:updatePasswordSuccess'} />
|
<Trans i18nKey={'account:updatePasswordSuccess'} />
|
||||||
</AlertTitle>
|
</AlertTitle>
|
||||||
@@ -123,8 +130,12 @@ function SuccessState() {
|
|||||||
</Alert>
|
</Alert>
|
||||||
|
|
||||||
<Link href={'/'}>
|
<Link href={'/'}>
|
||||||
<Button variant={'outline'}>
|
<Button variant={'outline'} className={'w-full'}>
|
||||||
<Trans i18nKey={'common:backToHomePage'} />
|
<ArrowLeftIcon className={'mr-2 h-4'} />
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<Trans i18nKey={'common:backToHomePage'} />
|
||||||
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -135,12 +146,14 @@ function ErrorState(props: { onRetry: () => void }) {
|
|||||||
return (
|
return (
|
||||||
<div className={'flex flex-col space-y-4'}>
|
<div className={'flex flex-col space-y-4'}>
|
||||||
<Alert variant={'destructive'}>
|
<Alert variant={'destructive'}>
|
||||||
|
<ExclamationTriangleIcon className={'s-6'} />
|
||||||
|
|
||||||
<AlertTitle>
|
<AlertTitle>
|
||||||
<Trans i18nKey={'auth:resetPasswordError'} />
|
<Trans i18nKey={'common:genericError'} />
|
||||||
</AlertTitle>
|
</AlertTitle>
|
||||||
|
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
<Trans i18nKey={'common:genericError'} />
|
<Trans i18nKey={'auth:resetPasswordError'} />
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ const PasswordResetSchema = z.object({
|
|||||||
email: z.string().email(),
|
email: z.string().email(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function PasswordResetRequestContainer(params: { redirectTo: string }) {
|
export function PasswordResetRequestContainer(params: {
|
||||||
|
redirectPath: string;
|
||||||
|
}) {
|
||||||
const { t } = useTranslation('auth');
|
const { t } = useTranslation('auth');
|
||||||
const resetPasswordMutation = useRequestResetPassword();
|
const resetPasswordMutation = useRequestResetPassword();
|
||||||
const error = resetPasswordMutation.error;
|
const error = resetPasswordMutation.error;
|
||||||
@@ -55,7 +57,8 @@ export function PasswordResetRequestContainer(params: { redirectTo: string }) {
|
|||||||
onSubmit={form.handleSubmit(({ email }) => {
|
onSubmit={form.handleSubmit(({ email }) => {
|
||||||
return resetPasswordMutation.mutateAsync({
|
return resetPasswordMutation.mutateAsync({
|
||||||
email,
|
email,
|
||||||
redirectTo: params.redirectTo,
|
redirectTo: new URL(params.redirectPath, window.location.origin)
|
||||||
|
.href,
|
||||||
});
|
});
|
||||||
})}
|
})}
|
||||||
className={'w-full'}
|
className={'w-full'}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { isBrowser } from '@supabase/ssr';
|
|||||||
import { Divider } from '@kit/ui/divider';
|
import { Divider } from '@kit/ui/divider';
|
||||||
import { If } from '@kit/ui/if';
|
import { If } from '@kit/ui/if';
|
||||||
|
|
||||||
import { EmailOtpContainer } from './email-otp-container';
|
|
||||||
import { MagicLinkAuthContainer } from './magic-link-auth-container';
|
import { MagicLinkAuthContainer } from './magic-link-auth-container';
|
||||||
import { OauthProviders } from './oauth-providers';
|
import { OauthProviders } from './oauth-providers';
|
||||||
import { PasswordSignInContainer } from './password-sign-in-container';
|
import { PasswordSignInContainer } from './password-sign-in-container';
|
||||||
@@ -23,7 +22,6 @@ export function SignInMethodsContainer(props: {
|
|||||||
providers: {
|
providers: {
|
||||||
password: boolean;
|
password: boolean;
|
||||||
magicLink: boolean;
|
magicLink: boolean;
|
||||||
otp: boolean;
|
|
||||||
oAuth: Provider[];
|
oAuth: Provider[];
|
||||||
};
|
};
|
||||||
}) {
|
}) {
|
||||||
@@ -48,20 +46,15 @@ export function SignInMethodsContainer(props: {
|
|||||||
<MagicLinkAuthContainer redirectUrl={redirectUrl} />
|
<MagicLinkAuthContainer redirectUrl={redirectUrl} />
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
<If condition={props.providers.otp}>
|
|
||||||
<EmailOtpContainer
|
|
||||||
onSignIn={onSignIn}
|
|
||||||
redirectUrl={redirectUrl}
|
|
||||||
shouldCreateUser={false}
|
|
||||||
/>
|
|
||||||
</If>
|
|
||||||
|
|
||||||
<If condition={props.providers.oAuth.length}>
|
<If condition={props.providers.oAuth.length}>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<OauthProviders
|
<OauthProviders
|
||||||
enabledProviders={props.providers.oAuth}
|
enabledProviders={props.providers.oAuth}
|
||||||
redirectUrl={redirectUrl}
|
paths={{
|
||||||
|
callback: props.paths.callback,
|
||||||
|
returnPath: props.paths.home,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</If>
|
</If>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -7,27 +7,27 @@ import { isBrowser } from '@supabase/ssr';
|
|||||||
import { Divider } from '@kit/ui/divider';
|
import { Divider } from '@kit/ui/divider';
|
||||||
import { If } from '@kit/ui/if';
|
import { If } from '@kit/ui/if';
|
||||||
|
|
||||||
import { EmailOtpContainer } from './email-otp-container';
|
|
||||||
import { MagicLinkAuthContainer } from './magic-link-auth-container';
|
import { MagicLinkAuthContainer } from './magic-link-auth-container';
|
||||||
import { OauthProviders } from './oauth-providers';
|
import { OauthProviders } from './oauth-providers';
|
||||||
import { EmailPasswordSignUpContainer } from './password-sign-up-container';
|
import { EmailPasswordSignUpContainer } from './password-sign-up-container';
|
||||||
|
|
||||||
export function SignUpMethodsContainer(props: {
|
export function SignUpMethodsContainer(props: {
|
||||||
callbackPath: string;
|
paths: {
|
||||||
|
callback: string;
|
||||||
|
appHome: string;
|
||||||
|
};
|
||||||
|
|
||||||
providers: {
|
providers: {
|
||||||
password: boolean;
|
password: boolean;
|
||||||
magicLink: boolean;
|
magicLink: boolean;
|
||||||
otp: boolean;
|
|
||||||
oAuth: Provider[];
|
oAuth: Provider[];
|
||||||
};
|
};
|
||||||
|
|
||||||
inviteCode?: string;
|
inviteToken?: string;
|
||||||
}) {
|
}) {
|
||||||
const redirectUrl = new URL(
|
const redirectUrl = isBrowser()
|
||||||
props.callbackPath,
|
? new URL(props.paths.callback, window?.location.origin).toString()
|
||||||
isBrowser() ? window?.location.origin : '',
|
: '';
|
||||||
).toString();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -37,26 +37,21 @@ export function SignUpMethodsContainer(props: {
|
|||||||
|
|
||||||
<If condition={props.providers.magicLink}>
|
<If condition={props.providers.magicLink}>
|
||||||
<MagicLinkAuthContainer
|
<MagicLinkAuthContainer
|
||||||
inviteCode={props.inviteCode}
|
inviteToken={props.inviteToken}
|
||||||
redirectUrl={redirectUrl}
|
redirectUrl={redirectUrl}
|
||||||
/>
|
/>
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
<If condition={props.providers.otp}>
|
|
||||||
<EmailOtpContainer
|
|
||||||
redirectUrl={redirectUrl}
|
|
||||||
shouldCreateUser={true}
|
|
||||||
inviteCode={props.inviteCode}
|
|
||||||
/>
|
|
||||||
</If>
|
|
||||||
|
|
||||||
<If condition={props.providers.oAuth.length}>
|
<If condition={props.providers.oAuth.length}>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<OauthProviders
|
<OauthProviders
|
||||||
enabledProviders={props.providers.oAuth}
|
enabledProviders={props.providers.oAuth}
|
||||||
redirectUrl={redirectUrl}
|
inviteToken={props.inviteToken}
|
||||||
inviteCode={props.inviteCode}
|
paths={{
|
||||||
|
callback: props.paths.callback,
|
||||||
|
returnPath: props.paths.appHome,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</If>
|
</If>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
"@kit/tsconfig": "0.1.0"
|
"@kit/tsconfig": "0.1.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"@kit/supabase": "0.1.0",
|
"@kit/supabase": "0.1.0",
|
||||||
"@kit/ui": "0.1.0",
|
"@kit/ui": "0.1.0",
|
||||||
"@kit/shared": "0.1.0",
|
"@kit/shared": "0.1.0",
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ import { Database } from '@kit/supabase/database';
|
|||||||
type Role = Database['public']['Enums']['account_role'];
|
type Role = Database['public']['Enums']['account_role'];
|
||||||
|
|
||||||
export const UpdateInvitationSchema = z.object({
|
export const UpdateInvitationSchema = z.object({
|
||||||
id: z.bigint(),
|
invitationId: z.number(),
|
||||||
role: z.custom<Role>(() => z.string().min(1)),
|
role: z.custom<Role>(() => z.string().min(1)),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,9 +16,6 @@
|
|||||||
"./cookies/*": "./src/cookies/*.ts",
|
"./cookies/*": "./src/cookies/*.ts",
|
||||||
"./utils": "./src/utils.ts"
|
"./utils": "./src/utils.ts"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
|
||||||
"react": "^18.2.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pino": "^8.19.0"
|
"pino": "^8.19.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
|
import { SupabaseClient } from '@supabase/supabase-js';
|
||||||
|
|
||||||
import { invariant } from '@epic-web/invariant';
|
import { invariant } from '@epic-web/invariant';
|
||||||
import { createBrowserClient } from '@supabase/ssr';
|
import { createBrowserClient } from '@supabase/ssr';
|
||||||
|
|
||||||
import { Database } from '../database.types';
|
import { Database } from '../database.types';
|
||||||
|
|
||||||
let client: ReturnType<typeof createBrowserClient<Database>>;
|
let client: SupabaseClient<Database>;
|
||||||
|
|
||||||
export function getSupabaseBrowserClient<GenericSchema = Database>() {
|
export function getSupabaseBrowserClient() {
|
||||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||||
const SUPABASE_ANON_KEY = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
const SUPABASE_ANON_KEY = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
||||||
|
|
||||||
@@ -16,7 +18,7 @@ export function getSupabaseBrowserClient<GenericSchema = Database>() {
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
client = createBrowserClient<GenericSchema>(SUPABASE_URL, SUPABASE_ANON_KEY);
|
client = createBrowserClient<Database>(SUPABASE_URL, SUPABASE_ANON_KEY);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,6 @@
|
|||||||
"lucide-react": "0.307.0",
|
"lucide-react": "0.307.0",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"date-fns": "^3.2.0",
|
"date-fns": "^3.2.0",
|
||||||
"react": "18.2.0",
|
|
||||||
"react-dom": "18.2.0",
|
|
||||||
"react-hook-form": "^7.49.2"
|
"react-hook-form": "^7.49.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
import { LoadingOverlay } from './loading-overlay';
|
import { LoadingOverlay } from './loading-overlay';
|
||||||
import { TopLoadingBarIndicator } from './top-loading-bar-indicator';
|
import { TopLoadingBarIndicator } from './top-loading-bar-indicator';
|
||||||
import { Trans } from './trans';
|
import { Trans } from './trans';
|
||||||
|
|||||||
69
pnpm-lock.yaml
generated
69
pnpm-lock.yaml
generated
@@ -207,12 +207,6 @@ importers:
|
|||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.361.0
|
specifier: ^0.361.0
|
||||||
version: 0.361.0(react@18.2.0)
|
version: 0.361.0(react@18.2.0)
|
||||||
react:
|
|
||||||
specifier: ^18.2.0
|
|
||||||
version: 18.2.0
|
|
||||||
react-dom:
|
|
||||||
specifier: ^18.2.0
|
|
||||||
version: 18.2.0(react@18.2.0)
|
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.22.4
|
specifier: ^3.22.4
|
||||||
version: 3.22.4
|
version: 3.22.4
|
||||||
@@ -247,15 +241,12 @@ importers:
|
|||||||
'@kit/ui':
|
'@kit/ui':
|
||||||
specifier: 0.1.0
|
specifier: 0.1.0
|
||||||
version: link:../ui
|
version: link:../ui
|
||||||
|
'@supabase/supabase-js':
|
||||||
|
specifier: ^2.39.8
|
||||||
|
version: 2.40.0
|
||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.361.0
|
specifier: ^0.361.0
|
||||||
version: 0.361.0(react@18.2.0)
|
version: 0.361.0(react@18.2.0)
|
||||||
react:
|
|
||||||
specifier: ^18.2.0
|
|
||||||
version: 18.2.0
|
|
||||||
react-dom:
|
|
||||||
specifier: ^18.2.0
|
|
||||||
version: 18.2.0(react@18.2.0)
|
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.22.4
|
specifier: ^3.22.4
|
||||||
version: 3.22.4
|
version: 3.22.4
|
||||||
@@ -272,9 +263,6 @@ importers:
|
|||||||
'@kit/tsconfig':
|
'@kit/tsconfig':
|
||||||
specifier: 0.1.0
|
specifier: 0.1.0
|
||||||
version: link:../../tooling/typescript
|
version: link:../../tooling/typescript
|
||||||
'@supabase/supabase-js':
|
|
||||||
specifier: ^2.39.8
|
|
||||||
version: 2.40.0
|
|
||||||
|
|
||||||
packages/emails:
|
packages/emails:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -312,12 +300,6 @@ importers:
|
|||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.360.0
|
specifier: ^0.360.0
|
||||||
version: 0.360.0(react@18.2.0)
|
version: 0.360.0(react@18.2.0)
|
||||||
react:
|
|
||||||
specifier: ^18.2.0
|
|
||||||
version: 18.2.0
|
|
||||||
react-dom:
|
|
||||||
specifier: ^18.2.0
|
|
||||||
version: 18.2.0(react@18.2.0)
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@kit/eslint-config':
|
'@kit/eslint-config':
|
||||||
specifier: 0.2.0
|
specifier: 0.2.0
|
||||||
@@ -407,12 +389,6 @@ importers:
|
|||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.360.0
|
specifier: ^0.360.0
|
||||||
version: 0.360.0(react@18.2.0)
|
version: 0.360.0(react@18.2.0)
|
||||||
react:
|
|
||||||
specifier: ^18.2.0
|
|
||||||
version: 18.2.0
|
|
||||||
react-dom:
|
|
||||||
specifier: ^18.2.0
|
|
||||||
version: 18.2.0(react@18.2.0)
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@kit/eslint-config':
|
'@kit/eslint-config':
|
||||||
specifier: 0.2.0
|
specifier: 0.2.0
|
||||||
@@ -488,9 +464,6 @@ importers:
|
|||||||
pino:
|
pino:
|
||||||
specifier: ^8.19.0
|
specifier: ^8.19.0
|
||||||
version: 8.19.0
|
version: 8.19.0
|
||||||
react:
|
|
||||||
specifier: ^18.2.0
|
|
||||||
version: 18.2.0
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@kit/eslint-config':
|
'@kit/eslint-config':
|
||||||
specifier: 0.2.0
|
specifier: 0.2.0
|
||||||
@@ -638,9 +611,15 @@ importers:
|
|||||||
cmdk:
|
cmdk:
|
||||||
specifier: ^0.2.0
|
specifier: ^0.2.0
|
||||||
version: 0.2.1(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
|
version: 0.2.1(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
date-fns:
|
||||||
|
specifier: ^3.2.0
|
||||||
|
version: 3.6.0
|
||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: 0.307.0
|
specifier: 0.307.0
|
||||||
version: 0.307.0(react@18.2.0)
|
version: 0.307.0(react@18.2.0)
|
||||||
|
react-hook-form:
|
||||||
|
specifier: ^7.49.2
|
||||||
|
version: 7.51.1(react@18.2.0)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: ^14.1.0
|
specifier: ^14.1.0
|
||||||
version: 14.1.0(i18next@23.10.1)(react-dom@18.2.0)(react@18.2.0)
|
version: 14.1.0(i18next@23.10.1)(react-dom@18.2.0)(react@18.2.0)
|
||||||
@@ -675,27 +654,15 @@ importers:
|
|||||||
'@types/react-dom':
|
'@types/react-dom':
|
||||||
specifier: ^18.2.18
|
specifier: ^18.2.18
|
||||||
version: 18.2.22
|
version: 18.2.22
|
||||||
date-fns:
|
|
||||||
specifier: ^3.2.0
|
|
||||||
version: 3.6.0
|
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.56.0
|
specifier: ^8.56.0
|
||||||
version: 8.57.0
|
version: 8.57.0
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.4
|
||||||
version: 3.2.5
|
version: 3.2.5
|
||||||
react:
|
|
||||||
specifier: 18.2.0
|
|
||||||
version: 18.2.0
|
|
||||||
react-day-picker:
|
react-day-picker:
|
||||||
specifier: ^8.10.0
|
specifier: ^8.10.0
|
||||||
version: 8.10.0(date-fns@3.6.0)(react@18.2.0)
|
version: 8.10.0(date-fns@3.6.0)(react@18.2.0)
|
||||||
react-dom:
|
|
||||||
specifier: 18.2.0
|
|
||||||
version: 18.2.0(react@18.2.0)
|
|
||||||
react-hook-form:
|
|
||||||
specifier: ^7.49.2
|
|
||||||
version: 7.51.1(react@18.2.0)
|
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: 3.4.1
|
specifier: 3.4.1
|
||||||
version: 3.4.1
|
version: 3.4.1
|
||||||
@@ -4226,22 +4193,26 @@ packages:
|
|||||||
resolution: {integrity: sha512-BNzC5XhCzzCaggJ8s53DP+WeHHGT/NfTsx2wUSSGKR2/ikLFQTBCDzMvGz/PxYMqRko/LwncQtKXGOYp1PkPaw==}
|
resolution: {integrity: sha512-BNzC5XhCzzCaggJ8s53DP+WeHHGT/NfTsx2wUSSGKR2/ikLFQTBCDzMvGz/PxYMqRko/LwncQtKXGOYp1PkPaw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@supabase/gotrue-js@2.62.2:
|
/@supabase/gotrue-js@2.62.2:
|
||||||
resolution: {integrity: sha512-AP6e6W9rQXFTEJ7sTTNYQrNf0LCcnt1hUW+RIgUK+Uh3jbWvcIST7wAlYyNZiMlS9+PYyymWQ+Ykz/rOYSO0+A==}
|
resolution: {integrity: sha512-AP6e6W9rQXFTEJ7sTTNYQrNf0LCcnt1hUW+RIgUK+Uh3jbWvcIST7wAlYyNZiMlS9+PYyymWQ+Ykz/rOYSO0+A==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@supabase/node-fetch@2.6.15:
|
/@supabase/node-fetch@2.6.15:
|
||||||
resolution: {integrity: sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==}
|
resolution: {integrity: sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==}
|
||||||
engines: {node: 4.x || >=6.0.0}
|
engines: {node: 4.x || >=6.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-url: 5.0.0
|
whatwg-url: 5.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@supabase/postgrest-js@1.9.2:
|
/@supabase/postgrest-js@1.9.2:
|
||||||
resolution: {integrity: sha512-I6yHo8CC9cxhOo6DouDMy9uOfW7hjdsnCxZiaJuIVZm1dBGTFiQPgfMa9zXCamEWzNyWRjZvupAUuX+tqcl5Sw==}
|
resolution: {integrity: sha512-I6yHo8CC9cxhOo6DouDMy9uOfW7hjdsnCxZiaJuIVZm1dBGTFiQPgfMa9zXCamEWzNyWRjZvupAUuX+tqcl5Sw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@supabase/realtime-js@2.9.3:
|
/@supabase/realtime-js@2.9.3:
|
||||||
resolution: {integrity: sha512-lAp50s2n3FhGJFq+wTSXLNIDPw5Y0Wxrgt44eM5nLSA3jZNUUP3Oq2Ccd1CbZdVntPCWLZvJaU//pAd2NE+QnQ==}
|
resolution: {integrity: sha512-lAp50s2n3FhGJFq+wTSXLNIDPw5Y0Wxrgt44eM5nLSA3jZNUUP3Oq2Ccd1CbZdVntPCWLZvJaU//pAd2NE+QnQ==}
|
||||||
@@ -4253,6 +4224,7 @@ packages:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@supabase/ssr@0.1.0(@supabase/supabase-js@2.40.0):
|
/@supabase/ssr@0.1.0(@supabase/supabase-js@2.40.0):
|
||||||
resolution: {integrity: sha512-bIVrkqjAK5G3KjkIMKYKtAOlCgRRplEWjrlyRyXSOYtgDieiOhk2ZyNAPsEOa1By9OZVxuX5eAW1fitdnuxayw==}
|
resolution: {integrity: sha512-bIVrkqjAK5G3KjkIMKYKtAOlCgRRplEWjrlyRyXSOYtgDieiOhk2ZyNAPsEOa1By9OZVxuX5eAW1fitdnuxayw==}
|
||||||
@@ -4268,6 +4240,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-OpLoDRjFwClwc2cjTJZG8XviTiQH4Ik8sCiMK5v7et0MDu2QlXjCAW3ljxJB5+z/KazdMOTnySi+hysxWUPu3w==}
|
resolution: {integrity: sha512-OpLoDRjFwClwc2cjTJZG8XviTiQH4Ik8sCiMK5v7et0MDu2QlXjCAW3ljxJB5+z/KazdMOTnySi+hysxWUPu3w==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@supabase/supabase-js@2.40.0:
|
/@supabase/supabase-js@2.40.0:
|
||||||
resolution: {integrity: sha512-XF8OrsA13DYBL074sHH4M0NhXJCWhQ0R5JbVeVUytZ0coPMS9krRdzxl+0c4z4LLjqbm/Wdz0UYlTYM9MgnDag==}
|
resolution: {integrity: sha512-XF8OrsA13DYBL074sHH4M0NhXJCWhQ0R5JbVeVUytZ0coPMS9krRdzxl+0c4z4LLjqbm/Wdz0UYlTYM9MgnDag==}
|
||||||
@@ -4281,6 +4254,7 @@ packages:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@swc/core-darwin-arm64@1.3.101:
|
/@swc/core-darwin-arm64@1.3.101:
|
||||||
resolution: {integrity: sha512-mNFK+uHNPRXSnfTOG34zJOeMl2waM4hF4a2NY7dkMXrPqw9CoJn4MwTXJcyMiSz1/BnNjjTCHF3Yhj0jPxmkzQ==}
|
resolution: {integrity: sha512-mNFK+uHNPRXSnfTOG34zJOeMl2waM4hF4a2NY7dkMXrPqw9CoJn4MwTXJcyMiSz1/BnNjjTCHF3Yhj0jPxmkzQ==}
|
||||||
@@ -4716,6 +4690,7 @@ packages:
|
|||||||
|
|
||||||
/@types/phoenix@1.6.4:
|
/@types/phoenix@1.6.4:
|
||||||
resolution: {integrity: sha512-B34A7uot1Cv0XtaHRYDATltAdKx0BvVKNgYNqE4WjtPUa4VQJM7kxeXcVKaH+KS+kCmZ+6w+QaUdcljiheiBJA==}
|
resolution: {integrity: sha512-B34A7uot1Cv0XtaHRYDATltAdKx0BvVKNgYNqE4WjtPUa4VQJM7kxeXcVKaH+KS+kCmZ+6w+QaUdcljiheiBJA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/prismjs@1.26.3:
|
/@types/prismjs@1.26.3:
|
||||||
resolution: {integrity: sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==}
|
resolution: {integrity: sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==}
|
||||||
@@ -4786,6 +4761,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
|
resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.11.30
|
'@types/node': 20.11.30
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.3):
|
/@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.3):
|
||||||
resolution: {integrity: sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==}
|
resolution: {integrity: sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==}
|
||||||
@@ -9748,7 +9724,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
nanoid: 3.3.7
|
nanoid: 3.3.7
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
source-map-js: 1.0.2
|
source-map-js: 1.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/prelude-ls@1.2.1:
|
/prelude-ls@1.2.1:
|
||||||
@@ -10034,6 +10010,7 @@ packages:
|
|||||||
react: ^16.8.0 || ^17 || ^18
|
react: ^16.8.0 || ^17 || ^18
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-i18next@14.1.0(i18next@23.10.1)(react-dom@18.2.0)(react@18.2.0):
|
/react-i18next@14.1.0(i18next@23.10.1)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-3KwX6LHpbvGQ+sBEntjV4sYW3Zovjjl3fpoHbUwSgFHf0uRBcbeCBLR5al6ikncI5+W0EFb71QXZmfop+J6NrQ==}
|
resolution: {integrity: sha512-3KwX6LHpbvGQ+sBEntjV4sYW3Zovjjl3fpoHbUwSgFHf0uRBcbeCBLR5al6ikncI5+W0EFb71QXZmfop+J6NrQ==}
|
||||||
@@ -11113,7 +11090,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@alloc/quick-lru': 5.2.0
|
'@alloc/quick-lru': 5.2.0
|
||||||
arg: 5.0.2
|
arg: 5.0.2
|
||||||
chokidar: 3.5.3
|
chokidar: 3.6.0
|
||||||
didyoumean: 1.2.2
|
didyoumean: 1.2.2
|
||||||
dlv: 1.1.3
|
dlv: 1.1.3
|
||||||
fast-glob: 3.3.2
|
fast-glob: 3.3.2
|
||||||
@@ -11296,6 +11273,7 @@ packages:
|
|||||||
|
|
||||||
/tr46@0.0.3:
|
/tr46@0.0.3:
|
||||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/tree-cli@0.6.7:
|
/tree-cli@0.6.7:
|
||||||
resolution: {integrity: sha512-jfnB5YKY6Glf6bsFmQ9W97TtkPVLnHsjOR6ZdRf4zhyFRQeLheasvzE5XBJI2Hxt7ZyMyIbXUV7E2YPZbixgtA==}
|
resolution: {integrity: sha512-jfnB5YKY6Glf6bsFmQ9W97TtkPVLnHsjOR6ZdRf4zhyFRQeLheasvzE5XBJI2Hxt7ZyMyIbXUV7E2YPZbixgtA==}
|
||||||
@@ -11872,6 +11850,7 @@ packages:
|
|||||||
|
|
||||||
/webidl-conversions@3.0.1:
|
/webidl-conversions@3.0.1:
|
||||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/webpack-bundle-analyzer@4.10.1:
|
/webpack-bundle-analyzer@4.10.1:
|
||||||
resolution: {integrity: sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==}
|
resolution: {integrity: sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==}
|
||||||
@@ -11946,6 +11925,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tr46: 0.0.3
|
tr46: 0.0.3
|
||||||
webidl-conversions: 3.0.1
|
webidl-conversions: 3.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/which-boxed-primitive@1.0.2:
|
/which-boxed-primitive@1.0.2:
|
||||||
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
||||||
@@ -12087,6 +12067,7 @@ packages:
|
|||||||
optional: true
|
optional: true
|
||||||
utf-8-validate:
|
utf-8-validate:
|
||||||
optional: true
|
optional: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/xmlhttprequest-ssl@2.0.0:
|
/xmlhttprequest-ssl@2.0.0:
|
||||||
resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==}
|
resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==}
|
||||||
|
|||||||
Reference in New Issue
Block a user