From 259c3100a3666fab1e7ae5a2cff741b75c742205 Mon Sep 17 00:00:00 2001 From: nilangadilhara Date: Tue, 30 Sep 2025 16:59:17 +0530 Subject: [PATCH 01/49] Add complete login frontend with authentication system - Implement user/employee/admin role-based login interface - Add authentication context with mock providers - Create signup, login, and password reset pages - Fix TailwindCSS v4 compatibility issues by downgrading to v3 - Add notification service for auth events - Configure proper PostCSS setup - Update dependencies for React 19 compatibility --- package-lock.json | 1681 ++++++++++------- package.json | 17 +- postcss.config.js | 6 + postcss.config.mjs | 5 - src/app/(user)/(auth)/login/page.tsx | 90 + .../(auth)/password-reset/[token]/page.tsx | 156 ++ src/app/(user)/(auth)/password-reset/page.tsx | 99 + src/app/(user)/(auth)/request-reset/page.tsx | 134 ++ src/app/(user)/(auth)/signup/page.tsx | 128 ++ src/app/context/AuthContext.tsx | 51 + src/app/globals.css | 21 +- src/lib/notificationService.ts | 36 + tailwind.config.js | 18 + tsconfig.json | 2 +- 14 files changed, 1786 insertions(+), 658 deletions(-) create mode 100644 postcss.config.js delete mode 100644 postcss.config.mjs create mode 100644 src/app/(user)/(auth)/login/page.tsx create mode 100644 src/app/(user)/(auth)/password-reset/[token]/page.tsx create mode 100644 src/app/(user)/(auth)/password-reset/page.tsx create mode 100644 src/app/(user)/(auth)/request-reset/page.tsx create mode 100644 src/app/(user)/(auth)/signup/page.tsx create mode 100644 src/app/context/AuthContext.tsx create mode 100644 src/lib/notificationService.ts create mode 100644 tailwind.config.js diff --git a/package-lock.json b/package-lock.json index 3ed9679..da7dde8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,13 +14,14 @@ }, "devDependencies": { "@eslint/eslintrc": "^3", - "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "autoprefixer": "^10.4.21", "eslint": "^9", "eslint-config-next": "15.5.3", - "tailwindcss": "^4", + "postcss": "^8.5.6", + "tailwindcss": "^3.4.17", "typescript": "^5" } }, @@ -681,17 +682,22 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "license": "ISC", "dependencies": { - "minipass": "^7.0.4" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=12" } }, "node_modules/@jridgewell/gen-mapping": { @@ -705,17 +711,6 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -949,6 +944,17 @@ "node": ">=12.4.0" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -972,282 +978,6 @@ "tslib": "^2.8.0" } }, - "node_modules/@tailwindcss/node": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.13.tgz", - "integrity": "sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.4", - "enhanced-resolve": "^5.18.3", - "jiti": "^2.5.1", - "lightningcss": "1.30.1", - "magic-string": "^0.30.18", - "source-map-js": "^1.2.1", - "tailwindcss": "4.1.13" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.13.tgz", - "integrity": "sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.4", - "tar": "^7.4.3" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.13", - "@tailwindcss/oxide-darwin-arm64": "4.1.13", - "@tailwindcss/oxide-darwin-x64": "4.1.13", - "@tailwindcss/oxide-freebsd-x64": "4.1.13", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.13", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.13", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.13", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.13", - "@tailwindcss/oxide-linux-x64-musl": "4.1.13", - "@tailwindcss/oxide-wasm32-wasi": "4.1.13", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.13", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.13" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.13.tgz", - "integrity": "sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.13.tgz", - "integrity": "sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.13.tgz", - "integrity": "sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.13.tgz", - "integrity": "sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.13.tgz", - "integrity": "sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.13.tgz", - "integrity": "sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.13.tgz", - "integrity": "sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.13.tgz", - "integrity": "sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.13.tgz", - "integrity": "sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.13.tgz", - "integrity": "sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.4.5", - "@emnapi/runtime": "^1.4.5", - "@emnapi/wasi-threads": "^1.0.4", - "@napi-rs/wasm-runtime": "^0.2.12", - "@tybys/wasm-util": "^0.10.0", - "tslib": "^2.8.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.13.tgz", - "integrity": "sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.13.tgz", - "integrity": "sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/postcss": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.13.tgz", - "integrity": "sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.1.13", - "@tailwindcss/oxide": "4.1.13", - "postcss": "^8.4.41", - "tailwindcss": "4.1.13" - } - }, "node_modules/@tybys/wasm-util": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", @@ -1907,6 +1637,19 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1923,6 +1666,34 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2117,6 +1888,44 @@ "node": ">= 0.4" } }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -2160,6 +1969,29 @@ "dev": true, "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.9.tgz", + "integrity": "sha512-hY/u2lxLrbecMEWSB0IpGzGyDyeoMFQhCvZd2jGFSE5I17Fh01sYUBPCJtkWERw7zrac9+cIghxm/ytJa2X8iA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -2184,6 +2016,40 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.26.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz", + "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.3", + "caniuse-lite": "^1.0.30001741", + "electron-to-chromium": "^1.5.218", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -2244,6 +2110,16 @@ "node": ">=6" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001741", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz", @@ -2281,14 +2157,42 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, "engines": { - "node": ">=18" + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/client-only": { @@ -2342,6 +2246,16 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2364,6 +2278,19 @@ "node": ">= 8" } }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -2497,12 +2424,26 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz", "integrity": "sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==", - "devOptional": true, "license": "Apache-2.0", + "optional": true, "engines": { "node": ">=8" } }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -2531,6 +2472,20 @@ "node": ">= 0.4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.227", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.227.tgz", + "integrity": "sha512-ITxuoPfJu3lsNWUi2lBM2PaBPYgH3uqmxut5vmBxgYvyI4AlJ6P3Cai1O76mOrkJCBzq0IxWg/NtqOrpu/0gKA==", + "dev": true, + "license": "ISC" + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -2538,20 +2493,6 @@ "dev": true, "license": "MIT" }, - "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/es-abstract": { "version": "1.24.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", @@ -2729,6 +2670,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3309,6 +3260,52 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -3420,6 +3417,27 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3433,6 +3451,32 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -3476,13 +3520,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -3697,6 +3734,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", @@ -3814,6 +3864,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-generator-function": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", @@ -4076,12 +4136,30 @@ "node": ">= 0.4" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jiti": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -4200,259 +4278,40 @@ "node": ">= 0.8.0" } }, - "node_modules/lightningcss": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", - "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-darwin-arm64": "1.30.1", - "lightningcss-darwin-x64": "1.30.1", - "lightningcss-freebsd-x64": "1.30.1", - "lightningcss-linux-arm-gnueabihf": "1.30.1", - "lightningcss-linux-arm64-gnu": "1.30.1", - "lightningcss-linux-arm64-musl": "1.30.1", - "lightningcss-linux-x64-gnu": "1.30.1", - "lightningcss-linux-x64-musl": "1.30.1", - "lightningcss-win32-arm64-msvc": "1.30.1", - "lightningcss-win32-x64-msvc": "1.30.1" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", - "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", - "cpu": [ - "arm64" - ], + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=14" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/antonk52" } }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", - "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", - "cpu": [ - "x64" - ], + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "license": "MIT" }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", - "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", - "cpu": [ - "x64" - ], + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, "engines": { - "node": ">= 12.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", - "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", - "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", - "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", - "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", - "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", - "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", - "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash.merge": { @@ -4475,15 +4334,12 @@ "loose-envify": "cli.js" } }, - "node_modules/magic-string": { - "version": "0.30.19", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", - "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } + "license": "ISC" }, "node_modules/math-intrinsics": { "version": "1.1.0", @@ -4552,35 +4408,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/minizlib": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", - "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4588,6 +4415,18 @@ "dev": true, "license": "MIT" }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -4709,6 +4548,33 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-releases": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz", + "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4719,6 +4585,16 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -4900,6 +4776,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4940,6 +4823,23 @@ "dev": true, "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -4959,6 +4859,26 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -4998,6 +4918,97 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -5079,6 +5090,29 @@ "dev": true, "license": "MIT" }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -5458,10 +5492,23 @@ "side-channel-map": "^1.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/simple-swizzle": { @@ -5504,6 +5551,70 @@ "node": ">= 0.4" } }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -5617,6 +5728,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -5663,6 +5814,29 @@ } } }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5690,42 +5864,140 @@ } }, "node_modules/tailwindcss": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz", - "integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==", + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.6", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } }, - "node_modules/tapable": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz", - "integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==", + "node_modules/tailwindcss/node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "engines": { + "node": ">=8.6.0" } }, - "node_modules/tar": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", - "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "node_modules/tailwindcss/node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", - "yallist": "^5.0.0" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=18" + "node": ">= 6" + } + }, + "node_modules/tailwindcss/node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" } }, "node_modules/tinyglobby": { @@ -5802,6 +6074,13 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -5987,6 +6266,37 @@ "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -5997,6 +6307,13 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6112,14 +6429,112 @@ "node": ">=0.10.0" } }, - "node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" } }, "node_modules/yocto-queue": { diff --git a/package.json b/package.json index 89b65e8..e987814 100644 --- a/package.json +++ b/package.json @@ -3,25 +3,26 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev --turbopack", - "build": "next build --turbopack", + "dev": "next dev", + "build": "next build", "start": "next start", "lint": "eslint" }, "dependencies": { + "next": "15.5.3", "react": "19.1.0", - "react-dom": "19.1.0", - "next": "15.5.3" + "react-dom": "19.1.0" }, "devDependencies": { - "typescript": "^5", + "@eslint/eslintrc": "^3", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "@tailwindcss/postcss": "^4", - "tailwindcss": "^4", + "autoprefixer": "^10.4.21", "eslint": "^9", "eslint-config-next": "15.5.3", - "@eslint/eslintrc": "^3" + "postcss": "^8.5.6", + "tailwindcss": "^3.4.17", + "typescript": "^5" } } diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/postcss.config.mjs b/postcss.config.mjs deleted file mode 100644 index c7bcb4b..0000000 --- a/postcss.config.mjs +++ /dev/null @@ -1,5 +0,0 @@ -const config = { - plugins: ["@tailwindcss/postcss"], -}; - -export default config; diff --git a/src/app/(user)/(auth)/login/page.tsx b/src/app/(user)/(auth)/login/page.tsx new file mode 100644 index 0000000..4fb9bc1 --- /dev/null +++ b/src/app/(user)/(auth)/login/page.tsx @@ -0,0 +1,90 @@ +"use client"; + +const LoginPage = () => { + const handleSubmit = (e: any) => { + e.preventDefault(); + const formData = new FormData(e.target); + const email = formData.get('email'); + const password = formData.get('password'); + + console.log('Login attempt:', { email, password }); + // Add your login logic here + }; + + return ( +
+
+

LOGIN

+

+ If you have an account with us, please log in. +

+ +
+ + + + + +
+ +
+
+
+
+
+
+ Or continue with +
+
+ +
+ +
+
+ +

+ Don't have an account?{" "} + + Create an account + {" "} + or{" "} + + Forgot your password? + +

+
+
+ ); +}; + +export default LoginPage; \ No newline at end of file diff --git a/src/app/(user)/(auth)/password-reset/[token]/page.tsx b/src/app/(user)/(auth)/password-reset/[token]/page.tsx new file mode 100644 index 0000000..af4555f --- /dev/null +++ b/src/app/(user)/(auth)/password-reset/[token]/page.tsx @@ -0,0 +1,156 @@ +"use client"; + +import React, { useState, useEffect } from "react"; +import Link from "next/link"; +import { useRouter, useParams, useSearchParams } from "next/navigation"; +import { authNotifications } from "@/lib/notificationService"; + +const TokenResetPage = () => { + // Get token from URL parameter + const params = useParams(); + const token = params.token as string; + const searchParams = useSearchParams(); + + // Check if request is coming from admin + const isAdminRequest = searchParams.get('from') === 'admin'; + + const [password, setPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); + const [error, setError] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [isSuccess, setIsSuccess] = useState(false); + const [isMounted, setIsMounted] = useState(false); + const router = useRouter(); + + // Set isMounted to true after component mounts (prevents hydration issues) + useEffect(() => { + setIsMounted(true); + console.log("Token from URL:", token); + }, [token]); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setError(""); + + // Validate passwords + if (password !== confirmPassword) { + setError("Passwords do not match."); + return; + } + + if (password.length < 8) { + setError("Password must be at least 8 characters long."); + return; + } + + setIsLoading(true); + + try { + const response = await fetch('/api/auth/reset-password', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ token, password }), + }); + + const data = await response.json(); + + if (data.success) { + setIsSuccess(true); + authNotifications.passwordResetSuccess(); + + // Redirect to login after 3 seconds + setTimeout(() => { + router.push('/login'); + }, 3000); + } else { + setError(data.error || 'Failed to reset password'); + } + } catch (error) { + console.error('Error resetting password:', error); + setError('An error occurred. Please try again later.'); + } finally { + setIsLoading(false); + } + }; + + return ( +
+
+

+ RESET YOUR PASSWORD +

+ + {!isMounted ? ( +
+
+
+ ) : isSuccess ? ( +
+

Password reset successful!

+

+ Your password has been updated. You will be redirected to the login page in a few seconds. +

+ + Go to {isAdminRequest ? 'admin login' : 'login'} now + +
+ ) : ( + <> +

Enter your new password.

+ +
+ setPassword(e.target.value)} + required + disabled={isLoading} + /> + + setConfirmPassword(e.target.value)} + required + disabled={isLoading} + /> + + {error &&

{error}

} + + +
+ + )} +
+
+ ); +}; + +export default TokenResetPage; diff --git a/src/app/(user)/(auth)/password-reset/page.tsx b/src/app/(user)/(auth)/password-reset/page.tsx new file mode 100644 index 0000000..5998b41 --- /dev/null +++ b/src/app/(user)/(auth)/password-reset/page.tsx @@ -0,0 +1,99 @@ +"use client"; + +import React, { useState } from "react"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { authNotifications } from "@/lib/notificationService"; + +const RequestResetPage = () => { + const [email, setEmail] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [isSubmitted, setIsSubmitted] = useState(false); + const router = useRouter(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsLoading(true); + + try { + const response = await fetch('/api/auth/request-reset', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ email }), + }); + + const data = await response.json(); + + if (data.success) { + setIsSubmitted(true); + authNotifications.passwordResetSent(); + } else { + throw new Error(data.error || 'Failed to request password reset'); + } + } catch (error) { + console.log('Error requesting password reset:', error); + authNotifications.loginError('Failed to request password reset. Please try again.'); + } finally { + setIsLoading(false); + } + }; + + return ( +
+
+

+ FORGOT YOUR PASSWORD? +

+

+ Enter your email address to receive a password reset link. +

+ + {isSubmitted ? ( +
+

Password reset email sent!

+

+ If your email exists in our system, you will receive a password reset link shortly. + Please check your inbox and spam folder. +

+ + Return to login + +
+ ) : ( +
+ setEmail(e.target.value)} + required + disabled={isLoading} + /> + + + +

+ Remember your password?{" "} + + Back to login + +

+
+ )} +
+
+ ); +}; + +export default RequestResetPage; diff --git a/src/app/(user)/(auth)/request-reset/page.tsx b/src/app/(user)/(auth)/request-reset/page.tsx new file mode 100644 index 0000000..e4dd14a --- /dev/null +++ b/src/app/(user)/(auth)/request-reset/page.tsx @@ -0,0 +1,134 @@ + +"use client"; + +import React, { useState, useEffect, Suspense } from "react"; +import Link from "next/link"; +import { useSearchParams } from "next/navigation"; +import { authNotifications } from "@/lib/notificationService"; + +const RequestResetContent = () => { + const [email, setEmail] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [isSubmitted, setIsSubmitted] = useState(false); + const searchParams = useSearchParams(); + + // Check if request is coming from admin login page + const isAdminRequest = searchParams.get('from') === 'admin'; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsLoading(true); + + try { + const response = await fetch('/api/auth/request-reset', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ email }), + }); + + const data = await response.json(); + + if (data.success) { + setIsSubmitted(true); + authNotifications.passwordResetSent(); + } else { + throw new Error(data.error || 'Failed to request password reset'); + } + } catch (error) { + console.error('Error requesting password reset:', error); + authNotifications.loginError('Failed to request password reset. Please try again.'); + } finally { + setIsLoading(false); + } + }; + + return ( +
+
+

+ FORGOT YOUR PASSWORD? +

+

+ Enter your email address to receive a password reset link. +

+ + {isSubmitted ? ( +
+

Password reset email sent!

+

+ If your email exists in our system, you will receive a password reset link shortly. + Please check your inbox and spam folder. +

+ + Return to {isAdminRequest ? 'admin login' : 'login'} + +
+ ) : ( +
+ setEmail(e.target.value)} + required + disabled={isLoading} + /> + + + +

+ Remember your password?{" "} + + Back to {isAdminRequest ? 'admin login' : 'login'} + +

+
+ )} +
+
+ ); +}; + +const RequestResetPage = () => { + return ( + +
+
+

Loading...

+
+ + }> + +
+ ); +}; + +export default RequestResetPage; diff --git a/src/app/(user)/(auth)/signup/page.tsx b/src/app/(user)/(auth)/signup/page.tsx new file mode 100644 index 0000000..9eb4607 --- /dev/null +++ b/src/app/(user)/(auth)/signup/page.tsx @@ -0,0 +1,128 @@ +"use client"; + +import React, { useState } from "react"; +import Link from "next/link"; +import { useAuth } from "@/app/context/AuthContext"; +import { useRouter } from "next/navigation"; + +import { authNotifications } from "@/lib/notificationService"; + +const SignupPage = () => { + const [firstName, setFirstName] = useState(""); + const [lastName, setLastName] = useState(""); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(""); + + const { signup } = useAuth(); + const router = useRouter(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsLoading(true); + setError(""); + + try { + const success = await signup(email, password, `${firstName} ${lastName}`); + + if (success) { + authNotifications.signupSuccess(); + router.push("/"); // Redirect to home page + } else { + setError("Failed to create account. Email might already be in use."); + authNotifications.signupError("Failed to create account"); + } + } catch (err) { + console.error("Signup error:", err); + setError("An error occurred during signup"); + authNotifications.signupError("An error occurred during signup"); + } finally { + setIsLoading(false); + } + }; + + return ( +
+
+

+ CREATE AN ACCOUNT +

+

+ Enter your information below to proceed. If you already have an + account, please log in instead. +

+ + {error && ( +
+ {error} +
+ )} + +
+
+ setFirstName(e.target.value)} + disabled={isLoading} + required + /> + setLastName(e.target.value)} + disabled={isLoading} + required + /> +
+ + setEmail(e.target.value)} + disabled={isLoading} + required + /> + + setPassword(e.target.value)} + disabled={isLoading} + required + minLength={6} + /> + + +
+ +

+ Already have an account?{" "} + + Login + +

+
+
+ ); +}; + +export default SignupPage; diff --git a/src/app/context/AuthContext.tsx b/src/app/context/AuthContext.tsx new file mode 100644 index 0000000..129409c --- /dev/null +++ b/src/app/context/AuthContext.tsx @@ -0,0 +1,51 @@ +'use client'; + +// Simple context without hooks for now +interface User { + id: string; + email: string; + name: string; + role: 'USER' | 'EMPLOYEE' | 'ADMIN'; +} + +interface AuthContextType { + user: User | null; + login: (email: string, password: string) => Promise; + signup: (email: string, password: string, name: string) => Promise; + logout: () => void; + loading: boolean; + isAuthenticated: boolean; +} + +// Mock implementation for now +export const useAuth = (): AuthContextType => { + return { + user: null, + login: async (email: string, password: string) => { + console.log('Login attempted with:', email); + // Mock login logic - replace with actual API call + if (email && password) { + return true; + } + return false; + }, + signup: async (email: string, password: string, name: string) => { + console.log('Signup attempted with:', { email, name }); + // Mock signup logic - replace with actual API call + if (email && password && name) { + return true; + } + return false; + }, + logout: () => { + console.log('Logout'); + }, + loading: false, + isAuthenticated: false, + }; +}; + +// Placeholder AuthProvider component +export const AuthProvider = ({ children }: { children: any }) => { + return children; +}; \ No newline at end of file diff --git a/src/app/globals.css b/src/app/globals.css index a2dc41e..f916460 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,17 +1,12 @@ -@import "tailwindcss"; +@tailwind base; +@tailwind components; +@tailwind utilities; :root { --background: #ffffff; --foreground: #171717; } -@theme inline { - --color-background: var(--background); - --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); -} - @media (prefers-color-scheme: dark) { :root { --background: #0a0a0a; @@ -20,7 +15,11 @@ } body { - background: var(--background); - color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; + color: rgb(var(--foreground)); + background: linear-gradient( + to bottom, + transparent, + rgb(var(--background)) + ) + rgb(var(--background)); } diff --git a/src/lib/notificationService.ts b/src/lib/notificationService.ts new file mode 100644 index 0000000..c7a046d --- /dev/null +++ b/src/lib/notificationService.ts @@ -0,0 +1,36 @@ +export const authNotifications = { + loginSuccess: () => { + console.log('Login successful'); + // You can implement toast notifications here later + }, + + loginError: (message: string) => { + console.error('Login error:', message); + // You can implement toast notifications here later + }, + + logoutSuccess: () => { + console.log('Logout successful'); + // You can implement toast notifications here later + }, + + signupSuccess: () => { + console.log('Signup successful'); + // You can implement toast notifications here later + }, + + signupError: (message: string) => { + console.error('Signup error:', message); + // You can implement toast notifications here later + }, + + passwordResetSent: () => { + console.log('Password reset email sent'); + // You can implement toast notifications here later + }, + + passwordResetSuccess: () => { + console.log('Password reset successful'); + // You can implement toast notifications here later + } +}; \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..4f7350a --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,18 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", + "./src/components/**/*.{js,ts,jsx,tsx,mdx}", + "./src/app/**/*.{js,ts,jsx,tsx,mdx}", + ], + theme: { + extend: { + colors: { + background: "var(--background)", + foreground: "var(--foreground)", + }, + }, + }, + plugins: [], +} + diff --git a/tsconfig.json b/tsconfig.json index c133409..ff5c04d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, - "strict": true, + "strict": false, "noEmit": true, "esModuleInterop": true, "module": "esnext", From 882a7a7ea51e6ff771e12f3eee38464efe311d28 Mon Sep 17 00:00:00 2001 From: kin-lgtm <143951269+kin-lgtm@users.noreply.github.com> Date: Sat, 1 Nov 2025 22:03:56 +0530 Subject: [PATCH 02/49] pages and components --- .vscode/c_cpp_properties.json | 18 ++++++ .vscode/launch.json | 24 ++++++++ .vscode/settings.json | 59 +++++++++++++++++++ src/app/admin/appointments/[id]/page.tsx | 0 src/app/admin/appointments/page.tsx | 0 src/app/admin/customers/page.tsx | 0 src/app/admin/dashboard/page.tsx | 0 src/app/admin/employees/[id]/page.tsx | 0 src/app/admin/employees/page.tsx | 0 src/app/admin/layout.tsx | 0 src/app/admin/projects/[id]/page.tsx | 0 src/app/admin/projects/page.tsx | 0 src/app/admin/services/page.tsx | 0 src/app/admin/settings/page.tsx | 0 src/app/auth/forgot-password/page.tsx | 0 src/app/auth/layout.tsx | 0 .../{(user)/(auth) => auth}/login/page.tsx | 0 .../password-reset/[token]/page.tsx | 0 .../(auth) => auth}/password-reset/page.tsx | 0 .../(auth) => auth}/request-reset/page.tsx | 0 .../{(user)/(auth) => auth}/signup/page.tsx | 0 src/app/context/NotificationContext.tsx | 0 src/app/customer/appointments/[id]/page.tsx | 0 .../appointments/[id]/progress/page.tsx | 0 src/app/customer/appointments/new/page.tsx | 0 src/app/customer/appointments/page.tsx | 0 src/app/customer/dashboard/page.tsx | 0 src/app/customer/layout.tsx | 0 src/app/customer/notifications/page.tsx | 0 src/app/customer/profile/page.tsx | 0 src/app/customer/projects/[id]/page.tsx | 0 src/app/customer/projects/page.tsx | 0 src/app/customer/services/[id]/page.tsx | 0 src/app/customer/services/page.tsx | 0 src/app/customer/vehicles/[id]/edit/page.tsx | 0 src/app/customer/vehicles/[id]/page.tsx | 0 src/app/customer/vehicles/add/page.tsx | 0 src/app/customer/vehicles/page.tsx | 0 src/app/employee/appointments/[id]/page.tsx | 0 src/app/employee/appointments/page.tsx | 0 src/app/employee/dashboard/page.tsx | 0 src/app/employee/layout.tsx | 0 src/app/employee/profile/page.tsx | 0 .../progress/[appointmentId]/page.tsx | 0 src/app/employee/progress/page.tsx | 0 .../time-logs/[appointmentId]/page.tsx | 0 src/app/employee/time-logs/page.tsx | 0 .../appointments/AppointmentCard.tsx | 0 .../appointments/AppointmentList.tsx | 0 src/components/appointments/BookingForm.tsx | 0 .../appointments/BookingSummary.tsx | 0 .../appointments/ProgressTracker.tsx | 0 src/components/auth/ForgotPasswordForm.tsx | 0 src/components/auth/LoginForm.tsx | 0 src/components/auth/ProtectedRoute.tsx | 0 src/components/auth/ResetPasswordForm.tsx | 0 src/components/auth/RoleGuard.tsx | 0 src/components/auth/SignupForm.tsx | 0 .../customer/profile/ProfileForm.tsx | 0 .../customer/vehicles/VehicleCard.tsx | 0 .../customer/vehicles/VehicleForm.tsx | 0 .../customer/vehicles/VehicleList.tsx | 0 .../dashboard/admin/AdminDashboard.tsx | 0 .../dashboard/customer/CustomerDashboard.tsx | 0 .../customer/UpcomingAppointments.tsx | 0 .../dashboard/customer/VehiclesList.tsx | 0 .../dashboard/employee/EmployeeDashboard.tsx | 0 .../dashboard/employee/TodayAppointments.tsx | 0 src/components/layout/AdminLayout.tsx | 0 src/components/layout/CustomerLayout.tsx | 0 src/components/layout/EmployeeLayout.tsx | 0 src/components/layout/Footer.tsx | 0 src/components/layout/Header.tsx | 0 src/components/layout/Sidebar.tsx | 0 .../notifications/NotificationList.tsx | 0 src/components/profile/ProfileCard.tsx | 0 src/components/profile/ProfileForm.tsx | 0 src/components/services/ServiceCard.tsx | 0 src/components/services/ServiceDetails.tsx | 0 src/components/services/ServiceForm.tsx | 0 src/components/services/ServiceList.tsx | 0 src/components/time-logs/TimeLogCard.tsx | 0 src/components/time-logs/TimeLogList.tsx | 0 src/components/vehicles/VehicleCard.tsx | 0 src/components/vehicles/VehicleDetails.tsx | 0 src/components/vehicles/VehicleForm.tsx | 0 src/components/vehicles/VehicleList.tsx | 0 87 files changed, 101 insertions(+) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 src/app/admin/appointments/[id]/page.tsx create mode 100644 src/app/admin/appointments/page.tsx create mode 100644 src/app/admin/customers/page.tsx create mode 100644 src/app/admin/dashboard/page.tsx create mode 100644 src/app/admin/employees/[id]/page.tsx create mode 100644 src/app/admin/employees/page.tsx create mode 100644 src/app/admin/layout.tsx create mode 100644 src/app/admin/projects/[id]/page.tsx create mode 100644 src/app/admin/projects/page.tsx create mode 100644 src/app/admin/services/page.tsx create mode 100644 src/app/admin/settings/page.tsx create mode 100644 src/app/auth/forgot-password/page.tsx create mode 100644 src/app/auth/layout.tsx rename src/app/{(user)/(auth) => auth}/login/page.tsx (100%) rename src/app/{(user)/(auth) => auth}/password-reset/[token]/page.tsx (100%) rename src/app/{(user)/(auth) => auth}/password-reset/page.tsx (100%) rename src/app/{(user)/(auth) => auth}/request-reset/page.tsx (100%) rename src/app/{(user)/(auth) => auth}/signup/page.tsx (100%) create mode 100644 src/app/context/NotificationContext.tsx create mode 100644 src/app/customer/appointments/[id]/page.tsx create mode 100644 src/app/customer/appointments/[id]/progress/page.tsx create mode 100644 src/app/customer/appointments/new/page.tsx create mode 100644 src/app/customer/appointments/page.tsx create mode 100644 src/app/customer/dashboard/page.tsx create mode 100644 src/app/customer/layout.tsx create mode 100644 src/app/customer/notifications/page.tsx create mode 100644 src/app/customer/profile/page.tsx create mode 100644 src/app/customer/projects/[id]/page.tsx create mode 100644 src/app/customer/projects/page.tsx create mode 100644 src/app/customer/services/[id]/page.tsx create mode 100644 src/app/customer/services/page.tsx create mode 100644 src/app/customer/vehicles/[id]/edit/page.tsx create mode 100644 src/app/customer/vehicles/[id]/page.tsx create mode 100644 src/app/customer/vehicles/add/page.tsx create mode 100644 src/app/customer/vehicles/page.tsx create mode 100644 src/app/employee/appointments/[id]/page.tsx create mode 100644 src/app/employee/appointments/page.tsx create mode 100644 src/app/employee/dashboard/page.tsx create mode 100644 src/app/employee/layout.tsx create mode 100644 src/app/employee/profile/page.tsx create mode 100644 src/app/employee/progress/[appointmentId]/page.tsx create mode 100644 src/app/employee/progress/page.tsx create mode 100644 src/app/employee/time-logs/[appointmentId]/page.tsx create mode 100644 src/app/employee/time-logs/page.tsx create mode 100644 src/components/appointments/AppointmentCard.tsx create mode 100644 src/components/appointments/AppointmentList.tsx create mode 100644 src/components/appointments/BookingForm.tsx create mode 100644 src/components/appointments/BookingSummary.tsx create mode 100644 src/components/appointments/ProgressTracker.tsx create mode 100644 src/components/auth/ForgotPasswordForm.tsx create mode 100644 src/components/auth/LoginForm.tsx create mode 100644 src/components/auth/ProtectedRoute.tsx create mode 100644 src/components/auth/ResetPasswordForm.tsx create mode 100644 src/components/auth/RoleGuard.tsx create mode 100644 src/components/auth/SignupForm.tsx create mode 100644 src/components/customer/profile/ProfileForm.tsx create mode 100644 src/components/customer/vehicles/VehicleCard.tsx create mode 100644 src/components/customer/vehicles/VehicleForm.tsx create mode 100644 src/components/customer/vehicles/VehicleList.tsx create mode 100644 src/components/dashboard/admin/AdminDashboard.tsx create mode 100644 src/components/dashboard/customer/CustomerDashboard.tsx create mode 100644 src/components/dashboard/customer/UpcomingAppointments.tsx create mode 100644 src/components/dashboard/customer/VehiclesList.tsx create mode 100644 src/components/dashboard/employee/EmployeeDashboard.tsx create mode 100644 src/components/dashboard/employee/TodayAppointments.tsx create mode 100644 src/components/layout/AdminLayout.tsx create mode 100644 src/components/layout/CustomerLayout.tsx create mode 100644 src/components/layout/EmployeeLayout.tsx create mode 100644 src/components/layout/Footer.tsx create mode 100644 src/components/layout/Header.tsx create mode 100644 src/components/layout/Sidebar.tsx create mode 100644 src/components/notifications/NotificationList.tsx create mode 100644 src/components/profile/ProfileCard.tsx create mode 100644 src/components/profile/ProfileForm.tsx create mode 100644 src/components/services/ServiceCard.tsx create mode 100644 src/components/services/ServiceDetails.tsx create mode 100644 src/components/services/ServiceForm.tsx create mode 100644 src/components/services/ServiceList.tsx create mode 100644 src/components/time-logs/TimeLogCard.tsx create mode 100644 src/components/time-logs/TimeLogList.tsx create mode 100644 src/components/vehicles/VehicleCard.tsx create mode 100644 src/components/vehicles/VehicleDetails.tsx create mode 100644 src/components/vehicles/VehicleForm.tsx create mode 100644 src/components/vehicles/VehicleList.tsx diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..cea4d3f --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "windows-gcc-x64", + "includePath": [ + "${workspaceFolder}/**" + ], + "compilerPath": "gcc", + "cStandard": "${default}", + "cppStandard": "${default}", + "intelliSenseMode": "windows-gcc-x64", + "compilerArgs": [ + "" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..b2bd4aa --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C/C++ Runner: Debug Session", + "type": "cppdbg", + "request": "launch", + "args": [], + "stopAtEntry": false, + "externalConsole": true, + "cwd": "d:/sprint588/Github/ead-frontend/src/app/(user)/(auth)", + "program": "d:/sprint588/Github/ead-frontend/src/app/(user)/(auth)/build/Debug/outDebug", + "MIMode": "gdb", + "miDebuggerPath": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..bb879da --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,59 @@ +{ + "C_Cpp_Runner.cCompilerPath": "gcc", + "C_Cpp_Runner.cppCompilerPath": "g++", + "C_Cpp_Runner.debuggerPath": "gdb", + "C_Cpp_Runner.cStandard": "", + "C_Cpp_Runner.cppStandard": "", + "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat", + "C_Cpp_Runner.useMsvc": false, + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wshadow", + "-Wformat=2", + "-Wcast-align", + "-Wconversion", + "-Wsign-conversion", + "-Wnull-dereference" + ], + "C_Cpp_Runner.msvcWarnings": [ + "/W4", + "/permissive-", + "/w14242", + "/w14287", + "/w14296", + "/w14311", + "/w14826", + "/w44062", + "/w44242", + "/w14905", + "/w14906", + "/w14263", + "/w44265", + "/w14928" + ], + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.compilerArgs": [], + "C_Cpp_Runner.linkerArgs": [], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": [ + "*", + "**/*" + ], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**" + ], + "C_Cpp_Runner.useAddressSanitizer": false, + "C_Cpp_Runner.useUndefinedSanitizer": false, + "C_Cpp_Runner.useLeakSanitizer": false, + "C_Cpp_Runner.showCompilationTime": false, + "C_Cpp_Runner.useLinkTimeOptimization": false, + "C_Cpp_Runner.msvcSecureNoWarnings": false +} \ No newline at end of file diff --git a/src/app/admin/appointments/[id]/page.tsx b/src/app/admin/appointments/[id]/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/admin/appointments/page.tsx b/src/app/admin/appointments/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/admin/customers/page.tsx b/src/app/admin/customers/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/admin/dashboard/page.tsx b/src/app/admin/dashboard/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/admin/employees/[id]/page.tsx b/src/app/admin/employees/[id]/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/admin/employees/page.tsx b/src/app/admin/employees/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/admin/layout.tsx b/src/app/admin/layout.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/admin/projects/[id]/page.tsx b/src/app/admin/projects/[id]/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/admin/projects/page.tsx b/src/app/admin/projects/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/admin/services/page.tsx b/src/app/admin/services/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/admin/settings/page.tsx b/src/app/admin/settings/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/auth/forgot-password/page.tsx b/src/app/auth/forgot-password/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/auth/layout.tsx b/src/app/auth/layout.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/(user)/(auth)/login/page.tsx b/src/app/auth/login/page.tsx similarity index 100% rename from src/app/(user)/(auth)/login/page.tsx rename to src/app/auth/login/page.tsx diff --git a/src/app/(user)/(auth)/password-reset/[token]/page.tsx b/src/app/auth/password-reset/[token]/page.tsx similarity index 100% rename from src/app/(user)/(auth)/password-reset/[token]/page.tsx rename to src/app/auth/password-reset/[token]/page.tsx diff --git a/src/app/(user)/(auth)/password-reset/page.tsx b/src/app/auth/password-reset/page.tsx similarity index 100% rename from src/app/(user)/(auth)/password-reset/page.tsx rename to src/app/auth/password-reset/page.tsx diff --git a/src/app/(user)/(auth)/request-reset/page.tsx b/src/app/auth/request-reset/page.tsx similarity index 100% rename from src/app/(user)/(auth)/request-reset/page.tsx rename to src/app/auth/request-reset/page.tsx diff --git a/src/app/(user)/(auth)/signup/page.tsx b/src/app/auth/signup/page.tsx similarity index 100% rename from src/app/(user)/(auth)/signup/page.tsx rename to src/app/auth/signup/page.tsx diff --git a/src/app/context/NotificationContext.tsx b/src/app/context/NotificationContext.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/appointments/[id]/page.tsx b/src/app/customer/appointments/[id]/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/appointments/[id]/progress/page.tsx b/src/app/customer/appointments/[id]/progress/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/appointments/new/page.tsx b/src/app/customer/appointments/new/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/appointments/page.tsx b/src/app/customer/appointments/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/dashboard/page.tsx b/src/app/customer/dashboard/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/layout.tsx b/src/app/customer/layout.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/notifications/page.tsx b/src/app/customer/notifications/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/profile/page.tsx b/src/app/customer/profile/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/projects/[id]/page.tsx b/src/app/customer/projects/[id]/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/projects/page.tsx b/src/app/customer/projects/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/services/[id]/page.tsx b/src/app/customer/services/[id]/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/services/page.tsx b/src/app/customer/services/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/vehicles/[id]/edit/page.tsx b/src/app/customer/vehicles/[id]/edit/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/vehicles/[id]/page.tsx b/src/app/customer/vehicles/[id]/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/vehicles/add/page.tsx b/src/app/customer/vehicles/add/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/customer/vehicles/page.tsx b/src/app/customer/vehicles/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/employee/appointments/[id]/page.tsx b/src/app/employee/appointments/[id]/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/employee/appointments/page.tsx b/src/app/employee/appointments/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/employee/dashboard/page.tsx b/src/app/employee/dashboard/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/employee/layout.tsx b/src/app/employee/layout.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/employee/profile/page.tsx b/src/app/employee/profile/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/employee/progress/[appointmentId]/page.tsx b/src/app/employee/progress/[appointmentId]/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/employee/progress/page.tsx b/src/app/employee/progress/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/employee/time-logs/[appointmentId]/page.tsx b/src/app/employee/time-logs/[appointmentId]/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/app/employee/time-logs/page.tsx b/src/app/employee/time-logs/page.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/appointments/AppointmentCard.tsx b/src/components/appointments/AppointmentCard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/appointments/AppointmentList.tsx b/src/components/appointments/AppointmentList.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/appointments/BookingForm.tsx b/src/components/appointments/BookingForm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/appointments/BookingSummary.tsx b/src/components/appointments/BookingSummary.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/appointments/ProgressTracker.tsx b/src/components/appointments/ProgressTracker.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/auth/ForgotPasswordForm.tsx b/src/components/auth/ForgotPasswordForm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/auth/LoginForm.tsx b/src/components/auth/LoginForm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/auth/ProtectedRoute.tsx b/src/components/auth/ProtectedRoute.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/auth/ResetPasswordForm.tsx b/src/components/auth/ResetPasswordForm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/auth/RoleGuard.tsx b/src/components/auth/RoleGuard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/auth/SignupForm.tsx b/src/components/auth/SignupForm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/customer/profile/ProfileForm.tsx b/src/components/customer/profile/ProfileForm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/customer/vehicles/VehicleCard.tsx b/src/components/customer/vehicles/VehicleCard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/customer/vehicles/VehicleForm.tsx b/src/components/customer/vehicles/VehicleForm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/customer/vehicles/VehicleList.tsx b/src/components/customer/vehicles/VehicleList.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/admin/AdminDashboard.tsx b/src/components/dashboard/admin/AdminDashboard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/customer/CustomerDashboard.tsx b/src/components/dashboard/customer/CustomerDashboard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/customer/UpcomingAppointments.tsx b/src/components/dashboard/customer/UpcomingAppointments.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/customer/VehiclesList.tsx b/src/components/dashboard/customer/VehiclesList.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/employee/EmployeeDashboard.tsx b/src/components/dashboard/employee/EmployeeDashboard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/employee/TodayAppointments.tsx b/src/components/dashboard/employee/TodayAppointments.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/layout/AdminLayout.tsx b/src/components/layout/AdminLayout.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/layout/CustomerLayout.tsx b/src/components/layout/CustomerLayout.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/layout/EmployeeLayout.tsx b/src/components/layout/EmployeeLayout.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/notifications/NotificationList.tsx b/src/components/notifications/NotificationList.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/profile/ProfileCard.tsx b/src/components/profile/ProfileCard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/profile/ProfileForm.tsx b/src/components/profile/ProfileForm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/services/ServiceCard.tsx b/src/components/services/ServiceCard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/services/ServiceDetails.tsx b/src/components/services/ServiceDetails.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/services/ServiceForm.tsx b/src/components/services/ServiceForm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/services/ServiceList.tsx b/src/components/services/ServiceList.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/time-logs/TimeLogCard.tsx b/src/components/time-logs/TimeLogCard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/time-logs/TimeLogList.tsx b/src/components/time-logs/TimeLogList.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/vehicles/VehicleCard.tsx b/src/components/vehicles/VehicleCard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/vehicles/VehicleDetails.tsx b/src/components/vehicles/VehicleDetails.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/vehicles/VehicleForm.tsx b/src/components/vehicles/VehicleForm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/vehicles/VehicleList.tsx b/src/components/vehicles/VehicleList.tsx new file mode 100644 index 0000000..e69de29 From 37102002d8598acc7a292448bc6878dfc6d77198 Mon Sep 17 00:00:00 2001 From: kin-lgtm <143951269+kin-lgtm@users.noreply.github.com> Date: Sat, 1 Nov 2025 22:04:12 +0530 Subject: [PATCH 03/49] add types --- src/types/appointment.types.ts | 0 src/types/auth.types.ts | 0 src/types/dashboard.types.ts | 0 src/types/notification.types.ts | 0 src/types/progress.types.ts | 0 src/types/project.type.ts | 0 src/types/service.types.ts | 0 src/types/timelog.types.ts | 0 src/types/user.types.ts | 0 src/types/vehicle.types.ts | 0 10 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/types/appointment.types.ts create mode 100644 src/types/auth.types.ts create mode 100644 src/types/dashboard.types.ts create mode 100644 src/types/notification.types.ts create mode 100644 src/types/progress.types.ts create mode 100644 src/types/project.type.ts create mode 100644 src/types/service.types.ts create mode 100644 src/types/timelog.types.ts create mode 100644 src/types/user.types.ts create mode 100644 src/types/vehicle.types.ts diff --git a/src/types/appointment.types.ts b/src/types/appointment.types.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types/auth.types.ts b/src/types/auth.types.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types/dashboard.types.ts b/src/types/dashboard.types.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types/notification.types.ts b/src/types/notification.types.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types/progress.types.ts b/src/types/progress.types.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types/project.type.ts b/src/types/project.type.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types/service.types.ts b/src/types/service.types.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types/timelog.types.ts b/src/types/timelog.types.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types/user.types.ts b/src/types/user.types.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types/vehicle.types.ts b/src/types/vehicle.types.ts new file mode 100644 index 0000000..e69de29 From 6bdfe490650db3f4bd3d39f7907c437da6dcdc09 Mon Sep 17 00:00:00 2001 From: dilusha-ola Date: Tue, 4 Nov 2025 00:04:00 +0530 Subject: [PATCH 04/49] create header,sidebar of customers --- package-lock.json | 24 +++-- package.json | 3 +- src/app/customer/dashboard/page.tsx | 51 +++++++++++ src/app/customer/layout.tsx | 7 ++ src/app/customer/my-appointments/page.tsx | 93 ++++++++++++++++++++ src/app/customer/my-projects/page.tsx | 102 ++++++++++++++++++++++ src/components/layout/Header.tsx | 10 +++ src/components/layout/Sidebar.tsx | 59 +++++++++++++ 8 files changed, 335 insertions(+), 14 deletions(-) create mode 100644 src/app/customer/my-appointments/page.tsx create mode 100644 src/app/customer/my-projects/page.tsx diff --git a/package-lock.json b/package-lock.json index da7dde8..e408a11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "next": "15.5.3", "react": "19.1.0", - "react-dom": "19.1.0" + "react-dom": "19.1.0", + "react-icons": "^5.5.0" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -4152,18 +4153,6 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jiti": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", - "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5083,6 +5072,15 @@ "react": "^19.1.0" } }, + "node_modules/react-icons": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", + "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index e987814..a82582d 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "dependencies": { "next": "15.5.3", "react": "19.1.0", - "react-dom": "19.1.0" + "react-dom": "19.1.0", + "react-icons": "^5.5.0" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/src/app/customer/dashboard/page.tsx b/src/app/customer/dashboard/page.tsx index e69de29..fb54fd7 100644 --- a/src/app/customer/dashboard/page.tsx +++ b/src/app/customer/dashboard/page.tsx @@ -0,0 +1,51 @@ +import Sidebar from "@/components/layout/Sidebar"; +import Header from "@/components/layout/Header"; + +export default function Dashboard() { + return ( +
+ +
+ +
+

Hello,

+

Hi James

+ + {/* Stats */} +
+
+

3

+

Vehicles

+
+
+

2

+

Upcoming Appointments

+
+
+

1

+

Projects

+
+
+ + {/* Upcoming Appointments */} +

Upcoming Appointments

+
+

Brake Pad Checking

+

Toyota ABC-2345

+
+ Sunday, 12 June + 11:00AM–12:00AM +
+
+ + {/* Ongoing Projects */} +

Ongoing Projects

+
+

Seats Repairing

+

Toyota CBB-5475

+

Starting Date: Sunday, 12 June

+
+
+
+ ); +} diff --git a/src/app/customer/layout.tsx b/src/app/customer/layout.tsx index e69de29..3739ccf 100644 --- a/src/app/customer/layout.tsx +++ b/src/app/customer/layout.tsx @@ -0,0 +1,7 @@ +export default function CustomerLayout({ + children, +}: { + children: React.ReactNode; +}) { + return <>{children}; +} diff --git a/src/app/customer/my-appointments/page.tsx b/src/app/customer/my-appointments/page.tsx new file mode 100644 index 0000000..0ebde28 --- /dev/null +++ b/src/app/customer/my-appointments/page.tsx @@ -0,0 +1,93 @@ +import Sidebar from "@/components/layout/Sidebar"; +import TopBar from "@/components/layout/Header"; + +export default function MyAppointments() { + return ( +
+ + + +
+

Hello,

+

Hi James

+ + {/* Stats */} +
+
+

3

+

Completed

+
+
+

2

+

Upcoming

+
+
+ + {/* Upcoming Appointments */} +
+

Upcoming Appointments

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDServiceVehicleDateTimeStatus
#1234CheckupABD204010.09.202011.00am–12.00amUpcoming
#1235Oil ChangeCBA305017.09.202511.00am–12.00amUpcoming
+
+ + {/* Completed */} +

Completed Appointments

+
+ + + + + + + + + + + + + + + + + + + + + +
IDServiceVehicleDateTimeStatus
#1234CheckupABD204010.09.202011.00am–12.00amCompleted
+
+
+
+ ); +} diff --git a/src/app/customer/my-projects/page.tsx b/src/app/customer/my-projects/page.tsx new file mode 100644 index 0000000..56e4a44 --- /dev/null +++ b/src/app/customer/my-projects/page.tsx @@ -0,0 +1,102 @@ +import Sidebar from "@/components/layout/Sidebar"; +import Header from "@/components/layout/Header"; + + +export default function Projects() { + return ( +
+ +
+ +
+

Hello,

+

Hi James

+ + {/* Stats */} +
+
+

3

+

Completed

+
+
+

2

+

Ongoing

+
+
+ + {/* Ongoing Projects */} +
+

Ongoing Projects

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDTaskVehicle NoDateTimeStatus
#1234Modify BodyCar10.09.202011.00am–12.00amOngoing
#1235Modify SeatsVan17.09.202511.00am–12.00amOngoing
+
+ + {/* Completed Projects */} +

Completed Projects

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDTaskVehicle NoDateTimeStatus
#1236Modify EngineCar10.09.202011.00am–12.00amCompleted
#1237Modify SeatsVan17.09.202511.00am–12.00amCompleted
+
+
+
+ ); +} diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index e69de29..50e11fc 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -0,0 +1,10 @@ +import { IoNotificationsOutline } from "react-icons/io5"; + +export default function Header({ title }: { title: string }) { + return ( +
+

{title}

+ +
+ ); +} diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index e69de29..87775fb 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -0,0 +1,59 @@ +"use client"; +import { useState } from "react"; +import { FiMenu, FiLogOut } from "react-icons/fi"; +import { FaCar, FaCalendarAlt, FaProjectDiagram, FaUser, FaComments } from "react-icons/fa"; +import Link from "next/link"; + +export default function Sidebar() { + const [open, setOpen] = useState(false); + + return ( + <> + {/* Toggle Button (Mobile) */} + + + {/* Sidebar */} +
+
+
+ User Photo +
+

User name

+
+ + + + +
+ + ); +} From b5b43023e8adc51bdff05a9412fa4ea9077d8f94 Mon Sep 17 00:00:00 2001 From: dilusha-ola Date: Tue, 4 Nov 2025 01:08:38 +0530 Subject: [PATCH 05/49] use consistent font sizes and colors and alignments --- src/api/mockApiService.ts | 130 +++++++++++++ src/app/customer/dashboard/page.tsx | 134 +++++++++++--- src/app/customer/my-appointments/page.tsx | 203 +++++++++++++------- src/app/customer/my-projects/page.tsx | 214 ++++++++++++++-------- src/components/layout/Header.tsx | 6 +- src/components/layout/Sidebar.tsx | 33 ++-- src/data/mockData.ts | 188 +++++++++++++++++++ src/types/index.ts | 67 +++++++ 8 files changed, 778 insertions(+), 197 deletions(-) create mode 100644 src/api/mockApiService.ts create mode 100644 src/data/mockData.ts create mode 100644 src/types/index.ts diff --git a/src/api/mockApiService.ts b/src/api/mockApiService.ts new file mode 100644 index 0000000..a7b7eb5 --- /dev/null +++ b/src/api/mockApiService.ts @@ -0,0 +1,130 @@ +/** + * Mock API Service + * Simulates backend API calls with mock data + * Replace these with real API calls when backend is ready + */ + +import { + mockCustomer, + mockVehicles, + mockAppointments, + mockProjects +} from '@/data/mockData'; +import type { Customer, Vehicle, Appointment, Project, DashboardStats } from '@/types'; + +// Simulate network delay +const delay = (ms: number = 300) => new Promise(resolve => setTimeout(resolve, ms)); + +/** + * Customer Service + */ +export const customerService = { + async getProfile(): Promise { + await delay(); + return mockCustomer; + } +}; + +/** + * Vehicle Service + */ +export const vehicleService = { + async getCustomerVehicles(customerId: string): Promise { + await delay(); + return mockVehicles.filter(v => v.customerId === customerId); + }, + + async getVehicleById(vehicleId: string): Promise { + await delay(); + return mockVehicles.find(v => v.id === vehicleId); + } +}; + +/** + * Appointment Service (Pre-defined Services) + */ +export const appointmentService = { + async getCustomerAppointments(customerId: string): Promise { + await delay(); + return mockAppointments.filter(a => a.customerId === customerId); + }, + + async getUpcomingAppointments(customerId: string): Promise { + await delay(); + return mockAppointments.filter( + a => a.customerId === customerId && a.status === 'Upcoming' + ); + }, + + async getCompletedAppointments(customerId: string): Promise { + await delay(); + return mockAppointments.filter( + a => a.customerId === customerId && a.status === 'Completed' + ); + }, + + async getAppointmentById(appointmentId: string): Promise { + await delay(); + return mockAppointments.find(a => a.id === appointmentId); + } +}; + +/** + * Project Service (Custom Services) + */ +export const projectService = { + async getCustomerProjects(customerId: string): Promise { + await delay(); + return mockProjects.filter(p => p.customerId === customerId); + }, + + async getOngoingProjects(customerId: string): Promise { + await delay(); + return mockProjects.filter( + p => p.customerId === customerId && p.status === 'Ongoing' + ); + }, + + async getCompletedProjects(customerId: string): Promise { + await delay(); + return mockProjects.filter( + p => p.customerId === customerId && p.status === 'Completed' + ); + }, + + async getProjectById(projectId: string): Promise { + await delay(); + return mockProjects.find(p => p.id === projectId); + } +}; + +/** + * Dashboard Service + */ +export const dashboardService = { + async getDashboardStats(customerId: string): Promise { + await delay(); + + const vehicles = mockVehicles.filter(v => v.customerId === customerId); + const upcomingAppointments = mockAppointments.filter( + a => a.customerId === customerId && a.status === 'Upcoming' + ); + const completedAppointments = mockAppointments.filter( + a => a.customerId === customerId && a.status === 'Completed' + ); + const ongoingProjects = mockProjects.filter( + p => p.customerId === customerId && p.status === 'Ongoing' + ); + const completedProjects = mockProjects.filter( + p => p.customerId === customerId && p.status === 'Completed' + ); + + return { + totalVehicles: vehicles.length, + upcomingAppointments: upcomingAppointments.length, + ongoingProjects: ongoingProjects.length, + completedAppointments: completedAppointments.length, + completedProjects: completedProjects.length + }; + } +}; diff --git a/src/app/customer/dashboard/page.tsx b/src/app/customer/dashboard/page.tsx index fb54fd7..de9ea52 100644 --- a/src/app/customer/dashboard/page.tsx +++ b/src/app/customer/dashboard/page.tsx @@ -1,50 +1,130 @@ +'use client'; + +import { useEffect, useState } from 'react'; import Sidebar from "@/components/layout/Sidebar"; import Header from "@/components/layout/Header"; +import { dashboardService, customerService, appointmentService, projectService } from '@/api/mockApiService'; +import type { Customer, Appointment, Project, DashboardStats } from '@/types'; export default function Dashboard() { + const [customer, setCustomer] = useState(null); + const [stats, setStats] = useState(null); + const [upcomingAppointments, setUpcomingAppointments] = useState([]); + const [ongoingProjects, setOngoingProjects] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + loadDashboardData(); + }, []); + + const loadDashboardData = async () => { + try { + setLoading(true); + const customerData = await customerService.getProfile(); + setCustomer(customerData); + + const [statsData, appointmentsData, projectsData] = await Promise.all([ + dashboardService.getDashboardStats(customerData.id), + appointmentService.getUpcomingAppointments(customerData.id), + projectService.getOngoingProjects(customerData.id) + ]); + + setStats(statsData); + setUpcomingAppointments(appointmentsData); + setOngoingProjects(projectsData); + } catch (error) { + console.error('Failed to load dashboard data:', error); + } finally { + setLoading(false); + } + }; + + const formatDate = (dateString: string) => { + const date = new Date(dateString); + return date.toLocaleDateString('en-US', { + weekday: 'long', + month: 'long', + day: 'numeric' + }); + }; + + if (loading) { + return ( +
+
+
+

Loading dashboard...

+
+
+ ); + } + return (
-
-

Hello,

-

Hi James

+
+

Hello,

+

Hi {customer?.name}

{/* Stats */} -
-
-

3

-

Vehicles

+
+
+

{stats?.totalVehicles || 0}

+

Vehicles

-
-

2

-

Upcoming Appointments

+
+

{stats?.upcomingAppointments || 0}

+

Upcoming Appointments

-
-

1

-

Projects

+
+

{stats?.ongoingProjects || 0}

+

Ongoing Projects

{/* Upcoming Appointments */} -

Upcoming Appointments

-
-

Brake Pad Checking

-

Toyota ABC-2345

-
- Sunday, 12 June - 11:00AM–12:00AM +

Upcoming Appointments

+ {upcomingAppointments.length === 0 ? ( +
+ No upcoming appointments
-
+ ) : ( +
+ {upcomingAppointments.map((appointment) => ( +
+

{appointment.serviceName}

+

{appointment.vehicleNumber}

+
+ {formatDate(appointment.date)} + {appointment.time} +
+
+ ))} +
+ )} {/* Ongoing Projects */} -

Ongoing Projects

-
-

Seats Repairing

-

Toyota CBB-5475

-

Starting Date: Sunday, 12 June

-
+

Ongoing Projects

+ {ongoingProjects.length === 0 ? ( +
+ No ongoing projects +
+ ) : ( +
+ {ongoingProjects.map((project) => ( +
+

{project.taskName}

+

{project.vehicleNumber}

+

Starting Date: {formatDate(project.startDate)}

+ {project.estimatedCost && ( +

Estimated Cost: ${project.estimatedCost}

+ )} +
+ ))} +
+ )}
); diff --git a/src/app/customer/my-appointments/page.tsx b/src/app/customer/my-appointments/page.tsx index 0ebde28..1f4b638 100644 --- a/src/app/customer/my-appointments/page.tsx +++ b/src/app/customer/my-appointments/page.tsx @@ -1,92 +1,155 @@ +'use client'; + +import { useEffect, useState } from 'react'; import Sidebar from "@/components/layout/Sidebar"; import TopBar from "@/components/layout/Header"; +import { appointmentService, customerService } from '@/api/mockApiService'; +import type { Appointment, Customer } from '@/types'; export default function MyAppointments() { + const [customer, setCustomer] = useState(null); + const [upcomingAppointments, setUpcomingAppointments] = useState([]); + const [completedAppointments, setCompletedAppointments] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + loadAppointments(); + }, []); + + const loadAppointments = async () => { + try { + setLoading(true); + const customerData = await customerService.getProfile(); + setCustomer(customerData); + + const [upcoming, completed] = await Promise.all([ + appointmentService.getUpcomingAppointments(customerData.id), + appointmentService.getCompletedAppointments(customerData.id) + ]); + + setUpcomingAppointments(upcoming); + setCompletedAppointments(completed); + } catch (error) { + console.error('Failed to load appointments:', error); + } finally { + setLoading(false); + } + }; + + const formatDate = (dateString: string) => { + const date = new Date(dateString); + return date.toLocaleDateString('en-US', { + day: '2-digit', + month: '2-digit', + year: 'numeric' + }); + }; + + if (loading) { + return ( +
+
+
+

Loading appointments...

+
+
+ ); + } + return (
-
-

Hello,

-

Hi James

+
+

Hello,

+

Hi {customer?.name}

{/* Stats */} -
-
-

3

-

Completed

+
+
+

{completedAppointments.length}

+

Completed

-
-

2

-

Upcoming

+
+

{upcomingAppointments.length}

+

Upcoming

{/* Upcoming Appointments */} -
-

Upcoming Appointments

- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IDServiceVehicleDateTimeStatus
#1234CheckupABD204010.09.202011.00am–12.00amUpcoming
#1235Oil ChangeCBA305017.09.202511.00am–12.00amUpcoming
+
+

Upcoming Appointments

+
+ + {upcomingAppointments.length === 0 ? ( +
+ No upcoming appointments +
+ ) : ( +
+ + + + + + + + + + + + + {upcomingAppointments.map((appointment) => ( + + + + + + + + + ))} + +
IDServiceVehicleDateTimeStatus
{appointment.id}{appointment.serviceName}{appointment.vehicleNumber}{formatDate(appointment.date)}{appointment.time}{appointment.status}
+
+ )} {/* Completed */} -

Completed Appointments

-
- - - - - - - - - - - - - - - - - - - - - -
IDServiceVehicleDateTimeStatus
#1234CheckupABD204010.09.202011.00am–12.00amCompleted
-
+

Completed Appointments

+ {completedAppointments.length === 0 ? ( +
+ No completed appointments yet +
+ ) : ( +
+ + + + + + + + + + + + + {completedAppointments.map((appointment) => ( + + + + + + + + + ))} + +
IDServiceVehicleDateTimeStatus
{appointment.id}{appointment.serviceName}{appointment.vehicleNumber}{formatDate(appointment.date)}{appointment.time}{appointment.status}
+
+ )}
); diff --git a/src/app/customer/my-projects/page.tsx b/src/app/customer/my-projects/page.tsx index 56e4a44..a966431 100644 --- a/src/app/customer/my-projects/page.tsx +++ b/src/app/customer/my-projects/page.tsx @@ -1,101 +1,155 @@ +'use client'; + +import { useEffect, useState } from 'react'; import Sidebar from "@/components/layout/Sidebar"; -import Header from "@/components/layout/Header"; - +import Header from "@/components/layout/Header"; +import { projectService, customerService } from '@/api/mockApiService'; +import type { Project, Customer } from '@/types'; export default function Projects() { + const [customer, setCustomer] = useState(null); + const [ongoingProjects, setOngoingProjects] = useState([]); + const [completedProjects, setCompletedProjects] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + loadProjects(); + }, []); + + const loadProjects = async () => { + try { + setLoading(true); + const customerData = await customerService.getProfile(); + setCustomer(customerData); + + const [ongoing, completed] = await Promise.all([ + projectService.getOngoingProjects(customerData.id), + projectService.getCompletedProjects(customerData.id) + ]); + + setOngoingProjects(ongoing); + setCompletedProjects(completed); + } catch (error) { + console.error('Failed to load projects:', error); + } finally { + setLoading(false); + } + }; + + const formatDate = (dateString: string) => { + const date = new Date(dateString); + return date.toLocaleDateString('en-US', { + day: '2-digit', + month: '2-digit', + year: 'numeric' + }); + }; + + if (loading) { + return ( +
+
+
+

Loading projects...

+
+
+ ); + } + return (
-
-

Hello,

-

Hi James

+
+

Hello,

+

Hi {customer?.name}

{/* Stats */} -
-
-

3

-

Completed

+
+
+

{completedProjects.length}

+

Completed

-
-

2

-

Ongoing

+
+

{ongoingProjects.length}

+

Ongoing

{/* Ongoing Projects */} -
-

Ongoing Projects

- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IDTaskVehicle NoDateTimeStatus
#1234Modify BodyCar10.09.202011.00am–12.00amOngoing
#1235Modify SeatsVan17.09.202511.00am–12.00amOngoing
+
+

Ongoing Projects

+
+ {ongoingProjects.length === 0 ? ( +
+ No ongoing projects +
+ ) : ( +
+ + + + + + + + + + + + + {ongoingProjects.map((project) => ( + + + + + + + + + ))} + +
IDTaskVehicle NoDateTimeStatus
{project.id}{project.taskName}{project.vehicleNumber}{formatDate(project.startDate)}{project.time}{project.status}
+
+ )} + {/* Completed Projects */} -

Completed Projects

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IDTaskVehicle NoDateTimeStatus
#1236Modify EngineCar10.09.202011.00am–12.00amCompleted
#1237Modify SeatsVan17.09.202511.00am–12.00amCompleted
-
+

Completed Projects

+ {completedProjects.length === 0 ? ( +
+ No completed projects yet +
+ ) : ( +
+ + + + + + + + + + + + + {completedProjects.map((project) => ( + + + + + + + + + ))} + +
IDTaskVehicle NoDateTimeStatus
{project.id}{project.taskName}{project.vehicleNumber}{formatDate(project.startDate)}{project.time}{project.status}
+
+ )}
); diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 50e11fc..0181fe4 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -2,9 +2,9 @@ import { IoNotificationsOutline } from "react-icons/io5"; export default function Header({ title }: { title: string }) { return ( -
-

{title}

- +
+

{title}

+
); } diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index 87775fb..c72a9dd 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -23,35 +23,34 @@ export default function Sidebar() { ${open ? "translate-x-0" : "-translate-x-full"} md:translate-x-0`} >
-
+
User Photo
-

User name

-
diff --git a/src/data/mockData.ts b/src/data/mockData.ts new file mode 100644 index 0000000..d5ee583 --- /dev/null +++ b/src/data/mockData.ts @@ -0,0 +1,188 @@ +/** + * Mock Data for Customer Dashboard + * Simulates data from backend API + */ + +import type { Customer, Vehicle, Appointment, Project } from '@/types'; + +// Current logged-in customer (mock) +export const mockCustomer: Customer = { + id: 'CUST001', + name: 'James Wilson', + email: 'james.wilson@email.com', + phone: '+1 (555) 123-4567', + joinedDate: '2024-01-15' +}; + +// Customer's vehicles +export const mockVehicles: Vehicle[] = [ + { + id: 'VEH001', + customerId: 'CUST001', + vehicleNumber: 'ABC-2345', + make: 'Toyota', + model: 'Camry', + year: 2020, + type: 'Car' + }, + { + id: 'VEH002', + customerId: 'CUST001', + vehicleNumber: 'CBB-5475', + make: 'Toyota', + model: 'Hiace', + year: 2019, + type: 'Van' + }, + { + id: 'VEH003', + customerId: 'CUST001', + vehicleNumber: 'XYZ-7890', + make: 'Honda', + model: 'CR-V', + year: 2021, + type: 'SUV' + } +]; + +// Appointments (Pre-defined Services) +export const mockAppointments: Appointment[] = [ + { + id: 'APT001', + customerId: 'CUST001', + vehicleId: 'VEH001', + vehicleNumber: 'ABC-2345', + serviceName: 'Brake Pad Checking', + date: '2025-11-12', + time: '11:00 AM - 12:00 PM', + status: 'Upcoming', + assignedEmployee: 'Mike Johnson', + approvedBy: 'Admin Sarah' + }, + { + id: 'APT002', + customerId: 'CUST001', + vehicleId: 'VEH003', + vehicleNumber: 'XYZ-7890', + serviceName: 'Oil Change', + date: '2025-11-15', + time: '02:00 PM - 03:00 PM', + status: 'Upcoming', + assignedEmployee: 'David Smith' + }, + { + id: 'APT003', + customerId: 'CUST001', + vehicleId: 'VEH001', + vehicleNumber: 'ABC-2345', + serviceName: 'Regular Checkup', + date: '2025-10-20', + time: '10:00 AM - 11:00 AM', + status: 'Completed', + assignedEmployee: 'Mike Johnson', + approvedBy: 'Admin Sarah' + }, + { + id: 'APT004', + customerId: 'CUST001', + vehicleId: 'VEH002', + vehicleNumber: 'CBB-5475', + serviceName: 'Tire Rotation', + date: '2025-09-15', + time: '09:00 AM - 10:00 AM', + status: 'Completed', + assignedEmployee: 'David Smith' + }, + { + id: 'APT005', + customerId: 'CUST001', + vehicleId: 'VEH003', + vehicleNumber: 'XYZ-7890', + serviceName: 'Battery Replacement', + date: '2025-08-10', + time: '03:00 PM - 04:00 PM', + status: 'Completed', + assignedEmployee: 'Mike Johnson' + } +]; + +// Projects (Custom Services) +export const mockProjects: Project[] = [ + { + id: 'PRJ001', + customerId: 'CUST001', + vehicleId: 'VEH002', + vehicleNumber: 'CBB-5475', + vehicleType: 'Van', + taskName: 'Seats Repairing', + description: 'Custom leather seat repair and modification', + startDate: '2025-11-05', + time: '09:00 AM - 05:00 PM', + status: 'Ongoing', + assignedEmployee: 'Robert Brown', + approvedBy: 'Admin Sarah', + estimatedCost: 1200, + notes: 'High priority - Customer deadline: Nov 20' + }, + { + id: 'PRJ002', + customerId: 'CUST001', + vehicleId: 'VEH001', + vehicleNumber: 'ABC-2345', + vehicleType: 'Car', + taskName: 'Modify Body', + description: 'Custom body kit installation', + startDate: '2025-10-25', + time: '08:00 AM - 06:00 PM', + status: 'Ongoing', + assignedEmployee: 'James Miller', + approvedBy: 'Admin John', + estimatedCost: 2500 + }, + { + id: 'PRJ003', + customerId: 'CUST001', + vehicleId: 'VEH003', + vehicleNumber: 'XYZ-7890', + vehicleType: 'SUV', + taskName: 'Modify Engine', + description: 'Engine performance upgrade', + startDate: '2025-08-15', + completedDate: '2025-09-10', + time: '10:00 AM - 04:00 PM', + status: 'Completed', + assignedEmployee: 'Robert Brown', + approvedBy: 'Admin Sarah', + estimatedCost: 3500 + }, + { + id: 'PRJ004', + customerId: 'CUST001', + vehicleId: 'VEH002', + vehicleNumber: 'CBB-5475', + vehicleType: 'Van', + taskName: 'Modify Seats', + description: 'Additional seats installation', + startDate: '2025-07-20', + completedDate: '2025-08-05', + time: '09:00 AM - 05:00 PM', + status: 'Completed', + assignedEmployee: 'James Miller', + estimatedCost: 1800 + }, + { + id: 'PRJ005', + customerId: 'CUST001', + vehicleId: 'VEH001', + vehicleNumber: 'ABC-2345', + vehicleType: 'Car', + taskName: 'Sound System Installation', + description: 'Premium audio system upgrade', + startDate: '2025-06-10', + completedDate: '2025-06-15', + time: '10:00 AM - 02:00 PM', + status: 'Completed', + assignedEmployee: 'David Smith', + estimatedCost: 900 + } +]; diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..74e4b20 --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,67 @@ +/** + * TypeScript Types for Automobile Service Management + */ + +// Customer Types +export interface Customer { + id: string; + name: string; + email: string; + phone: string; + joinedDate: string; +} + +// Vehicle Types +export interface Vehicle { + id: string; + customerId: string; + vehicleNumber: string; + make: string; + model: string; + year: number; + type: 'Car' | 'Van' | 'Truck' | 'SUV'; +} + +// Appointment Types (Pre-defined Services) +export interface Appointment { + id: string; + customerId: string; + vehicleId: string; + vehicleNumber: string; + serviceName: string; + date: string; + time: string; + status: 'Upcoming' | 'Completed' | 'Cancelled'; + assignedEmployee?: string; + approvedBy?: string; + notes?: string; +} + +// Project Types (Custom Services) +export interface Project { + id: string; + customerId: string; + vehicleId: string; + vehicleNumber: string; + vehicleType: string; + taskName: string; + description: string; + startDate: string; + estimatedEndDate?: string; + completedDate?: string; + time: string; + status: 'Ongoing' | 'Completed' | 'Cancelled'; + assignedEmployee?: string; + approvedBy?: string; + estimatedCost?: number; + notes?: string; +} + +// Dashboard Stats +export interface DashboardStats { + totalVehicles: number; + upcomingAppointments: number; + ongoingProjects: number; + completedAppointments: number; + completedProjects: number; +} From e8d9efefb508362d2cf6c712672303b6c05bca53 Mon Sep 17 00:00:00 2001 From: dilusha-ola Date: Tue, 4 Nov 2025 01:55:36 +0530 Subject: [PATCH 06/49] set components and pages related to mobile size. --- src/app/customer/dashboard/page.tsx | 16 ++--- src/app/customer/my-appointments/page.tsx | 14 ++-- src/app/customer/my-projects/page.tsx | 14 ++-- src/app/globals.css | 11 ++++ src/components/layout/Header.tsx | 6 +- src/components/layout/Sidebar.tsx | 80 +++++++++++++++++------ 6 files changed, 96 insertions(+), 45 deletions(-) diff --git a/src/app/customer/dashboard/page.tsx b/src/app/customer/dashboard/page.tsx index de9ea52..8e2b687 100644 --- a/src/app/customer/dashboard/page.tsx +++ b/src/app/customer/dashboard/page.tsx @@ -64,28 +64,28 @@ export default function Dashboard() {
-
+

Hello,

-

Hi {customer?.name}

+

Hi {customer?.name}

{/* Stats */} -
-
+
+

{stats?.totalVehicles || 0}

Vehicles

-
+

{stats?.upcomingAppointments || 0}

Upcoming Appointments

-
+

{stats?.ongoingProjects || 0}

Ongoing Projects

{/* Upcoming Appointments */} -

Upcoming Appointments

+

Upcoming Appointments

{upcomingAppointments.length === 0 ? (
No upcoming appointments @@ -106,7 +106,7 @@ export default function Dashboard() { )} {/* Ongoing Projects */} -

Ongoing Projects

+

Ongoing Projects

{ongoingProjects.length === 0 ? (
No ongoing projects diff --git a/src/app/customer/my-appointments/page.tsx b/src/app/customer/my-appointments/page.tsx index 1f4b638..ae22a4d 100644 --- a/src/app/customer/my-appointments/page.tsx +++ b/src/app/customer/my-appointments/page.tsx @@ -61,17 +61,17 @@ export default function MyAppointments() { -
+

Hello,

-

Hi {customer?.name}

+

Hi {customer?.name}

{/* Stats */} -
-
+
+

{completedAppointments.length}

Completed

-
+

{upcomingAppointments.length}

Upcoming

@@ -79,7 +79,7 @@ export default function MyAppointments() { {/* Upcoming Appointments */}
-

Upcoming Appointments

+

Upcoming Appointments

@@ -117,7 +117,7 @@ export default function MyAppointments() { )} {/* Completed */} -

Completed Appointments

+

Completed Appointments

{completedAppointments.length === 0 ? (
No completed appointments yet diff --git a/src/app/customer/my-projects/page.tsx b/src/app/customer/my-projects/page.tsx index a966431..28b18b0 100644 --- a/src/app/customer/my-projects/page.tsx +++ b/src/app/customer/my-projects/page.tsx @@ -61,17 +61,17 @@ export default function Projects() {
-
+

Hello,

-

Hi {customer?.name}

+

Hi {customer?.name}

{/* Stats */} -
-
+
+

{completedProjects.length}

Completed

-
+

{ongoingProjects.length}

Ongoing

@@ -79,7 +79,7 @@ export default function Projects() { {/* Ongoing Projects */}
-

Ongoing Projects

+

Ongoing Projects

@@ -117,7 +117,7 @@ export default function Projects() { )} {/* Completed Projects */} -

Completed Projects

+

Completed Projects

{completedProjects.length === 0 ? (
No completed projects yet diff --git a/src/app/globals.css b/src/app/globals.css index f916460..7b2b337 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -23,3 +23,14 @@ body { ) rgb(var(--background)); } + +/* Hide scrollbar for Chrome, Safari and Opera */ +.scrollbar-hide::-webkit-scrollbar { + display: none; +} + +/* Hide scrollbar for IE, Edge and Firefox */ +.scrollbar-hide { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 0181fe4..cec4e01 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -2,9 +2,9 @@ import { IoNotificationsOutline } from "react-icons/io5"; export default function Header({ title }: { title: string }) { return ( -
-

{title}

- +
+

{title}

+
); } diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index c72a9dd..33fb36c 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -1,56 +1,96 @@ "use client"; import { useState } from "react"; +import { usePathname } from "next/navigation"; import { FiMenu, FiLogOut } from "react-icons/fi"; import { FaCar, FaCalendarAlt, FaProjectDiagram, FaUser, FaComments } from "react-icons/fa"; import Link from "next/link"; export default function Sidebar() { const [open, setOpen] = useState(false); + const pathname = usePathname(); return ( <> {/* Toggle Button (Mobile) */} + {/* Overlay (Mobile) */} + {open && ( +
setOpen(false)} + /> + )} + {/* Sidebar */}
-
-
+
+
User Photo
-
From 8cb4e8c14cbcafb33cf1c4db44460d087e92d5fa Mon Sep 17 00:00:00 2001 From: dilusha-ola Date: Tue, 4 Nov 2025 03:16:10 +0530 Subject: [PATCH 07/49] update --- src/app/customer/dashboard/page.tsx | 70 +++++++++--------- src/app/customer/my-appointments/page.tsx | 89 ++++++++++++----------- src/app/customer/my-projects/page.tsx | 88 +++++++++++----------- src/components/layout/Header.tsx | 6 +- src/components/layout/Sidebar.tsx | 16 ++-- 5 files changed, 138 insertions(+), 131 deletions(-) diff --git a/src/app/customer/dashboard/page.tsx b/src/app/customer/dashboard/page.tsx index 8e2b687..5e65721 100644 --- a/src/app/customer/dashboard/page.tsx +++ b/src/app/customer/dashboard/page.tsx @@ -64,23 +64,24 @@ export default function Dashboard() {
-
-

Hello,

-

Hi {customer?.name}

+
+
+

Hello,

+

Hi {customer?.name}

- {/* Stats */} -
-
-

{stats?.totalVehicles || 0}

-

Vehicles

+ {/* Stats */} +
+
+

{stats?.totalVehicles || 0}

+

Vehicles

-
-

{stats?.upcomingAppointments || 0}

-

Upcoming Appointments

+
+

{stats?.upcomingAppointments || 0}

+

Upcoming Appointments

-
-

{stats?.ongoingProjects || 0}

-

Ongoing Projects

+
+

{stats?.ongoingProjects || 0}

+

Ongoing Projects

@@ -91,17 +92,17 @@ export default function Dashboard() { No upcoming appointments
) : ( -
- {upcomingAppointments.map((appointment) => ( -
-

{appointment.serviceName}

-

{appointment.vehicleNumber}

-
- {formatDate(appointment.date)} - {appointment.time} +
+ {upcomingAppointments.map((appointment) => ( +
+

{appointment.serviceName}

+

{appointment.vehicleNumber}

+
+ {formatDate(appointment.date)} + {appointment.time} +
-
- ))} + ))}
)} @@ -112,20 +113,21 @@ export default function Dashboard() { No ongoing projects
) : ( -
+
{ongoingProjects.map((project) => ( -
-

{project.taskName}

-

{project.vehicleNumber}

-

Starting Date: {formatDate(project.startDate)}

+
+

{project.taskName}

+

{project.vehicleNumber}

+

Starting Date: {formatDate(project.startDate)}

{project.estimatedCost && ( -

Estimated Cost: ${project.estimatedCost}

+

Estimated Cost: ${project.estimatedCost}

)}
- ))} -
- )} + ))} +
+ )} +
); -} +} \ No newline at end of file diff --git a/src/app/customer/my-appointments/page.tsx b/src/app/customer/my-appointments/page.tsx index ae22a4d..959a2f4 100644 --- a/src/app/customer/my-appointments/page.tsx +++ b/src/app/customer/my-appointments/page.tsx @@ -61,35 +61,37 @@ export default function MyAppointments() { -
-

Hello,

-

Hi {customer?.name}

+
+
+

Hello,

+

Hi {customer?.name}

- {/* Stats */} -
-
-

{completedAppointments.length}

-

Completed

+ {/* Stats */} +
+
+

{completedAppointments.length}

+

Completed

+
+
+

{upcomingAppointments.length}

+

Upcoming

+
-
-

{upcomingAppointments.length}

-

Upcoming

-
-
- {/* Upcoming Appointments */} -
-

Upcoming Appointments

- -
- - {upcomingAppointments.length === 0 ? ( -
- No upcoming appointments + {/* Upcoming Appointments */} +
+

Upcoming Appointments

+
- ) : ( -
- + + {upcomingAppointments.length === 0 ? ( +
+ No upcoming appointments +
+ ) : ( +
+
@@ -103,12 +105,12 @@ export default function MyAppointments() { {upcomingAppointments.map((appointment) => ( - - - - - - + + + + + + ))} @@ -116,14 +118,14 @@ export default function MyAppointments() { )} - {/* Completed */} -

Completed Appointments

- {completedAppointments.length === 0 ? ( -
- No completed appointments yet -
- ) : ( -
+ {/* Completed */} +

Completed Appointments

+ {completedAppointments.length === 0 ? ( +
+ No completed appointments yet +
+ ) : ( +
ID
{appointment.id}{appointment.serviceName}{appointment.vehicleNumber}{formatDate(appointment.date)}{appointment.time}{appointment.status}{appointment.id}{appointment.serviceName}{appointment.vehicleNumber}{formatDate(appointment.date)}{appointment.time}{appointment.status}
@@ -146,10 +148,11 @@ export default function MyAppointments() { ))} - -
{appointment.status}
-
- )} + + +
+ )} +
); diff --git a/src/app/customer/my-projects/page.tsx b/src/app/customer/my-projects/page.tsx index 28b18b0..1106f28 100644 --- a/src/app/customer/my-projects/page.tsx +++ b/src/app/customer/my-projects/page.tsx @@ -61,35 +61,36 @@ export default function Projects() {
-
-

Hello,

-

Hi {customer?.name}

+
+
+

Hello,

+

Hi {customer?.name}

- {/* Stats */} -
-
-

{completedProjects.length}

-

Completed

+ {/* Stats */} +
+
+

{completedProjects.length}

+

Completed

+
+
+

{ongoingProjects.length}

+

Ongoing

+
-
-

{ongoingProjects.length}

-

Ongoing

-
-
- {/* Ongoing Projects */} -
-

Ongoing Projects

- -
- - {ongoingProjects.length === 0 ? ( -
- No ongoing projects + {/* Ongoing Projects */} +
+

Ongoing Projects

+
- ) : ( -
- + + {ongoingProjects.length === 0 ? ( +
+ No ongoing projects +
+ ) : ( +
+
@@ -103,12 +104,12 @@ export default function Projects() { {ongoingProjects.map((project) => ( - - - - - - + + + + + + ))} @@ -116,14 +117,14 @@ export default function Projects() { )} - {/* Completed Projects */} -

Completed Projects

- {completedProjects.length === 0 ? ( -
- No completed projects yet -
- ) : ( -
+ {/* Completed Projects */} +

Completed Projects

+ {completedProjects.length === 0 ? ( +
+ No completed projects yet +
+ ) : ( +
ID
{project.id}{project.taskName}{project.vehicleNumber}{formatDate(project.startDate)}{project.time}{project.status}{project.id}{project.taskName}{project.vehicleNumber}{formatDate(project.startDate)}{project.time}{project.status}
@@ -146,10 +147,11 @@ export default function Projects() { ))} - -
{project.status}
-
- )} + + +
+ )} +
); diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index cec4e01..0771c71 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -2,9 +2,9 @@ import { IoNotificationsOutline } from "react-icons/io5"; export default function Header({ title }: { title: string }) { return ( -
-

{title}

- +
+

{title}

+
); } diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index 33fb36c..7ed5510 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -29,16 +29,16 @@ export default function Sidebar() { {/* Sidebar */}
-
+
User Photo
-
From 656321a956d97acff50343a64e61eba9102b0a1e Mon Sep 17 00:00:00 2001 From: dilusha-ola Date: Tue, 4 Nov 2025 03:37:19 +0530 Subject: [PATCH 08/49] responsive to desktop and tablets. --- src/components/layout/Sidebar.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index 7ed5510..923fe75 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -11,26 +11,26 @@ export default function Sidebar() { return ( <> - {/* Toggle Button (Mobile) */} + {/* Toggle Button (Mobile & Tablet) */} - {/* Overlay (Mobile) */} + {/* Overlay (Mobile & Tablet) */} {open && (
setOpen(false)} /> )} {/* Sidebar */}
From ec54ec4dc62fc602c86c5783a176cf16bae20451 Mon Sep 17 00:00:00 2001 From: dilusha-ola Date: Tue, 4 Nov 2025 09:44:34 +0530 Subject: [PATCH 09/49] more responsive --- src/app/customer/dashboard/page.tsx | 17 +++--------- src/app/customer/layout.tsx | 33 ++++++++++++++++++++++- src/app/customer/my-appointments/page.tsx | 20 ++++---------- src/app/customer/my-projects/page.tsx | 19 ++++--------- src/components/layout/Header.tsx | 6 ++--- src/components/layout/Sidebar.tsx | 3 ++- 6 files changed, 51 insertions(+), 47 deletions(-) diff --git a/src/app/customer/dashboard/page.tsx b/src/app/customer/dashboard/page.tsx index 5e65721..6dafb0f 100644 --- a/src/app/customer/dashboard/page.tsx +++ b/src/app/customer/dashboard/page.tsx @@ -1,8 +1,6 @@ 'use client'; import { useEffect, useState } from 'react'; -import Sidebar from "@/components/layout/Sidebar"; -import Header from "@/components/layout/Header"; import { dashboardService, customerService, appointmentService, projectService } from '@/api/mockApiService'; import type { Customer, Appointment, Project, DashboardStats } from '@/types'; @@ -60,14 +58,9 @@ export default function Dashboard() { } return ( -
- -
- -
-
-

Hello,

-

Hi {customer?.name}

+ <> +

Hello,

+

Hi {customer?.name}

{/* Stats */}
@@ -126,8 +119,6 @@ export default function Dashboard() { ))}
)} -
-
-
+ ); } \ No newline at end of file diff --git a/src/app/customer/layout.tsx b/src/app/customer/layout.tsx index 3739ccf..eb83dd5 100644 --- a/src/app/customer/layout.tsx +++ b/src/app/customer/layout.tsx @@ -1,7 +1,38 @@ +'use client'; + +import Sidebar from "@/components/layout/Sidebar"; +import Header from "@/components/layout/Header"; +import { usePathname } from "next/navigation"; + export default function CustomerLayout({ children, }: { children: React.ReactNode; }) { - return <>{children}; + const pathname = usePathname(); + + // Extract page title from pathname + const getPageTitle = () => { + if (pathname?.includes('/my-appointments')) return 'My Appointments'; + if (pathname?.includes('/my-projects')) return 'My Projects'; + if (pathname?.includes('/dashboard')) return 'Dashboard'; + if (pathname?.includes('/vehicles')) return 'My Vehicles'; + if (pathname?.includes('/profile')) return 'Profile'; + if (pathname?.includes('/chatbot')) return 'Chatbot'; + return 'Dashboard'; + }; + + return ( +
+ +
+ + {/* Main Content Area with responsive margins */} +
+
+ {children} +
+
+
+ ); } diff --git a/src/app/customer/my-appointments/page.tsx b/src/app/customer/my-appointments/page.tsx index 959a2f4..8075c3a 100644 --- a/src/app/customer/my-appointments/page.tsx +++ b/src/app/customer/my-appointments/page.tsx @@ -1,8 +1,6 @@ 'use client'; import { useEffect, useState } from 'react'; -import Sidebar from "@/components/layout/Sidebar"; -import TopBar from "@/components/layout/Header"; import { appointmentService, customerService } from '@/api/mockApiService'; import type { Appointment, Customer } from '@/types'; @@ -57,15 +55,9 @@ export default function MyAppointments() { } return ( -
- - - -
-
-

Hello,

-

Hi {customer?.name}

+ <> +

Hello,

+

Hi {customer?.name}

{/* Stats */}
@@ -119,7 +111,7 @@ export default function MyAppointments() { )} {/* Completed */} -

Completed Appointments

+

Completed Appointments

{completedAppointments.length === 0 ? (
No completed appointments yet @@ -152,8 +144,6 @@ export default function MyAppointments() {
)} -
-
-
+ ); } diff --git a/src/app/customer/my-projects/page.tsx b/src/app/customer/my-projects/page.tsx index 1106f28..0949da3 100644 --- a/src/app/customer/my-projects/page.tsx +++ b/src/app/customer/my-projects/page.tsx @@ -1,8 +1,6 @@ 'use client'; import { useEffect, useState } from 'react'; -import Sidebar from "@/components/layout/Sidebar"; -import Header from "@/components/layout/Header"; import { projectService, customerService } from '@/api/mockApiService'; import type { Project, Customer } from '@/types'; @@ -57,14 +55,9 @@ export default function Projects() { } return ( -
- -
- -
-
-

Hello,

-

Hi {customer?.name}

+ <> +

Hello,

+

Hi {customer?.name}

{/* Stats */}
@@ -118,7 +111,7 @@ export default function Projects() { )} {/* Completed Projects */} -

Completed Projects

+

Completed Projects

{completedProjects.length === 0 ? (
No completed projects yet @@ -151,8 +144,6 @@ export default function Projects() {
)} -
-
-
+ ); } diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 0771c71..33551a0 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -2,9 +2,9 @@ import { IoNotificationsOutline } from "react-icons/io5"; export default function Header({ title }: { title: string }) { return ( -
-

{title}

- +
+

{title}

+
); } diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index 923fe75..e254972 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -3,6 +3,7 @@ import { useState } from "react"; import { usePathname } from "next/navigation"; import { FiMenu, FiLogOut } from "react-icons/fi"; import { FaCar, FaCalendarAlt, FaProjectDiagram, FaUser, FaComments } from "react-icons/fa"; +import { MdDashboard } from "react-icons/md"; import Link from "next/link"; export default function Sidebar() { @@ -45,7 +46,7 @@ export default function Sidebar() { pathname?.includes('/customer/dashboard') ? 'bg-blue-500 text-white' : 'hover:bg-gray-100' }`} > - Dashboard + Dashboard Date: Tue, 4 Nov 2025 10:36:13 +0530 Subject: [PATCH 10/49] update paddings --- src/app/customer/dashboard/page.tsx | 6 +-- src/app/customer/layout.tsx | 4 +- src/app/customer/my-appointments/page.tsx | 63 +++++++++++++---------- src/app/customer/my-projects/page.tsx | 63 +++++++++++++---------- 4 files changed, 79 insertions(+), 57 deletions(-) diff --git a/src/app/customer/dashboard/page.tsx b/src/app/customer/dashboard/page.tsx index 6dafb0f..6b70b04 100644 --- a/src/app/customer/dashboard/page.tsx +++ b/src/app/customer/dashboard/page.tsx @@ -79,7 +79,7 @@ export default function Dashboard() {
{/* Upcoming Appointments */} -

Upcoming Appointments

+

Upcoming Appointments

{upcomingAppointments.length === 0 ? (
No upcoming appointments @@ -100,13 +100,13 @@ export default function Dashboard() { )} {/* Ongoing Projects */} -

Ongoing Projects

+

Ongoing Projects

{ongoingProjects.length === 0 ? (
No ongoing projects
) : ( -
+
{ongoingProjects.map((project) => (

{project.taskName}

diff --git a/src/app/customer/layout.tsx b/src/app/customer/layout.tsx index eb83dd5..f9d8c09 100644 --- a/src/app/customer/layout.tsx +++ b/src/app/customer/layout.tsx @@ -28,8 +28,8 @@ export default function CustomerLayout({
{/* Main Content Area with responsive margins */} -
-
+
+
{children}
diff --git a/src/app/customer/my-appointments/page.tsx b/src/app/customer/my-appointments/page.tsx index 8075c3a..4238d26 100644 --- a/src/app/customer/my-appointments/page.tsx +++ b/src/app/customer/my-appointments/page.tsx @@ -9,6 +9,7 @@ export default function MyAppointments() { const [upcomingAppointments, setUpcomingAppointments] = useState([]); const [completedAppointments, setCompletedAppointments] = useState([]); const [loading, setLoading] = useState(true); + const [showAllCompleted, setShowAllCompleted] = useState(false); useEffect(() => { loadAppointments(); @@ -117,32 +118,42 @@ export default function MyAppointments() { No completed appointments yet
) : ( -
- - - - - - - - - - - - - {completedAppointments.map((appointment) => ( - - - - - - - - - ))} - -
IDServiceVehicleDateTimeStatus
{appointment.id}{appointment.serviceName}{appointment.vehicleNumber}{formatDate(appointment.date)}{appointment.time}{appointment.status}
-
+ <> +
+ + + + + + + + + + + + + {(showAllCompleted ? completedAppointments : completedAppointments.slice(0, 5)).map((appointment) => ( + + + + + + + + + ))} + +
IDServiceVehicleDateTimeStatus
{appointment.id}{appointment.serviceName}{appointment.vehicleNumber}{formatDate(appointment.date)}{appointment.time}{appointment.status}
+
+ {completedAppointments.length > 5 && ( + + )} + )} ); diff --git a/src/app/customer/my-projects/page.tsx b/src/app/customer/my-projects/page.tsx index 0949da3..9ab3b6d 100644 --- a/src/app/customer/my-projects/page.tsx +++ b/src/app/customer/my-projects/page.tsx @@ -9,6 +9,7 @@ export default function Projects() { const [ongoingProjects, setOngoingProjects] = useState([]); const [completedProjects, setCompletedProjects] = useState([]); const [loading, setLoading] = useState(true); + const [showAllCompleted, setShowAllCompleted] = useState(false); useEffect(() => { loadProjects(); @@ -117,32 +118,42 @@ export default function Projects() { No completed projects yet
) : ( -
- - - - - - - - - - - - - {completedProjects.map((project) => ( - - - - - - - - - ))} - -
IDTaskVehicle NoDateTimeStatus
{project.id}{project.taskName}{project.vehicleNumber}{formatDate(project.startDate)}{project.time}{project.status}
-
+ <> +
+ + + + + + + + + + + + + {(showAllCompleted ? completedProjects : completedProjects.slice(0, 5)).map((project) => ( + + + + + + + + + ))} + +
IDTaskVehicle NoDateTimeStatus
{project.id}{project.taskName}{project.vehicleNumber}{formatDate(project.startDate)}{project.time}{project.status}
+
+ {completedProjects.length > 5 && ( + + )} + )} ); From 328a744e5281bf2634c5f17f4f08d91df8ee430e Mon Sep 17 00:00:00 2001 From: kin-lgtm <143951269+kin-lgtm@users.noreply.github.com> Date: Tue, 4 Nov 2025 19:06:14 +0530 Subject: [PATCH 11/49] Create ProfileForm --- src/components/profile/ProfileForm.tsx | 107 +++++++++++++++++++++++++ src/types/index.ts | 6 ++ 2 files changed, 113 insertions(+) diff --git a/src/components/profile/ProfileForm.tsx b/src/components/profile/ProfileForm.tsx index e69de29..a763f63 100644 --- a/src/components/profile/ProfileForm.tsx +++ b/src/components/profile/ProfileForm.tsx @@ -0,0 +1,107 @@ +"use client"; + +import React, { useState } from "react"; +import type { Customer } from '@/types'; + +export default function ProfileForm({ + customer, + onSave, +}: { + customer: Customer; + onSave: (c: Partial) => Promise | void; +}) { + const [form, setForm] = useState>(customer || {}); + const [saving, setSaving] = useState(false); + + const handle = (e: React.ChangeEvent) => { + const { name, value } = e.target as HTMLInputElement; + setForm((s) => ({ ...s, [name]: value })); + }; + + const submit = async (e: React.FormEvent) => { + e.preventDefault(); + setSaving(true); + try { + await onSave(form); + } finally { + setSaving(false); + } + }; + + return ( +
+
+ {/* Customer Name */} +
+ + +
+ + {/* Email */} +
+ + +
+ + {/* NIC Number */} +
+ + +
+ + {/* Telephone Number */} +
+ + +
+ + {/* Address */} +
+ +