Files
MOPC-Portal/src/components/settings/defaults-settings-form.tsx
Matt a606292aaa Initial commit: MOPC platform with Docker deployment setup
Full Next.js 15 platform with tRPC, Prisma, PostgreSQL, NextAuth.
Includes production Dockerfile (multi-stage, port 7600), docker-compose
with registry-based image pull, Gitea Actions CI workflow, nginx config
for portal.monaco-opc.com, deployment scripts, and DEPLOYMENT.md guide.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 13:41:32 +01:00

182 lines
5.8 KiB
TypeScript

'use client'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { toast } from 'sonner'
import { Loader2, Settings } from 'lucide-react'
import { trpc } from '@/lib/trpc/client'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
const COMMON_TIMEZONES = [
{ value: 'Europe/Monaco', label: 'Monaco (CET/CEST)' },
{ value: 'Europe/Paris', label: 'Paris (CET/CEST)' },
{ value: 'Europe/London', label: 'London (GMT/BST)' },
{ value: 'America/New_York', label: 'New York (EST/EDT)' },
{ value: 'America/Los_Angeles', label: 'Los Angeles (PST/PDT)' },
{ value: 'Asia/Tokyo', label: 'Tokyo (JST)' },
{ value: 'Asia/Singapore', label: 'Singapore (SGT)' },
{ value: 'Australia/Sydney', label: 'Sydney (AEST/AEDT)' },
{ value: 'UTC', label: 'UTC' },
]
const formSchema = z.object({
default_timezone: z.string().min(1, 'Timezone is required'),
default_page_size: z.string().regex(/^\d+$/, 'Must be a number'),
autosave_interval_seconds: z.string().regex(/^\d+$/, 'Must be a number'),
})
type FormValues = z.infer<typeof formSchema>
interface DefaultsSettingsFormProps {
settings: {
default_timezone?: string
default_page_size?: string
autosave_interval_seconds?: string
}
}
export function DefaultsSettingsForm({ settings }: DefaultsSettingsFormProps) {
const utils = trpc.useUtils()
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
default_timezone: settings.default_timezone || 'Europe/Monaco',
default_page_size: settings.default_page_size || '20',
autosave_interval_seconds: settings.autosave_interval_seconds || '30',
},
})
const updateSettings = trpc.settings.updateMultiple.useMutation({
onSuccess: () => {
toast.success('Default settings saved successfully')
utils.settings.getByCategory.invalidate({ category: 'DEFAULTS' })
},
onError: (error) => {
toast.error(`Failed to save settings: ${error.message}`)
},
})
const onSubmit = (data: FormValues) => {
updateSettings.mutate({
settings: [
{ key: 'default_timezone', value: data.default_timezone },
{ key: 'default_page_size', value: data.default_page_size },
{ key: 'autosave_interval_seconds', value: data.autosave_interval_seconds },
],
})
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<FormField
control={form.control}
name="default_timezone"
render={({ field }) => (
<FormItem>
<FormLabel>Default Timezone</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select timezone" />
</SelectTrigger>
</FormControl>
<SelectContent>
{COMMON_TIMEZONES.map((tz) => (
<SelectItem key={tz.value} value={tz.value}>
{tz.label}
</SelectItem>
))}
</SelectContent>
</Select>
<FormDescription>
Timezone used for displaying dates and deadlines across the platform
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="default_page_size"
render={({ field }) => (
<FormItem>
<FormLabel>Default Page Size</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select page size" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="10">10 items per page</SelectItem>
<SelectItem value="20">20 items per page</SelectItem>
<SelectItem value="50">50 items per page</SelectItem>
<SelectItem value="100">100 items per page</SelectItem>
</SelectContent>
</Select>
<FormDescription>
Default number of items shown in lists and tables
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="autosave_interval_seconds"
render={({ field }) => (
<FormItem>
<FormLabel>Autosave Interval (seconds)</FormLabel>
<FormControl>
<Input type="number" min="10" max="120" placeholder="30" {...field} />
</FormControl>
<FormDescription>
How often evaluation forms are automatically saved while editing.
Lower values provide better data protection but increase server load.
Recommended: 30 seconds.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" disabled={updateSettings.isPending}>
{updateSettings.isPending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Saving...
</>
) : (
<>
<Settings className="mr-2 h-4 w-4" />
Save Default Settings
</>
)}
</Button>
</form>
</Form>
)
}