242f63ab26
- DB: 7 new user prefs (sound per slot, per-type toggles, vibration, mute, volume). - API: PATCH /auth/me/notification-preferences with whitelisted partial update, integer guard for volume, and hydrated AuthUser response. AuthUser now exposes the 7 new fields. - Frontend: Web Audio synth library (8 sounds), settings popover with global mute/vibration/volume/per-type toggles, slot tabs, sound preview buttons, shift+click on bell for quick mute. Concurrency-safe optimistic updates with monotonic seq counter. RTL-correct toggle knob transforms. - Socket hook plays sound on notification_created (orders/meetings only) when tab is hidden, respecting global mute and per-type toggles. - Audio unlock hook mounted globally to satisfy autoplay restrictions. - AR/EN translations added. Pre-existing TS errors in executive-meetings.ts (font_settings) and pre-existing test failures in test workflow are unrelated to this task.
78 lines
2.7 KiB
TypeScript
78 lines
2.7 KiB
TypeScript
import { Switch, Route, Router as WouterRouter } from "wouter";
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
import { Toaster } from "@/components/ui/toaster";
|
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
import { AuthProvider } from "@/contexts/AuthContext";
|
|
import { useNotificationsSocket } from "@/hooks/use-notifications-socket";
|
|
import { useAudioUnlock } from "@/hooks/use-audio-unlock";
|
|
import { UpcomingMeetingAlert } from "@/components/executive-meetings/upcoming-meeting-alert";
|
|
import NotFound from "@/pages/not-found";
|
|
import LoginPage from "@/pages/login";
|
|
import RegisterPage from "@/pages/register";
|
|
import ForgotPasswordPage from "@/pages/forgot-password";
|
|
import ResetPasswordPage from "@/pages/reset-password";
|
|
import HomePage from "@/pages/home";
|
|
import ServicesPage from "@/pages/services";
|
|
import ChatPage from "@/pages/chat";
|
|
import NotificationsPage from "@/pages/notifications";
|
|
import AdminPage from "@/pages/admin";
|
|
import NotesPage from "@/pages/notes";
|
|
import MyOrdersPage from "@/pages/my-orders";
|
|
import OrdersIncomingPage from "@/pages/orders-incoming";
|
|
import ExecutiveMeetingsPage from "@/pages/executive-meetings";
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: false,
|
|
staleTime: 30_000,
|
|
},
|
|
},
|
|
});
|
|
|
|
function NotificationsSocketBridge() {
|
|
useNotificationsSocket();
|
|
useAudioUnlock();
|
|
return null;
|
|
}
|
|
|
|
function Router() {
|
|
return (
|
|
<AuthProvider>
|
|
<NotificationsSocketBridge />
|
|
<UpcomingMeetingAlert />
|
|
<Switch>
|
|
<Route path="/login" component={LoginPage} />
|
|
<Route path="/register" component={RegisterPage} />
|
|
<Route path="/forgot-password" component={ForgotPasswordPage} />
|
|
<Route path="/reset-password" component={ResetPasswordPage} />
|
|
<Route path="/services" component={ServicesPage} />
|
|
<Route path="/chat" component={ChatPage} />
|
|
<Route path="/notifications" component={NotificationsPage} />
|
|
<Route path="/admin" component={AdminPage} />
|
|
<Route path="/notes" component={NotesPage} />
|
|
<Route path="/my-orders" component={MyOrdersPage} />
|
|
<Route path="/orders/incoming" component={OrdersIncomingPage} />
|
|
<Route path="/executive-meetings" component={ExecutiveMeetingsPage} />
|
|
<Route path="/" component={HomePage} />
|
|
<Route component={NotFound} />
|
|
</Switch>
|
|
</AuthProvider>
|
|
);
|
|
}
|
|
|
|
function App() {
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<TooltipProvider>
|
|
<WouterRouter base={import.meta.env.BASE_URL.replace(/\/$/, "")}>
|
|
<Router />
|
|
</WouterRouter>
|
|
<Toaster />
|
|
</TooltipProvider>
|
|
</QueryClientProvider>
|
|
);
|
|
}
|
|
|
|
export default App;
|