Update admin action functionalities and UI
This commit includes several changes to the admin functionality. Most notably, it updates the actions deleteUser and banUser to deleteAccount and updates the UI for admin actions. It also includes new variants for badges, and adds new icons to buttons. In addition, it updates the user schemas to match these changes.
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import { BadgeX, Ban, ShieldPlus, Trash, VenetianMask } from 'lucide-react';
|
||||||
|
|
||||||
import { Database } from '@kit/supabase/database';
|
import { Database } from '@kit/supabase/database';
|
||||||
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
||||||
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
||||||
@@ -67,28 +69,44 @@ async function PersonalAccountPage(props: { account: Account }) {
|
|||||||
<span>{props.account.name}</span>
|
<span>{props.account.name}</span>
|
||||||
|
|
||||||
<Badge variant={'outline'}>Personal Account</Badge>
|
<Badge variant={'outline'}>Personal Account</Badge>
|
||||||
|
|
||||||
|
<If condition={isBanned}>
|
||||||
|
<Badge variant={'destructive'}>Banned</Badge>
|
||||||
|
</If>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className={'flex space-x-2'}>
|
<div className={'flex space-x-1'}>
|
||||||
<AdminImpersonateUserDialog userId={props.account.id}>
|
|
||||||
<Button variant={'ghost'}>Impersonate</Button>
|
|
||||||
</AdminImpersonateUserDialog>
|
|
||||||
|
|
||||||
<If condition={isBanned}>
|
<If condition={isBanned}>
|
||||||
<AdminReactivateUserDialog userId={props.account.id}>
|
<AdminReactivateUserDialog userId={props.account.id}>
|
||||||
<Button variant={'ghost'}>Reactivate</Button>
|
<Button size={'sm'} variant={'ghost'}>
|
||||||
|
<ShieldPlus className={'mr-1 h-4'} />
|
||||||
|
Reactivate
|
||||||
|
</Button>
|
||||||
</AdminReactivateUserDialog>
|
</AdminReactivateUserDialog>
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
<If condition={!isBanned}>
|
<If condition={!isBanned}>
|
||||||
<AdminBanUserDialog userId={props.account.id}>
|
<AdminBanUserDialog userId={props.account.id}>
|
||||||
<Button variant={'ghost'}>Ban</Button>
|
<Button size={'sm'} variant={'ghost'}>
|
||||||
|
<Ban className={'mr-1 h-4'} />
|
||||||
|
Ban
|
||||||
|
</Button>
|
||||||
</AdminBanUserDialog>
|
</AdminBanUserDialog>
|
||||||
|
|
||||||
|
<AdminImpersonateUserDialog userId={props.account.id}>
|
||||||
|
<Button size={'sm'} variant={'ghost'}>
|
||||||
|
<VenetianMask className={'mr-1 h-4'} />
|
||||||
|
Impersonate
|
||||||
|
</Button>
|
||||||
|
</AdminImpersonateUserDialog>
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
<AdminDeleteUserDialog userId={props.account.id}>
|
<AdminDeleteUserDialog userId={props.account.id}>
|
||||||
<Button variant={'destructive'}>Delete</Button>
|
<Button size={'sm'} variant={'destructive'}>
|
||||||
|
<BadgeX className={'mr-1 h-4'} />
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
</AdminDeleteUserDialog>
|
</AdminDeleteUserDialog>
|
||||||
</div>
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
@@ -134,7 +152,10 @@ async function TeamAccountPage(props: {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<AdminDeleteAccountDialog accountId={props.account.id}>
|
<AdminDeleteAccountDialog accountId={props.account.id}>
|
||||||
<Button variant={'destructive'}>Delete</Button>
|
<Button size={'sm'} variant={'destructive'}>
|
||||||
|
<BadgeX className={'mr-1 h-4'} />
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
</AdminDeleteAccountDialog>
|
</AdminDeleteAccountDialog>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
import { Input } from '@kit/ui/input';
|
import { Input } from '@kit/ui/input';
|
||||||
|
|
||||||
import { banUser } from '../lib/server/admin-server-actions';
|
import { banUser } from '../lib/server/admin-server-actions';
|
||||||
import { DeleteUserSchema } from '../lib/server/schema/admin-actions.schema';
|
import { BanUserSchema } from '../lib/server/schema/admin-actions.schema';
|
||||||
|
|
||||||
export function AdminBanUserDialog(
|
export function AdminBanUserDialog(
|
||||||
props: React.PropsWithChildren<{
|
props: React.PropsWithChildren<{
|
||||||
@@ -34,7 +34,7 @@ export function AdminBanUserDialog(
|
|||||||
}>,
|
}>,
|
||||||
) {
|
) {
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
resolver: zodResolver(DeleteUserSchema),
|
resolver: zodResolver(BanUserSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
userId: props.userId,
|
userId: props.userId,
|
||||||
confirmation: '',
|
confirmation: '',
|
||||||
@@ -57,7 +57,9 @@ export function AdminBanUserDialog(
|
|||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
className={'flex flex-col space-y-8'}
|
className={'flex flex-col space-y-8'}
|
||||||
onSubmit={form.handleSubmit(banUser)}
|
onSubmit={form.handleSubmit((data) => {
|
||||||
|
return banUser(data);
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<FormField
|
<FormField
|
||||||
name={'confirmation'}
|
name={'confirmation'}
|
||||||
|
|||||||
@@ -58,7 +58,9 @@ export function AdminDeleteAccountDialog(
|
|||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
className={'flex flex-col space-y-8'}
|
className={'flex flex-col space-y-8'}
|
||||||
onSubmit={form.handleSubmit(deleteAccount)}
|
onSubmit={form.handleSubmit((data) => {
|
||||||
|
return deleteAccount(data);
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<FormField
|
<FormField
|
||||||
name={'confirmation'}
|
name={'confirmation'}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import {
|
|||||||
} from '@kit/ui/form';
|
} from '@kit/ui/form';
|
||||||
import { Input } from '@kit/ui/input';
|
import { Input } from '@kit/ui/input';
|
||||||
|
|
||||||
import { deleteUser } from '../lib/server/admin-server-actions';
|
import { deleteAccount, deleteUser } from '../lib/server/admin-server-actions';
|
||||||
import { DeleteUserSchema } from '../lib/server/schema/admin-actions.schema';
|
import { DeleteUserSchema } from '../lib/server/schema/admin-actions.schema';
|
||||||
|
|
||||||
export function AdminDeleteUserDialog(
|
export function AdminDeleteUserDialog(
|
||||||
@@ -59,7 +59,9 @@ export function AdminDeleteUserDialog(
|
|||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
className={'flex flex-col space-y-8'}
|
className={'flex flex-col space-y-8'}
|
||||||
onSubmit={form.handleSubmit(deleteUser)}
|
onSubmit={form.handleSubmit((data) => {
|
||||||
|
return deleteAccount(data);
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<FormField
|
<FormField
|
||||||
name={'confirmation'}
|
name={'confirmation'}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import { Input } from '@kit/ui/input';
|
|||||||
import { LoadingOverlay } from '@kit/ui/loading-overlay';
|
import { LoadingOverlay } from '@kit/ui/loading-overlay';
|
||||||
|
|
||||||
import { impersonateUser } from '../lib/server/admin-server-actions';
|
import { impersonateUser } from '../lib/server/admin-server-actions';
|
||||||
import { DeleteUserSchema } from '../lib/server/schema/admin-actions.schema';
|
import { ImpersonateUserSchema } from '../lib/server/schema/admin-actions.schema';
|
||||||
|
|
||||||
export function AdminImpersonateUserDialog(
|
export function AdminImpersonateUserDialog(
|
||||||
props: React.PropsWithChildren<{
|
props: React.PropsWithChildren<{
|
||||||
@@ -41,7 +41,7 @@ export function AdminImpersonateUserDialog(
|
|||||||
}>,
|
}>,
|
||||||
) {
|
) {
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
resolver: zodResolver(DeleteUserSchema),
|
resolver: zodResolver(ImpersonateUserSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
userId: props.userId,
|
userId: props.userId,
|
||||||
confirmation: '',
|
confirmation: '',
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
@@ -24,7 +26,7 @@ import {
|
|||||||
import { Input } from '@kit/ui/input';
|
import { Input } from '@kit/ui/input';
|
||||||
|
|
||||||
import { reactivateUser } from '../lib/server/admin-server-actions';
|
import { reactivateUser } from '../lib/server/admin-server-actions';
|
||||||
import { DeleteUserSchema } from '../lib/server/schema/admin-actions.schema';
|
import { ReactivateUserSchema } from '../lib/server/schema/admin-actions.schema';
|
||||||
|
|
||||||
export function AdminReactivateUserDialog(
|
export function AdminReactivateUserDialog(
|
||||||
props: React.PropsWithChildren<{
|
props: React.PropsWithChildren<{
|
||||||
@@ -32,7 +34,7 @@ export function AdminReactivateUserDialog(
|
|||||||
}>,
|
}>,
|
||||||
) {
|
) {
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
resolver: zodResolver(DeleteUserSchema),
|
resolver: zodResolver(ReactivateUserSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
userId: props.userId,
|
userId: props.userId,
|
||||||
confirmation: '',
|
confirmation: '',
|
||||||
@@ -55,7 +57,9 @@ export function AdminReactivateUserDialog(
|
|||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
className={'flex flex-col space-y-8'}
|
className={'flex flex-col space-y-8'}
|
||||||
onSubmit={form.handleSubmit(reactivateUser)}
|
onSubmit={form.handleSubmit((data) => {
|
||||||
|
return reactivateUser(data);
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<FormField
|
<FormField
|
||||||
name={'confirmation'}
|
name={'confirmation'}
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ export const banUser = enhanceAdminAction(
|
|||||||
await service.banUser(userId);
|
await service.banUser(userId);
|
||||||
|
|
||||||
revalidateAdmin();
|
revalidateAdmin();
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
schema: BanUserSchema,
|
schema: BanUserSchema,
|
||||||
@@ -47,6 +51,10 @@ export const reactivateUser = enhanceAdminAction(
|
|||||||
await service.reactivateUser(userId);
|
await service.reactivateUser(userId);
|
||||||
|
|
||||||
revalidateAdmin();
|
revalidateAdmin();
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
schema: ReactivateUserSchema,
|
schema: ReactivateUserSchema,
|
||||||
@@ -83,6 +91,10 @@ export const deleteUser = enhanceAdminAction(
|
|||||||
await service.deleteUser(userId);
|
await service.deleteUser(userId);
|
||||||
|
|
||||||
revalidateAdmin();
|
revalidateAdmin();
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
schema: DeleteUserSchema,
|
schema: DeleteUserSchema,
|
||||||
@@ -102,6 +114,10 @@ export const deleteAccount = enhanceAdminAction(
|
|||||||
await service.deleteAccount(accountId);
|
await service.deleteAccount(accountId);
|
||||||
|
|
||||||
revalidateAdmin();
|
revalidateAdmin();
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
schema: DeleteAccountSchema,
|
schema: DeleteAccountSchema,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
const confirmationSchema = z.object({
|
const ConfirmationSchema = z.object({
|
||||||
confirmation: z.custom((value) => value === 'CONFIRM'),
|
confirmation: z.custom<string>((value) => value === 'CONFIRM'),
|
||||||
});
|
});
|
||||||
|
|
||||||
const UserIdSchema = confirmationSchema.extend({
|
const UserIdSchema = ConfirmationSchema.extend({
|
||||||
userId: z.string().uuid(),
|
userId: z.string().uuid(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -13,6 +13,6 @@ export const ReactivateUserSchema = UserIdSchema;
|
|||||||
export const ImpersonateUserSchema = UserIdSchema;
|
export const ImpersonateUserSchema = UserIdSchema;
|
||||||
export const DeleteUserSchema = UserIdSchema;
|
export const DeleteUserSchema = UserIdSchema;
|
||||||
|
|
||||||
export const DeleteAccountSchema = confirmationSchema.extend({
|
export const DeleteAccountSchema = ConfirmationSchema.extend({
|
||||||
accountId: z.string().uuid(),
|
accountId: z.string().uuid(),
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user