first commit
This commit is contained in:
154
src/features/settings/components/PreferencesForm.tsx
Normal file
154
src/features/settings/components/PreferencesForm.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
'use client';
|
||||
|
||||
import {useState} from 'react';
|
||||
import {VStack, HStack} from '@astryxdesign/core/Layout';
|
||||
import {FormLayout} from '@astryxdesign/core/FormLayout';
|
||||
import {Selector} from '@astryxdesign/core/Selector';
|
||||
import {Button} from '@astryxdesign/core/Button';
|
||||
import {Text} from '@astryxdesign/core/Text';
|
||||
import {useToast} from '@astryxdesign/core/Toast';
|
||||
import {StaticPanel} from '@/shared/components/patterns/PanelCard';
|
||||
import {useThemeMode} from '@/shared/providers/ThemeModeProvider';
|
||||
import type {ThemeMode} from '@/shared/theme/themeMode';
|
||||
|
||||
/** Theme mode is deliberately absent — it lives in ThemeModeProvider. */
|
||||
export interface SystemPreferences {
|
||||
currency: 'INR' | 'USD' | 'EUR' | 'GBP';
|
||||
language: 'en' | 'hi' | 'kn' | 'ta';
|
||||
dateFormat: 'DD/MM/YYYY' | 'MM/DD/YYYY' | 'YYYY-MM-DD';
|
||||
defaultLanding: '/dashboard' | '/stores' | '/lyts' | '/staff';
|
||||
}
|
||||
|
||||
const DEFAULT_PREFS: SystemPreferences = {
|
||||
currency: 'INR',
|
||||
language: 'en',
|
||||
dateFormat: 'DD/MM/YYYY',
|
||||
defaultLanding: '/dashboard',
|
||||
};
|
||||
|
||||
export function PreferencesForm() {
|
||||
const toast = useToast();
|
||||
/**
|
||||
* Theme is the one preference that does NOT go through the save cycle.
|
||||
* It repaints the workspace the instant it changes and persists itself to
|
||||
* the theme-mode cookie, so there is nothing left for Save to commit — and
|
||||
* a mode you can see but have not "saved" would be the confusing state.
|
||||
* The rest of the form is still mock local state.
|
||||
*/
|
||||
const {mode: themeMode, setMode: setThemeMode} = useThemeMode();
|
||||
const [prefs, setPrefs] = useState<SystemPreferences>(DEFAULT_PREFS);
|
||||
const [savedPrefs, setSavedPrefs] = useState<SystemPreferences>(DEFAULT_PREFS);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const set = <K extends keyof SystemPreferences>(
|
||||
key: K,
|
||||
val: SystemPreferences[K],
|
||||
) => setPrefs((p) => ({...p, [key]: val}));
|
||||
|
||||
const isDirty = JSON.stringify(prefs) !== JSON.stringify(savedPrefs);
|
||||
|
||||
const handleSave = () => {
|
||||
setIsSaving(true);
|
||||
setTimeout(() => {
|
||||
setSavedPrefs(prefs);
|
||||
setIsSaving(false);
|
||||
toast({body: 'Workspace preferences updated'});
|
||||
}, 400);
|
||||
};
|
||||
|
||||
return (
|
||||
<StaticPanel
|
||||
title="Workspace Display & Formatting Preferences"
|
||||
subtitle="Customize theme mode, reporting currency, language and default start screen."
|
||||
actions={
|
||||
<HStack gap={2} vAlign="center">
|
||||
{isDirty ? (
|
||||
<Text size="sm" color="secondary">
|
||||
Unsaved changes
|
||||
</Text>
|
||||
) : null}
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
label="Reset"
|
||||
isDisabled={!isDirty || isSaving}
|
||||
onClick={() => setPrefs(savedPrefs)}
|
||||
/>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
label="Save Preferences"
|
||||
isDisabled={!isDirty}
|
||||
isLoading={isSaving}
|
||||
onClick={handleSave}
|
||||
/>
|
||||
</HStack>
|
||||
}
|
||||
>
|
||||
<VStack gap={5}>
|
||||
<FormLayout direction="horizontal">
|
||||
<Selector
|
||||
label="Theme Interface Mode"
|
||||
value={themeMode}
|
||||
onChange={(v) => setThemeMode(v as ThemeMode)}
|
||||
options={[
|
||||
{label: 'Dark Mode (Monochrome Premium)', value: 'dark'},
|
||||
{label: 'Light Mode', value: 'light'},
|
||||
{label: 'System OS Preference', value: 'system'},
|
||||
]}
|
||||
/>
|
||||
<Selector
|
||||
label="Reporting Base Currency"
|
||||
value={prefs.currency}
|
||||
onChange={(v) => set('currency', v as SystemPreferences['currency'])}
|
||||
options={[
|
||||
{label: 'INR (₹ Indian Rupee)', value: 'INR'},
|
||||
{label: 'USD ($ US Dollar)', value: 'USD'},
|
||||
{label: 'EUR (€ Euro)', value: 'EUR'},
|
||||
{label: 'GBP (£ British Pound)', value: 'GBP'},
|
||||
]}
|
||||
/>
|
||||
</FormLayout>
|
||||
|
||||
<FormLayout direction="horizontal">
|
||||
<Selector
|
||||
label="Workspace Language"
|
||||
value={prefs.language}
|
||||
onChange={(v) => set('language', v as SystemPreferences['language'])}
|
||||
options={[
|
||||
{label: 'English (US & India)', value: 'en'},
|
||||
{label: 'Hindi (हिंदी)', value: 'hi'},
|
||||
{label: 'Kannada (ಕನ್ನಡ)', value: 'kn'},
|
||||
{label: 'Tamil (தமிழ்)', value: 'ta'},
|
||||
]}
|
||||
/>
|
||||
<Selector
|
||||
label="Date Formatting"
|
||||
value={prefs.dateFormat}
|
||||
onChange={(v) => set('dateFormat', v as SystemPreferences['dateFormat'])}
|
||||
options={[
|
||||
{label: 'DD/MM/YYYY (e.g. 05/08/2026)', value: 'DD/MM/YYYY'},
|
||||
{label: 'MM/DD/YYYY (e.g. 08/05/2026)', value: 'MM/DD/YYYY'},
|
||||
{label: 'YYYY-MM-DD (e.g. 2026-08-05)', value: 'YYYY-MM-DD'},
|
||||
]}
|
||||
/>
|
||||
</FormLayout>
|
||||
|
||||
<FormLayout direction="horizontal">
|
||||
<Selector
|
||||
label="Default Home Landing Module"
|
||||
value={prefs.defaultLanding}
|
||||
onChange={(v) => set('defaultLanding', v as SystemPreferences['defaultLanding'])}
|
||||
options={[
|
||||
{label: 'Dashboard Overview', value: '/dashboard'},
|
||||
{label: 'Store Locations', value: '/stores'},
|
||||
{label: 'Lyts & Rewards Catalogue', value: '/lyts'},
|
||||
{label: 'Staff Roster & Performance', value: '/staff'},
|
||||
]}
|
||||
/>
|
||||
</FormLayout>
|
||||
</VStack>
|
||||
</StaticPanel>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user