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
; }`;
+
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" && }
;
}