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>
This commit is contained in:
181
src/components/settings/defaults-settings-form.tsx
Normal file
181
src/components/settings/defaults-settings-form.tsx
Normal file
@@ -0,0 +1,181 @@
|
||||
'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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user