diff --git a/client/src/components/modals/SettingsModal.tsx b/client/src/components/modals/SettingsModal.tsx index c44e784..505724c 100644 --- a/client/src/components/modals/SettingsModal.tsx +++ b/client/src/components/modals/SettingsModal.tsx @@ -21,6 +21,7 @@ export default function SettingsModal({ isOpen, onClose, onSave }: Readonly(null); const styleThemeRef = useRef(null); const showButterfliesRef = useRef(null); + const autoOrderChoiceRef = useRef(null); const reminderTimeRef = useRef(null); const boltDeliveredRef = useRef(null); @@ -83,6 +84,9 @@ export default function SettingsModal({ isOpen, onClose, onSave }: Readonly + + + + Po založení skupinové objednávky nebo připojení k existující se vaše dnešní volba stravování přepne na "Budu objednávat". Volba Pizza day zůstane beze změny. + +
diff --git a/client/src/context/settings.tsx b/client/src/context/settings.tsx index d1a4bc5..0ffff62 100644 --- a/client/src/context/settings.tsx +++ b/client/src/context/settings.tsx @@ -8,6 +8,7 @@ const ACCENT_HUE_KEY = 'accent_hue'; const LEGACY_COLOR_THEME_KEY = 'color_theme'; const STYLE_THEME_KEY = 'style_theme'; const SHOW_BUTTERFLIES_KEY = 'show_butterflies'; +const AUTO_ORDER_CHOICE_KEY = 'auto_order_choice'; export type ThemePreference = 'system' | 'light' | 'dark'; @@ -32,6 +33,7 @@ export type SettingsContextProps = { effectiveDark: boolean, styleTheme: StyleTheme, showButterflies: boolean, + autoOrderChoice: boolean, setBankAccountNumber: (accountNumber?: string) => void, setBankAccountHolderName: (holderName?: string) => void, setHideSoupsOption: (hideSoups?: boolean) => void, @@ -39,6 +41,7 @@ export type SettingsContextProps = { setAccentHue: (hue: number) => void, setStyleTheme: (theme: StyleTheme) => void, setShowButterflies: (show: boolean) => void, + setAutoOrderChoice: (enabled: boolean) => void, } type ContextProps = { @@ -90,6 +93,15 @@ function getInitialShowButterflies(): boolean { return true; } +function getInitialAutoOrderChoice(): boolean { + try { + return localStorage.getItem(AUTO_ORDER_CHOICE_KEY) === 'true'; + } catch { + // localStorage nedostupný + } + return false; +} + function getInitialAccentHue(): number { try { const saved = localStorage.getItem(ACCENT_HUE_KEY); @@ -158,6 +170,7 @@ function useProvideSettings(): SettingsContextProps { const [accentHue, setHue] = useState(getInitialAccentHue); const [styleTheme, setStyle] = useState(getInitialStyleTheme); const [showButterflies, setShowButterfliesState] = useState(getInitialShowButterflies); + const [autoOrderChoice, setAutoOrderChoiceState] = useState(getInitialAutoOrderChoice); const [effectiveDark, setEffectiveDark] = useState(() => { try { const pref = localStorage.getItem(THEME_KEY) as ThemePreference | null; @@ -235,6 +248,10 @@ function useProvideSettings(): SettingsContextProps { localStorage.setItem(SHOW_BUTTERFLIES_KEY, showButterflies ? 'true' : 'false'); }, [showButterflies]); + useEffect(() => { + localStorage.setItem(AUTO_ORDER_CHOICE_KEY, autoOrderChoice ? 'true' : 'false'); + }, [autoOrderChoice]); + // Aplikuje accent barvy při změně hue nebo přepnutí světlý/tmavý. // Tematické styly (Umamusume, My Little Pony, Hell Girl, K-ON!, Bocchi the Rock!) mají vlastní pevnou paletu, accent barvu proto uplatňuje jen jednoduchý styl. useEffect(() => { @@ -274,6 +291,10 @@ function useProvideSettings(): SettingsContextProps { setShowButterfliesState(show); } + function setAutoOrderChoice(enabled: boolean) { + setAutoOrderChoiceState(enabled); + } + return { bankAccount, holderName, @@ -290,5 +311,7 @@ function useProvideSettings(): SettingsContextProps { setStyleTheme, showButterflies, setShowButterflies, + autoOrderChoice, + setAutoOrderChoice, } } diff --git a/client/src/pages/OrderGroupsPage.tsx b/client/src/pages/OrderGroupsPage.tsx index 15238e3..0f42456 100644 --- a/client/src/pages/OrderGroupsPage.tsx +++ b/client/src/pages/OrderGroupsPage.tsx @@ -7,8 +7,8 @@ import DatePicker, { registerLocale } from 'react-datepicker'; import { cs } from 'date-fns/locale'; import 'react-datepicker/dist/react-datepicker.css'; import { - ClientData, GroupState, MealSlot, OrderGroup, OrderGroupMember, PendingQr, TrackingProvider, - StoreMenuDish, getData, createGroup, deleteGroup, addGroupMember, removeGroupMember, updateGroupMember, setGroupState, updateGroupTimes, setTracking, getOrderDates, getStoreMenu, + ClientData, GroupState, LunchChoice, MealSlot, OrderGroup, OrderGroupMember, PendingQr, TrackingProvider, + StoreMenuDish, getData, createGroup, deleteGroup, addGroupMember, removeGroupMember, updateGroupMember, setGroupState, updateGroupTimes, setTracking, getOrderDates, getStoreMenu, addChoice, } from '../../../types'; import MenuHintCell from '../components/MenuHintCell'; import EaterBadge from '../components/EaterBadge'; @@ -261,6 +261,22 @@ export default function OrderGroupsPage() { return true; }; + /** + * Pokud to má uživatel zapnuté v nastavení, přepne jeho dnešní volbu stravování na "Budu objednávat". + * Volbu nemění, pokud již objednává, nebo je přihlášen na Pizza day (změnou by přišel o objednané pizzy). + */ + const switchChoiceToOrdering = async () => { + if (!settings?.autoOrderChoice || !auth?.login) return; + const lunch = await getData({ query: { slot: MealSlot.OBED } }); + const choices = lunch.data?.choices; + if (!choices) return; + if (auth.login in (choices[LunchChoice.OBJEDNAVAM] ?? {}) || auth.login in (choices[LunchChoice.PIZZA] ?? {})) return; + const result = await addChoice({ body: { locationKey: LunchChoice.OBJEDNAVAM, slot: MealSlot.OBED } }); + if (result.error) { + setPageError(`Nepodařilo se přepnout volbu stravování: ${(result.error as any).error || 'Nastala chyba'}`); + } + }; + const handleCreate = async () => { if (!newGroupName || !auth?.login) return; setCreating(true); @@ -271,13 +287,17 @@ export default function OrderGroupsPage() { if (ok) { setNewGroupName(''); setNewGroupUrl(''); + await switchChoiceToOrdering(); } setCreating(false); }; - const handleJoin = (groupId: string) => - refresh(() => addGroupMember({ body: { id: groupId } })); + const handleJoin = async (groupId: string) => { + if (await refresh(() => addGroupMember({ body: { id: groupId } }))) { + await switchChoiceToOrdering(); + } + }; const handleToggleLock = (group: OrderGroup) => { const next = group.state === GroupState.OPEN ? GroupState.LOCKED : GroupState.OPEN; diff --git a/server/changelogs/2026-10-19.json b/server/changelogs/2026-10-19.json new file mode 100644 index 0000000..2c3783d --- /dev/null +++ b/server/changelogs/2026-10-19.json @@ -0,0 +1,3 @@ +[ + "Nové nastavení: po založení skupinové objednávky nebo připojení k ní se vaše dnešní volba automaticky přepne na \"Budu objednávat\"" +]