Files
carmanagement/validate-phase16-design.mjs
root d7fb7b7a7b
Build & Deploy / Build & Push Docker Image (push) Failing after 47s
Build & Deploy / Deploy to VPS (push) Has been skipped
Test / API Unit Tests (push) Failing after 5m4s
Test / Marketplace Unit Tests (push) Failing after 4m55s
Test / Admin Unit Tests (push) Successful in 9m37s
Test / Dashboard Unit Tests (push) Successful in 9m37s
Test / API Integration Tests (push) Successful in 9m54s
redesign the homepage
2026-06-26 16:27:21 -04:00

120 lines
4.9 KiB
JavaScript

import { readFile, readdir, stat } from 'node:fs/promises';
import path from 'node:path';
import process from 'node:process';
import { fileURLToPath } from 'node:url';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const errors = [];
async function exists(target) {
try { await stat(target); return true; } catch { return false; }
}
async function walk(directory) {
const files = [];
for (const entry of await readdir(directory, { withFileTypes: true })) {
if (['node_modules', '.next', '.turbo', 'dist', 'coverage'].includes(entry.name)) continue;
const target = path.join(directory, entry.name);
if (entry.isDirectory()) files.push(...(await walk(target)));
else files.push(target);
}
return files;
}
function requireText(contents, required, label) {
for (const marker of required) {
if (!contents.includes(marker)) errors.push(`${label}: missing ${marker}`);
}
}
for (const app of ['admin', 'api', 'dashboard', 'homepage', 'storefront']) {
if (!(await exists(path.join(root, app)))) errors.push(`missing application directory: ${app}`);
if (!(await exists(path.join(root, app, 'package.json')))) errors.push(`${app}: missing package.json`);
}
for (const app of ['admin', 'dashboard']) {
const tokenPath = path.join(root, app, 'src/styles/phase16-tokens.css');
const globalsPath = path.join(root, app, 'src/app/globals.css');
if (!(await exists(tokenPath))) errors.push(`${app}: missing Phase 16 token file`);
if (!(await exists(globalsPath))) errors.push(`${app}: missing globals.css`);
const tokens = await readFile(tokenPath, 'utf8');
requireText(tokens, [
'--rdg-blue-700', '--rdg-orange-600', '--rdg-sidebar-size',
'--rdg-header-size', '--rdg-radius-lg', '--rdg-shadow-card',
], `${app} tokens`);
const globals = await readFile(globalsPath, 'utf8');
requireText(globals, [
'phase16-tokens.css', '.rdg-app-shell', '.rdg-sidebar', '.rdg-topbar',
'.rdg-page-hero', '.rdg-page-heading', '.btn-primary', '.btn-conversion',
'.panel', '.field', '@media (forced-colors: active)',
], `${app} globals`);
const withoutComments = globals.replace(/\/\*[\s\S]*?\*\//g, '');
const balance = [...withoutComments].reduce((value, character) =>
character === '{' ? value + 1 : character === '}' ? value - 1 : value, 0);
if (balance !== 0) errors.push(`${app}: unbalanced CSS braces (${balance})`);
}
const dashboardLayout = await readFile(path.join(root, 'dashboard/src/app/(dashboard)/layout.tsx'), 'utf8');
requireText(dashboardLayout, ['rdg-app-shell', 'rdg-workspace', 'rdg-app-main', 'rdg-app-content'], 'dashboard shell');
const dashboardSidebar = await readFile(path.join(root, 'dashboard/src/components/layout/Sidebar.tsx'), 'utf8');
requireText(dashboardSidebar, ['rdg-sidebar', 'rdg-nav-item', 'aria-current', 'RentalDriveGo'], 'dashboard sidebar');
const dashboardTopbar = await readFile(path.join(root, 'dashboard/src/components/layout/TopBar.tsx'), 'utf8');
requireText(dashboardTopbar, ['rdg-topbar', 'rdg-system-status', 'rdg-search-field'], 'dashboard topbar');
const adminLayout = await readFile(path.join(root, 'admin/src/app/dashboard/layout.tsx'), 'utf8');
requireText(adminLayout, [
'rdg-app-shell', 'rdg-sidebar', 'rdg-nav-item', 'rdg-topbar',
'rdg-system-status', 'aria-current', 'RentalDriveGo',
], 'admin shell');
const routeRoots = [
path.join(root, 'admin/src/app/dashboard'),
path.join(root, 'dashboard/src/app/(dashboard)'),
];
for (const routeRoot of routeRoots) {
const pages = (await walk(routeRoot)).filter((file) => file.endsWith('page.tsx'));
for (const page of pages) {
const contents = await readFile(page, 'utf8');
if (!['rdg-page-heading', 'rdg-page-hero'].some((marker) => contents.includes(marker))) {
errors.push(`${path.relative(root, page)}: missing Phase 16 page heading or hero`);
}
}
}
for (const app of ['admin', 'dashboard']) {
for (const file of await walk(path.join(root, app, 'src'))) {
if (!/\.(ts|tsx|css|json)$/.test(file)) continue;
const contents = await readFile(file, 'utf8');
if (/RentalDriveGo/i.test(contents)) errors.push(`${path.relative(root, file)}: retired RentalDriveGo brand remains`);
}
}
const authChecks = [
'dashboard/src/app/sign-in/[[...sign-in]]/SignInPageClient.tsx',
'dashboard/src/app/sign-up/[[...sign-up]]/SignUpForm.tsx',
];
for (const relative of authChecks) {
const contents = await readFile(path.join(root, relative), 'utf8');
if (!contents.includes('PublicPageLayout')) errors.push(`${relative}: shared public layout not applied`);
}
for (const relative of [
'storefront/src/components/public/SiteNavbar.tsx',
'storefront/src/components/public/SiteFooter.tsx',
'storefront/src/components/public/SitePageLayout.tsx',
]) {
if (!(await exists(path.join(root, relative)))) errors.push(`missing shared storefront component: ${relative}`);
}
if (errors.length) {
console.error(errors.join('\n'));
process.exit(1);
}
console.log('Phase 16 dashboard/admin design checks passed.');