Revert "Unify workspace dropdowns; Update layouts (#458)"

This reverts commit 4bc8448a1d.
This commit is contained in:
gbuomprisco
2026-03-11 14:47:47 +08:00
parent 4bc8448a1d
commit 4912e402a3
530 changed files with 11182 additions and 14382 deletions

View File

@@ -7,7 +7,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { ColumnDef } from '@tanstack/react-table';
import { EllipsisVertical } from 'lucide-react';
import { useForm, useWatch } from 'react-hook-form';
import * as z from 'zod';
import { z } from 'zod';
import { Tables } from '@kit/supabase/database';
import { Button } from '@kit/ui/button';
@@ -77,7 +77,7 @@ export function AdminAccountsTable(
}
function AccountsTableFilters(props: {
filters: z.output<typeof FiltersSchema>;
filters: z.infer<typeof FiltersSchema>;
}) {
const form = useForm({
resolver: zodResolver(FiltersSchema),
@@ -92,7 +92,7 @@ function AccountsTableFilters(props: {
const router = useRouter();
const pathName = usePathname();
const onSubmit = ({ type, query }: z.output<typeof FiltersSchema>) => {
const onSubmit = ({ type, query }: z.infer<typeof FiltersSchema>) => {
const params = new URLSearchParams({
account_type: type,
query: query ?? '',
@@ -105,12 +105,6 @@ function AccountsTableFilters(props: {
const type = useWatch({ control: form.control, name: 'type' });
const options = {
all: 'All Accounts',
team: 'Team',
personal: 'Personal',
};
return (
<Form {...form}>
<form
@@ -122,7 +116,7 @@ function AccountsTableFilters(props: {
onValueChange={(value) => {
form.setValue(
'type',
value as z.output<typeof FiltersSchema>['type'],
value as z.infer<typeof FiltersSchema>['type'],
{
shouldValidate: true,
shouldDirty: true,
@@ -134,20 +128,16 @@ function AccountsTableFilters(props: {
}}
>
<SelectTrigger>
<SelectValue placeholder={'Account Type'}>
{(value: keyof typeof options) => options[value]}
</SelectValue>
<SelectValue placeholder={'Account Type'} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Account Type</SelectLabel>
{Object.entries(options).map(([key, value]) => (
<SelectItem key={key} value={key}>
{value}
</SelectItem>
))}
<SelectItem value={'all'}>All accounts</SelectItem>
<SelectItem value={'team'}>Team</SelectItem>
<SelectItem value={'personal'}>Personal</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
@@ -167,8 +157,6 @@ function AccountsTableFilters(props: {
</FormItem>
)}
/>
<button type="submit" hidden />
</form>
</Form>
);
@@ -223,13 +211,11 @@ function getColumns(): ColumnDef<Account>[] {
return (
<div className={'flex justify-end'}>
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button variant={'outline'} size={'icon'}>
<EllipsisVertical className={'h-4'} />
</Button>
}
/>
<DropdownMenuTrigger asChild>
<Button variant={'outline'} size={'icon'}>
<EllipsisVertical className={'h-4'} />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align={'end'}>
<DropdownMenuGroup>

View File

@@ -1,9 +1,8 @@
'use client';
import { useState } from 'react';
import { useState, useTransition } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useAction } from 'next-safe-action/hooks';
import { useForm } from 'react-hook-form';
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
@@ -42,7 +41,7 @@ export function AdminBanUserDialog(
return (
<AlertDialog open={open} onOpenChange={setOpen}>
<AlertDialogTrigger render={props.children as React.ReactElement} />
<AlertDialogTrigger asChild>{props.children}</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -61,9 +60,8 @@ export function AdminBanUserDialog(
}
function BanUserForm(props: { userId: string; onSuccess: () => void }) {
const { execute, isPending, hasErrored } = useAction(banUserAction, {
onSuccess: () => props.onSuccess(),
});
const [pending, startTransition] = useTransition();
const [error, setError] = useState<boolean>(false);
const form = useForm({
resolver: zodResolver(BanUserSchema),
@@ -78,9 +76,18 @@ function BanUserForm(props: { userId: string; onSuccess: () => void }) {
<form
data-test={'admin-ban-user-form'}
className={'flex flex-col space-y-8'}
onSubmit={form.handleSubmit((data) => execute(data))}
onSubmit={form.handleSubmit((data) => {
startTransition(async () => {
try {
await banUserAction(data);
props.onSuccess();
} catch {
setError(true);
}
});
})}
>
<If condition={hasErrored}>
<If condition={error}>
<Alert variant={'destructive'}>
<AlertTitle>Error</AlertTitle>
@@ -118,10 +125,10 @@ function BanUserForm(props: { userId: string; onSuccess: () => void }) {
/>
<AlertDialogFooter>
<AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>
<AlertDialogCancel disabled={pending}>Cancel</AlertDialogCancel>
<Button disabled={isPending} type={'submit'} variant={'destructive'}>
{isPending ? 'Banning...' : 'Ban User'}
<Button disabled={pending} type={'submit'} variant={'destructive'}>
{pending ? 'Banning...' : 'Ban User'}
</Button>
</AlertDialogFooter>
</form>

View File

@@ -1,9 +1,8 @@
'use client';
import { useState } from 'react';
import { useState, useTransition } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useAction } from 'next-safe-action/hooks';
import { useForm } from 'react-hook-form';
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
@@ -39,6 +38,8 @@ import {
} from '../lib/server/schema/create-user.schema';
export function AdminCreateUserDialog(props: React.PropsWithChildren) {
const [pending, startTransition] = useTransition();
const [error, setError] = useState<string | null>(null);
const [open, setOpen] = useState(false);
const form = useForm({
@@ -51,19 +52,28 @@ export function AdminCreateUserDialog(props: React.PropsWithChildren) {
mode: 'onChange',
});
const { execute, isPending, result } = useAction(createUserAction, {
onSuccess: () => {
toast.success('User created successfully');
form.reset();
setOpen(false);
},
});
const onSubmit = (data: CreateUserSchemaType) => {
startTransition(async () => {
try {
const result = await createUserAction(data);
const error = result.serverError;
if (result.success) {
toast.success('User creates successfully');
form.reset();
setOpen(false);
}
setError(null);
} catch (e) {
setError(e instanceof Error ? e.message : 'Error');
}
});
};
return (
<AlertDialog open={open} onOpenChange={setOpen}>
<AlertDialogTrigger render={props.children as React.ReactElement} />
<AlertDialogTrigger asChild>{props.children}</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -78,9 +88,7 @@ export function AdminCreateUserDialog(props: React.PropsWithChildren) {
<form
data-test={'admin-create-user-form'}
className={'flex flex-col space-y-4'}
onSubmit={form.handleSubmit((data: CreateUserSchemaType) =>
execute(data),
)}
onSubmit={form.handleSubmit(onSubmit)}
>
<If condition={!!error}>
<Alert variant={'destructive'}>
@@ -158,8 +166,8 @@ export function AdminCreateUserDialog(props: React.PropsWithChildren) {
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<Button disabled={isPending} type={'submit'}>
{isPending ? 'Creating...' : 'Create User'}
<Button disabled={pending} type={'submit'}>
{pending ? 'Creating...' : 'Create User'}
</Button>
</AlertDialogFooter>
</form>

View File

@@ -1,7 +1,8 @@
'use client';
import { useState, useTransition } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useAction } from 'next-safe-action/hooks';
import { useForm } from 'react-hook-form';
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
@@ -36,7 +37,8 @@ export function AdminDeleteAccountDialog(
accountId: string;
}>,
) {
const { execute, isPending, hasErrored } = useAction(deleteAccountAction);
const [pending, startTransition] = useTransition();
const [error, setError] = useState<boolean>(false);
const form = useForm({
resolver: zodResolver(DeleteAccountSchema),
@@ -48,7 +50,7 @@ export function AdminDeleteAccountDialog(
return (
<AlertDialog>
<AlertDialogTrigger render={props.children as React.ReactElement} />
<AlertDialogTrigger asChild>{props.children}</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -63,11 +65,20 @@ export function AdminDeleteAccountDialog(
<Form {...form}>
<form
data-test={'admin-delete-account-form'}
data-form={'admin-delete-account-form'}
className={'flex flex-col space-y-8'}
onSubmit={form.handleSubmit((data) => execute(data))}
onSubmit={form.handleSubmit((data) => {
startTransition(async () => {
try {
await deleteAccountAction(data);
setError(false);
} catch {
setError(true);
}
});
})}
>
<If condition={hasErrored}>
<If condition={error}>
<Alert variant={'destructive'}>
<AlertTitle>Error</AlertTitle>
@@ -109,11 +120,11 @@ export function AdminDeleteAccountDialog(
<AlertDialogCancel>Cancel</AlertDialogCancel>
<Button
disabled={isPending}
disabled={pending}
type={'submit'}
variant={'destructive'}
>
{isPending ? 'Deleting...' : 'Delete'}
{pending ? 'Deleting...' : 'Delete'}
</Button>
</AlertDialogFooter>
</form>

View File

@@ -1,7 +1,10 @@
'use client';
import { useState, useTransition } from 'react';
import { isRedirectError } from 'next/dist/client/components/redirect-error';
import { zodResolver } from '@hookform/resolvers/zod';
import { useAction } from 'next-safe-action/hooks';
import { useForm } from 'react-hook-form';
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
@@ -36,7 +39,8 @@ export function AdminDeleteUserDialog(
userId: string;
}>,
) {
const { execute, isPending, hasErrored } = useAction(deleteUserAction);
const [pending, startTransition] = useTransition();
const [error, setError] = useState<boolean>(false);
const form = useForm({
resolver: zodResolver(DeleteUserSchema),
@@ -48,7 +52,7 @@ export function AdminDeleteUserDialog(
return (
<AlertDialog>
<AlertDialogTrigger render={props.children as React.ReactElement} />
<AlertDialogTrigger asChild>{props.children}</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -65,9 +69,23 @@ export function AdminDeleteUserDialog(
<form
data-test={'admin-delete-user-form'}
className={'flex flex-col space-y-8'}
onSubmit={form.handleSubmit((data) => execute(data))}
onSubmit={form.handleSubmit((data) => {
startTransition(async () => {
try {
await deleteUserAction(data);
setError(false);
} catch {
if (isRedirectError(error)) {
// Do nothing
} else {
setError(true);
}
}
});
})}
>
<If condition={hasErrored}>
<If condition={error}>
<Alert variant={'destructive'}>
<AlertTitle>Error</AlertTitle>
@@ -109,11 +127,11 @@ export function AdminDeleteUserDialog(
<AlertDialogCancel>Cancel</AlertDialogCancel>
<Button
disabled={isPending}
disabled={pending}
type={'submit'}
variant={'destructive'}
>
{isPending ? 'Deleting...' : 'Delete'}
{pending ? 'Deleting...' : 'Delete'}
</Button>
</AlertDialogFooter>
</form>

View File

@@ -1,10 +1,9 @@
'use client';
import { useState } from 'react';
import { useState, useTransition } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useQuery } from '@tanstack/react-query';
import { useAction } from 'next-safe-action/hooks';
import { useForm } from 'react-hook-form';
import { useSupabase } from '@kit/supabase/hooks/use-supabase';
@@ -54,13 +53,8 @@ export function AdminImpersonateUserDialog(
refreshToken: string;
}>();
const { execute, isPending, hasErrored } = useAction(impersonateUserAction, {
onSuccess: ({ data }) => {
if (data) {
setTokens(data);
}
},
});
const [isPending, startTransition] = useTransition();
const [error, setError] = useState<boolean | null>(null);
if (tokens) {
return (
@@ -74,7 +68,7 @@ export function AdminImpersonateUserDialog(
return (
<AlertDialog>
<AlertDialogTrigger render={props.children as React.ReactElement} />
<AlertDialogTrigger asChild>{props.children}</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -97,9 +91,19 @@ export function AdminImpersonateUserDialog(
<form
data-test={'admin-impersonate-user-form'}
className={'flex flex-col space-y-8'}
onSubmit={form.handleSubmit((data) => execute(data))}
onSubmit={form.handleSubmit((data) => {
startTransition(async () => {
try {
const result = await impersonateUserAction(data);
setTokens(result);
} catch {
setError(true);
}
});
})}
>
<If condition={hasErrored}>
<If condition={error}>
<Alert variant={'destructive'}>
<AlertTitle>Error</AlertTitle>

View File

@@ -1,9 +1,8 @@
'use client';
import { useState } from 'react';
import { useState, useTransition } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useAction } from 'next-safe-action/hooks';
import { useForm } from 'react-hook-form';
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
@@ -42,7 +41,7 @@ export function AdminReactivateUserDialog(
return (
<AlertDialog open={open} onOpenChange={setOpen}>
<AlertDialogTrigger render={props.children as React.ReactElement} />
<AlertDialogTrigger asChild>{props.children}</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -63,9 +62,8 @@ export function AdminReactivateUserDialog(
}
function ReactivateUserForm(props: { userId: string; onSuccess: () => void }) {
const { execute, isPending, hasErrored } = useAction(reactivateUserAction, {
onSuccess: () => props.onSuccess(),
});
const [pending, startTransition] = useTransition();
const [error, setError] = useState<boolean>(false);
const form = useForm({
resolver: zodResolver(ReactivateUserSchema),
@@ -80,9 +78,18 @@ function ReactivateUserForm(props: { userId: string; onSuccess: () => void }) {
<form
data-test={'admin-reactivate-user-form'}
className={'flex flex-col space-y-8'}
onSubmit={form.handleSubmit((data) => execute(data))}
onSubmit={form.handleSubmit((data) => {
startTransition(async () => {
try {
await reactivateUserAction(data);
props.onSuccess();
} catch {
setError(true);
}
});
})}
>
<If condition={hasErrored}>
<If condition={error}>
<Alert variant={'destructive'}>
<AlertTitle>Error</AlertTitle>
@@ -120,10 +127,10 @@ function ReactivateUserForm(props: { userId: string; onSuccess: () => void }) {
/>
<AlertDialogFooter>
<AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>
<AlertDialogCancel disabled={pending}>Cancel</AlertDialogCancel>
<Button disabled={isPending} type={'submit'}>
{isPending ? 'Reactivating...' : 'Reactivate User'}
<Button disabled={pending} type={'submit'}>
{pending ? 'Reactivating...' : 'Reactivate User'}
</Button>
</AlertDialogFooter>
</form>

View File

@@ -1,9 +1,10 @@
'use client';
import { useState, useTransition } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useAction } from 'next-safe-action/hooks';
import { useForm } from 'react-hook-form';
import * as z from 'zod';
import { z } from 'zod';
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
import {
@@ -50,22 +51,33 @@ export function AdminResetPasswordDialog(
},
});
const { execute, isPending, hasErrored, hasSucceeded } = useAction(
resetPasswordAction,
{
onSuccess: () => {
const [isPending, startTransition] = useTransition();
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState(false);
const onSubmit = form.handleSubmit((data) => {
setError(null);
setSuccess(false);
startTransition(async () => {
try {
await resetPasswordAction(data);
setSuccess(true);
form.reset({ userId: props.userId, confirmation: '' });
toast.success('Password reset email successfully sent');
},
onError: () => {
} catch (e) {
setError(e instanceof Error ? e.message : String(e));
toast.error('We hit an error. Please read the logs.');
},
},
);
}
});
});
return (
<AlertDialog>
<AlertDialogTrigger render={props.children as React.ReactElement} />
<AlertDialogTrigger asChild>{props.children}</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -78,10 +90,7 @@ export function AdminResetPasswordDialog(
<div className="relative">
<Form {...form}>
<form
onSubmit={form.handleSubmit((data) => execute(data))}
className="space-y-4"
>
<form onSubmit={onSubmit} className="space-y-4">
<FormField
control={form.control}
name="confirmation"
@@ -106,7 +115,7 @@ export function AdminResetPasswordDialog(
)}
/>
<If condition={hasErrored}>
<If condition={!!error}>
<Alert variant="destructive">
<AlertTitle>
We encountered an error while sending the email
@@ -118,7 +127,7 @@ export function AdminResetPasswordDialog(
</Alert>
</If>
<If condition={hasSucceeded}>
<If condition={success}>
<Alert>
<AlertTitle>
Password reset email sent successfully