Improve 'Leave Team' process with logging and confirmation step
Added logging to the 'Leave Team' functionality to track user actions, and implemented a confirmation input to further validate a user's intent to leave a team. Also revised the user-facing prompt for more clarity on the team leaving process. Corresponding changes were applied to the relevant services and front-end components.
This commit is contained in:
@@ -56,7 +56,7 @@ export function TeamAccountDangerZone({
|
||||
const userIsPrimaryOwner = user?.id === primaryOwnerUserId;
|
||||
|
||||
if (userIsPrimaryOwner) {
|
||||
return <DeleteTeamContainer account={account} />;
|
||||
return <LeaveTeamContainer account={account} />;
|
||||
}
|
||||
|
||||
return <LeaveTeamContainer account={account} />;
|
||||
@@ -240,6 +240,20 @@ function LeaveTeamContainer(props: {
|
||||
id: string;
|
||||
};
|
||||
}) {
|
||||
const form = useForm({
|
||||
resolver: zodResolver(
|
||||
z.object({
|
||||
confirmation: z.string().refine((value) => value === 'LEAVE', {
|
||||
message: 'Confirmation required to leave team',
|
||||
path: ['confirmation'],
|
||||
}),
|
||||
}),
|
||||
),
|
||||
defaultValues: {
|
||||
confirmation: '',
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<p className={'text-muted-foreground text-sm'}>
|
||||
@@ -276,18 +290,58 @@ function LeaveTeamContainer(props: {
|
||||
</AlertDialogHeader>
|
||||
|
||||
<ErrorBoundary fallback={<LeaveTeamErrorAlert />}>
|
||||
<form action={leaveTeamAccountAction}>
|
||||
<input type={'hidden'} value={props.account.id} name={'id'} />
|
||||
</form>
|
||||
<Form {...form}>
|
||||
<form
|
||||
className={'flex flex-col space-y-4'}
|
||||
action={leaveTeamAccountAction}
|
||||
>
|
||||
<input
|
||||
type={'hidden'}
|
||||
value={props.account.id}
|
||||
name={'accountId'}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
name={'confirmation'}
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans i18nKey={'teams:leaveTeamInputLabel'} />
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
data-test="leave-team-input-field"
|
||||
type="text"
|
||||
className="w-full"
|
||||
placeholder=""
|
||||
pattern="LEAVE"
|
||||
required
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
<Trans i18nKey={'teams:leaveTeamInputDescription'} />
|
||||
</FormDescription>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>
|
||||
<Trans i18nKey={'common:cancel'} />
|
||||
</AlertDialogCancel>
|
||||
|
||||
<LeaveTeamSubmitButton />
|
||||
</AlertDialogFooter>
|
||||
</form>
|
||||
</Form>
|
||||
</ErrorBoundary>
|
||||
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>
|
||||
<Trans i18nKey={'common:cancel'} />
|
||||
</AlertDialogCancel>
|
||||
|
||||
<LeaveTeamSubmitButton />
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
@@ -310,15 +364,23 @@ function LeaveTeamSubmitButton() {
|
||||
|
||||
function LeaveTeamErrorAlert() {
|
||||
return (
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'teams:leaveTeamErrorHeading'} />
|
||||
</AlertTitle>
|
||||
<>
|
||||
<Alert variant={'destructive'}>
|
||||
<AlertTitle>
|
||||
<Trans i18nKey={'teams:leaveTeamErrorHeading'} />
|
||||
</AlertTitle>
|
||||
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'common:genericError'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<AlertDescription>
|
||||
<Trans i18nKey={'common:genericError'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>
|
||||
<Trans i18nKey={'common:cancel'} />
|
||||
</AlertDialogCancel>
|
||||
</AlertDialogFooter>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,4 +2,5 @@ import { z } from 'zod';
|
||||
|
||||
export const LeaveTeamAccountSchema = z.object({
|
||||
accountId: z.string(),
|
||||
confirmation: z.custom((value) => value === 'LEAVE'),
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
||||
import 'server-only';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { Logger } from '@kit/shared/logger';
|
||||
import { Database } from '@kit/supabase/database';
|
||||
|
||||
const Schema = z.object({
|
||||
@@ -11,9 +12,18 @@ const Schema = z.object({
|
||||
});
|
||||
|
||||
export class LeaveTeamAccountService {
|
||||
private readonly namespace = 'leave-team-account';
|
||||
|
||||
constructor(private readonly adminClient: SupabaseClient<Database>) {}
|
||||
|
||||
async leaveTeamAccount(params: z.infer<typeof Schema>) {
|
||||
const ctx = {
|
||||
...params,
|
||||
name: this.namespace,
|
||||
};
|
||||
|
||||
Logger.info(ctx, 'Leaving team account');
|
||||
|
||||
const { accountId, userId } = Schema.parse(params);
|
||||
|
||||
const { error } = await this.adminClient
|
||||
@@ -25,7 +35,11 @@ export class LeaveTeamAccountService {
|
||||
});
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
Logger.error({ ...ctx, error }, 'Failed to leave team account');
|
||||
|
||||
throw new Error('Failed to leave team account');
|
||||
}
|
||||
|
||||
Logger.info(ctx, 'Successfully left team account');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user