Update labels and refine hooks for teams and billing modules
This commit modifies several language labels and refines hooks related to 'teams' and 'billing' modules for better clarity and consistency. It also includes the deletion of unused locale files and package dependencies transfered to 'peerDependencies'. Lastly, it introduces minor enhancements in server command, error logging functionality, and scripts to interact with Stripe.
This commit is contained in:
@@ -14,7 +14,6 @@ import {
|
||||
} from '@kit/ui/dialog';
|
||||
import { ErrorBoundary } from '@kit/ui/error-boundary';
|
||||
import { Form, FormControl, FormItem, FormLabel } from '@kit/ui/form';
|
||||
import { Heading } from '@kit/ui/heading';
|
||||
import { Input } from '@kit/ui/input';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
@@ -28,12 +27,12 @@ function DeleteAccountContainer() {
|
||||
return (
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<div className={'flex flex-col space-y-1'}>
|
||||
<Heading level={6}>
|
||||
<Trans i18nKey={'profile:deleteAccount'} />
|
||||
</Heading>
|
||||
<span className={'text-sm font-medium'}>
|
||||
<Trans i18nKey={'account:deleteAccount'} />
|
||||
</span>
|
||||
|
||||
<p className={'text-muted-foreground text-sm'}>
|
||||
<Trans i18nKey={'profile:deleteAccountDescription'} />
|
||||
<Trans i18nKey={'account:deleteAccountDescription'} />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -49,14 +48,14 @@ function DeleteAccountModal() {
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button data-test={'delete-account-button'} variant={'destructive'}>
|
||||
<Trans i18nKey={'profile:deleteAccount'} />
|
||||
<Trans i18nKey={'account:deleteAccount'} />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<Trans i18nKey={'profile:deleteAccount'} />
|
||||
<Trans i18nKey={'account:deleteAccount'} />
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -83,7 +82,7 @@ function DeleteAccountForm() {
|
||||
>
|
||||
<div className={'flex flex-col space-y-2'}>
|
||||
<div>
|
||||
<Trans i18nKey={'profile:deleteAccountDescription'} />
|
||||
<Trans i18nKey={'account:deleteAccountDescription'} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -94,7 +93,7 @@ function DeleteAccountForm() {
|
||||
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans i18nKey={'profile:deleteProfileConfirmationInputLabel'} />
|
||||
<Trans i18nKey={'account:deleteProfileConfirmationInputLabel'} />
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
@@ -127,7 +126,7 @@ function DeleteAccountSubmitButton() {
|
||||
value={'delete'}
|
||||
variant={'destructive'}
|
||||
>
|
||||
<Trans i18nKey={'profile:deleteAccount'} />
|
||||
<Trans i18nKey={'account:deleteAccount'} />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -138,7 +137,7 @@ function DeleteAccountErrorAlert() {
|
||||
<ExclamationTriangleIcon className={'h-4'} />
|
||||
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'profile:deleteAccountErrorHeading'} />
|
||||
<Trans i18nKey={'account:deleteAccountErrorHeading'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@kit/ui/card';
|
||||
import { If } from '@kit/ui/if';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { AccountDangerZone } from './account-danger-zone';
|
||||
import { UpdateAccountDetailsFormContainer } from './update-account-details-form-container';
|
||||
@@ -22,7 +29,13 @@ export function PersonalAccountSettingsContainer(
|
||||
<div className={'flex w-full flex-col space-y-8 pb-32'}>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Your Profile Picture</CardTitle>
|
||||
<CardTitle>
|
||||
<Trans i18nKey={'account:accountImage'} />
|
||||
</CardTitle>
|
||||
|
||||
<CardDescription>
|
||||
<Trans i18nKey={'account:accountImageDescription'} />
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
@@ -32,7 +45,13 @@ export function PersonalAccountSettingsContainer(
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Your Details</CardTitle>
|
||||
<CardTitle>
|
||||
<Trans i18nKey={'account:name'} />
|
||||
</CardTitle>
|
||||
|
||||
<CardDescription>
|
||||
<Trans i18nKey={'account:nameDescription'} />
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
@@ -42,7 +61,13 @@ export function PersonalAccountSettingsContainer(
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Update your Email</CardTitle>
|
||||
<CardTitle>
|
||||
<Trans i18nKey={'account:updateEmailCardTitle'} />
|
||||
</CardTitle>
|
||||
|
||||
<CardDescription>
|
||||
<Trans i18nKey={'account:updateEmailCardDescription'} />
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
@@ -52,7 +77,13 @@ export function PersonalAccountSettingsContainer(
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Update your Password</CardTitle>
|
||||
<CardTitle>
|
||||
<Trans i18nKey={'account:updatePasswordCardTitle'} />
|
||||
</CardTitle>
|
||||
|
||||
<CardDescription>
|
||||
<Trans i18nKey={'account:updatePasswordCardDescription'} />
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
@@ -63,7 +94,13 @@ export function PersonalAccountSettingsContainer(
|
||||
<If condition={props.features.enableAccountDeletion}>
|
||||
<Card className={'border-destructive border-2'}>
|
||||
<CardHeader>
|
||||
<CardTitle>Danger Zone</CardTitle>
|
||||
<CardTitle>
|
||||
<Trans i18nKey={'account:dangerZone'} />
|
||||
</CardTitle>
|
||||
|
||||
<CardDescription>
|
||||
<Trans i18nKey={'account:dangerZoneDescription'} />
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
|
||||
@@ -33,7 +33,7 @@ function MultiFactorAuthSetupModal(
|
||||
const onEnrollSuccess = useCallback(() => {
|
||||
props.setIsOpen(false);
|
||||
|
||||
return toast.success(t(`profile:multiFactorSetupSuccess`));
|
||||
return toast.success(t(`multiFactorSetupSuccess`));
|
||||
}, [props, t]);
|
||||
|
||||
return (
|
||||
@@ -41,7 +41,7 @@ function MultiFactorAuthSetupModal(
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<Trans i18nKey={'profile:setupMfaButtonLabel'} />
|
||||
<Trans i18nKey={'account:setupMfaButtonLabel'} />
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -109,7 +109,7 @@ function MultiFactorAuthSetupForm({
|
||||
return (
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<Alert variant={'destructive'}>
|
||||
<Trans i18nKey={'profile:multiFactorSetupError'} />
|
||||
<Trans i18nKey={'account:multiFactorSetupError'} />
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
@@ -132,7 +132,7 @@ function MultiFactorAuthSetupForm({
|
||||
>
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<Label>
|
||||
<Trans i18nKey={'profile:verificationCode'} />
|
||||
<Trans i18nKey={'account:verificationCode'} />
|
||||
|
||||
<OtpInput
|
||||
onInvalid={() => setVerificationCode('')}
|
||||
@@ -140,16 +140,16 @@ function MultiFactorAuthSetupForm({
|
||||
/>
|
||||
|
||||
<span>
|
||||
<Trans i18nKey={'profile:verifyActivationCodeDescription'} />
|
||||
<Trans i18nKey={'account:verifyActivationCodeDescription'} />
|
||||
</span>
|
||||
</Label>
|
||||
|
||||
<div className={'flex justify-end space-x-2'}>
|
||||
<Button disabled={!verificationCode} type={'submit'}>
|
||||
{state.loading ? (
|
||||
<Trans i18nKey={'profile:verifyingCode'} />
|
||||
<Trans i18nKey={'account:verifyingCode'} />
|
||||
) : (
|
||||
<Trans i18nKey={'profile:enableMfaFactor'} />
|
||||
<Trans i18nKey={'account:enableMfaFactor'} />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -210,7 +210,7 @@ function FactorQrCode({
|
||||
return (
|
||||
<div className={'flex w-full flex-col space-y-2'}>
|
||||
<Alert variant={'destructive'}>
|
||||
<Trans i18nKey={'profile:qrCodeError'} />
|
||||
<Trans i18nKey={'account:qrCodeError'} />
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
@@ -231,7 +231,7 @@ function FactorQrCode({
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<p>
|
||||
<span className={'text-base'}>
|
||||
<Trans i18nKey={'profile:multiFactorModalHeading'} />
|
||||
<Trans i18nKey={'account:multiFactorModalHeading'} />
|
||||
</span>
|
||||
</p>
|
||||
|
||||
@@ -264,18 +264,18 @@ function FactorNameForm(
|
||||
>
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<Label>
|
||||
<Trans i18nKey={'profile:factorNameLabel'} />
|
||||
<Trans i18nKey={'account:factorNameLabel'} />
|
||||
|
||||
<Input autoComplete={'off'} required name={inputName} />
|
||||
|
||||
<span>
|
||||
<Trans i18nKey={'profile:factorNameHint'} />
|
||||
<Trans i18nKey={'account:factorNameHint'} />
|
||||
</span>
|
||||
</Label>
|
||||
|
||||
<div className={'flex justify-end space-x-2'}>
|
||||
<Button type={'submit'}>
|
||||
<Trans i18nKey={'profile:factorNameSubmitLabel'} />
|
||||
<Trans i18nKey={'account:factorNameSubmitLabel'} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,6 @@ import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { toast } from 'sonner';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { Database } from '@kit/supabase/database';
|
||||
import { Button } from '@kit/ui/button';
|
||||
@@ -18,13 +17,10 @@ import { Input } from '@kit/ui/input';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { useUpdateAccountData } from '../../hooks/use-update-account';
|
||||
import { AccountDetailsSchema } from '../../schema/account-details.schema';
|
||||
|
||||
type UpdateUserDataParams = Database['public']['Tables']['accounts']['Update'];
|
||||
|
||||
const AccountInfoSchema = z.object({
|
||||
displayName: z.string().min(2).max(100),
|
||||
});
|
||||
|
||||
export function UpdateAccountDetailsForm({
|
||||
displayName,
|
||||
onUpdate,
|
||||
@@ -35,10 +31,10 @@ export function UpdateAccountDetailsForm({
|
||||
onUpdate: (user: Partial<UpdateUserDataParams>) => void;
|
||||
}) {
|
||||
const updateAccountMutation = useUpdateAccountData(userId);
|
||||
const { t } = useTranslation();
|
||||
const { t } = useTranslation('account');
|
||||
|
||||
const form = useForm({
|
||||
resolver: zodResolver(AccountInfoSchema),
|
||||
resolver: zodResolver(AccountDetailsSchema),
|
||||
defaultValues: {
|
||||
displayName,
|
||||
},
|
||||
@@ -51,10 +47,10 @@ export function UpdateAccountDetailsForm({
|
||||
onUpdate(data);
|
||||
});
|
||||
|
||||
return toast.promise(promise, {
|
||||
success: t(`profile:updateProfileSuccess`),
|
||||
error: t(`profile:updateProfileError`),
|
||||
loading: t(`profile:updateProfileLoading`),
|
||||
return toast.promise(() => promise, {
|
||||
success: t(`updateProfileSuccess`),
|
||||
error: t(`updateProfileError`),
|
||||
loading: t(`:pdateProfileLoading`),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -72,7 +68,7 @@ export function UpdateAccountDetailsForm({
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans i18nKey={'profile:displayNameLabel'} />
|
||||
<Trans i18nKey={'account:name'} />
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
@@ -92,7 +88,7 @@ export function UpdateAccountDetailsForm({
|
||||
|
||||
<div>
|
||||
<Button disabled={updateAccountMutation.isPending}>
|
||||
<Trans i18nKey={'profile:updateProfileSubmitLabel'} />
|
||||
<Trans i18nKey={'account:updateProfileSubmitLabel'} />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import { useSupabase } from '@kit/supabase/hooks/use-supabase';
|
||||
import ImageUploader from '@kit/ui/image-uploader';
|
||||
import { ImageUploader } from '@kit/ui/image-uploader';
|
||||
import { LoadingOverlay } from '@kit/ui/loading-overlay';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
@@ -42,10 +42,10 @@ function UploadProfileAvatarForm(props: {
|
||||
onAvatarUpdated: () => void;
|
||||
}) {
|
||||
const client = useSupabase();
|
||||
const { t } = useTranslation('profile');
|
||||
const { t } = useTranslation('account');
|
||||
|
||||
const createToaster = useCallback(
|
||||
(promise: Promise<unknown>) => {
|
||||
(promise: () => Promise<unknown>) => {
|
||||
return toast.promise(promise, {
|
||||
success: t(`updateProfileSuccess`),
|
||||
error: t(`updateProfileError`),
|
||||
@@ -68,37 +68,39 @@ function UploadProfileAvatarForm(props: {
|
||||
};
|
||||
|
||||
if (file) {
|
||||
const promise = removeExistingStorageFile().then(() =>
|
||||
uploadUserProfilePhoto(client, file, props.userId)
|
||||
.then((pictureUrl) => {
|
||||
const promise = () =>
|
||||
removeExistingStorageFile().then(() =>
|
||||
uploadUserProfilePhoto(client, file, props.userId)
|
||||
.then((pictureUrl) => {
|
||||
return client
|
||||
.from('accounts')
|
||||
.update({
|
||||
picture_url: pictureUrl,
|
||||
})
|
||||
.eq('id', props.userId)
|
||||
.throwOnError();
|
||||
})
|
||||
.then(() => {
|
||||
props.onAvatarUpdated();
|
||||
}),
|
||||
);
|
||||
|
||||
createToaster(promise);
|
||||
} else {
|
||||
const promise = () =>
|
||||
removeExistingStorageFile()
|
||||
.then(() => {
|
||||
return client
|
||||
.from('accounts')
|
||||
.update({
|
||||
picture_url: pictureUrl,
|
||||
picture_url: null,
|
||||
})
|
||||
.eq('id', props.userId)
|
||||
.throwOnError();
|
||||
})
|
||||
.then(() => {
|
||||
props.onAvatarUpdated();
|
||||
}),
|
||||
);
|
||||
|
||||
createToaster(promise);
|
||||
} else {
|
||||
const promise = removeExistingStorageFile()
|
||||
.then(() => {
|
||||
return client
|
||||
.from('accounts')
|
||||
.update({
|
||||
picture_url: null,
|
||||
})
|
||||
.eq('id', props.userId)
|
||||
.throwOnError();
|
||||
})
|
||||
.then(() => {
|
||||
props.onAvatarUpdated();
|
||||
});
|
||||
});
|
||||
|
||||
createToaster(promise);
|
||||
}
|
||||
@@ -110,11 +112,11 @@ function UploadProfileAvatarForm(props: {
|
||||
<ImageUploader value={props.pictureUrl} onValueChange={onValueChange}>
|
||||
<div className={'flex flex-col space-y-1'}>
|
||||
<span className={'text-sm'}>
|
||||
<Trans i18nKey={'profile:profilePictureHeading'} />
|
||||
<Trans i18nKey={'account:profilePictureHeading'} />
|
||||
</span>
|
||||
|
||||
<span className={'text-xs'}>
|
||||
<Trans i18nKey={'profile:profilePictureSubheading'} />
|
||||
<Trans i18nKey={'account:profilePictureSubheading'} />
|
||||
</span>
|
||||
</div>
|
||||
</ImageUploader>
|
||||
@@ -142,9 +144,7 @@ async function uploadUserProfilePhoto(
|
||||
const extension = photoFile.name.split('.').pop();
|
||||
const fileName = await getAvatarFileName(userId, extension);
|
||||
|
||||
const result = await bucket.upload(fileName, bytes, {
|
||||
upsert: true,
|
||||
});
|
||||
const result = await bucket.upload(fileName, bytes);
|
||||
|
||||
if (!result.error) {
|
||||
return bucket.getPublicUrl(fileName).data.publicUrl;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import type { User } from '@supabase/gotrue-js';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { toast } from 'sonner';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { useUpdateUser } from '@kit/supabase/hooks/use-update-user-mutation';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
||||
@@ -25,32 +22,13 @@ import { If } from '@kit/ui/if';
|
||||
import { Input } from '@kit/ui/input';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
const UpdateEmailSchema = z
|
||||
.object({
|
||||
email: z.string().email(),
|
||||
repeatEmail: z.string().email(),
|
||||
})
|
||||
.refine(
|
||||
(values) => {
|
||||
return values.email === values.repeatEmail;
|
||||
},
|
||||
{
|
||||
path: ['repeatEmail'],
|
||||
message: 'Emails do not match',
|
||||
},
|
||||
);
|
||||
import { UpdateEmailSchema } from '../../schema/update-email.schema';
|
||||
|
||||
function createEmailResolver(currentEmail: string) {
|
||||
function createEmailResolver(currentEmail: string, errorMessage: string) {
|
||||
return zodResolver(
|
||||
UpdateEmailSchema.refine(
|
||||
(values) => {
|
||||
return values.email !== currentEmail;
|
||||
},
|
||||
{
|
||||
path: ['email'],
|
||||
message: 'New email must be different from current email',
|
||||
},
|
||||
),
|
||||
UpdateEmailSchema.withTranslation(errorMessage).refine((schema) => {
|
||||
return schema.email !== currentEmail;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -61,31 +39,31 @@ export function UpdateEmailForm({
|
||||
user: User;
|
||||
callbackPath: string;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { t } = useTranslation('account');
|
||||
const updateUserMutation = useUpdateUser();
|
||||
|
||||
const updateEmail = useCallback(
|
||||
(email: string) => {
|
||||
const redirectTo = new URL(callbackPath, window.location.host).toString();
|
||||
const updateEmail = ({ email }: { email: string }) => {
|
||||
// then, we update the user's email address
|
||||
const promise = async () => {
|
||||
const redirectTo = new URL(
|
||||
callbackPath,
|
||||
window.location.origin,
|
||||
).toString();
|
||||
|
||||
// then, we update the user's email address
|
||||
const promise = updateUserMutation.mutateAsync({ email, redirectTo });
|
||||
await updateUserMutation.mutateAsync({ email, redirectTo });
|
||||
};
|
||||
|
||||
return toast.promise(promise, {
|
||||
success: t(`profile:updateEmailSuccess`),
|
||||
loading: t(`profile:updateEmailLoading`),
|
||||
error: (error: Error) => {
|
||||
return error.message ?? t(`profile:updateEmailError`);
|
||||
},
|
||||
});
|
||||
},
|
||||
[callbackPath, t, updateUserMutation],
|
||||
);
|
||||
toast.promise(promise, {
|
||||
success: t(`updateEmailSuccess`),
|
||||
loading: t(`updateEmailLoading`),
|
||||
error: t(`updateEmailError`),
|
||||
});
|
||||
};
|
||||
|
||||
const currentEmail = user.email;
|
||||
|
||||
const form = useForm({
|
||||
resolver: createEmailResolver(currentEmail!),
|
||||
resolver: createEmailResolver(currentEmail!, t('emailNotMatching')),
|
||||
defaultValues: {
|
||||
email: '',
|
||||
repeatEmail: '',
|
||||
@@ -97,18 +75,16 @@ export function UpdateEmailForm({
|
||||
<form
|
||||
className={'flex flex-col space-y-4'}
|
||||
data-test={'update-email-form'}
|
||||
onSubmit={form.handleSubmit((values) => {
|
||||
return updateEmail(values.email);
|
||||
})}
|
||||
onSubmit={form.handleSubmit(updateEmail)}
|
||||
>
|
||||
<If condition={updateUserMutation.data}>
|
||||
<Alert variant={'success'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'profile:updateEmailSuccess'} />
|
||||
<Trans i18nKey={'account:updateEmailSuccess'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'profile:updateEmailSuccessMessage'} />
|
||||
<Trans i18nKey={'account:updateEmailSuccessMessage'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</If>
|
||||
@@ -118,7 +94,7 @@ export function UpdateEmailForm({
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans i18nKey={'profile:newEmail'} />
|
||||
<Trans i18nKey={'account:newEmail'} />
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
@@ -141,7 +117,7 @@ export function UpdateEmailForm({
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans i18nKey={'profile:repeatEmail'} />
|
||||
<Trans i18nKey={'account:repeatEmail'} />
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
@@ -160,8 +136,8 @@ export function UpdateEmailForm({
|
||||
/>
|
||||
|
||||
<div>
|
||||
<Button>
|
||||
<Trans i18nKey={'profile:updateEmailSubmitLabel'} />
|
||||
<Button disabled={updateUserMutation.isPending}>
|
||||
<Trans i18nKey={'account:updateEmailSubmitLabel'} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,10 @@ export function UpdatePasswordFormContainer(
|
||||
return <LoadingOverlay fullPage={false} />;
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const canUpdatePassword = user.identities?.some(
|
||||
(item) => item.provider === `email`,
|
||||
);
|
||||
@@ -32,7 +36,7 @@ export function UpdatePasswordFormContainer(
|
||||
function WarnCannotUpdatePasswordAlert() {
|
||||
return (
|
||||
<Alert variant={'warning'}>
|
||||
<Trans i18nKey={'profile:cannotUpdatePassword'} />
|
||||
<Trans i18nKey={'account:cannotUpdatePassword'} />
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import type { User } from '@supabase/gotrue-js';
|
||||
|
||||
@@ -8,7 +8,6 @@ import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { toast } from 'sonner';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { useUpdateUser } from '@kit/supabase/hooks/use-update-user-mutation';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
||||
@@ -26,21 +25,7 @@ import { Input } from '@kit/ui/input';
|
||||
import { Label } from '@kit/ui/label';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
const PasswordUpdateSchema = z
|
||||
.object({
|
||||
currentPassword: z.string().min(8).max(99),
|
||||
newPassword: z.string().min(8).max(99),
|
||||
repeatPassword: z.string().min(8).max(99),
|
||||
})
|
||||
.refine(
|
||||
(values) => {
|
||||
return values.newPassword === values.repeatPassword;
|
||||
},
|
||||
{
|
||||
path: ['repeatPassword'],
|
||||
message: 'Passwords do not match',
|
||||
},
|
||||
);
|
||||
import { PasswordUpdateSchema } from '../../schema/update-password.schema';
|
||||
|
||||
export const UpdatePasswordForm = ({
|
||||
user,
|
||||
@@ -49,57 +34,58 @@ export const UpdatePasswordForm = ({
|
||||
user: User;
|
||||
callbackPath: string;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { t } = useTranslation('account');
|
||||
const updateUserMutation = useUpdateUser();
|
||||
const [needsReauthentication, setNeedsReauthentication] = useState(false);
|
||||
|
||||
const form = useForm({
|
||||
resolver: zodResolver(PasswordUpdateSchema),
|
||||
resolver: zodResolver(
|
||||
PasswordUpdateSchema.withTranslation(t('passwordNotMatching')),
|
||||
),
|
||||
defaultValues: {
|
||||
currentPassword: '',
|
||||
newPassword: '',
|
||||
repeatPassword: '',
|
||||
},
|
||||
});
|
||||
|
||||
const updatePasswordFromCredential = useCallback(
|
||||
(password: string) => {
|
||||
const redirectTo = [window.location.origin, callbackPath].join('');
|
||||
const updatePasswordFromCredential = (password: string) => {
|
||||
const redirectTo = [window.location.origin, callbackPath].join('');
|
||||
|
||||
const promise = updateUserMutation
|
||||
.mutateAsync({ password, redirectTo })
|
||||
.then(() => {
|
||||
form.reset();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error?.includes('Password update requires reauthentication')) {
|
||||
setNeedsReauthentication(true);
|
||||
}
|
||||
});
|
||||
|
||||
toast.promise(promise, {
|
||||
success: t(`profile:updatePasswordSuccess`),
|
||||
error: t(`profile:updatePasswordError`),
|
||||
loading: t(`profile:updatePasswordLoading`),
|
||||
const promise = updateUserMutation
|
||||
.mutateAsync({ password, redirectTo })
|
||||
.catch((error) => {
|
||||
if (
|
||||
typeof error === 'string' &&
|
||||
error?.includes('Password update requires reauthentication')
|
||||
) {
|
||||
setNeedsReauthentication(true);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
},
|
||||
[callbackPath, updateUserMutation, t, form],
|
||||
);
|
||||
|
||||
const updatePasswordCallback = useCallback(
|
||||
async ({ newPassword }: { newPassword: string }) => {
|
||||
const email = user.email;
|
||||
toast.promise(() => promise, {
|
||||
success: t(`updatePasswordSuccess`),
|
||||
error: t(`updatePasswordError`),
|
||||
loading: t(`updatePasswordLoading`),
|
||||
});
|
||||
};
|
||||
|
||||
// if the user does not have an email assigned, it's possible they
|
||||
// don't have an email/password factor linked, and the UI is out of sync
|
||||
if (!email) {
|
||||
return Promise.reject(t(`profile:cannotUpdatePassword`));
|
||||
}
|
||||
const updatePasswordCallback = async ({
|
||||
newPassword,
|
||||
}: {
|
||||
newPassword: string;
|
||||
}) => {
|
||||
const email = user.email;
|
||||
|
||||
updatePasswordFromCredential(newPassword);
|
||||
},
|
||||
[user.email, updatePasswordFromCredential, t],
|
||||
);
|
||||
// if the user does not have an email assigned, it's possible they
|
||||
// don't have an email/password factor linked, and the UI is out of sync
|
||||
if (!email) {
|
||||
return Promise.reject(t(`cannotUpdatePassword`));
|
||||
}
|
||||
|
||||
updatePasswordFromCredential(newPassword);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
@@ -111,11 +97,11 @@ export const UpdatePasswordForm = ({
|
||||
<If condition={updateUserMutation.data}>
|
||||
<Alert variant={'success'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'profile:updatePasswordSuccess'} />
|
||||
<Trans i18nKey={'account:updatePasswordSuccess'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'profile:updatePasswordSuccessMessage'} />
|
||||
<Trans i18nKey={'account:updatePasswordSuccessMessage'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</If>
|
||||
@@ -123,11 +109,11 @@ export const UpdatePasswordForm = ({
|
||||
<If condition={needsReauthentication}>
|
||||
<Alert variant={'warning'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'profile:needsReauthentication'} />
|
||||
<Trans i18nKey={'account:needsReauthentication'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'profile:needsReauthenticationDescription'} />
|
||||
<Trans i18nKey={'account:needsReauthenticationDescription'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</If>
|
||||
@@ -139,7 +125,7 @@ export const UpdatePasswordForm = ({
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Label>
|
||||
<Trans i18nKey={'profile:newPassword'} />
|
||||
<Trans i18nKey={'account:newPassword'} />
|
||||
</Label>
|
||||
</FormLabel>
|
||||
|
||||
@@ -165,7 +151,7 @@ export const UpdatePasswordForm = ({
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Label>
|
||||
<Trans i18nKey={'profile:repeatPassword'} />
|
||||
<Trans i18nKey={'account:repeatPassword'} />
|
||||
</Label>
|
||||
</FormLabel>
|
||||
|
||||
@@ -185,8 +171,8 @@ export const UpdatePasswordForm = ({
|
||||
/>
|
||||
|
||||
<div>
|
||||
<Button>
|
||||
<Trans i18nKey={'profile:updatePasswordSubmitLabel'} />
|
||||
<Button disabled={updateUserMutation.isPending}>
|
||||
<Trans i18nKey={'account:updatePasswordSubmitLabel'} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const AccountDetailsSchema = z.object({
|
||||
displayName: z.string().min(2).max(100),
|
||||
});
|
||||
20
packages/features/accounts/src/schema/update-email.schema.ts
Normal file
20
packages/features/accounts/src/schema/update-email.schema.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const UpdateEmailSchema = {
|
||||
withTranslation: (errorMessage: string) => {
|
||||
return z
|
||||
.object({
|
||||
email: z.string().email(),
|
||||
repeatEmail: z.string().email(),
|
||||
})
|
||||
.refine(
|
||||
(values) => {
|
||||
return values.email === values.repeatEmail;
|
||||
},
|
||||
{
|
||||
path: ['repeatEmail'],
|
||||
message: errorMessage,
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const PasswordUpdateSchema = {
|
||||
withTranslation: (errorMessage: string) => {
|
||||
return z
|
||||
.object({
|
||||
newPassword: z.string().min(8).max(99),
|
||||
repeatPassword: z.string().min(8).max(99),
|
||||
})
|
||||
.refine(
|
||||
(values) => {
|
||||
return values.newPassword === values.repeatPassword;
|
||||
},
|
||||
{
|
||||
path: ['repeatPassword'],
|
||||
message: errorMessage,
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -80,9 +80,9 @@ function VerifyOtpForm({
|
||||
|
||||
<Button disabled={verifyOtpMutation.isPending || !verifyCode}>
|
||||
{verifyOtpMutation.isPending ? (
|
||||
<Trans i18nKey={'profile:verifyingCode'} />
|
||||
<Trans i18nKey={'account:verifyingCode'} />
|
||||
) : (
|
||||
<Trans i18nKey={'profile:submitVerificationCode'} />
|
||||
<Trans i18nKey={'account:submitVerificationCode'} />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -55,7 +55,7 @@ export function MultiFactorChallengeContainer({
|
||||
<form onSubmit={onSubmitClicked}>
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<span className={'text-sm'}>
|
||||
<Trans i18nKey={'profile:verifyActivationCodeDescription'} />
|
||||
<Trans i18nKey={'account:verifyActivationCodeDescription'} />
|
||||
</span>
|
||||
|
||||
<div className={'flex w-full flex-col space-y-2.5'}>
|
||||
@@ -67,7 +67,7 @@ export function MultiFactorChallengeContainer({
|
||||
<If condition={verifyMFAChallenge.error}>
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'profile:invalidVerificationCode'} />
|
||||
<Trans i18nKey={'account:invalidVerificationCode'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</If>
|
||||
@@ -75,9 +75,9 @@ export function MultiFactorChallengeContainer({
|
||||
|
||||
<Button disabled={verifyMFAChallenge.isPending || !verifyCode}>
|
||||
{verifyMFAChallenge.isPending ? (
|
||||
<Trans i18nKey={'profile:verifyingCode'} />
|
||||
<Trans i18nKey={'account:verifyingCode'} />
|
||||
) : (
|
||||
<Trans i18nKey={'profile:submitVerificationCode'} />
|
||||
<Trans i18nKey={'account:submitVerificationCode'} />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -154,7 +154,7 @@ function FactorsListContainer({
|
||||
<Spinner />
|
||||
|
||||
<div>
|
||||
<Trans i18nKey={'profile:loadingFactors'} />
|
||||
<Trans i18nKey={'account:loadingFactors'} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -165,7 +165,7 @@ function FactorsListContainer({
|
||||
<div className={'w-full'}>
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'profile:factorsListError'} />
|
||||
<Trans i18nKey={'account:factorsListError'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
@@ -178,7 +178,7 @@ function FactorsListContainer({
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<div>
|
||||
<Heading level={6}>
|
||||
<Trans i18nKey={'profile:selectFactor'} />
|
||||
<Trans i18nKey={'account:selectFactor'} />
|
||||
</Heading>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -114,11 +114,11 @@ function SuccessState() {
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'profile:updatePasswordSuccess'} />
|
||||
<Trans i18nKey={'account:updatePasswordSuccess'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'profile:updatePasswordSuccessMessage'} />
|
||||
<Trans i18nKey={'account:updatePasswordSuccessMessage'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
|
||||
@@ -30,10 +30,9 @@ export function SignInMethodsContainer(props: {
|
||||
const router = useRouter();
|
||||
const nextPath = useSearchParams().get('next') ?? props.paths.home;
|
||||
|
||||
const redirectUrl = new URL(
|
||||
props.paths.callback,
|
||||
isBrowser() ? window?.location.origin : '',
|
||||
).toString();
|
||||
const redirectUrl = isBrowser()
|
||||
? new URL(props.paths.callback, window?.location.origin).toString()
|
||||
: '';
|
||||
|
||||
const onSignIn = () => {
|
||||
router.replace(nextPath);
|
||||
|
||||
@@ -33,7 +33,7 @@ export function CreateTeamAccountDialog(
|
||||
<Dialog open={props.isOpen} onOpenChange={props.setIsOpen}>
|
||||
<DialogContent>
|
||||
<DialogTitle>
|
||||
<Trans i18nKey={'organization:createOrganizationModalHeading'} />
|
||||
<Trans i18nKey={'teams:createOrganizationModalHeading'} />
|
||||
</DialogTitle>
|
||||
|
||||
<CreateOrganizationAccountForm />
|
||||
@@ -77,7 +77,7 @@ function CreateOrganizationAccountForm() {
|
||||
return (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans i18nKey={'organization:organizationNameLabel'} />
|
||||
<Trans i18nKey={'teams:organizationNameLabel'} />
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
@@ -105,7 +105,7 @@ function CreateOrganizationAccountForm() {
|
||||
data-test={'confirm-create-organization-button'}
|
||||
disabled={pending}
|
||||
>
|
||||
<Trans i18nKey={'organization:createOrganizationSubmitLabel'} />
|
||||
<Trans i18nKey={'teams:createOrganizationSubmitLabel'} />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -117,11 +117,11 @@ function CreateOrganizationErrorAlert() {
|
||||
return (
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'organization:createOrganizationErrorHeading'} />
|
||||
<Trans i18nKey={'teams:createOrganizationErrorHeading'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'organization:createOrganizationErrorMessage'} />
|
||||
<Trans i18nKey={'teams:createOrganizationErrorMessage'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
@@ -90,11 +90,11 @@ function RemoveInvitationErrorAlert() {
|
||||
return (
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'organization:deleteInvitationErrorTitle'} />
|
||||
<Trans i18nKey={'teams:deleteInvitationErrorTitle'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'organization:deleteInvitationErrorMessage'} />
|
||||
<Trans i18nKey={'teams:deleteInvitationErrorMessage'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
@@ -42,11 +42,11 @@ export const UpdateInvitationDialog: React.FC<{
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<Trans i18nKey={'organization:updateMemberRoleModalHeading'} />
|
||||
<Trans i18nKey={'teams:updateMemberRoleModalHeading'} />
|
||||
</DialogTitle>
|
||||
|
||||
<DialogDescription>
|
||||
<Trans i18nKey={'organization:updateMemberRoleModalDescription'} />
|
||||
<Trans i18nKey={'teams:updateMemberRoleModalDescription'} />
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -139,7 +139,7 @@ function UpdateInvitationForm({
|
||||
/>
|
||||
|
||||
<Button data-test={'confirm-update-member-role'} disabled={pending}>
|
||||
<Trans i18nKey={'organization:updateRoleSubmitLabel'} />
|
||||
<Trans i18nKey={'teams:updateRoleSubmitLabel'} />
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
@@ -150,11 +150,11 @@ function UpdateRoleErrorAlert() {
|
||||
return (
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'organization:updateRoleErrorHeading'} />
|
||||
<Trans i18nKey={'teams:updateRoleErrorHeading'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'organization:updateRoleErrorMessage'} />
|
||||
<Trans i18nKey={'teams:updateRoleErrorMessage'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
@@ -211,7 +211,7 @@ function InviteMembersForm({
|
||||
<Plus className={'h-4'} />
|
||||
|
||||
<span>
|
||||
<Trans i18nKey={'organization:addAnotherMemberButtonLabel'} />
|
||||
<Trans i18nKey={'teams:addAnotherMemberButtonLabel'} />
|
||||
</span>
|
||||
</span>
|
||||
</Button>
|
||||
|
||||
@@ -84,7 +84,7 @@ function RemoveMemberForm({
|
||||
disabled={isSubmitting}
|
||||
onClick={onMemberRemoved}
|
||||
>
|
||||
<Trans i18nKey={'organization:removeMemberSubmitLabel'} />
|
||||
<Trans i18nKey={'teams:removeMemberSubmitLabel'} />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -95,11 +95,11 @@ function RemoveMemberErrorAlert() {
|
||||
return (
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'organization:removeMemberErrorHeading'} />
|
||||
<Trans i18nKey={'teams:removeMemberErrorHeading'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'organization:removeMemberErrorMessage'} />
|
||||
<Trans i18nKey={'teams:removeMemberErrorMessage'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
@@ -109,7 +109,7 @@ function TransferOrganizationOwnershipForm({
|
||||
|
||||
<p>
|
||||
<Trans
|
||||
i18nKey={'organization:transferOwnershipDisclaimer'}
|
||||
i18nKey={'teams:transferOwnershipDisclaimer'}
|
||||
values={{
|
||||
member: targetDisplayName,
|
||||
}}
|
||||
@@ -153,9 +153,9 @@ function TransferOrganizationOwnershipForm({
|
||||
>
|
||||
<If
|
||||
condition={pending}
|
||||
fallback={<Trans i18nKey={'organization:transferOwnership'} />}
|
||||
fallback={<Trans i18nKey={'teams:transferOwnership'} />}
|
||||
>
|
||||
<Trans i18nKey={'organization:transferringOwnership'} />
|
||||
<Trans i18nKey={'teams:transferringOwnership'} />
|
||||
</If>
|
||||
</Button>
|
||||
</form>
|
||||
@@ -167,11 +167,11 @@ function TransferOwnershipErrorAlert() {
|
||||
return (
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'organization:transferOrganizationErrorHeading'} />
|
||||
<Trans i18nKey={'teams:transferOrganizationErrorHeading'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'organization:transferOrganizationErrorMessage'} />
|
||||
<Trans i18nKey={'teams:transferOrganizationErrorMessage'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
@@ -43,11 +43,11 @@ export const UpdateMemberRoleDialog: React.FC<{
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<Trans i18nKey={'organization:updateMemberRoleModalHeading'} />
|
||||
<Trans i18nKey={'teams:updateMemberRoleModalHeading'} />
|
||||
</DialogTitle>
|
||||
|
||||
<DialogDescription>
|
||||
<Trans i18nKey={'organization:updateMemberRoleModalDescription'} />
|
||||
<Trans i18nKey={'teams:updateMemberRoleModalDescription'} />
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -140,7 +140,7 @@ function UpdateMemberForm({
|
||||
/>
|
||||
|
||||
<Button data-test={'confirm-update-member-role'} disabled={pending}>
|
||||
<Trans i18nKey={'organization:updateRoleSubmitLabel'} />
|
||||
<Trans i18nKey={'teams:updateRoleSubmitLabel'} />
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
@@ -151,11 +151,11 @@ function UpdateRoleErrorAlert() {
|
||||
return (
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'organization:updateRoleErrorHeading'} />
|
||||
<Trans i18nKey={'teams:updateRoleErrorHeading'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'organization:updateRoleErrorMessage'} />
|
||||
<Trans i18nKey={'teams:updateRoleErrorMessage'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
@@ -45,12 +45,12 @@ function DeleteOrganizationContainer(props: { account: AccountData }) {
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<div className={'flex flex-col space-y-1'}>
|
||||
<Heading level={6}>
|
||||
<Trans i18nKey={'organization:deleteOrganization'} />
|
||||
<Trans i18nKey={'teams:deleteOrganization'} />
|
||||
</Heading>
|
||||
|
||||
<p className={'text-sm text-gray-500'}>
|
||||
<Trans
|
||||
i18nKey={'organization:deleteOrganizationDescription'}
|
||||
i18nKey={'teams:deleteOrganizationDescription'}
|
||||
values={{
|
||||
organizationName: props.account.name,
|
||||
}}
|
||||
@@ -66,14 +66,14 @@ function DeleteOrganizationContainer(props: { account: AccountData }) {
|
||||
type={'button'}
|
||||
variant={'destructive'}
|
||||
>
|
||||
<Trans i18nKey={'organization:deleteOrganization'} />
|
||||
<Trans i18nKey={'teams:deleteOrganization'} />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<Trans i18nKey={'organization:deletingOrganization'} />
|
||||
<Trans i18nKey={'teams:deletingOrganization'} />
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -104,7 +104,7 @@ function DeleteOrganizationForm({ name, id }: { name: string; id: string }) {
|
||||
>
|
||||
<div>
|
||||
<Trans
|
||||
i18nKey={'organization:deleteOrganizationDisclaimer'}
|
||||
i18nKey={'teams:deleteOrganizationDisclaimer'}
|
||||
values={{
|
||||
organizationName: name,
|
||||
}}
|
||||
@@ -119,7 +119,7 @@ function DeleteOrganizationForm({ name, id }: { name: string; id: string }) {
|
||||
<input type="hidden" value={id} name={'id'} />
|
||||
|
||||
<Label>
|
||||
<Trans i18nKey={'organization:organizationNameInputLabel'} />
|
||||
<Trans i18nKey={'teams:organizationNameInputLabel'} />
|
||||
|
||||
<Input
|
||||
name={'name'}
|
||||
@@ -132,7 +132,7 @@ function DeleteOrganizationForm({ name, id }: { name: string; id: string }) {
|
||||
/>
|
||||
|
||||
<span className={'text-xs'}>
|
||||
<Trans i18nKey={'organization:deleteOrganizationInputField'} />
|
||||
<Trans i18nKey={'teams:deleteOrganizationInputField'} />
|
||||
</span>
|
||||
</Label>
|
||||
</div>
|
||||
@@ -154,7 +154,7 @@ function DeleteOrganizationSubmitButton() {
|
||||
disabled={pending}
|
||||
variant={'destructive'}
|
||||
>
|
||||
<Trans i18nKey={'organization:deleteOrganization'} />
|
||||
<Trans i18nKey={'teams:deleteOrganization'} />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -164,7 +164,7 @@ function LeaveOrganizationContainer(props: { account: AccountData }) {
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<p>
|
||||
<Trans
|
||||
i18nKey={'organization:leaveOrganizationDescription'}
|
||||
i18nKey={'teams:leaveOrganizationDescription'}
|
||||
values={{
|
||||
organizationName: props.account.name,
|
||||
}}
|
||||
@@ -179,16 +179,14 @@ function LeaveOrganizationContainer(props: { account: AccountData }) {
|
||||
type={'button'}
|
||||
variant={'destructive'}
|
||||
>
|
||||
<Trans i18nKey={'organization:leaveOrganization'} />
|
||||
<Trans i18nKey={'teams:leaveOrganization'} />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<Trans
|
||||
i18nKey={'organization:leavingOrganizationModalHeading'}
|
||||
/>
|
||||
<Trans i18nKey={'teams:leavingOrganizationModalHeading'} />
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -200,7 +198,7 @@ function LeaveOrganizationContainer(props: { account: AccountData }) {
|
||||
<div>
|
||||
<div>
|
||||
<Trans
|
||||
i18nKey={'organization:leaveOrganizationDisclaimer'}
|
||||
i18nKey={'teams:leaveOrganizationDisclaimer'}
|
||||
values={{
|
||||
organizationName: props.account?.name,
|
||||
}}
|
||||
@@ -230,7 +228,7 @@ function LeaveOrganizationSubmitButton() {
|
||||
disabled={pending}
|
||||
variant={'destructive'}
|
||||
>
|
||||
<Trans i18nKey={'organization:leaveOrganization'} />
|
||||
<Trans i18nKey={'teams:leaveOrganization'} />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -239,7 +237,7 @@ function LeaveOrganizationErrorAlert() {
|
||||
return (
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'organization:leaveOrganizationErrorHeading'} />
|
||||
<Trans i18nKey={'teams:leaveOrganizationErrorHeading'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
@@ -253,7 +251,7 @@ function DeleteOrganizationErrorAlert() {
|
||||
return (
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'organization:deleteOrganizationErrorHeading'} />
|
||||
<Trans i18nKey={'teams:deleteOrganizationErrorHeading'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
|
||||
@@ -66,9 +66,7 @@ export const UpdateOrganizationForm = (props: {
|
||||
return (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans
|
||||
i18nKey={'organization:organizationNameInputLabel'}
|
||||
/>
|
||||
<Trans i18nKey={'teams:organizationNameInputLabel'} />
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
@@ -90,7 +88,7 @@ export const UpdateOrganizationForm = (props: {
|
||||
data-test={'update-organization-submit-button'}
|
||||
disabled={updateAccountData.isPending}
|
||||
>
|
||||
<Trans i18nKey={'organization:updateOrganizationSubmitLabel'} />
|
||||
<Trans i18nKey={'teams:updateOrganizationSubmitLabel'} />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user