From 6b012a6aaeb9df98c5ba251b6e6c5c02731d459e Mon Sep 17 00:00:00 2001 From: shancheas Date: Thu, 27 Aug 2026 13:09:57 +0700 Subject: [PATCH] refactor: improve code formatting and organization across multiple components - Enhanced readability by restructuring code formatting in various components, including API documentation, user management, and sales modules. - Standardized table and object definitions for better clarity in API documentation. - Improved layout and indentation in React components for better maintainability. - Updated unit tests to reflect changes in formatting and ensure consistency. These changes enhance the overall code quality and maintainability of the project, making it easier for developers to navigate and understand the codebase. --- .agents/skills/index-layout/SKILL.md | 18 +- api.md | 225 +++++++++--------- .../customer.remote.transformer.test.ts | 4 +- .../detail-component/detail-contacts.tsx | 13 +- .../form-component/form-contacts.tsx | 13 +- .../domain/validators/product.validator.ts | 10 +- .../cycles/data/cycle.remote.service.test.ts | 4 +- .../cycles/domain/entities/cycle.entity.ts | 4 +- .../transformers/cycle.remote.transformer.ts | 7 +- .../presentation/pages/cycle.page.form.tsx | 13 +- .../presentation/pages/cycle.page.index.tsx | 3 +- .../transformers/plan.remote.transformer.ts | 4 +- .../detail-component/detail-general.tsx | 44 +++- .../form-component/form-general.tsx | 6 +- .../presentation/pages/plan.page.form.tsx | 15 +- .../modules/field/shared/relation-label.ts | 4 +- .../pages/sales-order.page.detail.tsx | 4 +- .../pages/sales-order.page.form.tsx | 11 +- .../modules/sales/shared/detail-general.tsx | 13 +- .../modules/sales/shared/detail-location.tsx | 6 +- .../modules/sales/shared/form-general.tsx | 8 +- .../main/modules/sales/shared/form-images.tsx | 7 +- .../modules/sales/shared/form-products.tsx | 19 +- .../sales/shared/sales-document.mapper.ts | 4 +- .../sales/shared/sales-document.validator.ts | 6 +- .../shared/use-sales-document-actions.tsx | 5 +- .../privilege.remote.transformer.test.ts | 4 +- .../form-component/form-permissions.tsx | 6 +- .../users/data/user.remote.service.test.ts | 4 +- .../users/domain/validators/user.validator.ts | 12 +- .../form-component/form-general.tsx | 18 +- .../users/presentation/factory/index.tsx | 6 +- .../domain/configuration-field-validators.ts | 37 ++- .../core/lib/filter-menu-by-view-privilege.ts | 4 +- .../src/components/map/location-map.test.tsx | 4 +- .../ui/src/components/map/location-map.tsx | 13 +- .../ui/src/components/map/location-point.ts | 7 +- packages/ui/src/components/map/osm.ts | 4 +- .../ui/src/components/map/route-geometry.ts | 4 +- packages/ui/src/components/map/route-map.tsx | 7 +- .../data-table/audit-column.utils.test.ts | 17 +- .../data-table/components/bulk-actions.tsx | 5 +- .../components/data-table/index.tsx | 6 +- .../providers/detail-page.provider.tsx | 3 +- 44 files changed, 371 insertions(+), 260 deletions(-) diff --git a/.agents/skills/index-layout/SKILL.md b/.agents/skills/index-layout/SKILL.md index 14e5966..a9a6bc7 100644 --- a/.agents/skills/index-layout/SKILL.md +++ b/.agents/skills/index-layout/SKILL.md @@ -45,7 +45,11 @@ Do **not** redeclare: // GOOD const columnDefs = [ { field: 'username', headerName: t('common:fields.username'), minWidth: 160 }, - { field: 'privilege', headerName: t('common:fields.privilege'), valueGetter: ({ data }) => relationLabel(data?.privilege) }, + { + field: 'privilege', + headerName: t('common:fields.privilege'), + valueGetter: ({ data }) => relationLabel(data?.privilege), + }, ]; // BAD — duplicates shared chrome @@ -59,12 +63,12 @@ const columnDefs = [ API and transformers map: -| Entity field | Meaning | -|---|---| -| `createdBy` | actor string, `{ username }`, or uuid | -| `createdAt` | unix ms | -| `updatedBy` | actor string, `{ username }`, or uuid | -| `updatedAt` | unix ms | +| Entity field | Meaning | +| ------------ | ------------------------------------- | +| `createdBy` | actor string, `{ username }`, or uuid | +| `createdAt` | unix ms | +| `updatedBy` | actor string, `{ username }`, or uuid | +| `updatedAt` | unix ms | `EnterpriseDataTable` postfix columns bind those names and fall back to legacy snake_case (`creator_name`, `created_at`, `editor_name`, `updated_at`) for leftover local/Pouch rows. diff --git a/api.md b/api.md index 92d0964..ae2ced6 100644 --- a/api.md +++ b/api.md @@ -25,10 +25,10 @@ Base URL: `http://localhost:{PORT}` (default **3000**). There is **no** global p ### Tokens -| Token | Type | Default lifetime | Transport | -| ----- | ---- | ---------------- | --------- | -| Access | JWT HS256 | `15m` (`JWT_ACCESS_EXPIRES_IN`) | `Authorization: Bearer …` | -| Refresh | Opaque 64-char string | 7 days (`REFRESH_TOKEN_EXPIRES_IN_MS`) | JSON body `refreshToken` | +| Token | Type | Default lifetime | Transport | +| ------- | --------------------- | -------------------------------------- | ------------------------- | +| Access | JWT HS256 | `15m` (`JWT_ACCESS_EXPIRES_IN`) | `Authorization: Bearer …` | +| Refresh | Opaque 64-char string | 7 days (`REFRESH_TOKEN_EXPIRES_IN_MS`) | JSON body `refreshToken` | Refresh **rotates**: each successful `POST /auth/refresh` returns a new pair; the old refresh token is invalid. @@ -111,11 +111,11 @@ CSV import uses `multipart/form-data` with field name **`file`** (max 1 MiB). Query (all optional): -| Param | Rules | Default | -| ----- | ----- | ------- | -| `page` | integer ≥ 1 | `1` | -| `limit` | 1–**200** | `10` | -| `offset` | integer ≥ 0 | — | +| Param | Rules | Default | +| -------- | ----------- | ------- | +| `page` | integer ≥ 1 | `1` | +| `limit` | 1–**200** | `10` | +| `offset` | integer ≥ 0 | — | If both `page` and `offset` are sent, **`page` wins**. `offset` maps to `page = floor(offset / limit) + 1`. @@ -123,7 +123,9 @@ Public response: ```json { - "data": [ /* items */ ], + "data": [ + /* items */ + ], "meta": { "currentPage": 1, "itemCount": 10, @@ -140,15 +142,15 @@ Public response: Unwrapped resource object, or: -| Operation | Status | Body | -| --------- | ------ | ---- | -| Create | `201` | resource DTO (detail shape) | -| Update / status | `200` | resource DTO | -| Delete | `204` | empty | -| Bulk delete | `200` | `{ "deleted": number }` | -| Bulk status | `200` | `{ "updated": number }` | -| Import | `200` | `{ "imported": number }` | -| Generate plans | `200` | `{ "created": number, "skipped": number }` | +| Operation | Status | Body | +| --------------- | ------ | ------------------------------------------ | +| Create | `201` | resource DTO (detail shape) | +| Update / status | `200` | resource DTO | +| Delete | `204` | empty | +| Bulk delete | `200` | `{ "deleted": number }` | +| Bulk status | `200` | `{ "updated": number }` | +| Import | `200` | `{ "imported": number }` | +| Generate plans | `200` | `{ "created": number, "skipped": number }` | ### Errors (NestJS default) @@ -162,14 +164,14 @@ Unwrapped resource object, or: `message` is a string or an array of validation strings. -| Status | Typical cause | -| ------ | ------------- | -| `400` | Validation, extra fields, invalid VO (phone/date/status), `status` on PATCH | -| `401` | Missing/expired/revoked JWT, bad credentials, invalid refresh | -| `403` | `Insufficient privilege` | -| `404` | `{Resource} not found` (for example `Branch not found`) | -| `409` | Unique conflict (username, code, cycle/plan already exists) | -| `429` | Rate limit | +| Status | Typical cause | +| ------ | --------------------------------------------------------------------------- | +| `400` | Validation, extra fields, invalid VO (phone/date/status), `status` on PATCH | +| `401` | Missing/expired/revoked JWT, bad credentials, invalid refresh | +| `403` | `Insufficient privilege` | +| `404` | `{Resource} not found` (for example `Branch not found`) | +| `409` | Unique conflict (username, code, cycle/plan already exists) | +| `429` | Rate limit | CSV batch failure: @@ -189,12 +191,12 @@ Core (configuration, privileges, cycles, plans, settings): `draft` | `active` | Sales statuses (use **only** these on that resource): -| Resource | Allowed | -| -------- | ------- | -| Sales request | `draft`, `pending`, `approved`, `rejected` | -| Sales order / packing slip | `draft`, `processed`, `completed`, `cancelled` | -| Sales invoice | `draft`, `processed`, `partial`, `completed`, `cancelled` | -| Sales payment | `draft`, `pending`, `approved`, `rejected` | +| Resource | Allowed | +| -------------------------- | --------------------------------------------------------- | +| Sales request | `draft`, `pending`, `approved`, `rejected` | +| Sales order / packing slip | `draft`, `processed`, `completed`, `cancelled` | +| Sales invoice | `draft`, `processed`, `partial`, `completed`, `cancelled` | +| Sales payment | `draft`, `pending`, `approved`, `rejected` | ### Dates @@ -230,43 +232,43 @@ Actions: `view` | `create` | `update` | `delete` | `import`. HTTP mapping: -| Handler | Action | -| ------- | ------ | -| `GET` list / detail | `view` | -| `POST /` create, `POST /plans/generate` | `create` | +| Handler | Action | +| --------------------------------------------------------------------------------------------------- | -------- | +| `GET` list / detail | `view` | +| `POST /` create, `POST /plans/generate` | `create` | | `PATCH /:id`, `PATCH /:id/status`, `POST /bulk-status`, nested customer contacts, plan destinations | `update` | -| `DELETE /:id`, `POST /bulk-delete` | `delete` | -| `POST /import` | `import` | +| `DELETE /:id`, `POST /bulk-delete` | `delete` | +| `POST /import` | `import` | Catalog (`GET /privilege-keys`, needs `PRIVILEGES` `view`): -| code | label | -| ---- | ----- | -| `PRIVILEGES` | Privileges | -| `USERS` | Users | -| `CONFIGURATION.DIVISION` | Divisions | -| `CONFIGURATION.BRANCH` | Branches | -| `CONFIGURATION.CUSTOMER` | Customers | -| `CONFIGURATION.EMPLOYEE` | Employees | -| `CONFIGURATION.PRODUCT` | Products | -| `SALES.REQUEST` | Sales requests | -| `SALES.ORDER` | Sales orders | -| `SALES.PACKING_SLIP` | Packing slips | -| `SALES.INVOICE` | Sales invoices | -| `SALES.PAYMENT` | Sales payments | -| `CONFIGURATION.SETTING` | Company settings | -| `SALES.CYCLE` | Sales cycles | -| `SALES.PLAN` | Sales plans | -| `LOGISTICS.CYCLE` | Logistics cycles | -| `LOGISTICS.PLAN` | Logistics plans | +| code | label | +| ------------------------ | ---------------- | +| `PRIVILEGES` | Privileges | +| `USERS` | Users | +| `CONFIGURATION.DIVISION` | Divisions | +| `CONFIGURATION.BRANCH` | Branches | +| `CONFIGURATION.CUSTOMER` | Customers | +| `CONFIGURATION.EMPLOYEE` | Employees | +| `CONFIGURATION.PRODUCT` | Products | +| `SALES.REQUEST` | Sales requests | +| `SALES.ORDER` | Sales orders | +| `SALES.PACKING_SLIP` | Packing slips | +| `SALES.INVOICE` | Sales invoices | +| `SALES.PAYMENT` | Sales payments | +| `CONFIGURATION.SETTING` | Company settings | +| `SALES.CYCLE` | Sales cycles | +| `SALES.PLAN` | Sales plans | +| `LOGISTICS.CYCLE` | Logistics cycles | +| `LOGISTICS.PLAN` | Logistics plans | ### Field purpose Cycles and plans do **not** use a single key. Privilege is resolved from `purpose`: -| purpose | cycle key | plan key | -| ------- | --------- | -------- | -| `sales` | `SALES.CYCLE` | `SALES.PLAN` | +| purpose | cycle key | plan key | +| ----------- | ----------------- | ---------------- | +| `sales` | `SALES.CYCLE` | `SALES.PLAN` | | `logistics` | `LOGISTICS.CYCLE` | `LOGISTICS.PLAN` | `purpose` is read from **body** (writes) or **query** (lists). If omitted, the user may proceed if they have the action on **either** purpose; list results are filtered to purposes they can view. Superadmin bypasses. @@ -279,17 +281,17 @@ Sales plans may attach `invoiceIds` only. Logistics plans may attach `packingSli Unless a section says otherwise, each resource below implements: -| Method | Path | Status | Notes | -| ------ | ---- | ------ | ----- | -| `GET` | `/{resource}` | `200` | Paginated `{ data, meta }` | -| `GET` | `/{resource}/:id` | `200` | Detail (may include nested arrays list omits) | -| `POST` | `/{resource}` | `201` | Create | -| `PATCH` | `/{resource}/:id` | `200` | Update — **no** `status` | -| `PATCH` | `/{resource}/:id/status` | `200` | `{ status }` | -| `DELETE` | `/{resource}/:id` | `204` | Hard delete (cycles/plans: archive) | -| `POST` | `/{resource}/bulk-delete` | `200` | `{ ids }` → `{ deleted }` | -| `POST` | `/{resource}/bulk-status` | `200` | `{ ids, status }` → `{ updated }` | -| `POST` | `/{resource}/import` | `200` | multipart `file` → `{ imported }` | +| Method | Path | Status | Notes | +| -------- | ------------------------- | ------ | --------------------------------------------- | +| `GET` | `/{resource}` | `200` | Paginated `{ data, meta }` | +| `GET` | `/{resource}/:id` | `200` | Detail (may include nested arrays list omits) | +| `POST` | `/{resource}` | `201` | Create | +| `PATCH` | `/{resource}/:id` | `200` | Update — **no** `status` | +| `PATCH` | `/{resource}/:id/status` | `200` | `{ status }` | +| `DELETE` | `/{resource}/:id` | `204` | Hard delete (cycles/plans: archive) | +| `POST` | `/{resource}/bulk-delete` | `200` | `{ ids }` → `{ deleted }` | +| `POST` | `/{resource}/bulk-status` | `200` | `{ ids, status }` → `{ updated }` | +| `POST` | `/{resource}/import` | `200` | multipart `file` → `{ imported }` | Audit fields on primary DTOs: `createdAt`, `updatedAt` (unix ms), `createdBy`, `updatedBy` (user UUID). @@ -352,9 +354,7 @@ List filters: `name`, `code`, `status`, `search` (name/code). "name": "Sales Staff", "code": "SALES_STAFF", "status": "draft", - "details": [ - { "privilegeKeyId": "uuid", "action": "view", "value": true } - ] + "details": [{ "privilegeKeyId": "uuid", "action": "view", "value": true }] } ``` @@ -467,11 +467,11 @@ Contact create: `name` required; `jobTitle?`, `phone?`, `mobilePhone?`, `notes?` ### Nested contacts (privilege = customer **update**) -| Method | Path | Status | Body | Response | -| ------ | ---- | ------ | ---- | -------- | -| `POST` | `/customers/:id/contacts` | `200` | create contact | full `CustomerDto` | -| `PATCH` | `/customers/:id/contacts/:contactId` | `200` | partial contact | full `CustomerDto` | -| `DELETE` | `/customers/:id/contacts/:contactId` | `204` | — | empty | +| Method | Path | Status | Body | Response | +| -------- | ------------------------------------ | ------ | --------------- | ------------------ | +| `POST` | `/customers/:id/contacts` | `200` | create contact | full `CustomerDto` | +| `PATCH` | `/customers/:id/contacts/:contactId` | `200` | partial contact | full `CustomerDto` | +| `DELETE` | `/customers/:id/contacts/:contactId` | `204` | — | empty | List filters: `code`, `name`, `phone`, `address`, `nfcId`, `status`, `search` (code/name/address). @@ -574,12 +574,8 @@ Detail adds: ```json { - "products": [ - { "id": "uuid", "productId": "uuid", "quantity": "2.0000", "price": "12500.0000" } - ], - "images": [ - { "id": "uuid", "url": "https://…", "description": null } - ] + "products": [{ "id": "uuid", "productId": "uuid", "quantity": "2.0000", "price": "12500.0000" }], + "images": [{ "id": "uuid", "url": "https://…", "description": null }] } ``` @@ -659,10 +655,10 @@ CSV required: `date` (allocations empty on import). Key: `CONFIGURATION.SETTING`. Singleton — no list/CRUD. -| Method | Path | Action | Notes | -| ------ | ---- | ------ | ----- | -| `GET` | `/settings` | view | `404` `{ "message": "Settings not configured" }` if never patched | -| `PATCH` | `/settings` | update | upserts | +| Method | Path | Action | Notes | +| ------- | ----------- | ------ | ----------------------------------------------------------------- | +| `GET` | `/settings` | view | `404` `{ "message": "Settings not configured" }` if never patched | +| `PATCH` | `/settings` | update | upserts | **Patch body:** `{ "cycleStartDate": "2026-01-05" }` (`YYYY-MM-DD` only). @@ -730,11 +726,12 @@ No hard delete: `DELETE` / `bulk-delete` archive. **Has CSV import.** Standard l "endBranchId": "uuid", "routeGeometry": { "type": "LineString", - "coordinates": [[106.8456, -6.2088], [107.0, -6.3]] + "coordinates": [ + [106.8456, -6.2088], + [107.0, -6.3] + ] }, - "destinations": [ - { "id": "uuid", "customerId": "uuid", "sortOrder": 0 } - ] + "destinations": [{ "id": "uuid", "customerId": "uuid", "sortOrder": 0 }] } ], "status": "draft", @@ -759,19 +756,19 @@ Privilege: `RequireFieldPrivilege('plan', action)` → `SALES.PLAN` or `LOGISTIC **No CSV import.** Delete archives. Extra routes: generate, add/remove destinations. -| Method | Path | Action | Status | Body / response | -| ------ | ---- | ------ | ------ | --------------- | -| `GET` | `/plans` | view | 200 | paginated | -| `GET` | `/plans/:id` | view | 200 | `PlanDto` | -| `POST` | `/plans/generate` | create | 200 | `{ employeeId, purpose, from, to }` → `{ created, skipped }` | -| `POST` | `/plans` | create | 201 | see below | -| `PATCH` | `/plans/:id` | update | 200 | no status | -| `PATCH` | `/plans/:id/status` | update | 200 | `{ status }` | -| `POST` | `/plans/:id/destinations` | update | 200 | `{ customerId, afterDestinationId? }` → `PlanDto` | -| `DELETE` | `/plans/:id/destinations/:destinationId` | update | **200** | `PlanDto` (not 204) | -| `DELETE` | `/plans/:id` | delete | 204 | archives | -| `POST` | `/plans/bulk-delete` | delete | 200 | `{ deleted }` | -| `POST` | `/plans/bulk-status` | update | 200 | `{ updated }` | +| Method | Path | Action | Status | Body / response | +| -------- | ---------------------------------------- | ------ | ------- | ------------------------------------------------------------ | +| `GET` | `/plans` | view | 200 | paginated | +| `GET` | `/plans/:id` | view | 200 | `PlanDto` | +| `POST` | `/plans/generate` | create | 200 | `{ employeeId, purpose, from, to }` → `{ created, skipped }` | +| `POST` | `/plans` | create | 201 | see below | +| `PATCH` | `/plans/:id` | update | 200 | no status | +| `PATCH` | `/plans/:id/status` | update | 200 | `{ status }` | +| `POST` | `/plans/:id/destinations` | update | 200 | `{ customerId, afterDestinationId? }` → `PlanDto` | +| `DELETE` | `/plans/:id/destinations/:destinationId` | update | **200** | `PlanDto` (not 204) | +| `DELETE` | `/plans/:id` | delete | 204 | archives | +| `POST` | `/plans/bulk-delete` | delete | 200 | `{ deleted }` | +| `POST` | `/plans/bulk-status` | update | 200 | `{ updated }` | Register static paths (`generate`, `bulk-delete`, `bulk-status`) before `:id`. @@ -898,14 +895,7 @@ type UnixMs = number; type DecimalString = string; type CoreStatus = 'draft' | 'active' | 'archived'; type FieldPurpose = 'sales' | 'logistics'; -type Weekday = - | 'monday' - | 'tuesday' - | 'wednesday' - | 'thursday' - | 'friday' - | 'saturday' - | 'sunday'; +type Weekday = 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday'; type PrivilegeAction = 'view' | 'create' | 'update' | 'delete' | 'import'; type PaginationMeta = { @@ -932,10 +922,7 @@ type Me = { username: string; isSuperadmin: boolean; privilege: { id: Uuid; name: string; code: string } | null; - permissions: Record< - string, - Record - >; + permissions: Record>; }; type RouteGeometry = { diff --git a/apps/web/src/apps/main/modules/configuration/customers/domain/transformers/customer.remote.transformer.test.ts b/apps/web/src/apps/main/modules/configuration/customers/domain/transformers/customer.remote.transformer.test.ts index a5ebc21..1d3c329 100644 --- a/apps/web/src/apps/main/modules/configuration/customers/domain/transformers/customer.remote.transformer.test.ts +++ b/apps/web/src/apps/main/modules/configuration/customers/domain/transformers/customer.remote.transformer.test.ts @@ -29,9 +29,7 @@ describe('CustomersRemoteDataTransformer', () => { it('includes named contacts on create and omits status', () => { const payload = transformer.transformCreatePayload(dto); - expect(payload.contacts).toEqual([ - { name: 'Andi Pratama', jobTitle: 'Manager', phone: '+6281111111111' }, - ]); + expect(payload.contacts).toEqual([{ name: 'Andi Pratama', jobTitle: 'Manager', phone: '+6281111111111' }]); expect(payload).not.toHaveProperty('status'); expect(payload).not.toHaveProperty('id'); }); diff --git a/apps/web/src/apps/main/modules/configuration/customers/presentation/components/detail-component/detail-contacts.tsx b/apps/web/src/apps/main/modules/configuration/customers/presentation/components/detail-component/detail-contacts.tsx index 73ea453..a30d091 100644 --- a/apps/web/src/apps/main/modules/configuration/customers/presentation/components/detail-component/detail-contacts.tsx +++ b/apps/web/src/apps/main/modules/configuration/customers/presentation/components/detail-component/detail-contacts.tsx @@ -13,7 +13,11 @@ import { Text, notifications, } from '@repo/ui/components'; -import { useDetailPageContext, useEnterpriseModuleConfigContext, useEnterpriseModuleTranslationContext } from '@repo/ui/foundations'; +import { + useDetailPageContext, + useEnterpriseModuleConfigContext, + useEnterpriseModuleTranslationContext, +} from '@repo/ui/foundations'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { Pencil, Plus, Trash2 } from 'lucide-react'; @@ -131,7 +135,12 @@ export function DetailContacts() { openEdit(contact)} aria-label={t('edit_contact')}> - handleDelete(contact)} aria-label={t('delete_contact')}> + handleDelete(contact)} + aria-label={t('delete_contact')} + > diff --git a/apps/web/src/apps/main/modules/configuration/customers/presentation/components/form-component/form-contacts.tsx b/apps/web/src/apps/main/modules/configuration/customers/presentation/components/form-component/form-contacts.tsx index 9bb5981..b60cf0c 100644 --- a/apps/web/src/apps/main/modules/configuration/customers/presentation/components/form-component/form-contacts.tsx +++ b/apps/web/src/apps/main/modules/configuration/customers/presentation/components/form-component/form-contacts.tsx @@ -1,4 +1,15 @@ -import { ActionIcon, Box, Button, FieldTextInput, FieldTextarea, Group, Paper, SimpleGrid, Stack, Text } from '@repo/ui/components'; +import { + ActionIcon, + Box, + Button, + FieldTextInput, + FieldTextarea, + Group, + Paper, + SimpleGrid, + Stack, + Text, +} from '@repo/ui/components'; import { useEnterpriseModuleTranslationContext, useFormPageContext } from '@repo/ui/foundations'; import { useFieldArray } from '@repo/ui/form'; import { Plus, Trash2 } from 'lucide-react'; diff --git a/apps/web/src/apps/main/modules/configuration/products/domain/validators/product.validator.ts b/apps/web/src/apps/main/modules/configuration/products/domain/validators/product.validator.ts index ed01c13..3d7cc89 100644 --- a/apps/web/src/apps/main/modules/configuration/products/domain/validators/product.validator.ts +++ b/apps/web/src/apps/main/modules/configuration/products/domain/validators/product.validator.ts @@ -28,14 +28,8 @@ export const createProductSchema = (t: (key: string) => string) => { return z.object({ code: configCodeSchema(t, PRODUCT_CODE_MAX), name: productNameSchema(t), - unit: z.preprocess( - emptyToUndefined, - compose(z.string(), maxLength(16, t('common:fields.unit'))).optional(), - ), + unit: z.preprocess(emptyToUndefined, compose(z.string(), maxLength(16, t('common:fields.unit'))).optional()), price: optionalDecimalStringSchema(t, 'common:fields.price'), - brand: z.preprocess( - emptyToUndefined, - compose(z.string(), maxLength(64, t('common:fields.brand'))).optional(), - ), + brand: z.preprocess(emptyToUndefined, compose(z.string(), maxLength(64, t('common:fields.brand'))).optional()), }); }; diff --git a/apps/web/src/apps/main/modules/field/cycles/data/cycle.remote.service.test.ts b/apps/web/src/apps/main/modules/field/cycles/data/cycle.remote.service.test.ts index 8e52fc9..a9f909e 100644 --- a/apps/web/src/apps/main/modules/field/cycles/data/cycle.remote.service.test.ts +++ b/apps/web/src/apps/main/modules/field/cycles/data/cycle.remote.service.test.ts @@ -40,9 +40,7 @@ describe('CyclesRemoteDataServices', () => { it('uses PATCH when editing a cycle', async () => { await service.edit('cyc-1', { cycleNumber: 2 } as any); - expect(httpClient.request).toHaveBeenCalledWith( - expect.objectContaining({ url: '/cycles/cyc-1', method: 'PATCH' }), - ); + expect(httpClient.request).toHaveBeenCalledWith(expect.objectContaining({ url: '/cycles/cyc-1', method: 'PATCH' })); }); it('bulk-deletes via POST /cycles/bulk-delete', async () => { diff --git a/apps/web/src/apps/main/modules/field/cycles/domain/entities/cycle.entity.ts b/apps/web/src/apps/main/modules/field/cycles/domain/entities/cycle.entity.ts index 0b014ae..407001e 100644 --- a/apps/web/src/apps/main/modules/field/cycles/domain/entities/cycle.entity.ts +++ b/apps/web/src/apps/main/modules/field/cycles/domain/entities/cycle.entity.ts @@ -51,7 +51,9 @@ export interface CycleDto { employeeId: string; purpose: FieldPurpose; cycleNumber: number; - weekdays?: CycleWeekdayEntity[] | Record; + weekdays?: + | CycleWeekdayEntity[] + | Record; status?: ConfigurationStatus; createdAt?: number; updatedAt?: number; diff --git a/apps/web/src/apps/main/modules/field/cycles/domain/transformers/cycle.remote.transformer.ts b/apps/web/src/apps/main/modules/field/cycles/domain/transformers/cycle.remote.transformer.ts index bba0e69..7d8361a 100644 --- a/apps/web/src/apps/main/modules/field/cycles/domain/transformers/cycle.remote.transformer.ts +++ b/apps/web/src/apps/main/modules/field/cycles/domain/transformers/cycle.remote.transformer.ts @@ -2,12 +2,7 @@ import { BaseDataTransformer } from '@repo/core-api/data-services'; import { omitEmptyFields } from '../../../../../../../core/domain/configuration-field-validators'; import { WEEKDAYS } from '../../../../../../../core/domain/configuration-field-validators'; import type { FieldPurpose } from '../../../../../../../core/domain/field-purpose'; -import type { - CycleEntity, - CycleWeekdayEntity, - CycleWeekdayRow, - CycleWeekdayWrite, -} from '../entities'; +import type { CycleEntity, CycleWeekdayEntity, CycleWeekdayRow, CycleWeekdayWrite } from '../entities'; function relationId(value: unknown): string | undefined { if (value && typeof value === 'object' && 'id' in value) { diff --git a/apps/web/src/apps/main/modules/field/cycles/presentation/pages/cycle.page.form.tsx b/apps/web/src/apps/main/modules/field/cycles/presentation/pages/cycle.page.form.tsx index 70b4aa2..7c4810b 100644 --- a/apps/web/src/apps/main/modules/field/cycles/presentation/pages/cycle.page.form.tsx +++ b/apps/web/src/apps/main/modules/field/cycles/presentation/pages/cycle.page.form.tsx @@ -44,7 +44,18 @@ export default function CyclePageForm({ formPageType }: { formPageType: FormPage formControl={formControl} formPageType={formPageType} ignoreKeyDuplicate={['id']} - ignoreKeyUpdate={['status', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy', 'id', 'purpose', 'employeeId', 'weekdays', 'routeGeometry']} + ignoreKeyUpdate={[ + 'status', + 'createdAt', + 'updatedAt', + 'createdBy', + 'updatedBy', + 'id', + 'purpose', + 'employeeId', + 'weekdays', + 'routeGeometry', + ]} highlightDataKey="cycleNumber" pageHeaderProps={{ title: title?.title, diff --git a/apps/web/src/apps/main/modules/field/cycles/presentation/pages/cycle.page.index.tsx b/apps/web/src/apps/main/modules/field/cycles/presentation/pages/cycle.page.index.tsx index caa1041..60c4c3b 100644 --- a/apps/web/src/apps/main/modules/field/cycles/presentation/pages/cycle.page.index.tsx +++ b/apps/web/src/apps/main/modules/field/cycles/presentation/pages/cycle.page.index.tsx @@ -29,7 +29,8 @@ export default function CyclePageIndex() { field: 'weekdayRows', headerName: t('section_weekdays'), minWidth: 140, - valueGetter: ({ data }) => data?.weekdayRows?.filter((row) => row.enabled).length ?? data?.weekdays?.length ?? 0, + valueGetter: ({ data }) => + data?.weekdayRows?.filter((row) => row.enabled).length ?? data?.weekdays?.length ?? 0, }, ]; }, [t]); diff --git a/apps/web/src/apps/main/modules/field/plans/domain/transformers/plan.remote.transformer.ts b/apps/web/src/apps/main/modules/field/plans/domain/transformers/plan.remote.transformer.ts index 7c12ead..a432b1d 100644 --- a/apps/web/src/apps/main/modules/field/plans/domain/transformers/plan.remote.transformer.ts +++ b/apps/web/src/apps/main/modules/field/plans/domain/transformers/plan.remote.transformer.ts @@ -65,7 +65,9 @@ export class PlansRemoteDataTransformer extends BaseDataTransformer if (this.purpose === 'sales') { payload.invoiceIds = relationIds(entity.invoices).length ? relationIds(entity.invoices) : entity.invoiceIds; } else { - payload.packingSlipIds = relationIds(entity.packingSlips).length ? relationIds(entity.packingSlips) : entity.packingSlipIds; + payload.packingSlipIds = relationIds(entity.packingSlips).length + ? relationIds(entity.packingSlips) + : entity.packingSlipIds; } return payload; } diff --git a/apps/web/src/apps/main/modules/field/plans/presentation/components/detail-component/detail-general.tsx b/apps/web/src/apps/main/modules/field/plans/presentation/components/detail-component/detail-general.tsx index a86b337..12b9b0c 100644 --- a/apps/web/src/apps/main/modules/field/plans/presentation/components/detail-component/detail-general.tsx +++ b/apps/web/src/apps/main/modules/field/plans/presentation/components/detail-component/detail-general.tsx @@ -1,6 +1,24 @@ -import { ActionIcon, Box, Button, FieldAsyncSelect, FieldValue, Group, Paper, RenderDate, SimpleGrid, Stack, StatusBadge, Text, notifications } from '@repo/ui/components'; +import { + ActionIcon, + Box, + Button, + FieldAsyncSelect, + FieldValue, + Group, + Paper, + RenderDate, + SimpleGrid, + Stack, + StatusBadge, + Text, + notifications, +} from '@repo/ui/components'; import { RouteMap } from '@repo/ui/map'; -import { useDetailPageContext, useEnterpriseModuleTranslationContext, useEnterpriseModuleDataServiceContext } from '@repo/ui/foundations'; +import { + useDetailPageContext, + useEnterpriseModuleTranslationContext, + useEnterpriseModuleDataServiceContext, +} from '@repo/ui/foundations'; import { useForm } from 'react-hook-form'; import { Plus, Trash2 } from 'lucide-react'; import { relationLabel } from '../../../../shared/relation-label'; @@ -39,10 +57,24 @@ export function DetailGeneral() { - } /> - - - } /> + } + /> + + + } + /> diff --git a/apps/web/src/apps/main/modules/field/plans/presentation/components/form-component/form-general.tsx b/apps/web/src/apps/main/modules/field/plans/presentation/components/form-component/form-general.tsx index 6aec4b2..1887ba5 100644 --- a/apps/web/src/apps/main/modules/field/plans/presentation/components/form-component/form-general.tsx +++ b/apps/web/src/apps/main/modules/field/plans/presentation/components/form-component/form-general.tsx @@ -1,5 +1,9 @@ import { Box, FieldAsyncSelect, FieldDatePicker, Paper, SimpleGrid, Text } from '@repo/ui/components'; -import { useEnterpriseModuleTranslationContext, useFormPageContext, useEnterpriseModuleConfigContext } from '@repo/ui/foundations'; +import { + useEnterpriseModuleTranslationContext, + useFormPageContext, + useEnterpriseModuleConfigContext, +} from '@repo/ui/foundations'; import { purposeFromModuleKey } from '../../../../../../../../core/domain/field-purpose'; import { loadEmployeeOptions } from '../../../../shared/load-employee-options'; import { loadBranchOptions } from '../../../../shared/load-branch-options'; diff --git a/apps/web/src/apps/main/modules/field/plans/presentation/pages/plan.page.form.tsx b/apps/web/src/apps/main/modules/field/plans/presentation/pages/plan.page.form.tsx index 2e3e7e8..2756b69 100644 --- a/apps/web/src/apps/main/modules/field/plans/presentation/pages/plan.page.form.tsx +++ b/apps/web/src/apps/main/modules/field/plans/presentation/pages/plan.page.form.tsx @@ -39,7 +39,20 @@ export default function PlanPageForm({ formPageType }: { formPageType: FormPageT formControl={formControl} formPageType={formPageType} ignoreKeyDuplicate={['id']} - ignoreKeyUpdate={['status', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy', 'id', 'purpose', 'employeeId', 'destinations', 'routeGeometry', 'invoiceIds', 'packingSlipIds']} + ignoreKeyUpdate={[ + 'status', + 'createdAt', + 'updatedAt', + 'createdBy', + 'updatedBy', + 'id', + 'purpose', + 'employeeId', + 'destinations', + 'routeGeometry', + 'invoiceIds', + 'packingSlipIds', + ]} highlightDataKey="date" pageHeaderProps={{ title: title?.title, diff --git a/apps/web/src/apps/main/modules/field/shared/relation-label.ts b/apps/web/src/apps/main/modules/field/shared/relation-label.ts index 5bdf681..7ea956b 100644 --- a/apps/web/src/apps/main/modules/field/shared/relation-label.ts +++ b/apps/web/src/apps/main/modules/field/shared/relation-label.ts @@ -1,6 +1,4 @@ -export function relationLabel( - item: { code?: string | null; name?: string; id?: string | number } | null | undefined, -) { +export function relationLabel(item: { code?: string | null; name?: string; id?: string | number } | null | undefined) { if (!item) return ''; if (item.code && item.name) return `${item.code} - ${item.name}`; return item.name || item.code || (item.id == null ? '' : String(item.id)); diff --git a/apps/web/src/apps/main/modules/sales/orders/presentation/pages/sales-order.page.detail.tsx b/apps/web/src/apps/main/modules/sales/orders/presentation/pages/sales-order.page.detail.tsx index abac559..f9e8cf1 100644 --- a/apps/web/src/apps/main/modules/sales/orders/presentation/pages/sales-order.page.detail.tsx +++ b/apps/web/src/apps/main/modules/sales/orders/presentation/pages/sales-order.page.detail.tsx @@ -24,7 +24,9 @@ export default function SalesOrderPageDetail() { { label: t('nav:sales-orders'), type: 'link', href: `${salesOrdersModuleConfig.webUrl}/index` }, ], }} - customPageActions={(data, pageActions) => actions.detailStatusActions(data as SalesOrderEntity, pageActions ?? [])} + customPageActions={(data, pageActions) => + actions.detailStatusActions(data as SalesOrderEntity, pageActions ?? []) + } > `${salesRequestsModuleConfig.webUrl}/detail/${id}`} /> diff --git a/apps/web/src/apps/main/modules/sales/orders/presentation/pages/sales-order.page.form.tsx b/apps/web/src/apps/main/modules/sales/orders/presentation/pages/sales-order.page.form.tsx index a0828ad..2666446 100644 --- a/apps/web/src/apps/main/modules/sales/orders/presentation/pages/sales-order.page.form.tsx +++ b/apps/web/src/apps/main/modules/sales/orders/presentation/pages/sales-order.page.form.tsx @@ -62,7 +62,16 @@ export default function SalesOrderPageForm({ formPageType }: { formPageType: For formControl={formControl} formPageType={formPageType} ignoreKeyDuplicate={['code']} - ignoreKeyUpdate={['status', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy', 'id', 'salesRequestId', 'salesRequest']} + ignoreKeyUpdate={[ + 'status', + 'createdAt', + 'updatedAt', + 'createdBy', + 'updatedBy', + 'id', + 'salesRequestId', + 'salesRequest', + ]} highlightDataKey="code" pageHeaderProps={{ title: title?.title, diff --git a/apps/web/src/apps/main/modules/sales/shared/detail-general.tsx b/apps/web/src/apps/main/modules/sales/shared/detail-general.tsx index aafcf03..cf76777 100644 --- a/apps/web/src/apps/main/modules/sales/shared/detail-general.tsx +++ b/apps/web/src/apps/main/modules/sales/shared/detail-general.tsx @@ -8,7 +8,9 @@ export function DetailGeneral({ }: { salesRequestHref?: (id: string) => string; } = {}) { - const { detailData } = useDetailPageContext(); + const { detailData } = useDetailPageContext< + SalesDocumentEntity & { salesRequestId?: string | null; salesRequest?: { id?: string; code?: string } | null } + >(); const { t } = useEnterpriseModuleTranslationContext(); const data = detailData; const salesRequestId = data?.salesRequestId ?? data?.salesRequest?.id; @@ -26,7 +28,10 @@ export function DetailGeneral({ value={data?.date} render={(val) => } /> - + @@ -36,9 +41,7 @@ export function DetailGeneral({ value={salesRequestId} render={() => salesRequestId ? ( - - {data?.salesRequest?.code || salesRequestId} - + {data?.salesRequest?.code || salesRequestId} ) : ( '-' ) diff --git a/apps/web/src/apps/main/modules/sales/shared/detail-location.tsx b/apps/web/src/apps/main/modules/sales/shared/detail-location.tsx index 0e400e3..e32f276 100644 --- a/apps/web/src/apps/main/modules/sales/shared/detail-location.tsx +++ b/apps/web/src/apps/main/modules/sales/shared/detail-location.tsx @@ -14,11 +14,7 @@ export function DetailLocation() { {t('section_location')} - + diff --git a/apps/web/src/apps/main/modules/sales/shared/form-general.tsx b/apps/web/src/apps/main/modules/sales/shared/form-general.tsx index 8473b70..d3453f1 100644 --- a/apps/web/src/apps/main/modules/sales/shared/form-general.tsx +++ b/apps/web/src/apps/main/modules/sales/shared/form-general.tsx @@ -32,7 +32,13 @@ export function FormGeneral() { placeholder="e.g. SR-20260826-0001" radius="md" /> - + control={formControl.control} name="salesPerson" diff --git a/apps/web/src/apps/main/modules/sales/shared/form-images.tsx b/apps/web/src/apps/main/modules/sales/shared/form-images.tsx index 54beb21..e24449a 100644 --- a/apps/web/src/apps/main/modules/sales/shared/form-images.tsx +++ b/apps/web/src/apps/main/modules/sales/shared/form-images.tsx @@ -15,7 +15,12 @@ export function FormImages() { {t('section_images')} - diff --git a/apps/web/src/apps/main/modules/sales/shared/form-products.tsx b/apps/web/src/apps/main/modules/sales/shared/form-products.tsx index 08cfc6c..371fc5d 100644 --- a/apps/web/src/apps/main/modules/sales/shared/form-products.tsx +++ b/apps/web/src/apps/main/modules/sales/shared/form-products.tsx @@ -1,4 +1,14 @@ -import { ActionIcon, Box, Button, FieldAsyncSelect, FieldTextInput, Group, Paper, Table, Text } from '@repo/ui/components'; +import { + ActionIcon, + Box, + Button, + FieldAsyncSelect, + FieldTextInput, + Group, + Paper, + Table, + Text, +} from '@repo/ui/components'; import { useEnterpriseModuleTranslationContext, useFormPageContext } from '@repo/ui/foundations'; import { useFieldArray, useWatch } from '@repo/ui/form'; import { Plus, Trash2 } from 'lucide-react'; @@ -70,7 +80,12 @@ export function FormProducts() { {currency.format(lineTotal(line?.quantity, line?.price))} - remove(index)} aria-label={t('remove_line')}> + remove(index)} + aria-label={t('remove_line')} + > diff --git a/apps/web/src/apps/main/modules/sales/shared/sales-document.mapper.ts b/apps/web/src/apps/main/modules/sales/shared/sales-document.mapper.ts index 29abc52..9658158 100644 --- a/apps/web/src/apps/main/modules/sales/shared/sales-document.mapper.ts +++ b/apps/web/src/apps/main/modules/sales/shared/sales-document.mapper.ts @@ -95,7 +95,9 @@ export function toSalesWritePayload( }; if (options?.includeSalesRequestId) { - payload.salesRequestId = relationId((entity as { salesRequest?: unknown }).salesRequest) ?? (entity as { salesRequestId?: string }).salesRequestId; + payload.salesRequestId = + relationId((entity as { salesRequest?: unknown }).salesRequest) ?? + (entity as { salesRequestId?: string }).salesRequestId; } return payload; diff --git a/apps/web/src/apps/main/modules/sales/shared/sales-document.validator.ts b/apps/web/src/apps/main/modules/sales/shared/sales-document.validator.ts index 0820ee4..9473df3 100644 --- a/apps/web/src/apps/main/modules/sales/shared/sales-document.validator.ts +++ b/apps/web/src/apps/main/modules/sales/shared/sales-document.validator.ts @@ -1,6 +1,10 @@ import { z } from 'zod'; import { compose, maxLength, required } from '@repo/ui/validators'; -import { configAddressSchema, optionalLatitudeSchema, optionalLongitudeSchema } from '../../../../../core/domain/configuration-field-validators'; +import { + configAddressSchema, + optionalLatitudeSchema, + optionalLongitudeSchema, +} from '../../../../../core/domain/configuration-field-validators'; import { decimalStringSchema } from '../../../../../core/domain/decimal-string.schema'; const NOTES_MAX = 1024; diff --git a/apps/web/src/apps/main/modules/sales/shared/use-sales-document-actions.tsx b/apps/web/src/apps/main/modules/sales/shared/use-sales-document-actions.tsx index eb20dce..55c8677 100644 --- a/apps/web/src/apps/main/modules/sales/shared/use-sales-document-actions.tsx +++ b/apps/web/src/apps/main/modules/sales/shared/use-sales-document-actions.tsx @@ -82,7 +82,10 @@ export function useSalesDocumentActions(documentType: SalesDocumentType) { icon: , variant: 'light' as const, onClick: () => { - void applyStatus(selectedRows.map((row) => String(row.id)), action.target); + void applyStatus( + selectedRows.map((row) => String(row.id)), + action.target, + ); }, }; }); diff --git a/apps/web/src/apps/main/modules/system/privileges/domain/transformers/privilege.remote.transformer.test.ts b/apps/web/src/apps/main/modules/system/privileges/domain/transformers/privilege.remote.transformer.test.ts index 665998b..b4b6893 100644 --- a/apps/web/src/apps/main/modules/system/privileges/domain/transformers/privilege.remote.transformer.test.ts +++ b/apps/web/src/apps/main/modules/system/privileges/domain/transformers/privilege.remote.transformer.test.ts @@ -95,9 +95,7 @@ describe('PrivilegesRemoteDataTransformer', () => { expect(payload).not.toHaveProperty('status'); expect(payload).not.toHaveProperty('id'); - expect(payload.details).toEqual( - expect.arrayContaining([{ privilegeKeyId: 'key-1', action: 'view', value: true }]), - ); + expect(payload.details).toEqual(expect.arrayContaining([{ privilegeKeyId: 'key-1', action: 'view', value: true }])); }); it('maps an empty details list to an empty matrix', () => { diff --git a/apps/web/src/apps/main/modules/system/privileges/presentation/components/form-component/form-permissions.tsx b/apps/web/src/apps/main/modules/system/privileges/presentation/components/form-component/form-permissions.tsx index 996425b..a490a68 100644 --- a/apps/web/src/apps/main/modules/system/privileges/presentation/components/form-component/form-permissions.tsx +++ b/apps/web/src/apps/main/modules/system/privileges/presentation/components/form-component/form-permissions.tsx @@ -56,11 +56,7 @@ export function FormPermissions() { {PRIVILEGE_ACTIONS.map((action) => ( - + ))} diff --git a/apps/web/src/apps/main/modules/system/users/data/user.remote.service.test.ts b/apps/web/src/apps/main/modules/system/users/data/user.remote.service.test.ts index a95e9e5..b16bd7e 100644 --- a/apps/web/src/apps/main/modules/system/users/data/user.remote.service.test.ts +++ b/apps/web/src/apps/main/modules/system/users/data/user.remote.service.test.ts @@ -40,9 +40,7 @@ describe('UsersRemoteDataServices', () => { it('uses PATCH when editing a user', async () => { await service.edit('user-1', { username: 'alice' } as any); - expect(httpClient.request).toHaveBeenCalledWith( - expect.objectContaining({ url: '/users/user-1', method: 'PATCH' }), - ); + expect(httpClient.request).toHaveBeenCalledWith(expect.objectContaining({ url: '/users/user-1', method: 'PATCH' })); }); it('bulk-deletes via POST /users/bulk-delete', async () => { diff --git a/apps/web/src/apps/main/modules/system/users/domain/validators/user.validator.ts b/apps/web/src/apps/main/modules/system/users/domain/validators/user.validator.ts index 149e084..888696f 100644 --- a/apps/web/src/apps/main/modules/system/users/domain/validators/user.validator.ts +++ b/apps/web/src/apps/main/modules/system/users/domain/validators/user.validator.ts @@ -13,14 +13,10 @@ export const createUserSchema = (t: (key: string) => string, options?: { require : z.union([z.literal(''), compose(z.string(), rangeLength(8, 72, passwordLabel))]).optional(); return z.object({ - username: compose( - z.string(), - required(usernameLabel), - rangeLength(3, 32, usernameLabel), - (schema: z.ZodString) => - schema.regex(USERNAME_PATTERN, { - message: JSON.stringify({ key: 'validation:invalid_format', values: { field: usernameLabel } }), - }), + username: compose(z.string(), required(usernameLabel), rangeLength(3, 32, usernameLabel), (schema: z.ZodString) => + schema.regex(USERNAME_PATTERN, { + message: JSON.stringify({ key: 'validation:invalid_format', values: { field: usernameLabel } }), + }), ), password, privilege: z.any().nullable().optional(), diff --git a/apps/web/src/apps/main/modules/system/users/presentation/components/form-component/form-general.tsx b/apps/web/src/apps/main/modules/system/users/presentation/components/form-component/form-general.tsx index c8ebede..34718a1 100644 --- a/apps/web/src/apps/main/modules/system/users/presentation/components/form-component/form-general.tsx +++ b/apps/web/src/apps/main/modules/system/users/presentation/components/form-component/form-general.tsx @@ -1,5 +1,13 @@ import { useEffect } from 'react'; -import { Box, FieldTextInput, FieldPasswordInput, FieldAsyncSelect, Paper, SimpleGrid, Text } from '@repo/ui/components'; +import { + Box, + FieldTextInput, + FieldPasswordInput, + FieldAsyncSelect, + Paper, + SimpleGrid, + Text, +} from '@repo/ui/components'; import { useEnterpriseModuleTranslationContext, useFormPageContext } from '@repo/ui/foundations'; import { loadPrivilegeOptions } from '../../load-privilege-options'; import { loadEmployeeOptions } from '../../load-employee-options'; @@ -34,15 +42,11 @@ export function FormGeneral({ requirePassword }: { requirePassword: boolean }) { const employee = formControl.watch('employee'); useEffect(() => { - hydrateRelation(formControl, 'privilege', 'privilegeId', privilege, (id) => - privilegesDataService.getOne(id), - ); + hydrateRelation(formControl, 'privilege', 'privilegeId', privilege, (id) => privilegesDataService.getOne(id)); }, [privilege, formControl]); useEffect(() => { - hydrateRelation(formControl, 'employee', 'employeeId', employee, (id) => - employeesDataService.getOne(id), - ); + hydrateRelation(formControl, 'employee', 'employeeId', employee, (id) => employeesDataService.getOne(id)); }, [employee, formControl]); return ( diff --git a/apps/web/src/apps/main/modules/system/users/presentation/factory/index.tsx b/apps/web/src/apps/main/modules/system/users/presentation/factory/index.tsx index 7e2013c..cf6a6e7 100644 --- a/apps/web/src/apps/main/modules/system/users/presentation/factory/index.tsx +++ b/apps/web/src/apps/main/modules/system/users/presentation/factory/index.tsx @@ -21,11 +21,7 @@ registerModuleNamespace(usersModuleConfig.translationNamespace, { export default function UsersModule() { return ( - - config={usersModuleConfig} - dataServices={usersDataService} - store={usersStore} - > + config={usersModuleConfig} dataServices={usersDataService} store={usersStore}> } /> } /> diff --git a/apps/web/src/core/domain/configuration-field-validators.ts b/apps/web/src/core/domain/configuration-field-validators.ts index b6f2011..3059e9c 100644 --- a/apps/web/src/core/domain/configuration-field-validators.ts +++ b/apps/web/src/core/domain/configuration-field-validators.ts @@ -33,13 +33,12 @@ function emptyToUndefinedNumber(value: unknown) { } export function configCodeSchema(t: (key: string) => string, max = CONFIG_CODE_MAX) { - return compose( - z.string(), - required(t('common:fields.code')), - maxLength(max, t('common:fields.code')), - ).regex(CODE_PATTERN, { - message: JSON.stringify({ key: 'validation:invalid_format', values: { field: t('common:fields.code') } }), - }); + return compose(z.string(), required(t('common:fields.code')), maxLength(max, t('common:fields.code'))).regex( + CODE_PATTERN, + { + message: JSON.stringify({ key: 'validation:invalid_format', values: { field: t('common:fields.code') } }), + }, + ); } export function configNameSchema(t: (key: string) => string) { @@ -69,13 +68,20 @@ export function optionalPhoneSchema() { } export function configAddressSchema(t: (key: string) => string) { - return compose(z.string(), required(t('common:fields.address')), maxLength(CONFIG_ADDRESS_MAX, t('common:fields.address'))); + return compose( + z.string(), + required(t('common:fields.address')), + maxLength(CONFIG_ADDRESS_MAX, t('common:fields.address')), + ); } export function weekdaySchema(t: (key: string) => string) { return z.enum(WEEKDAYS, { required_error: JSON.stringify({ key: 'validation:required', values: { field: t('common:fields.weekday') } }), - invalid_type_error: JSON.stringify({ key: 'validation:invalid_format', values: { field: t('common:fields.weekday') } }), + invalid_type_error: JSON.stringify({ + key: 'validation:invalid_format', + values: { field: t('common:fields.weekday') }, + }), }); } @@ -86,14 +92,19 @@ export function workingHoursSchema(t: (key: string) => string) { } export function optionalNfcIdSchema(t: (key: string) => string) { - return z.preprocess(emptyToUndefined, compose(z.string(), maxLength(CONFIG_NFC_ID_MAX, t('common:fields.nfcId'))).optional()); + return z.preprocess( + emptyToUndefined, + compose(z.string(), maxLength(CONFIG_NFC_ID_MAX, t('common:fields.nfcId'))).optional(), + ); } export function optionalLatitudeSchema() { return z.preprocess( emptyToUndefinedNumber, compose( - z.number({ invalid_type_error: JSON.stringify({ key: 'validation:invalid_format', values: { field: 'latitude' } }) }), + z.number({ + invalid_type_error: JSON.stringify({ key: 'validation:invalid_format', values: { field: 'latitude' } }), + }), minValue(-90, 'latitude'), maxValue(90, 'latitude'), ).optional(), @@ -104,7 +115,9 @@ export function optionalLongitudeSchema() { return z.preprocess( emptyToUndefinedNumber, compose( - z.number({ invalid_type_error: JSON.stringify({ key: 'validation:invalid_format', values: { field: 'longitude' } }) }), + z.number({ + invalid_type_error: JSON.stringify({ key: 'validation:invalid_format', values: { field: 'longitude' } }), + }), minValue(-180, 'longitude'), maxValue(180, 'longitude'), ).optional(), diff --git a/apps/web/src/core/lib/filter-menu-by-view-privilege.ts b/apps/web/src/core/lib/filter-menu-by-view-privilege.ts index 7b837ea..77c952d 100644 --- a/apps/web/src/core/lib/filter-menu-by-view-privilege.ts +++ b/apps/web/src/core/lib/filter-menu-by-view-privilege.ts @@ -10,9 +10,7 @@ export function filterMenuByViewPrivilege { - const children = item.children - ? filterMenuByViewPrivilege(item.children, privileges, false) - : undefined; + const children = item.children ? filterMenuByViewPrivilege(item.children, privileges, false) : undefined; if (item.moduleKey && privileges[item.moduleKey]?.ALLOW_VIEW !== true) { return []; diff --git a/packages/ui/src/components/map/location-map.test.tsx b/packages/ui/src/components/map/location-map.test.tsx index a10f23f..5b255ab 100644 --- a/packages/ui/src/components/map/location-map.test.tsx +++ b/packages/ui/src/components/map/location-map.test.tsx @@ -17,7 +17,9 @@ const { setView, panTo, invalidateSize } = vi.hoisted(() => ({ vi.mock('react-leaflet', () => ({ MapContainer: ({ children }: { children: React.ReactNode }) =>
{children}
, TileLayer: () =>
, - CircleMarker: ({ center }: { center: [number, number] }) =>
{`${center[0]},${center[1]}`}
, + CircleMarker: ({ center }: { center: [number, number] }) => ( +
{`${center[0]},${center[1]}`}
+ ), useMap: () => ({ setView, panTo, invalidateSize }), useMapEvents: (handlers: { click?: (event: LeafletClick) => void }) => { mapClick = handlers.click; diff --git a/packages/ui/src/components/map/location-map.tsx b/packages/ui/src/components/map/location-map.tsx index ace9562..3839826 100644 --- a/packages/ui/src/components/map/location-map.tsx +++ b/packages/ui/src/components/map/location-map.tsx @@ -123,10 +123,19 @@ export function LocationMap({ className="tg-map-viewport" style={{ cursor: interactive ? 'crosshair' : undefined }} > - + {position ? ( - + ) : null} {onChange ? : null} diff --git a/packages/ui/src/components/map/location-point.ts b/packages/ui/src/components/map/location-point.ts index bcca7d6..41502aa 100644 --- a/packages/ui/src/components/map/location-point.ts +++ b/packages/ui/src/components/map/location-point.ts @@ -43,7 +43,7 @@ export function clampLatitude(value: number): number { // which the form schemas reject. Keep 180 and -180 as authored instead of collapsing them. export function wrapLongitude(value: number): number { if (value >= -180 && value <= 180) return value; - const wrapped = ((value + 180) % 360 + 360) % 360 - 180; + const wrapped = ((((value + 180) % 360) + 360) % 360) - 180; return wrapped; } @@ -54,10 +54,7 @@ export function locationFromLatLng(lat: number, lng: number): { latitude: number }; } -export function mapViewForLocation( - latitude: unknown, - longitude: unknown, -): { center: [number, number]; zoom: number } { +export function mapViewForLocation(latitude: unknown, longitude: unknown): { center: [number, number]; zoom: number } { const point = toLocationLatLng(latitude, longitude); if (!point) { return { center: DEFAULT_MAP_CENTER, zoom: DEFAULT_MAP_ZOOM }; diff --git a/packages/ui/src/components/map/osm.ts b/packages/ui/src/components/map/osm.ts index 440194e..ef0da31 100644 --- a/packages/ui/src/components/map/osm.ts +++ b/packages/ui/src/components/map/osm.ts @@ -1,3 +1,3 @@ export const OSM_TILE_URL = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'; -export const OSM_ATTRIBUTION = '© OpenStreetMap contributors'; - +export const OSM_ATTRIBUTION = + '© OpenStreetMap contributors'; diff --git a/packages/ui/src/components/map/route-geometry.ts b/packages/ui/src/components/map/route-geometry.ts index 7e3496c..4d6b1bb 100644 --- a/packages/ui/src/components/map/route-geometry.ts +++ b/packages/ui/src/components/map/route-geometry.ts @@ -7,7 +7,5 @@ export function toLeafletLatLngs(geometry?: RouteGeometry | null): Array<[number if (!geometry?.coordinates?.length) { return []; } - return geometry.coordinates - .filter((pair) => Array.isArray(pair) && pair.length >= 2) - .map(([lng, lat]) => [lat, lng]); + return geometry.coordinates.filter((pair) => Array.isArray(pair) && pair.length >= 2).map(([lng, lat]) => [lat, lng]); } diff --git a/packages/ui/src/components/map/route-map.tsx b/packages/ui/src/components/map/route-map.tsx index cc93570..08b51e1 100644 --- a/packages/ui/src/components/map/route-map.tsx +++ b/packages/ui/src/components/map/route-map.tsx @@ -44,7 +44,12 @@ export function RouteMap({ geometry, height = 280 }: RouteMapProps) { {positions.map((position, index) => ( - + {index + 1} ))} diff --git a/packages/ui/src/foundations/enterprise-module/components/data-table/audit-column.utils.test.ts b/packages/ui/src/foundations/enterprise-module/components/data-table/audit-column.utils.test.ts index fc3d135..905acf6 100644 --- a/packages/ui/src/foundations/enterprise-module/components/data-table/audit-column.utils.test.ts +++ b/packages/ui/src/foundations/enterprise-module/components/data-table/audit-column.utils.test.ts @@ -1,24 +1,17 @@ import { describe, expect, it } from 'vitest'; import { DateUtils } from '@repo/utils'; -import { - EMPTY_AUDIT_DISPLAY, - formatAuditActor, - formatAuditTimestamp, - resolveAuditValue, -} from './audit-column.utils'; +import { EMPTY_AUDIT_DISPLAY, formatAuditActor, formatAuditTimestamp, resolveAuditValue } from './audit-column.utils'; describe('resolveAuditValue', () => { it('prefers camelCase over snake_case', () => { - expect( - resolveAuditValue({ createdBy: 'alice', creator_name: 'legacy' }, 'createdBy', 'creator_name'), - ).toBe('alice'); + expect(resolveAuditValue({ createdBy: 'alice', creator_name: 'legacy' }, 'createdBy', 'creator_name')).toBe( + 'alice', + ); }); it('falls back to snake_case when camelCase is missing', () => { expect(resolveAuditValue({ creator_name: 'legacy' }, 'createdBy', 'creator_name')).toBe('legacy'); - expect(resolveAuditValue({ created_at: 1_700_000_000_000 }, 'createdAt', 'created_at')).toBe( - 1_700_000_000_000, - ); + expect(resolveAuditValue({ created_at: 1_700_000_000_000 }, 'createdAt', 'created_at')).toBe(1_700_000_000_000); }); it('returns undefined when neither field is present', () => { diff --git a/packages/ui/src/foundations/enterprise-module/components/data-table/components/bulk-actions.tsx b/packages/ui/src/foundations/enterprise-module/components/data-table/components/bulk-actions.tsx index b49981d..062dd07 100644 --- a/packages/ui/src/foundations/enterprise-module/components/data-table/components/bulk-actions.tsx +++ b/packages/ui/src/foundations/enterprise-module/components/data-table/components/bulk-actions.tsx @@ -63,7 +63,10 @@ export function BulkActionMenu({ const hasActive = selectedRows.some((row) => row[statusKey]?.toLowerCase() === 'active'); const hasInactive = selectedRows.some( - (row) => row[statusKey]?.toLowerCase() === 'inactive' || row[statusKey]?.toLowerCase() === 'draft' || row[statusKey]?.toLowerCase() === 'archived', + (row) => + row[statusKey]?.toLowerCase() === 'inactive' || + row[statusKey]?.toLowerCase() === 'draft' || + row[statusKey]?.toLowerCase() === 'archived', ); const defaultActions: PageActionProps[] = []; diff --git a/packages/ui/src/foundations/enterprise-module/components/data-table/index.tsx b/packages/ui/src/foundations/enterprise-module/components/data-table/index.tsx index 4f49218..ef86bdf 100644 --- a/packages/ui/src/foundations/enterprise-module/components/data-table/index.tsx +++ b/packages/ui/src/foundations/enterprise-module/components/data-table/index.tsx @@ -282,7 +282,7 @@ export function EnterpriseDataTable(props: EnterpriseDataT const filterKeys = filterConfig?.defaultValues ? Object.keys(filterConfig.defaultValues) : Object.keys(filterData).filter( - (key) => key !== searchKey && !['page', 'limit', 'order_by', 'order_type'].includes(key), + (key) => key !== searchKey && !['page', 'limit', 'orderBy', 'orderType'].includes(key), ); return filterKeys.filter((key) => { @@ -773,8 +773,8 @@ export function EnterpriseDataTable(props: EnterpriseDataT const requestParams: Record = { page, limit, - order_by: orderBy, - order_type: orderType, + orderBy: orderBy, + orderType: orderType, ...filterRef.current, }; diff --git a/packages/ui/src/foundations/enterprise-module/providers/detail-page.provider.tsx b/packages/ui/src/foundations/enterprise-module/providers/detail-page.provider.tsx index 03b985c..37e2cef 100644 --- a/packages/ui/src/foundations/enterprise-module/providers/detail-page.provider.tsx +++ b/packages/ui/src/foundations/enterprise-module/providers/detail-page.provider.tsx @@ -504,7 +504,8 @@ export function EnterpriseDetailPageProvider( const isMasterData = moduleType === 'MASTER_DATA'; const isDataActive = detailData && ['active'].includes(detailData[statusKey]?.toLowerCase()); - const isDataInActive = detailData && ['inactive', 'draft', 'archived'].includes(detailData[statusKey]?.toLowerCase()); + const isDataInActive = + detailData && ['inactive', 'draft', 'archived'].includes(detailData[statusKey]?.toLowerCase()); // 1. Declare action with Privilege & Module Type conditions directly const rawActions = [