From 85483ee104c65377ea32cc123d8876028372bd22 Mon Sep 17 00:00:00 2001 From: B SIMAK AHMED Date: Sun, 27 Sep 2026 22:22:22 +0530 Subject: [PATCH] Update admin dashboard and build configuration --- scripts/ensure-admin-build.mjs | 88 +++++++++++++++++++++++------ src/routeTree.gen.ts | 21 +++++++ src/routes/_authenticated/admin.tsx | 4 ++ 3 files changed, 95 insertions(+), 18 deletions(-) diff --git a/scripts/ensure-admin-build.mjs b/scripts/ensure-admin-build.mjs index 712b847..16af64f 100644 --- a/scripts/ensure-admin-build.mjs +++ b/scripts/ensure-admin-build.mjs @@ -1,13 +1,17 @@ + import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const file = path.join(root, "src", "routes", "_authenticated", "admin.tsx"); + let source = fs.readFileSync(file, "utf8"); +const newline = source.includes("\r\n") ? "\r\n" : "\n"; // Keep the existing production build guard for the historical duplicate Metric. const duplicate = `\nfunction Metric({ label, value }: { label: string; value: number }) { return
{label}
{value}
; }`; + const count = source.split(duplicate).length - 1; if (count === 2) { @@ -21,34 +25,82 @@ if (count === 2) { throw new Error(`Unexpected Metric declaration count: ${count}`); } -// The Admin Control Center remains in the existing route file. This idempotent -// preparation step wires the Devices panel into that route for both dev and build. -const devicesImport = 'import { DevicesPanel } from "@/components/DevicesPanel";'; +// The Admin Control Center remains in the existing route file. +// This idempotent preparation step wires the Devices panel into that route +// for both development and production builds. + +const devicesImport = + 'import { DevicesPanel } from "@/components/DevicesPanel";'; + if (!source.includes(devicesImport)) { - const anchor = 'import { SecurityTab } from "@/components/SecurityTab";'; - if (!source.includes(anchor)) throw new Error("Admin SecurityTab import anchor not found"); - source = source.replace(anchor, `${anchor}\n${devicesImport}`); + const anchor = + 'import { SecurityTab } from "@/components/SecurityTab";'; + + if (!source.includes(anchor)) { + throw new Error("Admin SecurityTab import anchor not found"); + } + + source = source.replace( + anchor, + `${anchor}${newline}${devicesImport}` + ); } +// Add the Devices navigation item. const devicesNav = '["devices", "Devices", Monitor],'; + if (!source.includes(devicesNav)) { - const anchor = '["export", "Export", Download], ["trash", "Trash / Recovery", Archive], ["profile", "Admin Profile", Users],'; - if (!source.includes(anchor)) throw new Error("Admin navigation anchor not found"); - source = source.replace(anchor, `${anchor}\n ${devicesNav}`); + const anchor = + '["export", "Export", Download], ["trash", "Trash / Recovery", Archive], ["profile", "Admin Profile", Users],'; + + if (!source.includes(anchor)) { + throw new Error("Admin navigation anchor not found"); + } + + source = source.replace( + anchor, + `${anchor}${newline} ${devicesNav}` + ); } -if (source.includes(devicesNav) && !source.includes(" Monitor,")) { - const anchor = " MessageCircle,\n"; - if (!source.includes(anchor)) throw new Error("Admin lucide import anchor not found"); - source = source.replace(anchor, `${anchor} Monitor,\n`); +// Ensure Monitor is imported from lucide-react. +// Match the MessageCircle import regardless of line-ending format. +if ( + source.includes(devicesNav) && + !/^[ \t]*Monitor,[ \t]*$/m.test(source) +) { + const anchor = /^([ \t]*)MessageCircle,[ \t]*$/m; + + if (!anchor.test(source)) { + throw new Error("Admin lucide import anchor not found"); + } + + source = source.replace( + anchor, + (line, indentation) => + `${line}${newline}${indentation}Monitor,` + ); } -const devicesRender = '{tab === "devices" && }'; +// Render the Devices panel when its navigation tab is selected. +const devicesRender = + '{tab === "devices" && }'; + if (!source.includes(devicesRender)) { - const anchor = '{tab === "profile" && }'; - if (!source.includes(anchor)) throw new Error("Admin panel render anchor not found"); - source = source.replace(anchor, `${anchor}\n ${devicesRender}`); + const anchor = + '{tab === "profile" && }'; + + if (!source.includes(anchor)) { + throw new Error("Admin panel render anchor not found"); + } + + source = source.replace( + anchor, + `${anchor}${newline} ${devicesRender}` + ); } +// Write the updated Admin route. fs.writeFileSync(file, source, "utf8"); -console.log("Admin Devices integration: ready"); + +console.log("Admin Devices integration: ready"); \ No newline at end of file diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 44e6400..84c7590 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -11,6 +11,7 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as ThankYouRouteImport } from './routes/thank-you' import { Route as TermsRouteImport } from './routes/terms' +import { Route as ResumeAccessRouteImport } from './routes/resume-access' import { Route as ResetPasswordRouteImport } from './routes/reset-password' import { Route as ProjectsRouteImport } from './routes/projects' import { Route as PrivacyPolicyRouteImport } from './routes/privacy-policy' @@ -39,6 +40,11 @@ const TermsRoute = TermsRouteImport.update({ path: '/terms', getParentRoute: () => rootRouteImport, } as any) +const ResumeAccessRoute = ResumeAccessRouteImport.update({ + id: '/resume-access', + path: '/resume-access', + getParentRoute: () => rootRouteImport, +} as any) const ResetPasswordRoute = ResetPasswordRouteImport.update({ id: '/reset-password', path: '/reset-password', @@ -138,6 +144,7 @@ export interface FileRoutesByFullPath { '/privacy-policy': typeof PrivacyPolicyRoute '/projects': typeof ProjectsRoute '/reset-password': typeof ResetPasswordRoute + '/resume-access': typeof ResumeAccessRoute '/terms': typeof TermsRoute '/thank-you': typeof ThankYouRoute '/admin': typeof AuthenticatedAdminRoute @@ -158,6 +165,7 @@ export interface FileRoutesByTo { '/privacy-policy': typeof PrivacyPolicyRoute '/projects': typeof ProjectsRoute '/reset-password': typeof ResetPasswordRoute + '/resume-access': typeof ResumeAccessRoute '/terms': typeof TermsRoute '/thank-you': typeof ThankYouRoute '/admin': typeof AuthenticatedAdminRoute @@ -180,6 +188,7 @@ export interface FileRoutesById { '/privacy-policy': typeof PrivacyPolicyRoute '/projects': typeof ProjectsRoute '/reset-password': typeof ResetPasswordRoute + '/resume-access': typeof ResumeAccessRoute '/terms': typeof TermsRoute '/thank-you': typeof ThankYouRoute '/_authenticated/admin': typeof AuthenticatedAdminRoute @@ -202,6 +211,7 @@ export interface FileRouteTypes { | '/privacy-policy' | '/projects' | '/reset-password' + | '/resume-access' | '/terms' | '/thank-you' | '/admin' @@ -222,6 +232,7 @@ export interface FileRouteTypes { | '/privacy-policy' | '/projects' | '/reset-password' + | '/resume-access' | '/terms' | '/thank-you' | '/admin' @@ -243,6 +254,7 @@ export interface FileRouteTypes { | '/privacy-policy' | '/projects' | '/reset-password' + | '/resume-access' | '/terms' | '/thank-you' | '/_authenticated/admin' @@ -265,6 +277,7 @@ export interface RootRouteChildren { PrivacyPolicyRoute: typeof PrivacyPolicyRoute ProjectsRoute: typeof ProjectsRoute ResetPasswordRoute: typeof ResetPasswordRoute + ResumeAccessRoute: typeof ResumeAccessRoute TermsRoute: typeof TermsRoute ThankYouRoute: typeof ThankYouRoute BlogsSlugRoute: typeof BlogsSlugRoute @@ -286,6 +299,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof TermsRouteImport parentRoute: typeof rootRouteImport } + '/resume-access': { + id: '/resume-access' + path: '/resume-access' + fullPath: '/resume-access' + preLoaderRoute: typeof ResumeAccessRouteImport + parentRoute: typeof rootRouteImport + } '/reset-password': { id: '/reset-password' path: '/reset-password' @@ -450,6 +470,7 @@ const rootRouteChildren: RootRouteChildren = { PrivacyPolicyRoute: PrivacyPolicyRoute, ProjectsRoute: ProjectsRoute, ResetPasswordRoute: ResetPasswordRoute, + ResumeAccessRoute: ResumeAccessRoute, TermsRoute: TermsRoute, ThankYouRoute: ThankYouRoute, BlogsSlugRoute: BlogsSlugRoute, diff --git a/src/routes/_authenticated/admin.tsx b/src/routes/_authenticated/admin.tsx index 4f34f09..40aac54 100644 --- a/src/routes/_authenticated/admin.tsx +++ b/src/routes/_authenticated/admin.tsx @@ -20,6 +20,7 @@ import { LayoutDashboard, Mail, MessageCircle, + Monitor, Paperclip, Pencil, Plus, @@ -41,6 +42,7 @@ import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { PostEditor, type PostDraft } from "@/components/PostEditor"; import { SecurityTab } from "@/components/SecurityTab"; +import { DevicesPanel } from "@/components/DevicesPanel"; import { getAdminAuditEntries, recordAdminAudit } from "@/lib/admin-audit"; import { useAuth } from "@/hooks/use-auth"; import { toast } from "sonner"; @@ -89,6 +91,7 @@ const navItems = [ ["security", "Security", ShieldCheck], ["activity", "Audit / Activity", Activity], ["analytics", "Analytics", BarChart3], ["comments", "Comments", MessageCircle], ["engagement", "Engagement", ClipboardList], ["bookmarks", "Bookmarks", BookOpen], ["search", "Global Search", Search], ["health", "System Health", RefreshCw], ["export", "Export", Download], ["trash", "Trash / Recovery", Archive], ["profile", "Admin Profile", Users], + ["devices", "Devices", Monitor], ] as const; type AdminTab = (typeof navItems)[number][0]; @@ -133,6 +136,7 @@ function Admin() { {tab === "export" && } {tab === "trash" && } {tab === "profile" && } + {tab === "devices" && } ; }