feat(web): TODO-001 kill switch maintenance banner + disable timer creation
This commit is contained in:
parent
8ca9e27532
commit
8bddbec43c
@ -1,34 +1,32 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { createContext, useContext, useEffect, useState } from 'react';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { AuthProvider } from '@/lib/auth-context';
|
||||
import { initTelemetry, trackPageView } from '@/lib/telemetry';
|
||||
import { initFeatureFlags } from '@/lib/feature-flags';
|
||||
import { initDiagnostics } from '@/lib/diagnostics';
|
||||
import { checkKillSwitch } from '@/lib/kill-switch';
|
||||
import { MaintenanceBanner } from '@/components/MaintenanceBanner';
|
||||
import { ToastProvider } from '@bytelyst/ui';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
const MaintenanceContext = createContext(false);
|
||||
|
||||
export function useMaintenanceMode(): boolean {
|
||||
return useContext(MaintenanceContext);
|
||||
}
|
||||
|
||||
export function Providers({ children }: { children: ReactNode }) {
|
||||
const pathname = usePathname();
|
||||
const [isMaintenanceMode, setIsMaintenanceMode] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
initTelemetry();
|
||||
initFeatureFlags();
|
||||
initDiagnostics();
|
||||
// TODO-001: Kill switch maintenance banner
|
||||
// Priority: medium | Phase: 0
|
||||
// When checkKillSwitch() returns disabled=true:
|
||||
// 1. Set a React state flag (e.g. `isMaintenanceMode`)
|
||||
// 2. Render a <MaintenanceBanner /> component at the top of the app
|
||||
// 3. Disable timer creation buttons (pass flag via context or prop)
|
||||
// 4. Use --cm-warning-* design tokens for the banner styling
|
||||
// File to create: web/src/components/MaintenanceBanner.tsx
|
||||
checkKillSwitch().then((disabled) => {
|
||||
if (disabled) {
|
||||
// TODO-001: Surface this in the UI (see instructions above)
|
||||
}
|
||||
setIsMaintenanceMode(disabled);
|
||||
});
|
||||
}, []);
|
||||
|
||||
@ -40,7 +38,12 @@ export function Providers({ children }: { children: ReactNode }) {
|
||||
|
||||
return (
|
||||
<AuthProvider>
|
||||
<ToastProvider>{children}</ToastProvider>
|
||||
<MaintenanceContext.Provider value={isMaintenanceMode}>
|
||||
<ToastProvider>
|
||||
{isMaintenanceMode && <MaintenanceBanner />}
|
||||
{children}
|
||||
</ToastProvider>
|
||||
</MaintenanceContext.Provider>
|
||||
</AuthProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import type { UrgencyLevel } from '@/lib/urgency';
|
||||
import { CASCADE_PRESET_LABELS } from '@/lib/cascade';
|
||||
import type { CascadePreset } from '@/lib/cascade';
|
||||
import { X, AlarmClock, Timer, Coffee, Sparkles, CalendarDays } from 'lucide-react';
|
||||
import { useMaintenanceMode } from '@/app/providers';
|
||||
import { BUILT_IN_CATEGORIES, getCategoryById } from '@/lib/categories';
|
||||
import { parseNaturalLanguage } from '@/lib/nl-parser';
|
||||
import type { ParseResult } from '@/lib/nl-parser';
|
||||
@ -21,6 +22,7 @@ interface CreateTimerModalProps {
|
||||
|
||||
export function CreateTimerModal({ isOpen, onClose }: CreateTimerModalProps) {
|
||||
const { addAlarm, addCountdown, addPomodoro, addEvent } = useTimerStore();
|
||||
const maintenanceMode = useMaintenanceMode();
|
||||
|
||||
const [tab, setTab] = useState<TabType>('countdown');
|
||||
const [nlInput, setNlInput] = useState('');
|
||||
@ -570,13 +572,14 @@ export function CreateTimerModal({ isOpen, onClose }: CreateTimerModalProps) {
|
||||
{/* Create button */}
|
||||
<button
|
||||
onClick={handleCreate}
|
||||
className="w-full py-3 rounded-xl text-sm font-semibold transition-colors cursor-pointer"
|
||||
disabled={maintenanceMode}
|
||||
className="w-full py-3 rounded-xl text-sm font-semibold transition-colors cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
style={{
|
||||
backgroundColor: 'var(--cm-accent)',
|
||||
color: 'var(--cm-white)',
|
||||
}}
|
||||
>
|
||||
Create {tab === 'pomodoro' ? 'Pomodoro' : tab === 'alarm' ? 'Alarm' : 'Countdown'}
|
||||
{maintenanceMode ? 'Timer creation disabled (maintenance)' : `Create ${tab === 'pomodoro' ? 'Pomodoro' : tab === 'alarm' ? 'Alarm' : 'Countdown'}`}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
25
web/src/components/MaintenanceBanner.tsx
Normal file
25
web/src/components/MaintenanceBanner.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
'use client';
|
||||
|
||||
import { AlertTriangle } from 'lucide-react';
|
||||
|
||||
interface MaintenanceBannerProps {
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export function MaintenanceBanner({ message }: MaintenanceBannerProps) {
|
||||
return (
|
||||
<div
|
||||
role="alert"
|
||||
aria-label="Maintenance mode active"
|
||||
className="w-full px-4 py-3 flex items-center justify-center gap-2 text-sm font-medium"
|
||||
style={{
|
||||
backgroundColor: 'var(--cm-important-15)',
|
||||
color: 'var(--cm-important)',
|
||||
borderBottom: '1px solid var(--cm-important)',
|
||||
}}
|
||||
>
|
||||
<AlertTriangle size={16} aria-hidden="true" />
|
||||
<span>{message || 'ChronoMind is currently in maintenance mode. Timer creation is temporarily disabled.'}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user