diff --git a/README.md b/README.md index 1a202df..21a305f 100644 --- a/README.md +++ b/README.md @@ -48,3 +48,26 @@ This repository contains the source code for the TechTorque 2025 customer and em npm run setup-hooks ``` This configures automatic linting on commit and build checking on push. See [GIT_HOOKS.md](GIT_HOOKS.md) for details. + + ### š Environment + + - The frontend expects an API base to be available at runtime. You can configure this via the + `NEXT_PUBLIC_API_BASE_URL` environment variable. When not set, the runtime defaults to + `http://localhost:8080` (useful in development). + + - The AI chat widget reaches the AI chat proxy at `/api/v1/ai/chat` (or `{{NEXT_PUBLIC_API_BASE_URL}}/api/v1/ai/chat` when the public API base is set). This ensures the frontend talks to the configured API gateway or the local Next.js proxy. + +### šØ Theme & Styling (Centralized) + +- A single global stylesheet lives at `src/app/globals.css` and contains all theme variables for light & dark mode, plus utility classes like: + - `.theme-button-primary`, `.theme-button-secondary` ā semantic buttons + - `.theme-bg-primary`, `.theme-text-primary`, `.theme-border`, etc ā consistent building blocks + - `.automotive-accent`, `.accent-badge`, `.text-gradient-accent`, `.progress-accent` ā accent utilities + +- Theme switching is implemented using `src/app/contexts/ThemeContext.tsx` plus a small pre-hydration script in `src/app/layout.tsx` (so the app applies the saved system preference or previously saved theme before React mounts to avoid flashes). + +- Quick checks added: + - `npm run check:theme` ā verifies `globals.css` and `ThemeContext` contain expected hooks and variables. + - `npm run check:colors` ā scans `src/` for hardcoded hex/rgb color usage (ignores `globals.css`). + +If you're adding new UI colors, add variables to `src/app/globals.css` and use the semantic utility classes (or create new ones) ā this keeps light/dark behavior centralized and consistent across the app. diff --git a/package-lock.json b/package-lock.json index f14c5d8..2fa2a8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "axios": "^1.12.2", "js-cookie": "^3.0.5", "lucide-react": "^0.553.0", - "next": "^16.0.1", + "next": "^16.0.3", "react": "19.1.0", "react-dom": "19.1.0", "sockjs-client": "^1.6.1" @@ -765,9 +765,9 @@ } }, "node_modules/@next/env": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.1.tgz", - "integrity": "sha512-LFvlK0TG2L3fEOX77OC35KowL8D7DlFF45C0OvKMC4hy8c/md1RC4UMNDlUGJqfCoCS2VWrZ4dSE6OjaX5+8mw==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.3.tgz", + "integrity": "sha512-IqgtY5Vwsm14mm/nmQaRMmywCU+yyMIYfk3/MHZ2ZTJvwVbBn3usZnjMi1GacrMVzVcAxJShTCpZlPs26EdEjQ==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -781,9 +781,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.1.tgz", - "integrity": "sha512-R0YxRp6/4W7yG1nKbfu41bp3d96a0EalonQXiMe+1H9GTHfKxGNCGFNWUho18avRBPsO8T3RmdWuzmfurlQPbg==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.3.tgz", + "integrity": "sha512-MOnbd92+OByu0p6QBAzq1ahVWzF6nyfiH07dQDez4/Nku7G249NjxDVyEfVhz8WkLiOEU+KFVnqtgcsfP2nLXg==", "cpu": [ "arm64" ], @@ -797,9 +797,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.1.tgz", - "integrity": "sha512-kETZBocRux3xITiZtOtVoVvXyQLB7VBxN7L6EPqgI5paZiUlnsgYv4q8diTNYeHmF9EiehydOBo20lTttCbHAg==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.3.tgz", + "integrity": "sha512-i70C4O1VmbTivYdRlk+5lj9xRc2BlK3oUikt3yJeHT1unL4LsNtN7UiOhVanFdc7vDAgZn1tV/9mQwMkWOJvHg==", "cpu": [ "x64" ], @@ -813,9 +813,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.1.tgz", - "integrity": "sha512-hWg3BtsxQuSKhfe0LunJoqxjO4NEpBmKkE+P2Sroos7yB//OOX3jD5ISP2wv8QdUwtRehMdwYz6VB50mY6hqAg==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.3.tgz", + "integrity": "sha512-O88gCZ95sScwD00mn/AtalyCoykhhlokxH/wi1huFK+rmiP5LAYVs/i2ruk7xST6SuXN4NI5y4Xf5vepb2jf6A==", "cpu": [ "arm64" ], @@ -829,9 +829,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.1.tgz", - "integrity": "sha512-UPnOvYg+fjAhP3b1iQStcYPWeBFRLrugEyK/lDKGk7kLNua8t5/DvDbAEFotfV1YfcOY6bru76qN9qnjLoyHCQ==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.3.tgz", + "integrity": "sha512-CEErFt78S/zYXzFIiv18iQCbRbLgBluS8z1TNDQoyPi8/Jr5qhR3e8XHAIxVxPBjDbEMITprqELVc5KTfFj0gg==", "cpu": [ "arm64" ], @@ -845,9 +845,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.1.tgz", - "integrity": "sha512-Et81SdWkcRqAJziIgFtsFyJizHoWne4fzJkvjd6V4wEkWTB4MX6J0uByUb0peiJQ4WeAt6GGmMszE5KrXK6WKg==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.3.tgz", + "integrity": "sha512-Tc3i+nwt6mQ+Dwzcri/WNDj56iWdycGVh5YwwklleClzPzz7UpfaMw1ci7bLl6GRYMXhWDBfe707EXNjKtiswQ==", "cpu": [ "x64" ], @@ -861,9 +861,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.1.tgz", - "integrity": "sha512-qBbgYEBRrC1egcG03FZaVfVxrJm8wBl7vr8UFKplnxNRprctdP26xEv9nJ07Ggq4y1adwa0nz2mz83CELY7N6Q==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.3.tgz", + "integrity": "sha512-zTh03Z/5PBBPdTurgEtr6nY0vI9KR9Ifp/jZCcHlODzwVOEKcKRBtQIGrkc7izFgOMuXDEJBmirwpGqdM/ZixA==", "cpu": [ "x64" ], @@ -877,9 +877,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.1.tgz", - "integrity": "sha512-cPuBjYP6I699/RdbHJonb3BiRNEDm5CKEBuJ6SD8k3oLam2fDRMKAvmrli4QMDgT2ixyRJ0+DTkiODbIQhRkeQ==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.3.tgz", + "integrity": "sha512-Jc1EHxtZovcJcg5zU43X3tuqzl/sS+CmLgjRP28ZT4vk869Ncm2NoF8qSTaL99gh6uOzgM99Shct06pSO6kA6g==", "cpu": [ "arm64" ], @@ -893,9 +893,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.1.tgz", - "integrity": "sha512-XeEUJsE4JYtfrXe/LaJn3z1pD19fK0Q6Er8Qoufi+HqvdO4LEPyCxLUt4rxA+4RfYo6S9gMlmzCMU2F+AatFqQ==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.3.tgz", + "integrity": "sha512-N7EJ6zbxgIYpI/sWNzpVKRMbfEGgsWuOIvzkML7wxAAZhPk1Msxuo/JDu1PKjWGrAoOLaZcIX5s+/pF5LIbBBg==", "cpu": [ "x64" ], @@ -4739,12 +4739,12 @@ "license": "MIT" }, "node_modules/next": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/next/-/next-16.0.1.tgz", - "integrity": "sha512-e9RLSssZwd35p7/vOa+hoDFggUZIUbZhIUSLZuETCwrCVvxOs87NamoUzT+vbcNAL8Ld9GobBnWOA6SbV/arOw==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/next/-/next-16.0.3.tgz", + "integrity": "sha512-Ka0/iNBblPFcIubTA1Jjh6gvwqfjrGq1Y2MTI5lbjeLIAfmC+p5bQmojpRZqgHHVu5cG4+qdIiwXiBSm/8lZ3w==", "license": "MIT", "dependencies": { - "@next/env": "16.0.1", + "@next/env": "16.0.3", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", @@ -4757,14 +4757,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.0.1", - "@next/swc-darwin-x64": "16.0.1", - "@next/swc-linux-arm64-gnu": "16.0.1", - "@next/swc-linux-arm64-musl": "16.0.1", - "@next/swc-linux-x64-gnu": "16.0.1", - "@next/swc-linux-x64-musl": "16.0.1", - "@next/swc-win32-arm64-msvc": "16.0.1", - "@next/swc-win32-x64-msvc": "16.0.1", + "@next/swc-darwin-arm64": "16.0.3", + "@next/swc-darwin-x64": "16.0.3", + "@next/swc-linux-arm64-gnu": "16.0.3", + "@next/swc-linux-arm64-musl": "16.0.3", + "@next/swc-linux-x64-gnu": "16.0.3", + "@next/swc-linux-x64-musl": "16.0.3", + "@next/swc-win32-arm64-msvc": "16.0.3", + "@next/swc-win32-x64-msvc": "16.0.3", "sharp": "^0.34.4" }, "peerDependencies": { diff --git a/package.json b/package.json index 7a7262c..814355e 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "build": "next build --turbopack", "start": "next start", "lint": "eslint", + "check:colors": "node ./scripts/check-hardcoded-colors.js", + "check:theme": "node ./scripts/check-theme-setup.js", "setup-hooks": "chmod +x .githooks/pre-commit .githooks/pre-push && git config core.hooksPath .githooks && echo 'ā Git hooks configured successfully!'" }, "dependencies": { @@ -14,7 +16,7 @@ "axios": "^1.12.2", "js-cookie": "^3.0.5", "lucide-react": "^0.553.0", - "next": "^16.0.1", + "next": "^16.0.3", "react": "19.1.0", "react-dom": "19.1.0", "sockjs-client": "^1.6.1" diff --git a/scripts/check-hardcoded-colors.js b/scripts/check-hardcoded-colors.js new file mode 100644 index 0000000..0f512b5 --- /dev/null +++ b/scripts/check-hardcoded-colors.js @@ -0,0 +1,35 @@ +#!/usr/bin/env node +import fs from 'fs' +import path from 'path' + +const root = path.resolve(__dirname, '..', 'src') + +const hexRe = /#[0-9a-fA-F]{3,6}/g +const rgbRe = /rgba?\(/gi + +function walk(dir) { + const entries = fs.readdirSync(dir, { withFileTypes: true }) + for (const e of entries) { + const full = path.join(dir, e.name) + if (e.isDirectory()) { + walk(full) + } else if (e.isFile()) { + if (full.endsWith('globals.css')) continue + if (!full.endsWith('.css') && !full.endsWith('.tsx') && !full.endsWith('.ts') && !full.endsWith('.jsx') && !full.endsWith('.js') && !full.endsWith('.svg')) continue + const content = fs.readFileSync(full, 'utf8') + const hex = content.match(hexRe) + const rgb = content.match(rgbRe) + if ((hex && hex.length) || (rgb && rgb.length)) { + console.log(`Found in ${path.relative(process.cwd(), full)} -> hex:${hex ? hex.join(',') : '0'} rgb:${rgb ? rgb.length : 0}`) + } + } + } +} + +try { + walk(root) + console.log('\nSearch complete ā open the above files and replace hardcoded colors with theme variables in src/app/globals.css.') +} catch (err) { + console.error(err) + process.exit(1) +} diff --git a/scripts/check-theme-setup.js b/scripts/check-theme-setup.js new file mode 100644 index 0000000..7adccae --- /dev/null +++ b/scripts/check-theme-setup.js @@ -0,0 +1,27 @@ +#!/usr/bin/env node +import fs from 'fs' +import path from 'path' + +const globals = fs.readFileSync(path.resolve(__dirname, '../src/app/globals.css'), 'utf8') +const themeContext = fs.readFileSync(path.resolve(__dirname, '../src/app/contexts/ThemeContext.tsx'), 'utf8') + +let ok = true + +function assert(cond, msg) { + if (!cond) { + console.error('FAIL:', msg) + ok = false + } else { + console.log('OK:', msg) + } +} + +assert(globals.includes(':root'), 'globals.css has :root declarations') +assert(globals.includes('html.dark'), 'globals.css has html.dark overrides') +assert(globals.includes('--accent-primary'), 'globals.css defines --accent-primary var') + +assert(themeContext.includes("localStorage.getItem('theme')"), 'ThemeContext reads localStorage') +assert(themeContext.includes("document.documentElement.classList"), 'ThemeContext manipulates document.documentElement classList') + +if (!ok) process.exit(1) +console.log('\nTheme setup basic checks passed ā globals.css + ThemeContext look correctly configured.') diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 99eaafe..ad05582 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -94,7 +94,7 @@ export default function AdminDashboard() {
{error}
+{error}
{success}
diff --git a/src/app/auth/forgot-password/page.tsx b/src/app/auth/forgot-password/page.tsx index 139d021..e474f8d 100644 --- a/src/app/auth/forgot-password/page.tsx +++ b/src/app/auth/forgot-password/page.tsx @@ -6,8 +6,8 @@ import Link from 'next/link' import authService from '../../../services/authService' import ThemeToggle from '../../components/ThemeToggle' -const Icon = ({ d, size = 10 }: { d: string; size?: number }) => ( ); -const BoltIcon = ({size = 10}) =>{error}
+{error}