Quellcode durchsuchen

feat(dashboard): Profile page

Michael Bromley vor 9 Monaten
Ursprung
Commit
963fe35481

Datei-Diff unterdrückt, da er zu groß ist
+ 166 - 89
package-lock.json


+ 1 - 1
packages/dashboard/src/components/layout/nav-user.tsx

@@ -114,7 +114,7 @@ export function NavUser() {
                             </DropdownMenuGroup>
                             <DropdownMenuSeparator />
                             <DropdownMenuGroup>
-                                <DropdownMenuItem>
+                                <DropdownMenuItem asChild>
                                     <Link to="/profile">Profile</Link>
                                 </DropdownMenuItem>
                                 <DialogTrigger asChild>

+ 23 - 0
packages/dashboard/src/routes/_authenticated/_profile/profile.graphql.ts

@@ -0,0 +1,23 @@
+import { graphql } from '@/graphql/graphql.js';
+
+export const activeAdministratorDocument = graphql(`
+    query ActiveAdministrator {
+        activeAdministrator {
+            id
+            createdAt
+            updatedAt
+            firstName
+            lastName
+            emailAddress
+            customFields
+        }
+    }
+`);
+
+export const updateAdministratorDocument = graphql(`
+    mutation UpdateAdministrator($input: UpdateAdministratorInput!) {
+        updateAdministrator(input: $input) {
+            id
+        }
+    }
+`);

+ 171 - 0
packages/dashboard/src/routes/_authenticated/_profile/profile.tsx

@@ -0,0 +1,171 @@
+import { ErrorPage } from '@/components/shared/error-page.js';
+import { Button } from '@/components/ui/button.js';
+import {
+    Form,
+    FormControl,
+    FormField,
+    FormItem,
+    FormLabel,
+    FormMessage
+} from '@/components/ui/form.js';
+import { Input } from '@/components/ui/input.js';
+import {
+    CustomFieldsPageBlock,
+    Page,
+    PageActionBar,
+    PageBlock,
+    PageLayout,
+    PageTitle,
+} from '@/framework/layout-engine/page-layout.js';
+import { useDetailPage } from '@/framework/page/use-detail-page.js';
+import { api } from '@/graphql/api.js';
+import { Trans, useLingui } from '@lingui/react/macro';
+import { createFileRoute } from '@tanstack/react-router';
+import { toast } from 'sonner';
+import { activeAdministratorDocument, updateAdministratorDocument } from './profile.graphql.js';
+
+export const Route = createFileRoute('/_authenticated/_profile/profile')({
+    component: ProfilePage,
+    loader: async ({ context }) => {
+        await context.queryClient.ensureQueryData({
+            queryFn: () => api.query(activeAdministratorDocument),
+            queryKey: ['DetailPage', 'profile'],
+        });
+        return {
+            breadcrumb: [{ path: '/profile', label: <Trans>Profile</Trans> }],
+        };
+    },
+    errorComponent: ({ error }) => <ErrorPage message={error.message} />,
+});
+
+export function ProfilePage() {
+    const { i18n } = useLingui();
+
+    const { form, submitHandler, isPending } = useDetailPage({
+        queryDocument: activeAdministratorDocument,
+        entityField: 'activeAdministrator',
+        updateDocument: updateAdministratorDocument,
+        setValuesForUpdate: entity => {
+            return {
+                id: entity.id,
+                firstName: entity.firstName,
+                lastName: entity.lastName,
+                emailAddress: entity.emailAddress,
+                password: '',
+                customFields: entity.customFields,
+            };
+        },
+        transformUpdateInput: input => {
+            return {
+                ...input,
+                password: input.password?.length ? input.password : undefined,
+            };
+        },
+        params: { id: 'undefined' },
+        onSuccess: async data => {
+            toast(i18n.t('Successfully updated profile'), {
+                position: 'top-right',
+            });
+            form.reset(form.getValues());
+        },
+        onError: err => {
+            toast(i18n.t('Failed to update profile'), {
+                position: 'top-right',
+                description: err instanceof Error ? err.message : 'Unknown error',
+            });
+        },
+    });
+
+    return (
+        <Page>
+            <PageTitle>
+                <Trans>Profile</Trans>
+            </PageTitle>
+            <Form {...form}>
+                <form onSubmit={submitHandler} className="space-y-8">
+                    <PageActionBar>
+                        <div></div>
+                        <Button
+                            type="submit"
+                            disabled={!form.formState.isDirty || !form.formState.isValid || isPending}
+                        >
+                            <Trans>Update</Trans>
+                        </Button>
+                    </PageActionBar>
+                    <PageLayout>
+                        <PageBlock column="main">
+                            <div className="md:grid md:grid-cols-2 gap-4">
+                                <FormField
+                                    control={form.control}
+                                    name="firstName"
+                                    render={({ field }) => (
+                                        <FormItem>
+                                            <FormLabel>
+                                                <Trans>First name</Trans>
+                                            </FormLabel>
+                                            <FormControl>
+                                                <Input placeholder="" {...field} />
+                                            </FormControl>
+                                            <FormMessage />
+                                        </FormItem>
+                                    )}
+                                />
+                                <FormField
+                                    control={form.control}
+                                    name="lastName"
+                                    render={({ field }) => (
+                                        <FormItem>
+                                            <FormLabel>
+                                                <Trans>Last name</Trans>
+                                            </FormLabel>
+                                            <FormControl>
+                                                <Input placeholder="" {...field} />
+                                            </FormControl>
+                                            <FormMessage />
+                                        </FormItem>
+                                    )}
+                                />
+                                <FormField
+                                    control={form.control}
+                                    name="emailAddress"
+                                    render={({ field }) => (
+                                        <FormItem>
+                                            <FormLabel>
+                                                <Trans>Email Address or identifier</Trans>
+                                            </FormLabel>
+                                            <FormControl>
+                                                <Input placeholder="" {...field} />
+                                            </FormControl>
+                                            <FormMessage />
+                                        </FormItem>
+                                    )}
+                                />
+
+                                <FormField
+                                    control={form.control}
+                                    name="password"
+                                    render={({ field }) => (
+                                        <FormItem>
+                                            <FormLabel>
+                                                <Trans>Password</Trans>
+                                            </FormLabel>
+                                            <FormControl>
+                                                <Input placeholder="" type="password" {...field} />
+                                            </FormControl>
+                                            <FormMessage />
+                                        </FormItem>
+                                    )}
+                                />
+                            </div>
+                        </PageBlock>
+                        <CustomFieldsPageBlock
+                            column="main"
+                            entityType="Administrator"
+                            control={form.control}
+                        />
+                    </PageLayout>
+                </form>
+            </Form>
+        </Page>
+    );
+}

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.