Barazo default frontend
barazo.forum
1/**
2 * PluginSettingsModal - Modal dialog for editing a plugin's settings.
3 * Dynamically renders fields from the plugin's settingsSchema.
4 * @see specs/prd-web.md Section M13
5 */
6
7'use client'
8
9import { useState } from 'react'
10import { X } from '@phosphor-icons/react'
11import { SaveButton } from '@/components/admin/save-button'
12import { SettingsField } from '@/components/admin/plugins/settings-field'
13import type { Plugin } from '@/lib/api/types'
14import type { SaveStatus } from '@/hooks/use-save-state'
15
16interface PluginSettingsModalProps {
17 plugin: Plugin
18 onClose: () => void
19 onSave: (settings: Record<string, boolean | string | number>) => void
20 saveStatus: SaveStatus
21}
22
23export function PluginSettingsModal({
24 plugin,
25 onClose,
26 onSave,
27 saveStatus,
28}: PluginSettingsModalProps) {
29 const [values, setValues] = useState<Record<string, boolean | string | number>>(() => ({
30 ...plugin.settings,
31 }))
32
33 const handleChange = (key: string, value: boolean | string | number) => {
34 setValues((prev) => ({ ...prev, [key]: value }))
35 }
36
37 return (
38 <div
39 className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
40 role="dialog"
41 aria-modal="true"
42 aria-label={`${plugin.displayName} settings`}
43 >
44 <div className="w-full max-w-md rounded-lg border border-border bg-card p-6 shadow-lg">
45 <div className="mb-4 flex items-center justify-between">
46 <h2 className="text-lg font-semibold text-foreground">{plugin.displayName} Settings</h2>
47 <button
48 type="button"
49 onClick={onClose}
50 className="rounded-md p-1 text-muted-foreground transition-colors hover:text-foreground"
51 aria-label="Close settings"
52 >
53 <X size={18} aria-hidden="true" />
54 </button>
55 </div>
56
57 <div className="space-y-4">
58 {Object.entries(plugin.settingsSchema ?? {}).map(([key, schema]) => (
59 <SettingsField
60 key={key}
61 fieldKey={key}
62 schema={schema}
63 value={values[key] ?? schema.default}
64 onChange={(val) => handleChange(key, val)}
65 />
66 ))}
67
68 <div className="flex justify-end gap-2 pt-2">
69 <button
70 type="button"
71 onClick={onClose}
72 className="rounded-md border border-border px-3 py-1.5 text-sm text-foreground transition-colors hover:bg-muted"
73 >
74 Cancel
75 </button>
76 <SaveButton
77 status={saveStatus}
78 onClick={() => onSave(values)}
79 className="px-3 py-1.5"
80 />
81 </div>
82 </div>
83 </div>
84 </div>
85 )
86}