diff --git a/web/src/app/providers.tsx b/web/src/app/providers.tsx
index d0ab2d2..354da37 100644
--- a/web/src/app/providers.tsx
+++ b/web/src/app/providers.tsx
@@ -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 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 (
- {children}
+
+
+ {isMaintenanceMode && }
+ {children}
+
+
);
}
diff --git a/web/src/components/CreateTimerModal.tsx b/web/src/components/CreateTimerModal.tsx
index 45ac2af..eec61d6 100644
--- a/web/src/components/CreateTimerModal.tsx
+++ b/web/src/components/CreateTimerModal.tsx
@@ -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('countdown');
const [nlInput, setNlInput] = useState('');
@@ -570,13 +572,14 @@ export function CreateTimerModal({ isOpen, onClose }: CreateTimerModalProps) {
{/* Create button */}
diff --git a/web/src/components/MaintenanceBanner.tsx b/web/src/components/MaintenanceBanner.tsx
new file mode 100644
index 0000000..4d46e60
--- /dev/null
+++ b/web/src/components/MaintenanceBanner.tsx
@@ -0,0 +1,25 @@
+'use client';
+
+import { AlertTriangle } from 'lucide-react';
+
+interface MaintenanceBannerProps {
+ message?: string;
+}
+
+export function MaintenanceBanner({ message }: MaintenanceBannerProps) {
+ return (
+
+
+
{message || 'ChronoMind is currently in maintenance mode. Timer creation is temporarily disabled.'}
+
+ );
+}