From 4c2241ff721217b87b4f72737d90f85012ea8f74 Mon Sep 17 00:00:00 2001 From: "santasri.pachhal" Date: Wed, 17 Jun 2026 16:23:28 +0530 Subject: [PATCH] chore: update eslint and prettier configuration --- .cursor/mcp.json | 12 +- .env.example | 2 + .eslintignore | 7 - .husky/pre-commit | 4 +- .prettierrc | 11 +- eslint.config.js => eslint.config.mjs | 29 +- next-env.d.ts | 2 +- next.config.ts | 7 + package-lock.json | 477 +----------------- package.json | 15 +- src/app/(full-page)/login/page.tsx | 12 +- src/app/(modules)/access/page.tsx | 4 +- .../clients/components/ClientColumns.tsx | 8 +- .../clients/components/ClientSheet.tsx | 18 +- .../clients/hooks/useClientFilters.ts | 3 +- .../clients/hooks/useClientMutations.ts | 7 +- .../clients/hooks/useClientQueries.ts | 3 +- src/app/(modules)/clients/page.tsx | 3 +- src/app/(modules)/dashboard/page.tsx | 72 ++- .../package/components/PackageColumns.tsx | 18 +- .../package/components/PackageDialog.tsx | 49 +- .../(modules)/package/hooks/usePackageForm.ts | 17 +- .../package/hooks/usePackageQueries.ts | 5 +- .../plans/components/PlanColumns.tsx | 7 +- .../plans/components/PlanFilters.tsx | 5 +- .../(modules)/plans/components/PlanSheet.tsx | 8 +- src/app/(modules)/plans/hooks/usePlanForm.ts | 11 +- .../(modules)/plans/hooks/usePlanMutations.ts | 7 +- src/app/(modules)/plans/page.tsx | 16 +- .../project/components/ProjectColumns.tsx | 10 +- .../project/components/ProjectDialog.tsx | 50 +- .../(modules)/project/hooks/useProjectForm.ts | 8 +- .../project/hooks/useProjectQueries.ts | 8 +- src/app/(modules)/project/page.tsx | 9 +- src/app/(modules)/results/[videoId]/page.tsx | 22 +- src/app/(modules)/results/page.tsx | 6 +- .../roles/components/RoleColumns.tsx | 4 +- .../roles/components/RoleFilters.tsx | 5 +- .../(modules)/roles/components/RoleSheet.tsx | 19 +- src/app/(modules)/roles/hooks/useRoleForm.ts | 19 +- .../(modules)/roles/hooks/useRoleQueries.ts | 9 +- src/app/(modules)/roles/page.tsx | 7 +- .../segment/components/SegmentColumns.tsx | 28 +- .../segment/components/SegmentDialog.tsx | 60 ++- .../(modules)/segment/hooks/useSegmentForm.ts | 30 +- .../segment/hooks/useSegmentQueries.ts | 17 +- src/app/(modules)/segment/page.tsx | 15 +- .../tenants/components/TenantSheet.tsx | 41 +- .../tenants/hooks/useTenantFilters.ts | 3 +- .../(modules)/tenants/hooks/useTenantForm.ts | 6 +- .../tenants/hooks/useTenantMutations.ts | 4 +- src/app/(modules)/tenants/page.tsx | 7 +- src/app/(modules)/upload/[videoId]/page.tsx | 35 +- src/app/(modules)/upload/page.tsx | 71 ++- .../users/components/UserColumns.tsx | 13 +- .../users/components/UserFilters.tsx | 5 +- .../(modules)/users/components/UserSheet.tsx | 50 +- .../(modules)/users/components/UserStats.tsx | 7 +- .../(modules)/users/components/UserTable.tsx | 6 +- src/app/(modules)/users/hooks/useUserForm.ts | 3 +- .../(modules)/users/hooks/useUserMutations.ts | 9 +- .../(modules)/users/hooks/useUserQueries.ts | 3 +- src/app/layout.tsx | 11 +- src/components/app-breadcrumb.tsx | 4 +- src/components/app-sidebar.tsx | 44 +- .../async-combobox/AsyncCombobox.tsx | 15 +- .../async-combobox/VirtualComboboxList.tsx | 16 +- .../async-combobox/usePaginatedLookup.ts | 16 +- .../dashboard/chainage-bar-chart.tsx | 49 +- .../dashboard/dashboard-map-content.tsx | 52 +- src/components/dashboard/dashboard-map.tsx | 62 ++- .../dashboard/dashboard-skeleton.tsx | 16 +- .../dashboard/detection-donut-chart.tsx | 27 +- src/components/dashboard/stats-card.tsx | 4 +- src/components/data-table/Footer/index.tsx | 2 +- .../data-table/TableActionButton.tsx | 6 +- src/components/data-table/TableHeader.tsx | 25 +- src/components/data-table/index.tsx | 30 +- src/components/form/FormField.tsx | 7 +- src/components/lookups/RoleCombobox.tsx | 10 +- src/components/map-modal.tsx | 93 +++- src/components/mode-toogle.tsx | 12 +- src/components/nav-user.tsx | 27 +- src/components/page-header.tsx | 17 +- src/components/permission-tree.tsx | 13 +- src/components/project-selection-section.tsx | 149 ++++-- src/components/ui/avatar.tsx | 20 +- src/components/ui/badge.tsx | 6 +- src/components/ui/breadcrumb.tsx | 11 +- src/components/ui/button.tsx | 9 +- src/components/ui/card.tsx | 23 +- src/components/ui/chart.tsx | 53 +- src/components/ui/collapsible.tsx | 18 +- src/components/ui/combobox.tsx | 44 +- src/components/ui/dialog.tsx | 34 +- src/components/ui/dropdown-menu.tsx | 80 +-- src/components/ui/input-group.tsx | 42 +- src/components/ui/label.tsx | 5 +- src/components/ui/pagination.tsx | 33 +- src/components/ui/popover.tsx | 25 +- src/components/ui/progress.tsx | 5 +- src/components/ui/scroll-area.tsx | 6 +- src/components/ui/select.tsx | 27 +- src/components/ui/sheet.tsx | 17 +- src/components/ui/sidebar.tsx | 50 +- src/components/ui/stepper.tsx | 6 +- src/components/ui/table.tsx | 29 +- src/components/ui/tooltip.tsx | 22 +- src/components/ui/tree.tsx | 21 +- src/components/video-player-section.tsx | 137 +++-- .../video/detailed-summary-section.tsx | 117 +++-- src/components/video/detection-logs.tsx | 21 +- src/components/video/detection-stats-bar.tsx | 5 +- src/components/video/summary-section.tsx | 39 +- src/components/video/video-canvas-player.tsx | 13 +- src/config/menu.config.ts | 4 +- src/constants/detectionModeConfig.ts | 18 +- src/guards/GuestGuard.tsx | 7 +- src/guards/PermissionGuard.tsx | 6 +- src/hooks/use-cumulative-counts.ts | 4 +- src/hooks/use-frame-detection-map.ts | 20 +- src/hooks/use-gps-map.ts | 10 +- src/hooks/use-mobile.ts | 4 +- src/lib/video-storage.ts | 5 +- src/providers/AppInitializer.tsx | 10 +- src/providers/QueryProvider.tsx | 8 +- src/services/api/auth.service.ts | 27 +- src/services/api/chainage.service.ts | 37 +- src/services/api/client.service.ts | 61 ++- src/services/api/detection.service.ts | 5 +- src/services/api/package.service.ts | 37 +- src/services/api/plan.service.ts | 48 +- src/services/api/project.service.ts | 28 +- src/services/api/role.service.ts | 43 +- src/services/api/tenant.service.ts | 25 +- src/services/api/user.service.ts | 55 +- src/services/api/video.service.ts | 12 +- src/services/axios/axios.ts | 10 +- src/types/video.ts | 5 +- src/utils/canvas-drawing.ts | 15 +- 140 files changed, 2270 insertions(+), 1287 deletions(-) create mode 100644 .env.example delete mode 100644 .eslintignore rename eslint.config.js => eslint.config.mjs (64%) create mode 100644 next.config.ts diff --git a/.cursor/mcp.json b/.cursor/mcp.json index c55d0b8..2577c05 100644 --- a/.cursor/mcp.json +++ b/.cursor/mcp.json @@ -1,7 +1,7 @@ { - "mcpServers": { - "dual-graph": { - "url": "http://127.0.0.1:8080/mcp" - } - } -} \ No newline at end of file + "mcpServers": { + "dual-graph": { + "url": "http://127.0.0.1:8080/mcp" + } + } +} diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..014ad78 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +# Backend API base URL (no trailing slash) +NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1 diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 69ed372..0000000 --- a/.eslintignore +++ /dev/null @@ -1,7 +0,0 @@ -.next -node_modules -dist -build -coverage -public -.env* diff --git a/.husky/pre-commit b/.husky/pre-commit index aa36f76..64c5697 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,2 @@ #!/usr/bin/env sh -# . "$(dirname "$0")/_/husky.sh" - -# npx lint-staged +# npm run lint diff --git a/.prettierrc b/.prettierrc index bc0d87a..e94b1d4 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,9 +1,12 @@ { + "semi": true, "singleQuote": true, "trailingComma": "all", - "printWidth": 100, - "useTabs": false, + "printWidth": 80, "tabWidth": 2, - "semi": true, - "endOfLine": "auto" + "useTabs": false, + "endOfLine": "auto", + "arrowParens": "always", + "bracketSpacing": true, + "jsxSingleQuote": false } diff --git a/eslint.config.js b/eslint.config.mjs similarity index 64% rename from eslint.config.js rename to eslint.config.mjs index cb12384..ad96b94 100644 --- a/eslint.config.js +++ b/eslint.config.mjs @@ -1,21 +1,8 @@ import nextConfig from 'eslint-config-next'; import prettierPlugin from 'eslint-plugin-prettier'; -const prettierRules = { - 'prettier/prettier': [ - 'error', - { - singleQuote: true, - trailingComma: 'all', - printWidth: 100, - endOfLine: 'auto', - }, - ], -}; - const additionalRules = { - ...prettierRules, - // Some React rules are intentionally relaxed for this project. + 'prettier/prettier': 'error', 'react-hooks/set-state-in-effect': 'off', 'react-hooks/exhaustive-deps': 'warn', 'react-hooks/immutability': 'off', @@ -24,7 +11,17 @@ const additionalRules = { 'import/no-anonymous-default-export': 'off', }; -export default [ +const eslintConfig = [ + { + ignores: [ + '.next/**', + 'node_modules/**', + 'dist/**', + 'build/**', + 'coverage/**', + 'public/**', + ], + }, ...nextConfig, { files: ['**/*.{js,jsx,ts,tsx}'], @@ -34,3 +31,5 @@ export default [ rules: additionalRules, }, ]; + +export default eslintConfig; diff --git a/next-env.d.ts b/next-env.d.ts index 9edff1c..c4b7818 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..d680278 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from 'next'; + +const nextConfig: NextConfig = { + reactStrictMode: false, +}; + +export default nextConfig; diff --git a/package-lock.json b/package-lock.json index 6420be7..242c2db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,11 +51,10 @@ "autoprefixer": "^10.4.20", "baseline-browser-mapping": "^2.10.37", "eslint": "^9.39.4", - "eslint-config-next": "^16.1.7", + "eslint-config-next": "^16.0.10", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.5", "husky": "^9.1.7", - "lint-staged": "^16.4.0", "postcss": "^8.5", "prettier": "^3.8.1", "tailwindcss": "^4.1.9", @@ -1207,9 +1206,9 @@ "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.7.tgz", - "integrity": "sha512-v/bRGOJlfRCO+NDKt0bZlIIWjhMKU8xbgEQBo+rV9C8S6czZvs96LZ/v24/GvpEnovZlL4QDpku/RzWHVbmPpA==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.0.10.tgz", + "integrity": "sha512-b2NlWN70bbPLmfyoLvvidPKWENBYYIe017ZGUpElvQjDytCWgxPJx7L9juxHt0xHvNVA08ZHJdOyhGzon/KJuw==", "dev": true, "license": "MIT", "dependencies": { @@ -4032,35 +4031,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-escapes": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", - "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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", @@ -4559,39 +4529,6 @@ "url": "https://polar.sh/cva" } }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", - "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^8.0.0", - "string-width": "^8.2.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -4627,13 +4564,6 @@ "dev": true, "license": "MIT" }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -4646,16 +4576,6 @@ "node": ">= 0.8" } }, - "node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -5030,19 +4950,6 @@ "node": ">=10.13.0" } }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/es-abstract": { "version": "1.24.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", @@ -5301,13 +5208,13 @@ } }, "node_modules/eslint-config-next": { - "version": "16.1.7", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.7.tgz", - "integrity": "sha512-FTq1i/QDltzq+zf9aB/cKWAiZ77baG0V7h8dRQh3thVx7I4dwr6ZXQrWKAaTB7x5VwVXlzoUTyMLIVQPLj2gJg==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.0.10.tgz", + "integrity": "sha512-BxouZUm0I45K4yjOOIzj24nTi0H2cGo0y7xUmk+Po/PYtJXFBYVDS1BguE7t28efXjKdcN0tmiLivxQy//SsZg==", "dev": true, "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "16.1.7", + "@next/eslint-plugin-next": "16.0.10", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", @@ -6063,19 +5970,6 @@ "node": ">=6.9.0" } }, - "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -6571,22 +6465,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-generator-function": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", @@ -7253,68 +7131,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/lint-staged": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.4.0.tgz", - "integrity": "sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^14.0.3", - "listr2": "^9.0.5", - "picomatch": "^4.0.3", - "string-argv": "^0.3.2", - "tinyexec": "^1.0.4", - "yaml": "^2.8.2" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=20.17" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/lint-staged/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/listr2": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", - "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^5.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/listr2/node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "dev": true, - "license": "MIT" - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -7344,56 +7160,6 @@ "dev": true, "license": "MIT" }, - "node_modules/log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/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/log-update/node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -7489,19 +7255,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", @@ -7878,22 +7631,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -8009,9 +7746,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -8517,23 +8254,6 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -8545,13 +8265,6 @@ "node": ">=0.10.0" } }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -8843,49 +8556,6 @@ "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/isaacs" - } - }, - "node_modules/slice-ansi": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", - "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.3", - "is-fullwidth-code-point": "^5.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-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/sonner": { "version": "1.7.4", "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.7.4.tgz", @@ -8926,33 +8596,6 @@ "node": ">= 0.4" } }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", - "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.5.0", - "strip-ansi": "^7.1.2" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -9066,22 +8709,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -9207,16 +8834,6 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, - "node_modules/tinyexec": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", - "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -9753,62 +9370,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "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/wrap-ansi/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -9816,22 +9377,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 242d4a3..e8b6598 100644 --- a/package.json +++ b/package.json @@ -6,19 +6,11 @@ "prepare": "husky install", "build": "next build", "dev": "next dev", - "lint": "eslint . --ext .js,.jsx,.ts,.tsx", - "lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix", + "lint": "eslint .", + "lint:fix": "eslint . --fix", "format": "prettier --write .", "start": "next start" }, - "lint-staged": { - "*.+(js|jsx|ts|tsx)": [ - "npm run lint:fix" - ], - "*.+(json|md|css|scss|html)": [ - "npm run format" - ] - }, "dependencies": { "@base-ui/react": "^1.5.0", "@hookform/resolvers": "^5.4.0", @@ -63,11 +55,10 @@ "autoprefixer": "^10.4.20", "baseline-browser-mapping": "^2.10.37", "eslint": "^9.39.4", - "eslint-config-next": "^16.1.7", + "eslint-config-next": "^16.0.10", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.5", "husky": "^9.1.7", - "lint-staged": "^16.4.0", "postcss": "^8.5", "prettier": "^3.8.1", "tailwindcss": "^4.1.9", diff --git a/src/app/(full-page)/login/page.tsx b/src/app/(full-page)/login/page.tsx index d8ab0c4..12c140a 100644 --- a/src/app/(full-page)/login/page.tsx +++ b/src/app/(full-page)/login/page.tsx @@ -17,7 +17,9 @@ export default function LoginPage() {
-

VisionRoad

+

+ VisionRoad +

Sign in

Use your email and password to continue. @@ -39,7 +41,9 @@ export default function LoginPage() { })} /> {errors.email && ( -

{errors.email.message}

+

+ {errors.email.message} +

)}
@@ -57,7 +61,9 @@ export default function LoginPage() { })} /> {errors.password && ( -

{errors.password.message}

+

+ {errors.password.message} +

)} diff --git a/src/app/(modules)/access/page.tsx b/src/app/(modules)/access/page.tsx index 50194e6..de4c250 100644 --- a/src/app/(modules)/access/page.tsx +++ b/src/app/(modules)/access/page.tsx @@ -11,8 +11,8 @@ export default function AccessPage() {

Access denied

- You do not have permission to access any available module. Contact your administrator if - you need access. + You do not have permission to access any available module. Contact + your administrator if you need access.

diff --git a/src/app/(modules)/clients/components/ClientColumns.tsx b/src/app/(modules)/clients/components/ClientColumns.tsx index 296e0c8..9f405cd 100644 --- a/src/app/(modules)/clients/components/ClientColumns.tsx +++ b/src/app/(modules)/clients/components/ClientColumns.tsx @@ -21,7 +21,9 @@ export function useClientColumns(): ColumnDef[] { { accessorKey: 'name', header: 'Client', - cell: ({ row }) => {row.original.name}, + cell: ({ row }) => ( + {row.original.name} + ), }, { accessorKey: 'email', @@ -33,7 +35,9 @@ export function useClientColumns(): ColumnDef[] { cell: ({ row }) => (

{row.original.contact_name}

-

{row.original.contact_phone_number}

+

+ {row.original.contact_phone_number} +

), }, diff --git a/src/app/(modules)/clients/components/ClientSheet.tsx b/src/app/(modules)/clients/components/ClientSheet.tsx index 273fe0d..661bed3 100644 --- a/src/app/(modules)/clients/components/ClientSheet.tsx +++ b/src/app/(modules)/clients/components/ClientSheet.tsx @@ -38,8 +38,12 @@ export function ClientSheet({ - {clientId ? 'Edit Client' : 'Create Client'} - Manage company and primary contact details. + + {clientId ? 'Edit Client' : 'Create Client'} + + + Manage company and primary contact details. +
@@ -88,7 +92,11 @@ export function ClientSheet({
- +
@@ -141,7 +149,9 @@ export function ClientSheet({ Cancel diff --git a/src/app/(modules)/clients/hooks/useClientFilters.ts b/src/app/(modules)/clients/hooks/useClientFilters.ts index f9b6502..0c6b21b 100644 --- a/src/app/(modules)/clients/hooks/useClientFilters.ts +++ b/src/app/(modules)/clients/hooks/useClientFilters.ts @@ -12,7 +12,8 @@ export function useClientFilters() { const [limit, setLimitValue] = useState(10); const [sorting, setSortingValue] = useState([]); const [searchTerm, setSearchTermValue] = useState(''); - const [statusFilter, setStatusFilterValue] = useState('all'); + const [statusFilter, setStatusFilterValue] = + useState('all'); const debouncedSearchTerm = useDebounce(searchTerm.trim(), 400); const setSearchTerm = useCallback((value: string) => { diff --git a/src/app/(modules)/clients/hooks/useClientMutations.ts b/src/app/(modules)/clients/hooks/useClientMutations.ts index 4de6237..4d771aa 100644 --- a/src/app/(modules)/clients/hooks/useClientMutations.ts +++ b/src/app/(modules)/clients/hooks/useClientMutations.ts @@ -38,7 +38,9 @@ export function useSaveClientMutation({ onSaved }: { onSaved: () => void }) { queryClient.invalidateQueries({ queryKey: clientKeys.all }); }, onError: (_error, values) => { - toast.error(values.id ? 'Failed to update client' : 'Failed to create client'); + toast.error( + values.id ? 'Failed to update client' : 'Failed to create client', + ); }, }); } @@ -46,7 +48,8 @@ export function useSaveClientMutation({ onSaved }: { onSaved: () => void }) { export function useClientStatusMutation() { const queryClient = useQueryClient(); const mutation = useMutation({ - mutationFn: (client: Client) => clientService.updateClientStatus(client.id, !client.is_active), + mutationFn: (client: Client) => + clientService.updateClientStatus(client.id, !client.is_active), onSuccess: () => { toast.success('Client status updated'); queryClient.invalidateQueries({ queryKey: clientKeys.all }); diff --git a/src/app/(modules)/clients/hooks/useClientQueries.ts b/src/app/(modules)/clients/hooks/useClientQueries.ts index 37c83bd..2eab7cd 100644 --- a/src/app/(modules)/clients/hooks/useClientQueries.ts +++ b/src/app/(modules)/clients/hooks/useClientQueries.ts @@ -37,7 +37,8 @@ function buildClientListParams({ export function useClientsQuery(params: UseClientsQueryParams) { const { skip, limit, searchTerm, statusFilter, sorting } = params; const listParams = useMemo( - () => buildClientListParams({ skip, limit, searchTerm, statusFilter, sorting }), + () => + buildClientListParams({ skip, limit, searchTerm, statusFilter, sorting }), [limit, searchTerm, skip, sorting, statusFilter], ); diff --git a/src/app/(modules)/clients/page.tsx b/src/app/(modules)/clients/page.tsx index 355c056..a2bf831 100644 --- a/src/app/(modules)/clients/page.tsx +++ b/src/app/(modules)/clients/page.tsx @@ -44,7 +44,8 @@ export default function ClientsPage() { const clientForm = useClientForm({ onSaved: () => setIsSheetOpen(false), }); - const { openCreate: prepareCreateClient, openEdit: prepareEditClient } = clientForm; + const { openCreate: prepareCreateClient, openEdit: prepareEditClient } = + clientForm; const { register, handleSubmit, clientId, isSaving } = clientForm; const statusMutation = useClientStatusMutation(); const { mutate: updateClientStatus, pendingClientId } = statusMutation; diff --git a/src/app/(modules)/dashboard/page.tsx b/src/app/(modules)/dashboard/page.tsx index 5487af9..04db731 100644 --- a/src/app/(modules)/dashboard/page.tsx +++ b/src/app/(modules)/dashboard/page.tsx @@ -30,7 +30,11 @@ import { DashboardMap } from '@/components/dashboard/dashboard-map'; import { PageHeader } from '@/components/page-header'; import { projectService, projectSummaryService } from '@/services/api'; import { Project } from '@/types'; -import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover'; import { Button } from '@/components/ui/button'; import { DashboardSkeleton } from '@/components/dashboard/dashboard-skeleton'; import { toast } from 'sonner'; @@ -160,7 +164,8 @@ function calculateStats(summary: ProjectSummary | null): DetectionStats { chnDrainIssue > 0 || chnDefectiveCulvert > 0 ) { - const shortName = chnName.length > 20 ? chnName.substring(0, 20) + '...' : chnName; + const shortName = + chnName.length > 20 ? chnName.substring(0, 20) + '...' : chnName; chainageData.push({ name: shortName, defected_sign_board: chnDefectedSignboard, @@ -207,8 +212,12 @@ function calculateStats(summary: ProjectSummary | null): DetectionStats { export default function DashboardPage() { const [isLoading, setIsLoading] = useState(true); const [projects, setProjects] = useState([]); - const [selectedProjectId, setSelectedProjectId] = useState(null); - const [projectSummary, setProjectSummary] = useState(null); + const [selectedProjectId, setSelectedProjectId] = useState( + null, + ); + const [projectSummary, setProjectSummary] = useState( + null, + ); const [stats, setStats] = useState({ totalDefectedSignboard: 0, totalPothole: 0, @@ -230,7 +239,9 @@ export default function DashboardPage() { setProjects(projectsData.items); if (projectsData.items.length > 0) { - setSelectedProjectId(projectsData.items[projectsData.items.length - 1].id); + setSelectedProjectId( + projectsData.items[projectsData.items.length - 1].id, + ); } } catch (err) { console.error('Failed to load projects:', err); @@ -258,12 +269,18 @@ export default function DashboardPage() { : []; // Extract chainages from selected package - const [selectedPackageId, setSelectedPackageId] = useState(null); - const [selectedChainageId, setSelectedChainageId] = useState(null); // Changed 'selectedLocationId' to 'selectedChainageId' + const [selectedPackageId, setSelectedPackageId] = useState( + null, + ); + const [selectedChainageId, setSelectedChainageId] = useState( + null, + ); // Changed 'selectedLocationId' to 'selectedChainageId' const chainages = projectSummary && selectedPackageId && selectedPackageId !== 'all' - ? Object.keys(projectSummary.packages[selectedPackageId]?.chainages || {}).map((chnName) => ({ + ? Object.keys( + projectSummary.packages[selectedPackageId]?.chainages || {}, + ).map((chnName) => ({ id: chnName, name: chnName, })) @@ -281,9 +298,10 @@ export default function DashboardPage() { try { setIsLoading(true); - const summary = await projectSummaryService.getProjectSummary( - selectedProjectId, - ); + const summary = + await projectSummaryService.getProjectSummary( + selectedProjectId, + ); setProjectSummary(summary); } catch (err) { console.error('Failed to load project summary:', err); @@ -322,8 +340,15 @@ export default function DashboardPage() { // Auto-select last chainage when package is selected useEffect(() => { - if (projectSummary && selectedPackageId && selectedPackageId !== 'all' && selectedChainageId === null) { - const chainageIds = Object.keys(projectSummary.packages[selectedPackageId]?.chainages || {}); + if ( + projectSummary && + selectedPackageId && + selectedPackageId !== 'all' && + selectedChainageId === null + ) { + const chainageIds = Object.keys( + projectSummary.packages[selectedPackageId]?.chainages || {}, + ); if (chainageIds.length > 0) { setSelectedChainageId(chainageIds[chainageIds.length - 1]); } @@ -415,7 +440,8 @@ export default function DashboardPage() { chnDrainIssue > 0 || chnDefectiveCulvert > 0 ) { - const shortName = chnName.length > 20 ? chnName.substring(0, 20) + '...' : chnName; + const shortName = + chnName.length > 20 ? chnName.substring(0, 20) + '...' : chnName; chainageData.push({ name: shortName, defected_sign_board: chnDefectedSignboard, @@ -478,7 +504,10 @@ export default function DashboardPage() { Filters - +

@@ -577,7 +606,9 @@ export default function DashboardPage() { Detection Distribution - Breakdown of all detected road conditions + + Breakdown of all detected road conditions + - Severity by Segment + + Severity by Segment + Detections grouped by road segment - +
diff --git a/src/app/(modules)/package/components/PackageColumns.tsx b/src/app/(modules)/package/components/PackageColumns.tsx index afa6046..c460e3b 100644 --- a/src/app/(modules)/package/components/PackageColumns.tsx +++ b/src/app/(modules)/package/components/PackageColumns.tsx @@ -4,7 +4,11 @@ import { useMemo } from 'react'; import type { ColumnDef } from '@tanstack/react-table'; import { Badge } from '@/components/ui/badge'; -import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover'; import type { Package, Project } from '@/types'; function EmptyValue() { @@ -42,9 +46,7 @@ function StateBadges({ value }: { value: string | null }) {
-

- Other States -

+

Other States

{remainingStates.map((state) => ( {state} @@ -70,14 +72,16 @@ export function usePackageColumns(projects: Project[]) { accessorKey: 'project_id', header: 'Project', cell: ({ row }) => - projects.find((project) => project.id === row.original.project_id)?.name || - row.original.project_id, + projects.find((project) => project.id === row.original.project_id) + ?.name || row.original.project_id, }, { id: 'project_state', header: 'Project State', cell: ({ row }) => { - const project = projects.find((item) => item.id === row.original.project_id); + const project = projects.find( + (item) => item.id === row.original.project_id, + ); return ; }, }, diff --git a/src/app/(modules)/package/components/PackageDialog.tsx b/src/app/(modules)/package/components/PackageDialog.tsx index 64f5519..71b159f 100644 --- a/src/app/(modules)/package/components/PackageDialog.tsx +++ b/src/app/(modules)/package/components/PackageDialog.tsx @@ -57,14 +57,23 @@ export function PackageDialog({ canSubmit, isSaving, }: PackageDialogProps) { - const projectErrorMessage = isSubmitted ? errors.project_id?.message : undefined; + const projectErrorMessage = isSubmitted + ? errors.project_id?.message + : undefined; const nameErrorMessage = isSubmitted ? errors.name?.message : undefined; - const startErrorMessage = isSubmitted ? errors.chainage_start_km?.message : undefined; - const endErrorMessage = isSubmitted ? errors.chainage_end_km?.message : undefined; + const startErrorMessage = isSubmitted + ? errors.chainage_start_km?.message + : undefined; + const endErrorMessage = isSubmitted + ? errors.chainage_end_km?.message + : undefined; return ( - event.preventDefault()}> + event.preventDefault()} + >
@@ -101,12 +110,22 @@ export function PackageDialog({ ))} - + ) : null}
- + } > - + - + - + void }) { const packageId = useWatch({ control, name: 'id' }); const projectId = useWatch({ control, name: 'project_id' }) || ''; const packageName = useWatch({ control, name: 'name' }) || ''; - const canSubmit = projectId.trim().length > 0 && packageName.trim().length > 0; + const canSubmit = + projectId.trim().length > 0 && packageName.trim().length > 0; const saveMutation = useMutation({ mutationFn: (values: PackageFormValues) => { @@ -94,7 +97,9 @@ export function usePackageForm({ onSaved }: { onSaved: () => void }) { queryClient.invalidateQueries({ queryKey: packageKeys.all }); }, onError: (_error, values) => { - toast.error(values.id ? 'Failed to update package' : 'Failed to create package'); + toast.error( + values.id ? 'Failed to update package' : 'Failed to create package', + ); }, }); @@ -130,7 +135,11 @@ export function usePackageForm({ onSaved }: { onSaved: () => void }) { ); const setProjectId = useCallback( - (value: string) => setValue('project_id', value, { shouldDirty: true, shouldValidate: true }), + (value: string) => + setValue('project_id', value, { + shouldDirty: true, + shouldValidate: true, + }), [setValue], ); diff --git a/src/app/(modules)/package/hooks/usePackageQueries.ts b/src/app/(modules)/package/hooks/usePackageQueries.ts index 144174e..70a02ce 100644 --- a/src/app/(modules)/package/hooks/usePackageQueries.ts +++ b/src/app/(modules)/package/hooks/usePackageQueries.ts @@ -15,7 +15,10 @@ interface UsePackagesQueryParams { } export function usePackagesQuery({ skip, limit }: UsePackagesQueryParams) { - const listParams = useMemo(() => ({ skip, limit }), [limit, skip]); + const listParams = useMemo( + () => ({ skip, limit }), + [limit, skip], + ); return useQuery({ queryKey: packageKeys.list(listParams), diff --git a/src/app/(modules)/plans/components/PlanColumns.tsx b/src/app/(modules)/plans/components/PlanColumns.tsx index 291526e..2e5618d 100644 --- a/src/app/(modules)/plans/components/PlanColumns.tsx +++ b/src/app/(modules)/plans/components/PlanColumns.tsx @@ -37,7 +37,8 @@ export function usePlanColumns(): ColumnDef[] { { accessorKey: 'price', header: 'Price', - cell: ({ row }) => formatPrice(row.original.price, row.original.billing_cycle), + cell: ({ row }) => + formatPrice(row.original.price, row.original.billing_cycle), }, { accessorKey: 'trial_days', @@ -68,7 +69,9 @@ export function usePlanColumns(): ColumnDef[] { {row.original.is_active ? 'Active' : 'Inactive'} - {row.original.is_custom ? Custom : null} + {row.original.is_custom ? ( + Custom + ) : null}
), }, diff --git a/src/app/(modules)/plans/components/PlanFilters.tsx b/src/app/(modules)/plans/components/PlanFilters.tsx index faab44a..1ee9af4 100644 --- a/src/app/(modules)/plans/components/PlanFilters.tsx +++ b/src/app/(modules)/plans/components/PlanFilters.tsx @@ -31,7 +31,10 @@ export function PlanFilters({ placeholder="Search plans" className="w-full sm:w-72" /> - onStatusChange(value as PlanStatusFilter)} + > diff --git a/src/app/(modules)/plans/components/PlanSheet.tsx b/src/app/(modules)/plans/components/PlanSheet.tsx index a0506e9..65a94b0 100644 --- a/src/app/(modules)/plans/components/PlanSheet.tsx +++ b/src/app/(modules)/plans/components/PlanSheet.tsx @@ -201,7 +201,9 @@ export function PlanSheet({
- {permissionIds.length} selected + + {permissionIds.length} selected +
{isPermissionsLoading ? (
@@ -226,7 +228,9 @@ export function PlanSheet({ Cancel diff --git a/src/app/(modules)/plans/hooks/usePlanForm.ts b/src/app/(modules)/plans/hooks/usePlanForm.ts index c599497..3a8d758 100644 --- a/src/app/(modules)/plans/hooks/usePlanForm.ts +++ b/src/app/(modules)/plans/hooks/usePlanForm.ts @@ -117,7 +117,10 @@ export function usePlanForm({ max_organizations: plan.max_organizations ?? 0, max_users: plan.max_users ?? 0, max_roles: plan.max_roles ?? 0, - permission_ids: collectPermissionIdsByKeys(permissionTree, plan.permissions || []), + permission_ids: collectPermissionIdsByKeys( + permissionTree, + plan.permissions || [], + ), is_active: plan.is_active, is_custom: plan.is_custom, }); @@ -126,7 +129,11 @@ export function usePlanForm({ ); const setPermissionIds = useCallback( - (ids: number[]) => setValue('permission_ids', ids, { shouldDirty: true, shouldValidate: true }), + (ids: number[]) => + setValue('permission_ids', ids, { + shouldDirty: true, + shouldValidate: true, + }), [setValue], ); diff --git a/src/app/(modules)/plans/hooks/usePlanMutations.ts b/src/app/(modules)/plans/hooks/usePlanMutations.ts index f321b45..faef7a5 100644 --- a/src/app/(modules)/plans/hooks/usePlanMutations.ts +++ b/src/app/(modules)/plans/hooks/usePlanMutations.ts @@ -19,7 +19,9 @@ export function useSavePlanMutation({ onSaved }: { onSaved: () => void }) { onSaved(); }, onError: (_error, values) => { - toast.error(values.id ? 'Failed to update plan' : 'Failed to create plan'); + toast.error( + values.id ? 'Failed to update plan' : 'Failed to create plan', + ); }, }); } @@ -28,7 +30,8 @@ export function usePlanStatusMutation() { const queryClient = useQueryClient(); return useMutation({ - mutationFn: (plan: Plan) => planService.updatePlanStatus(plan.id, !plan.is_active), + mutationFn: (plan: Plan) => + planService.updatePlanStatus(plan.id, !plan.is_active), onSuccess: () => { toast.success('Plan status updated'); queryClient.invalidateQueries({ queryKey: planKeys.lists() }); diff --git a/src/app/(modules)/plans/page.tsx b/src/app/(modules)/plans/page.tsx index 2e855b1..4111f25 100644 --- a/src/app/(modules)/plans/page.tsx +++ b/src/app/(modules)/plans/page.tsx @@ -16,7 +16,10 @@ import { PlanTable } from './components/PlanTable'; import { usePlanFilters } from './hooks/usePlanFilters'; import { usePlanForm } from './hooks/usePlanForm'; import { usePlanStatusMutation } from './hooks/usePlanMutations'; -import { useOrganizationPermissionTreeQuery, usePlansQuery } from './hooks/usePlanQueries'; +import { + useOrganizationPermissionTreeQuery, + usePlansQuery, +} from './hooks/usePlanQueries'; export default function PlansPage() { const [isSheetOpen, setIsSheetOpen] = useState(false); @@ -57,8 +60,15 @@ export default function PlansPage() { onSaved: () => handleSheetOpenChange(false), }); const { openCreate: prepareCreatePlan, openEdit: prepareEditPlan } = planForm; - const { register, control, onSubmit, planId, permissionIds, setPermissionIds, isSaving } = - planForm; + const { + register, + control, + onSubmit, + planId, + permissionIds, + setPermissionIds, + isSaving, + } = planForm; const statusMutation = usePlanStatusMutation(); const openCreate = useCallback(() => { diff --git a/src/app/(modules)/project/components/ProjectColumns.tsx b/src/app/(modules)/project/components/ProjectColumns.tsx index 2745bbb..d9f3690 100644 --- a/src/app/(modules)/project/components/ProjectColumns.tsx +++ b/src/app/(modules)/project/components/ProjectColumns.tsx @@ -4,7 +4,11 @@ import { useMemo } from 'react'; import type { ColumnDef } from '@tanstack/react-table'; import { Badge } from '@/components/ui/badge'; -import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover'; import type { Project } from '@/types'; function EmptyValue() { @@ -42,9 +46,7 @@ function StateBadges({ value }: { value: string | null }) {
-

- Other States -

+

Other States

{remainingStates.map((state) => ( {state} diff --git a/src/app/(modules)/project/components/ProjectDialog.tsx b/src/app/(modules)/project/components/ProjectDialog.tsx index 94d35fa..6d3b33f 100644 --- a/src/app/(modules)/project/components/ProjectDialog.tsx +++ b/src/app/(modules)/project/components/ProjectDialog.tsx @@ -42,14 +42,21 @@ export function ProjectDialog({ isSaving, }: ProjectDialogProps) { const nameErrorMessage = isSubmitted ? errors.name?.message : undefined; - const startLatErrorMessage = isSubmitted ? errors.start_lat?.message : undefined; - const startLngErrorMessage = isSubmitted ? errors.start_lng?.message : undefined; + const startLatErrorMessage = isSubmitted + ? errors.start_lat?.message + : undefined; + const startLngErrorMessage = isSubmitted + ? errors.start_lng?.message + : undefined; const endLatErrorMessage = isSubmitted ? errors.end_lat?.message : undefined; const endLngErrorMessage = isSubmitted ? errors.end_lng?.message : undefined; return ( - event.preventDefault()}> + event.preventDefault()} + >
@@ -65,7 +72,12 @@ export function ProjectDialog({ - + - +
- + - +
- + - + void }) { queryClient.invalidateQueries({ queryKey: projectKeys.all }); }, onError: (_error, values) => { - toast.error(values.id ? 'Failed to update project' : 'Failed to create project'); + toast.error( + values.id ? 'Failed to update project' : 'Failed to create project', + ); }, }); diff --git a/src/app/(modules)/project/hooks/useProjectQueries.ts b/src/app/(modules)/project/hooks/useProjectQueries.ts index aec3303..e2bd113 100644 --- a/src/app/(modules)/project/hooks/useProjectQueries.ts +++ b/src/app/(modules)/project/hooks/useProjectQueries.ts @@ -15,7 +15,10 @@ interface UseProjectsQueryParams { } export function useProjectsQuery({ skip, limit }: UseProjectsQueryParams) { - const listParams = useMemo(() => ({ skip, limit }), [limit, skip]); + const listParams = useMemo( + () => ({ skip, limit }), + [limit, skip], + ); return useQuery({ queryKey: projectKeys.list(listParams), @@ -36,7 +39,8 @@ export function useDeleteProjectMutation() { }, onError: () => { toast.error('Deletion failed', { - description: 'The project could not be removed. Please try again or check your permissions.', + description: + 'The project could not be removed. Please try again or check your permissions.', }); }, }); diff --git a/src/app/(modules)/project/page.tsx b/src/app/(modules)/project/page.tsx index aa729a4..91b9ec9 100644 --- a/src/app/(modules)/project/page.tsx +++ b/src/app/(modules)/project/page.tsx @@ -12,7 +12,10 @@ import { ProjectTable } from './components/ProjectTable'; import { useProjectColumns } from './components/ProjectColumns'; import { useProjectFilters } from './hooks/useProjectFilters'; import { useProjectForm } from './hooks/useProjectForm'; -import { useDeleteProjectMutation, useProjectsQuery } from './hooks/useProjectQueries'; +import { + useDeleteProjectMutation, + useProjectsQuery, +} from './hooks/useProjectQueries'; export default function ProjectPage() { const [isDialogOpen, setIsDialogOpen] = useState(false); @@ -60,7 +63,9 @@ export default function ProjectPage() { const deleteProject = useCallback( (project: Project) => { - if (!confirm(`Are you sure you want to delete project "${project.name}"?`)) { + if ( + !confirm(`Are you sure you want to delete project "${project.name}"?`) + ) { return; } deleteProjectMutation.mutate(project); diff --git a/src/app/(modules)/results/[videoId]/page.tsx b/src/app/(modules)/results/[videoId]/page.tsx index ac66e9e..0661f13 100644 --- a/src/app/(modules)/results/[videoId]/page.tsx +++ b/src/app/(modules)/results/[videoId]/page.tsx @@ -19,8 +19,11 @@ export default function VideoResultsPage() { const router = useRouter(); const { videoId } = useParams() as { videoId: string }; const [session, setSession] = useState(null); - const [detectionData, setDetectionData] = useState(null); - const [detectionType, setDetectionType] = useState('pothole-detection'); + const [detectionData, setDetectionData] = useState( + null, + ); + const [detectionType, setDetectionType] = + useState('pothole-detection'); const [videoFile, setVideoFile] = useState(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); @@ -89,7 +92,9 @@ export default function VideoResultsPage() {
-

Loading detection results...

+

+ Loading detection results... +

); @@ -101,7 +106,10 @@ export default function VideoResultsPage() {

{error}

- @@ -116,7 +124,11 @@ export default function VideoResultsPage() {
- +
{session && ( diff --git a/src/app/(modules)/results/page.tsx b/src/app/(modules)/results/page.tsx index b925549..68108da 100644 --- a/src/app/(modules)/results/page.tsx +++ b/src/app/(modules)/results/page.tsx @@ -55,8 +55,10 @@ export default function ResultsPage() { }; const getTitle = () => { - if (detectionType === 'pothole-detection') return 'Pothole Detection Results'; - if (detectionType === 'sign-board-detection') return 'Signboard Detection Results'; + if (detectionType === 'pothole-detection') + return 'Pothole Detection Results'; + if (detectionType === 'sign-board-detection') + return 'Signboard Detection Results'; return 'Pothole & Signboard Detection Results'; }; diff --git a/src/app/(modules)/roles/components/RoleColumns.tsx b/src/app/(modules)/roles/components/RoleColumns.tsx index f50d6b1..249b86d 100644 --- a/src/app/(modules)/roles/components/RoleColumns.tsx +++ b/src/app/(modules)/roles/components/RoleColumns.tsx @@ -36,7 +36,9 @@ export function useRoleColumns(): ColumnDef[] { accessorKey: 'effective_status', header: 'Status', cell: ({ row }) => ( - + {row.original.effective_status ? 'Active' : 'Inactive'} ), diff --git a/src/app/(modules)/roles/components/RoleFilters.tsx b/src/app/(modules)/roles/components/RoleFilters.tsx index fda456d..1248d85 100644 --- a/src/app/(modules)/roles/components/RoleFilters.tsx +++ b/src/app/(modules)/roles/components/RoleFilters.tsx @@ -31,7 +31,10 @@ export function RoleFilters({ onChange={onSearchChange} placeholder="Search roles" /> - onStatusChange(value as StatusFilter)} + > diff --git a/src/app/(modules)/roles/components/RoleSheet.tsx b/src/app/(modules)/roles/components/RoleSheet.tsx index ccb7cdb..5dd6f80 100644 --- a/src/app/(modules)/roles/components/RoleSheet.tsx +++ b/src/app/(modules)/roles/components/RoleSheet.tsx @@ -54,7 +54,9 @@ export function RoleSheet({ isSaving, }: RoleSheetProps) { const nameErrorMessage = isSubmitted ? errors.name?.message : undefined; - const displayNameErrorMessage = isSubmitted ? errors.display_name?.message : undefined; + const displayNameErrorMessage = isSubmitted + ? errors.display_name?.message + : undefined; return ( @@ -72,7 +74,12 @@ export function RoleSheet({
- + {permissionIds.length} selected + + {permissionIds.length} selected + } > {isPermissionsLoading ? ( @@ -129,7 +138,9 @@ export function RoleSheet({ diff --git a/src/app/(modules)/roles/hooks/useRoleForm.ts b/src/app/(modules)/roles/hooks/useRoleForm.ts index 8d0e370..38aaf2c 100644 --- a/src/app/(modules)/roles/hooks/useRoleForm.ts +++ b/src/app/(modules)/roles/hooks/useRoleForm.ts @@ -61,7 +61,9 @@ export function useRoleForm({ const roleName = useWatch({ control, name: 'name' }) || ''; const displayName = useWatch({ control, name: 'display_name' }) || ''; const canSubmit = - roleName.trim().length > 0 && displayName.trim().length > 0 && permissionIds.length > 0; + roleName.trim().length > 0 && + displayName.trim().length > 0 && + permissionIds.length > 0; const saveMutation = useMutation({ mutationFn: (values: RoleFormValues) => @@ -81,7 +83,9 @@ export function useRoleForm({ queryClient.invalidateQueries({ queryKey: roleKeys.all }); }, onError: (_error, values) => { - toast.error(values.id ? 'Failed to update role' : 'Failed to create role'); + toast.error( + values.id ? 'Failed to update role' : 'Failed to create role', + ); }, }); @@ -116,14 +120,21 @@ export function useRoleForm({ name: role.name || '', display_name: role.display_name || '', description: role.description || '', - permission_ids: collectPermissionIdsByKeys(permissionTree, role.permissions || []), + permission_ids: collectPermissionIdsByKeys( + permissionTree, + role.permissions || [], + ), }); }, [permissionTree, reset], ); const setPermissionIds = useCallback( - (ids: number[]) => setValue('permission_ids', ids, { shouldDirty: true, shouldValidate: true }), + (ids: number[]) => + setValue('permission_ids', ids, { + shouldDirty: true, + shouldValidate: true, + }), [setValue], ); diff --git a/src/app/(modules)/roles/hooks/useRoleQueries.ts b/src/app/(modules)/roles/hooks/useRoleQueries.ts index ad8e050..561178c 100644 --- a/src/app/(modules)/roles/hooks/useRoleQueries.ts +++ b/src/app/(modules)/roles/hooks/useRoleQueries.ts @@ -32,7 +32,8 @@ function buildRoleListParams({ skip, limit, search_term: searchTerm || undefined, - effective_status: statusFilter === 'all' ? undefined : statusFilter === 'active', + effective_status: + statusFilter === 'all' ? undefined : statusFilter === 'active', ...getServerSortParams(sorting), }; } @@ -40,7 +41,8 @@ function buildRoleListParams({ export function useRolesQuery(params: UseRolesQueryParams) { const { skip, limit, searchTerm, statusFilter, sorting } = params; const listParams = useMemo( - () => buildRoleListParams({ skip, limit, searchTerm, statusFilter, sorting }), + () => + buildRoleListParams({ skip, limit, searchTerm, statusFilter, sorting }), [limit, searchTerm, skip, sorting, statusFilter], ); @@ -71,7 +73,8 @@ export function useRoleStatusMutation() { const queryClient = useQueryClient(); return useMutation({ - mutationFn: (role: Role) => roleService.updateRoleStatus(role.id, !role.effective_status), + mutationFn: (role: Role) => + roleService.updateRoleStatus(role.id, !role.effective_status), onSuccess: () => { toast.success('Role status updated'); queryClient.invalidateQueries({ queryKey: roleKeys.all }); diff --git a/src/app/(modules)/roles/page.tsx b/src/app/(modules)/roles/page.tsx index 77fc983..2eaebe2 100644 --- a/src/app/(modules)/roles/page.tsx +++ b/src/app/(modules)/roles/page.tsx @@ -23,7 +23,9 @@ import { } from './hooks/useRoleQueries'; export default function RolesPage() { - const organizationId = useAppStore((state) => state.user?.organization_id ?? null); + const organizationId = useAppStore( + (state) => state.user?.organization_id ?? null, + ); const [isSheetOpen, setIsSheetOpen] = useState(false); const { skip, @@ -66,7 +68,8 @@ export default function RolesPage() { isSaving, } = roleForm; const statusMutation = useRoleStatusMutation(); - const { mutate: updateRoleStatus, isPending: isStatusPending } = statusMutation; + const { mutate: updateRoleStatus, isPending: isStatusPending } = + statusMutation; const openCreate = useCallback(() => { prepareCreateRole(); diff --git a/src/app/(modules)/segment/components/SegmentColumns.tsx b/src/app/(modules)/segment/components/SegmentColumns.tsx index 89e4f67..1dc08c0 100644 --- a/src/app/(modules)/segment/components/SegmentColumns.tsx +++ b/src/app/(modules)/segment/components/SegmentColumns.tsx @@ -2,10 +2,19 @@ import { useMemo } from 'react'; import type { ColumnDef } from '@tanstack/react-table'; -import { ArrowDownCircle, ArrowUpCircle, MapPin, Milestone } from 'lucide-react'; +import { + ArrowDownCircle, + ArrowUpCircle, + MapPin, + Milestone, +} from 'lucide-react'; import { Badge } from '@/components/ui/badge'; -import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover'; import type { Chainage, Package, Project } from '@/types'; function EmptyValue() { @@ -43,9 +52,7 @@ function StateBadges({ value }: { value: string | null }) {
-

- Other States -

+

Other States

{remainingStates.map((state) => ( {state} @@ -78,7 +85,9 @@ export function useSegmentColumns(projects: Project[], packages: Package[]) { id: 'project', header: 'Project', cell: ({ row }) => { - const pkg = packages.find((item) => item.id === row.original.package_id); + const pkg = packages.find( + (item) => item.id === row.original.package_id, + ); const project = projects.find((item) => item.id === pkg?.project_id); return project?.name || ; }, @@ -87,7 +96,9 @@ export function useSegmentColumns(projects: Project[], packages: Package[]) { id: 'project_state', header: 'Project State', cell: ({ row }) => { - const pkg = packages.find((item) => item.id === row.original.package_id); + const pkg = packages.find( + (item) => item.id === row.original.package_id, + ); const project = projects.find((item) => item.id === pkg?.project_id); return ; }, @@ -127,7 +138,8 @@ export function useSegmentColumns(projects: Project[], packages: Package[]) { className="flex items-center gap-1.5 border-blue-500/50 text-blue-500" > - {row.original.start_lat.toFixed(4)}, {row.original.start_lng.toFixed(4)} + {row.original.start_lat.toFixed(4)},{' '} + {row.original.start_lng.toFixed(4)} ), }, diff --git a/src/app/(modules)/segment/components/SegmentDialog.tsx b/src/app/(modules)/segment/components/SegmentDialog.tsx index 70fc9fb..0ade163 100644 --- a/src/app/(modules)/segment/components/SegmentDialog.tsx +++ b/src/app/(modules)/segment/components/SegmentDialog.tsx @@ -95,7 +95,11 @@ export function SegmentDialog({ {!segmentId ? (
- + - + - + - +
) : null} @@ -218,7 +240,12 @@ export function SegmentDialog({ START COORDINATES

- + - +
- + - + .string() .trim() .min(1, message) - .refine((value) => Number.isFinite(Number(value)), { message: 'Enter a valid number' }); + .refine((value) => Number.isFinite(Number(value)), { + message: 'Enter a valid number', + }); const latitude = requiredNumber('Latitude is required').refine( (value) => { @@ -64,7 +66,9 @@ const defaultValues: SegmentFormValues = { direction: 'UP', }; -function toSegmentPayload(values: SegmentFormValues): ChainageCreate | ChainageUpdate { +function toSegmentPayload( + values: SegmentFormValues, +): ChainageCreate | ChainageUpdate { return { package_id: values.package_id, segment_name: values.segment_name.trim(), @@ -99,7 +103,8 @@ export function useSegmentForm({ onSaved }: { onSaved: () => void }) { const packageId = useWatch({ control, name: 'package_id' }) || ''; const direction = useWatch({ control, name: 'direction' }) || 'UP'; const segmentName = useWatch({ control, name: 'segment_name' }) || ''; - const chainageStartKm = useWatch({ control, name: 'chainage_start_km' }) || ''; + const chainageStartKm = + useWatch({ control, name: 'chainage_start_km' }) || ''; const chainageEndKm = useWatch({ control, name: 'chainage_end_km' }) || ''; const startLat = useWatch({ control, name: 'start_lat' }) || ''; const startLng = useWatch({ control, name: 'start_lng' }) || ''; @@ -130,14 +135,18 @@ export function useSegmentForm({ onSaved }: { onSaved: () => void }) { queryClient.invalidateQueries({ queryKey: segmentKeys.all }); }, onError: (_error, values) => { - toast.error(values.id ? 'Failed to update segment' : 'Failed to create segment'); + toast.error( + values.id ? 'Failed to update segment' : 'Failed to create segment', + ); }, }); const onSubmit = handleSubmit( (values) => saveMutation.mutate(values), (formErrors) => { - const firstMessage = Object.values(formErrors).find((error) => error?.message)?.message; + const firstMessage = Object.values(formErrors).find( + (error) => error?.message, + )?.message; if (firstMessage) { toast.error(String(firstMessage)); } @@ -169,14 +178,21 @@ export function useSegmentForm({ onSaved }: { onSaved: () => void }) { const setProjectId = useCallback( (value: string) => { - setValue('project_id', value, { shouldDirty: true, shouldValidate: true }); + setValue('project_id', value, { + shouldDirty: true, + shouldValidate: true, + }); setValue('package_id', '', { shouldDirty: true, shouldValidate: true }); }, [setValue], ); const setPackageId = useCallback( - (value: string) => setValue('package_id', value, { shouldDirty: true, shouldValidate: true }), + (value: string) => + setValue('package_id', value, { + shouldDirty: true, + shouldValidate: true, + }), [setValue], ); diff --git a/src/app/(modules)/segment/hooks/useSegmentQueries.ts b/src/app/(modules)/segment/hooks/useSegmentQueries.ts index e637703..31051c8 100644 --- a/src/app/(modules)/segment/hooks/useSegmentQueries.ts +++ b/src/app/(modules)/segment/hooks/useSegmentQueries.ts @@ -4,7 +4,11 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useMemo } from 'react'; import { toast } from 'sonner'; -import { chainageService, packageService, projectService } from '@/services/api'; +import { + chainageService, + packageService, + projectService, +} from '@/services/api'; import type { Chainage, PaginationParams } from '@/types'; import { segmentKeys } from '../queries/segmentKeys'; @@ -15,7 +19,10 @@ interface UseSegmentsQueryParams { } export function useSegmentsQuery({ skip, limit }: UseSegmentsQueryParams) { - const listParams = useMemo(() => ({ skip, limit }), [limit, skip]); + const listParams = useMemo( + () => ({ skip, limit }), + [limit, skip], + ); return useQuery({ queryKey: segmentKeys.list(listParams), @@ -40,7 +47,8 @@ export function useAllPackageOptionsQuery() { export function usePackagesByProjectQuery(projectId: string, enabled: boolean) { return useQuery({ queryKey: ['packages', 'by-project', projectId], - queryFn: () => packageService.getPackagesByProject(projectId, { skip: 0, limit: 1000 }), + queryFn: () => + packageService.getPackagesByProject(projectId, { skip: 0, limit: 1000 }), enabled: enabled && Boolean(projectId), }); } @@ -49,7 +57,8 @@ export function useDeleteSegmentMutation() { const queryClient = useQueryClient(); return useMutation({ - mutationFn: (segment: Chainage) => chainageService.deleteChainage(segment.id), + mutationFn: (segment: Chainage) => + chainageService.deleteChainage(segment.id), onSuccess: (_data, segment) => { toast.success('Segment deleted', { description: `${segment.segment_name} has been removed from the system.`, diff --git a/src/app/(modules)/segment/page.tsx b/src/app/(modules)/segment/page.tsx index 6c47605..5006dd5 100644 --- a/src/app/(modules)/segment/page.tsx +++ b/src/app/(modules)/segment/page.tsx @@ -48,7 +48,10 @@ export default function SegmentPage() { canSubmit, isSaving, } = segmentForm; - const projectPackagesQuery = usePackagesByProjectQuery(projectId, isDialogOpen); + const projectPackagesQuery = usePackagesByProjectQuery( + projectId, + isDialogOpen, + ); const openCreate = useCallback(() => { prepareCreateSegment(); @@ -57,7 +60,9 @@ export default function SegmentPage() { const openEdit = useCallback( (segment: Chainage) => { - const pkg = allPackagesQuery.data?.items.find((item) => item.id === segment.package_id); + const pkg = allPackagesQuery.data?.items.find( + (item) => item.id === segment.package_id, + ); prepareEditSegment(segment, pkg?.project_id || ''); setIsDialogOpen(true); }, @@ -76,7 +81,11 @@ export default function SegmentPage() { const deleteSegment = useCallback( (segment: Chainage) => { - if (!confirm(`Are you sure you want to delete segment "${segment.segment_name}"?`)) { + if ( + !confirm( + `Are you sure you want to delete segment "${segment.segment_name}"?`, + ) + ) { return; } deleteSegmentMutation.mutate(segment); diff --git a/src/app/(modules)/tenants/components/TenantSheet.tsx b/src/app/(modules)/tenants/components/TenantSheet.tsx index d881013..21401ae 100644 --- a/src/app/(modules)/tenants/components/TenantSheet.tsx +++ b/src/app/(modules)/tenants/components/TenantSheet.tsx @@ -67,15 +67,20 @@ export function TenantSheet({ - {tenantId ? 'Edit Tenant' : 'Create Tenant'} + + {tenantId ? 'Edit Tenant' : 'Create Tenant'} + - Bind a client and subscription plan, then invite the tenant administrator. + Bind a client and subscription plan, then invite the tenant + administrator.

Basic Information

-

Tenant identity and subscription binding.

+

+ Tenant identity and subscription binding. +

@@ -106,10 +111,16 @@ export function TenantSheet({
- @@ -123,10 +134,16 @@ export function TenantSheet({
- @@ -143,7 +160,11 @@ export function TenantSheet({
- +
@@ -226,7 +247,9 @@ export function TenantSheet({ Cancel diff --git a/src/app/(modules)/tenants/hooks/useTenantFilters.ts b/src/app/(modules)/tenants/hooks/useTenantFilters.ts index fd90854..40e1398 100644 --- a/src/app/(modules)/tenants/hooks/useTenantFilters.ts +++ b/src/app/(modules)/tenants/hooks/useTenantFilters.ts @@ -12,7 +12,8 @@ export function useTenantFilters() { const [limit, setLimitValue] = useState(10); const [sorting, setSortingValue] = useState([]); const [searchTerm, setSearchTermValue] = useState(''); - const [statusFilter, setStatusFilterValue] = useState('all'); + const [statusFilter, setStatusFilterValue] = + useState('all'); const debouncedSearchTerm = useDebounce(searchTerm.trim(), 400); const setSearchTerm = useCallback((value: string) => { diff --git a/src/app/(modules)/tenants/hooks/useTenantForm.ts b/src/app/(modules)/tenants/hooks/useTenantForm.ts index 7fe41da..382bd0c 100644 --- a/src/app/(modules)/tenants/hooks/useTenantForm.ts +++ b/src/app/(modules)/tenants/hooks/useTenantForm.ts @@ -82,7 +82,11 @@ export function useTenantForm({ onSaved }: { onSaved: () => void }) { } if (!isEditMode) { - if (!values.admin_first_name.trim() || !values.admin_last_name.trim() || !values.admin_email.trim()) { + if ( + !values.admin_first_name.trim() || + !values.admin_last_name.trim() || + !values.admin_email.trim() + ) { toast.error('Complete all required admin fields'); return; } diff --git a/src/app/(modules)/tenants/hooks/useTenantMutations.ts b/src/app/(modules)/tenants/hooks/useTenantMutations.ts index cad2d59..71ed679 100644 --- a/src/app/(modules)/tenants/hooks/useTenantMutations.ts +++ b/src/app/(modules)/tenants/hooks/useTenantMutations.ts @@ -58,7 +58,9 @@ export function useSaveTenantMutation({ onSaved }: { onSaved: () => void }) { onSaved(); }, onError: (_error, values) => { - toast.error(values.id ? 'Failed to update tenant' : 'Failed to create tenant'); + toast.error( + values.id ? 'Failed to update tenant' : 'Failed to create tenant', + ); }, }); } diff --git a/src/app/(modules)/tenants/page.tsx b/src/app/(modules)/tenants/page.tsx index c14f6c1..9bcac9e 100644 --- a/src/app/(modules)/tenants/page.tsx +++ b/src/app/(modules)/tenants/page.tsx @@ -122,7 +122,8 @@ export default function TenantsPage() { const total = tenantsQuery.data?.total ?? 0; const clients = clientsLookupQuery.data?.items ?? []; const plans = plansLookupQuery.data?.items ?? []; - const isLookupsLoading = clientsLookupQuery.isLoading || plansLookupQuery.isLoading; + const isLookupsLoading = + clientsLookupQuery.isLoading || plansLookupQuery.isLoading; const toolbar = useMemo( () => ( @@ -167,7 +168,9 @@ export default function TenantsPage() { onSortingChange={setSorting} onEdit={openEdit} onDelete={handleDelete} - pendingDeleteId={deleteMutation.isPending ? deleteMutation.variables : undefined} + pendingDeleteId={ + deleteMutation.isPending ? deleteMutation.variables : undefined + } />
diff --git a/src/app/(modules)/upload/[videoId]/page.tsx b/src/app/(modules)/upload/[videoId]/page.tsx index 47922f8..e12900c 100644 --- a/src/app/(modules)/upload/[videoId]/page.tsx +++ b/src/app/(modules)/upload/[videoId]/page.tsx @@ -11,7 +11,10 @@ import { ROUTES } from '@/utils/routes'; import { Button } from '@/components/ui/button'; const API_URL = process.env.NEXT_PUBLIC_API_URL; -const WS_URL = API_URL?.replace(/^https:\/\//, 'wss://').replace(/^http:\/\//, 'ws://'); +const WS_URL = API_URL?.replace(/^https:\/\//, 'wss://').replace( + /^http:\/\//, + 'ws://', +); export default function VideoProcessingPage() { const router = useRouter(); @@ -40,12 +43,12 @@ export default function VideoProcessingPage() { setProgress(data.progress || 0); let message = data.message || 'Processing...'; const uniqueCount = - data.unique_potholes ?? - data.unique_pothole ?? - data.unique_signboards ?? - data.unique_signboard ?? - data.unique_culverts ?? - data.unique_culvert ?? + data.unique_potholes ?? + data.unique_pothole ?? + data.unique_signboards ?? + data.unique_signboard ?? + data.unique_culverts ?? + data.unique_culvert ?? data.unique_drain_issue; if (uniqueCount !== undefined) { message += ` | Unique: ${uniqueCount} | Total: ${data.total_detections || 0}`; @@ -101,7 +104,9 @@ export default function VideoProcessingPage() { } if (statusData.status === 'error') { - setError(statusData.message || 'An error occurred during processing.'); + setError( + statusData.message || 'An error occurred during processing.', + ); setIsLoading(false); return; } @@ -203,7 +208,9 @@ export default function VideoProcessingPage() {
-

Uploading ...

+

+ Uploading ... +

ID: {videoId}

@@ -214,7 +221,9 @@ export default function VideoProcessingPage() { Progress - {progress}% + + {progress}% +

{error}

-
diff --git a/src/app/(modules)/upload/page.tsx b/src/app/(modules)/upload/page.tsx index fc8a821..46ad362 100644 --- a/src/app/(modules)/upload/page.tsx +++ b/src/app/(modules)/upload/page.tsx @@ -2,7 +2,13 @@ import { useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; @@ -49,17 +55,20 @@ export default function UploadPage() { // Load session on mount useEffect(() => { - // We don't load session on mount for the upload page to ensure + // We don't load session on mount for the upload page to ensure // project details are filled manually as requested. setIsLoading(false); }, []); - const handleSelectionChange = useCallback((selectedSession: SessionContext | null) => { - setSession(selectedSession); - if (selectedSession) { - sessionService.saveSession(selectedSession); - } - }, []); + const handleSelectionChange = useCallback( + (selectedSession: SessionContext | null) => { + setSession(selectedSession); + if (selectedSession) { + sessionService.saveSession(selectedSession); + } + }, + [], + ); const handleUpload = async () => { if (!file) { @@ -103,7 +112,8 @@ export default function UploadPage() { } catch (err) { let errorMessage = 'Upload failed'; if (err instanceof TypeError && err.message === 'Failed to fetch') { - errorMessage = 'Cannot connect to server. Please check if backend is running.'; + errorMessage = + 'Cannot connect to server. Please check if backend is running.'; } else if (err instanceof Error) { errorMessage = err.message; } @@ -120,7 +130,9 @@ export default function UploadPage() { ); } - const isSessionComplete = !!(session && sessionService.isSessionValid(session)); + const isSessionComplete = !!( + session && sessionService.isSessionValid(session) + ); const isFormValid = isSessionComplete && file && jsonFile; return ( @@ -140,14 +152,16 @@ export default function UploadPage() { - 1. Project Details + + 1. Project Details + Select the target project, package, and segment. - @@ -157,7 +171,13 @@ export default function UploadPage() { {/* Module 2: Upload Data */} - + 2. Upload Video Data @@ -170,7 +190,10 @@ export default function UploadPage() {
{/* Video File Input */}
-