Move business logic out of App Router into module packages, add boundary validation scripts, and keep all routes as thin re-exports without changing URLs or API behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
247 lines
12 KiB
JavaScript
247 lines
12 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Generates thin page.tsx route files for healthcare portals.
|
|
* Run: node scripts/generate-healthcare-routes.mjs
|
|
*/
|
|
import fs from "fs";
|
|
import path from "path";
|
|
import { fileURLToPath } from "url";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const appDir = path.join(__dirname, "..", "app", "healthcare");
|
|
|
|
function write(filePath, content) {
|
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
fs.writeFileSync(filePath, content, "utf8");
|
|
}
|
|
|
|
function pageImport(exportName, modulePath) {
|
|
return `"use client";
|
|
|
|
export { ${exportName} as default } from "${modulePath}";
|
|
`;
|
|
}
|
|
|
|
function layoutImport(portalId) {
|
|
return `"use client";
|
|
|
|
import { createPortalLayout } from "@/components/healthcare/createPortalLayout";
|
|
|
|
export default createPortalLayout("${portalId}");
|
|
`;
|
|
}
|
|
|
|
const portals = [
|
|
["patient", "patient"],
|
|
["doctor", "doctor"],
|
|
["reception", "reception"],
|
|
["clinic", "clinic"],
|
|
["hospital", "hospital"],
|
|
["pharmacy-portal", "pharmacy"],
|
|
["admin", "admin"],
|
|
];
|
|
|
|
for (const [dir, portalId] of portals) {
|
|
write(path.join(appDir, dir, "layout.tsx"), layoutImport(portalId));
|
|
}
|
|
|
|
const routes = {
|
|
patient: {
|
|
"page.tsx": ["PatientDashboard", "@/components/healthcare/pages/patient"],
|
|
"appointments/upcoming/page.tsx": ["PatientAppointmentsUpcoming", "@/components/healthcare/pages/patient"],
|
|
"appointments/past/page.tsx": ["PatientAppointmentsPast", "@/components/healthcare/pages/patient"],
|
|
"appointments/book/page.tsx": ["PatientAppointmentsBook", "@/components/healthcare/pages/patient"],
|
|
"medical-history/page.tsx": ["PatientMedicalHistory", "@/components/healthcare/pages/patient"],
|
|
"prescriptions/page.tsx": ["PatientPrescriptions", "@/components/healthcare/pages/patient"],
|
|
"lab-results/page.tsx": ["PatientLabResults", "@/components/healthcare/pages/patient"],
|
|
"invoices/page.tsx": ["PatientInvoices", "@/components/healthcare/pages/patient"],
|
|
"payments/page.tsx": ["PatientPayments", "@/components/healthcare/pages/patient"],
|
|
"profile/page.tsx": ["PatientProfile", "@/components/healthcare/pages/patient"],
|
|
"family/page.tsx": ["PatientFamily", "@/components/healthcare/pages/patient"],
|
|
"notifications/page.tsx": ["PatientNotifications", "@/components/healthcare/pages/patient"],
|
|
"messages/page.tsx": ["PatientMessages", "@/components/healthcare/pages/patient"],
|
|
"favorites/page.tsx": ["PatientFavorites", "@/components/healthcare/pages/patient"],
|
|
"reviews/page.tsx": ["PatientReviews", "@/components/healthcare/pages/patient"],
|
|
"settings/page.tsx": ["PatientSettings", "@/components/healthcare/pages/patient"],
|
|
},
|
|
doctor: {
|
|
"page.tsx": ["DoctorDashboard", "@/components/healthcare/pages/doctor"],
|
|
"schedule/today/page.tsx": ["DoctorScheduleToday", "@/components/healthcare/pages/doctor"],
|
|
"schedule/calendar/page.tsx": ["DoctorScheduleCalendar", "@/components/healthcare/pages/doctor"],
|
|
"availability/page.tsx": ["DoctorAvailability", "@/components/healthcare/pages/doctor"],
|
|
"leaves/page.tsx": ["DoctorLeaves", "@/components/healthcare/pages/doctor"],
|
|
"appointments/page.tsx": ["DoctorAppointments", "@/components/healthcare/pages/doctor"],
|
|
"patients/page.tsx": ["DoctorPatients", "@/components/healthcare/pages/doctor"],
|
|
"medical-records/page.tsx": ["DoctorMedicalRecords", "@/components/healthcare/pages/doctor"],
|
|
"prescriptions/page.tsx": ["DoctorPrescriptions", "@/components/healthcare/pages/doctor"],
|
|
"reports/page.tsx": ["DoctorReports", "@/components/healthcare/pages/doctor"],
|
|
"analytics/page.tsx": ["DoctorAnalytics", "@/components/healthcare/pages/doctor"],
|
|
"income/page.tsx": ["DoctorIncome", "@/components/healthcare/pages/doctor"],
|
|
"notifications/page.tsx": ["DoctorNotifications", "@/components/healthcare/pages/doctor"],
|
|
"messages/page.tsx": ["DoctorMessages", "@/components/healthcare/pages/doctor"],
|
|
"settings/page.tsx": ["DoctorSettings", "@/components/healthcare/pages/doctor"],
|
|
},
|
|
reception: {
|
|
"page.tsx": ["ReceptionDashboard", "@/components/healthcare/pages/reception"],
|
|
"queue/page.tsx": ["ReceptionQueue", "@/components/healthcare/pages/reception"],
|
|
"walk-in/page.tsx": ["ReceptionWalkIn", "@/components/healthcare/pages/reception"],
|
|
"calendar/page.tsx": ["ReceptionCalendar", "@/components/healthcare/pages/reception"],
|
|
"doctors/page.tsx": ["ReceptionDoctors", "@/components/healthcare/pages/reception"],
|
|
"patients/page.tsx": ["ReceptionPatients", "@/components/healthcare/pages/reception"],
|
|
"check-in/page.tsx": ["ReceptionCheckIn", "@/components/healthcare/pages/reception"],
|
|
"check-out/page.tsx": ["ReceptionCheckOut", "@/components/healthcare/pages/reception"],
|
|
"payments/page.tsx": ["ReceptionPayments", "@/components/healthcare/pages/reception"],
|
|
"reports/page.tsx": ["ReceptionReports", "@/components/healthcare/pages/reception"],
|
|
},
|
|
clinic: {
|
|
"page.tsx": ["ClinicDashboard", "@/components/healthcare/pages/clinic"],
|
|
"doctors/page.tsx": ["ClinicDoctors", "@/components/healthcare/pages/clinic"],
|
|
"receptionists/page.tsx": ["ClinicReceptionists", "@/components/healthcare/pages/clinic"],
|
|
"departments/page.tsx": ["ClinicDepartments", "@/components/healthcare/pages/clinic"],
|
|
"rooms/page.tsx": ["ClinicRooms", "@/components/healthcare/pages/clinic"],
|
|
"schedules/page.tsx": ["ClinicSchedules", "@/components/healthcare/pages/clinic"],
|
|
"resources/page.tsx": ["ClinicResources", "@/components/healthcare/pages/clinic"],
|
|
"patients/page.tsx": ["ClinicPatients", "@/components/healthcare/pages/clinic"],
|
|
"reports/page.tsx": ["ClinicReports", "@/components/healthcare/pages/clinic"],
|
|
"crm-integration/page.tsx": ["ClinicCrmIntegration", "@/components/healthcare/pages/clinic"],
|
|
"accounting-integration/page.tsx": ["ClinicAccountingIntegration", "@/components/healthcare/pages/clinic"],
|
|
},
|
|
hospital: {
|
|
"page.tsx": ["HospitalDashboard", "@/components/healthcare/pages/hospital"],
|
|
"departments/page.tsx": ["HospitalDepartments", "@/components/healthcare/pages/hospital"],
|
|
"doctors/page.tsx": ["HospitalDoctors", "@/components/healthcare/pages/hospital"],
|
|
"beds/page.tsx": ["HospitalBeds", "@/components/healthcare/pages/hospital"],
|
|
"clinics/page.tsx": ["HospitalClinics", "@/components/healthcare/pages/hospital"],
|
|
"appointments/page.tsx": ["HospitalAppointments", "@/components/healthcare/pages/hospital"],
|
|
"staff/page.tsx": ["HospitalStaff", "@/components/healthcare/pages/hospital"],
|
|
"resources/page.tsx": ["HospitalResources", "@/components/healthcare/pages/hospital"],
|
|
"reports/page.tsx": ["HospitalReports", "@/components/healthcare/pages/hospital"],
|
|
},
|
|
"pharmacy-portal": {
|
|
"page.tsx": ["PharmacyDashboard", "@/components/healthcare/pages/pharmacy"],
|
|
"incoming/page.tsx": ["PharmacyIncoming", "@/components/healthcare/pages/pharmacy"],
|
|
"preparation/page.tsx": ["PharmacyPreparation", "@/components/healthcare/pages/pharmacy"],
|
|
"ready/page.tsx": ["PharmacyReady", "@/components/healthcare/pages/pharmacy"],
|
|
"delivered/page.tsx": ["PharmacyDelivered", "@/components/healthcare/pages/pharmacy"],
|
|
"delivery/page.tsx": ["PharmacyDelivery", "@/components/healthcare/pages/pharmacy"],
|
|
"reports/page.tsx": ["PharmacyReports", "@/components/healthcare/pages/pharmacy"],
|
|
},
|
|
admin: {
|
|
"page.tsx": ["AdminDashboard", "@/components/healthcare/pages/admin"],
|
|
"organizations/page.tsx": ["AdminOrganizations", "@/components/healthcare/pages/admin"],
|
|
"clinics/page.tsx": ["AdminClinics", "@/components/healthcare/pages/admin"],
|
|
"doctors/page.tsx": ["AdminDoctors", "@/components/healthcare/pages/admin"],
|
|
"patients/page.tsx": ["AdminPatients", "@/components/healthcare/pages/admin"],
|
|
"pharmacies/page.tsx": ["AdminPharmacies", "@/components/healthcare/pages/admin"],
|
|
"users/page.tsx": ["AdminUsers", "@/components/healthcare/pages/admin"],
|
|
"permissions/page.tsx": ["AdminPermissions", "@/components/healthcare/pages/admin"],
|
|
"reports/page.tsx": ["AdminReports", "@/components/healthcare/pages/admin"],
|
|
"analytics/page.tsx": ["AdminAnalytics", "@/components/healthcare/pages/admin"],
|
|
"logs/page.tsx": ["AdminLogs", "@/components/healthcare/pages/admin"],
|
|
"monitoring/page.tsx": ["AdminMonitoring", "@/components/healthcare/pages/admin"],
|
|
"settings/page.tsx": ["AdminSettings", "@/components/healthcare/pages/admin"],
|
|
},
|
|
site: {
|
|
"layout.tsx": null,
|
|
"page.tsx": ["PublicHome", "@/components/healthcare/pages/public"],
|
|
"features/page.tsx": ["PublicFeatures", "@/components/healthcare/pages/public"],
|
|
"pricing/page.tsx": ["PublicPricing", "@/components/healthcare/pages/public"],
|
|
"faq/page.tsx": ["PublicFaq", "@/components/healthcare/pages/public"],
|
|
"about/page.tsx": ["PublicAbout", "@/components/healthcare/pages/public"],
|
|
"contact/page.tsx": ["PublicContact", "@/components/healthcare/pages/public"],
|
|
"find-doctor/page.tsx": ["PublicFindDoctor", "@/components/healthcare/pages/public"],
|
|
"find-clinic/page.tsx": ["PublicFindClinic", "@/components/healthcare/pages/public"],
|
|
"find-hospital/page.tsx": ["PublicFindHospital", "@/components/healthcare/pages/public"],
|
|
"search/page.tsx": ["PublicSearch", "@/components/healthcare/pages/public"],
|
|
"doctor/[id]/page.tsx": ["PublicDoctorProfile", "@/components/healthcare/pages/public"],
|
|
"clinic/[id]/page.tsx": ["PublicClinicProfile", "@/components/healthcare/pages/public"],
|
|
"hospital/[id]/page.tsx": ["PublicHospitalProfile", "@/components/healthcare/pages/public"],
|
|
"book/page.tsx": ["PublicBook", "@/components/healthcare/pages/public"],
|
|
"book/success/page.tsx": ["PublicBookSuccess", "@/components/healthcare/pages/public"],
|
|
"tracking/[id]/page.tsx": ["PublicTracking", "@/components/healthcare/pages/public"],
|
|
},
|
|
hub: {
|
|
"page.tsx": ["HealthcareHub", "@/components/healthcare/pages/hub"],
|
|
},
|
|
auth: {
|
|
"login/page.tsx": ["HealthcareAuthLogin", "@/components/healthcare/pages/hub"],
|
|
},
|
|
mobile: {
|
|
"[portal]/page.tsx": ["HealthcareMobilePortal", "@/components/healthcare/pages/hub"],
|
|
},
|
|
};
|
|
|
|
write(
|
|
path.join(appDir, "site", "layout.tsx"),
|
|
`import { PublicHealthcareLayout } from "@/components/healthcare/PublicHealthcareLayout";
|
|
|
|
export default function SiteLayout({ children }: { children: React.ReactNode }) {
|
|
return <PublicHealthcareLayout>{children}</PublicHealthcareLayout>;
|
|
}
|
|
`
|
|
);
|
|
|
|
for (const [portal, files] of Object.entries(routes)) {
|
|
for (const [rel, spec] of Object.entries(files)) {
|
|
if (spec === null) continue;
|
|
const [exportName, mod] = spec;
|
|
write(path.join(appDir, portal, rel), pageImport(exportName, mod));
|
|
}
|
|
}
|
|
|
|
write(
|
|
path.join(appDir, "page.tsx"),
|
|
`"use client";
|
|
|
|
import { useEffect } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { LoadingState } from "@/components/ds";
|
|
|
|
export default function HealthcareRootRedirect() {
|
|
const router = useRouter();
|
|
useEffect(() => {
|
|
router.replace("/healthcare/hub");
|
|
}, [router]);
|
|
return <LoadingState label="در حال انتقال…" />;
|
|
}
|
|
`
|
|
);
|
|
|
|
const legacyRedirects = {
|
|
clinics: "/healthcare/admin/clinics",
|
|
doctors: "/healthcare/admin/doctors",
|
|
patients: "/healthcare/admin/patients",
|
|
departments: "/healthcare/clinic/departments",
|
|
branches: "/healthcare/hospital/clinics",
|
|
appointments: "/healthcare/reception/calendar",
|
|
settings: "/healthcare/admin/settings",
|
|
"medical-records": "/healthcare/doctor/medical-records",
|
|
"doctor-panel": "/healthcare/doctor",
|
|
"patient-portal": "/healthcare/patient",
|
|
"clinic-management": "/healthcare/clinic",
|
|
pharmacy: "/healthcare/pharmacy-portal",
|
|
delivery: "/healthcare/pharmacy-portal/delivery",
|
|
};
|
|
|
|
for (const [legacy, target] of Object.entries(legacyRedirects)) {
|
|
write(
|
|
path.join(appDir, legacy, "page.tsx"),
|
|
`"use client";
|
|
|
|
import { useEffect } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { LoadingState } from "@/components/ds";
|
|
|
|
export default function LegacyRedirect() {
|
|
const router = useRouter();
|
|
useEffect(() => {
|
|
router.replace("${target}");
|
|
}, [router]);
|
|
return <LoadingState label="در حال انتقال…" />;
|
|
}
|
|
`
|
|
);
|
|
}
|
|
|
|
console.log("Generated healthcare routes.");
|