diff --git a/prisma/seed.ts b/prisma/seed.ts index 777c947..a4f34eb 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -38,7 +38,7 @@ async function main() { ...settingsData, { key: admin ? (admin?.user?.id as string) : (mailExists?.id as string), - value: 'en', + value: '{ "language": "en" }', description: 'User Settings', relation: 'user', }, diff --git a/src/components/form/settings-form.tsx b/src/components/form/settings-form.tsx index f88306c..8e05e37 100644 --- a/src/components/form/settings-form.tsx +++ b/src/components/form/settings-form.tsx @@ -1,6 +1,6 @@ import { m } from '@/paraglide/messages'; import { settingQueries } from '@/service/queries'; -import { updateSettings } from '@/service/setting.api'; +import { updateAdminSettings } from '@/service/setting.api'; import { settingSchema, SettingsInput } from '@/service/setting.schema'; import { GearIcon } from '@phosphor-icons/react'; import { useForm } from '@tanstack/react-form'; @@ -10,6 +10,7 @@ import { Button } from '../ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '../ui/card'; import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field'; import { Input } from '../ui/input'; +import { Skeleton } from '../ui/skeleton'; import { Textarea } from '../ui/textarea'; const defaultValues: SettingsInput = { @@ -21,13 +22,15 @@ const defaultValues: SettingsInput = { const SettingsForm = () => { const queryClient = useQueryClient(); - const { data: settings } = useQuery(settingQueries.list()); + const { data: settings, isLoading } = useQuery(settingQueries.listAdmin()); const updateMutation = useMutation({ - mutationFn: updateSettings, + mutationFn: updateAdminSettings, onSuccess: () => { // setLocale(variables.data.site_language as Locale); - queryClient.invalidateQueries({ queryKey: settingQueries.all }); + queryClient.invalidateQueries({ + queryKey: [...settingQueries.all, 'list'], + }); toast.success(m.settings_messages_update_success(), { richColors: true, }); @@ -50,6 +53,9 @@ const SettingsForm = () => { }, }); + if (isLoading) + return ; + return ( @@ -145,37 +151,6 @@ const SettingsForm = () => { ); }} /> - {/* { - const isInvalid = - field.state.meta.isTouched && !field.state.meta.isValid; - return ( - - - {m.settings_form_language()} - - - {isInvalid && ( - - )} - - ); - }} - /> */} diff --git a/src/components/form/user-settings-form.tsx b/src/components/form/user-settings-form.tsx new file mode 100644 index 0000000..d2f6330 --- /dev/null +++ b/src/components/form/user-settings-form.tsx @@ -0,0 +1,131 @@ +import { m } from '@/paraglide/messages'; +import { Locale, setLocale } from '@/paraglide/runtime'; +import { settingQueries } from '@/service/queries'; +import { updateUserSettings } from '@/service/setting.api'; +import { UserSettingInput, userSettingSchema } from '@/service/setting.schema'; +import { GearIcon } from '@phosphor-icons/react'; +import { useForm } from '@tanstack/react-form'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useEffect } from 'react'; +import { toast } from 'sonner'; +import { Button } from '../ui/button'; +import { Card, CardContent, CardHeader, CardTitle } from '../ui/card'; +import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '../ui/select'; +import { Skeleton } from '../ui/skeleton'; + +const defaultValues: UserSettingInput = { + language: '', +}; + +const UserSettingsForm = () => { + const queryClient = useQueryClient(); + + const { data, isLoading } = useQuery(settingQueries.listUser()); + + const updateMutation = useMutation({ + mutationFn: updateUserSettings, + onSuccess: (_, variables) => { + setLocale(variables.data.language as Locale); + queryClient.invalidateQueries({ + queryKey: [...settingQueries.all, 'listUser'], + }); + toast.success(m.settings_messages_update_success(), { + richColors: true, + }); + }, + }); + + const form = useForm({ + defaultValues, + validators: { + onSubmit: userSettingSchema, + onChange: userSettingSchema, + }, + onSubmit: ({ value }) => { + updateMutation.mutate({ data: value as UserSettingInput }); + }, + }); + + useEffect(() => { + if (data?.value?.language) { + setTimeout(() => { + form.setFieldValue('language', data.value.language); + }, 0); + } + }, [data, form]); + + return ( + + + + + {m.settings_ui_title()} + + + +
{ + e.preventDefault(); + e.stopPropagation(); + form.handleSubmit(); + }} + > + + {isLoading ? ( +
+ + +
+ ) : ( + { + const isInvalid = + field.state.meta.isTouched && !field.state.meta.isValid; + return ( + + + {m.settings_form_language()} + + + {isInvalid && ( + + )} + + ); + }} + /> + )} + + + +
+
+
+
+ ); +}; + +export default UserSettingsForm; diff --git a/src/components/sidebar/RouterBreadcrumb.tsx b/src/components/sidebar/RouterBreadcrumb.tsx index 1cad4b0..37c6a4d 100644 --- a/src/components/sidebar/RouterBreadcrumb.tsx +++ b/src/components/sidebar/RouterBreadcrumb.tsx @@ -17,11 +17,8 @@ export type BreadcrumbValue = const RouterBreadcrumb = () => { const matches = useMatches() - console.log(matches); - const breadcrumbs = matches.flatMap((match) => { const staticData = match.staticData; - console.log(staticData); if (!staticData?.breadcrumb) return []; const breadcrumbValue = diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx index cba1d26..7641172 100644 --- a/src/components/ui/select.tsx +++ b/src/components/ui/select.tsx @@ -1,13 +1,13 @@ -import * as React from "react" -import { Select as SelectPrimitive } from "radix-ui" +import { Select as SelectPrimitive } from 'radix-ui'; +import * as React from 'react'; -import { cn } from "@/lib/utils" -import { CaretDownIcon, CheckIcon, CaretUpIcon } from "@phosphor-icons/react" +import { cn } from '@/lib/utils'; +import { CaretDownIcon, CaretUpIcon, CheckIcon } from '@phosphor-icons/react'; function Select({ ...props }: React.ComponentProps) { - return + return ; } function SelectGroup({ @@ -17,33 +17,33 @@ function SelectGroup({ return ( - ) + ); } function SelectValue({ ...props }: React.ComponentProps) { - return + return ; } function SelectTrigger({ className, - size = "default", + size = 'default', children, ...props }: React.ComponentProps & { - size?: "sm" | "default" + size?: 'sm' | 'default'; }) { return ( @@ -52,21 +52,26 @@ function SelectTrigger({ - ) + ); } function SelectContent({ className, children, - position = "item-aligned", - align = "center", + position = 'item-aligned', + align = 'center', ...props }: React.ComponentProps) { return ( {children} @@ -84,7 +89,7 @@ function SelectContent({ - ) + ); } function SelectLabel({ @@ -94,10 +99,10 @@ function SelectLabel({ return ( - ) + ); } function SelectItem({ @@ -109,8 +114,8 @@ function SelectItem({ @@ -121,7 +126,7 @@ function SelectItem({ {children} - ) + ); } function SelectSeparator({ @@ -131,10 +136,13 @@ function SelectSeparator({ return ( - ) + ); } function SelectScrollUpButton({ @@ -144,13 +152,15 @@ function SelectScrollUpButton({ return ( - + - ) + ); } function SelectScrollDownButton({ @@ -160,13 +170,15 @@ function SelectScrollDownButton({ return ( - + - ) + ); } export { @@ -180,4 +192,4 @@ export { SelectSeparator, SelectTrigger, SelectValue, -} +}; diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx index d8c3757..753b5af 100644 --- a/src/components/ui/textarea.tsx +++ b/src/components/ui/textarea.tsx @@ -7,12 +7,12 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {