Files
siprouter/ts_web/router.ts

65 lines
1.8 KiB
TypeScript

/**
* URL router for the SipRouter dashboard.
* Maps URL paths to views in dees-simple-appdash.
*/
const VIEWS = ['overview', 'calls', 'phone', 'routes', 'voicemail', 'ivr', 'contacts', 'providers', 'log'] as const;
type TViewSlug = (typeof VIEWS)[number];
class AppRouter {
private currentView: TViewSlug = 'overview';
private onNavigate: ((view: TViewSlug) => void) | null = null;
private suppressPush = false;
init(): void {
// Parse initial URL.
const path = location.pathname.replace(/^\/+/, '').split('/')[0] || 'overview';
if (VIEWS.includes(path as TViewSlug)) {
this.currentView = path as TViewSlug;
}
// Handle browser back/forward.
window.addEventListener('popstate', () => {
const p = location.pathname.replace(/^\/+/, '').split('/')[0] || 'overview';
if (VIEWS.includes(p as TViewSlug)) {
this.suppressPush = true;
this.navigateTo(p as TViewSlug);
this.suppressPush = false;
}
});
}
setNavigateHandler(handler: (view: TViewSlug) => void): void {
this.onNavigate = handler;
}
navigateTo(view: TViewSlug, skipCallback = false): void {
this.currentView = view;
if (!this.suppressPush) {
const url = `/${view}`;
if (location.pathname !== url) {
history.pushState(null, '', url);
}
}
if (!skipCallback) {
this.onNavigate?.(view);
}
}
/** Called when the user selects a tab in dees-simple-appdash. */
onViewSelect(viewName: string): void {
const slug = viewName.toLowerCase().replace(/\s+/g, '-');
const mapped = VIEWS.find((v) => v === slug || viewName.toLowerCase().startsWith(v));
if (mapped) {
this.navigateTo(mapped);
}
}
getCurrentView(): TViewSlug {
return this.currentView;
}
}
export const appRouter = new AppRouter();
export type { TViewSlug };