@open-mercato/core 0.6.8-develop.7096.1.97319f09f6 → 0.6.8-develop.7100.1.fbf66fca35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/auth/api/users/route.js +13 -5
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/lib/userIdFilter.js +16 -0
- package/dist/modules/auth/lib/userIdFilter.js.map +7 -0
- package/dist/modules/devices/acl.js +9 -1
- package/dist/modules/devices/acl.js.map +2 -2
- package/dist/modules/devices/backend/devices/[id]/page.js +4 -20
- package/dist/modules/devices/backend/devices/[id]/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/create/page.js +17 -1
- package/dist/modules/devices/backend/devices/create/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/page.js +13 -21
- package/dist/modules/devices/backend/devices/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js +34 -0
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js.map +7 -0
- package/dist/modules/devices/backend/devices/userOptions.js +52 -0
- package/dist/modules/devices/backend/devices/userOptions.js.map +7 -0
- package/dist/modules/devices/setup.js +6 -2
- package/dist/modules/devices/setup.js.map +2 -2
- package/dist/modules/wms/api/warehouseSearch.js +21 -0
- package/dist/modules/wms/api/warehouseSearch.js.map +7 -0
- package/dist/modules/wms/api/warehouses/route.js +13 -9
- package/dist/modules/wms/api/warehouses/route.js.map +2 -2
- package/dist/modules/wms/commands/configuration.js +59 -5
- package/dist/modules/wms/commands/configuration.js.map +2 -2
- package/dist/modules/wms/commands/shared.js +4 -0
- package/dist/modules/wms/commands/shared.js.map +2 -2
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js +158 -0
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js +29 -103
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +2 -2
- package/dist/modules/wms/components/backend/warehouseFormOptions.js +66 -0
- package/dist/modules/wms/components/backend/warehouseFormOptions.js.map +7 -0
- package/package.json +7 -7
- package/src/modules/auth/api/users/route.ts +18 -5
- package/src/modules/auth/lib/userIdFilter.ts +31 -0
- package/src/modules/devices/AGENTS.md +12 -1
- package/src/modules/devices/acl.ts +9 -1
- package/src/modules/devices/backend/devices/[id]/page.tsx +5 -19
- package/src/modules/devices/backend/devices/create/page.tsx +17 -1
- package/src/modules/devices/backend/devices/page.tsx +20 -24
- package/src/modules/devices/backend/devices/useDeviceUserLabels.ts +45 -0
- package/src/modules/devices/backend/devices/userOptions.ts +99 -0
- package/src/modules/devices/i18n/de.json +3 -2
- package/src/modules/devices/i18n/en.json +3 -2
- package/src/modules/devices/i18n/es.json +3 -2
- package/src/modules/devices/i18n/ko.json +3 -2
- package/src/modules/devices/i18n/pl.json +3 -2
- package/src/modules/devices/setup.ts +6 -2
- package/src/modules/wms/api/warehouseSearch.ts +23 -0
- package/src/modules/wms/api/warehouses/route.ts +13 -9
- package/src/modules/wms/commands/configuration.ts +73 -7
- package/src/modules/wms/commands/shared.ts +9 -0
- package/src/modules/wms/components/backend/WarehouseEditDialog.tsx +216 -0
- package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +31 -139
- package/src/modules/wms/components/backend/warehouseFormOptions.ts +72 -0
- package/src/modules/wms/i18n/de.json +2 -0
- package/src/modules/wms/i18n/en.json +2 -0
- package/src/modules/wms/i18n/es.json +2 -0
- package/src/modules/wms/i18n/ko.json +2 -0
- package/src/modules/wms/i18n/pl.json +2 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/wms/commands/shared.ts"],
|
|
4
|
-
"sourcesContent": ["import type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { ensureOrganizationScope } from '@open-mercato/shared/lib/commands/scope'\nimport type { CrudIndexerConfig, CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n InventoryBalance,\n InventoryMovement,\n InventoryReservation,\n WarehouseZone,\n} from '../data/entities'\n\nexport function ensureTenantScope(ctx: CommandRuntimeContext, tenantId: string): void {\n const currentTenant = ctx.auth?.tenantId ?? null\n if (currentTenant && currentTenant !== tenantId) {\n throw new CrudHttpError(403, { error: 'Forbidden' })\n }\n}\n\nexport function requireId(id: string | null | undefined, label: string): string {\n if (typeof id === 'string' && id.trim().length > 0) return id.trim()\n throw new CrudHttpError(400, { error: `${label} id is required.` })\n}\n\nexport function normalizeOptionalString(value: string | null | undefined): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\nexport function toNumericString(value: number | string | null | undefined, fallback = '0'): string {\n if (typeof value === 'string' && value.trim().length > 0) return value.trim()\n if (typeof value === 'number' && Number.isFinite(value)) return String(value)\n return fallback\n}\n\n// CRUD indexer configs \u2014 used by emitCrudSideEffects to drive query_index updates.\n// Cache invalidation cross-aliases (e.g. balance lists invalidated when a reservation mutates)\n// are declared in command-level metadata.context.cacheAliases so the command bus picks them up.\nexport const inventoryBalanceCrudIndexer: CrudIndexerConfig<InventoryBalance> = {\n entityType: E.wms.inventory_balance,\n}\n\nexport const inventoryReservationCrudIndexer: CrudIndexerConfig<InventoryReservation> = {\n entityType: E.wms.inventory_reservation,\n}\n\nexport const inventoryMovementCrudIndexer: CrudIndexerConfig<InventoryMovement> = {\n entityType: E.wms.inventory_movement,\n}\n\n// Zones are read through the hybrid query engine, which projects `cf:*` out of\n// `entity_indexes` rather than joining `custom_field_values`. Without this indexer the\n// zone commands write custom field values that no read path can ever see (#5239).\nexport const warehouseZoneCrudIndexer: CrudIndexerConfig<WarehouseZone> = {\n entityType: E.wms.warehouse_zone,\n}\n\nexport const inventoryBalanceCrudEvents: CrudEventsConfig<InventoryBalance> = {\n module: 'wms',\n entity: 'inventory_balance',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\nexport const inventoryReservationCrudEvents: CrudEventsConfig<InventoryReservation> = {\n module: 'wms',\n entity: 'inventory_reservation',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\nexport const inventoryMovementCrudEvents: CrudEventsConfig<InventoryMovement> = {\n module: 'wms',\n entity: 'inventory_movement',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\n// Cache alias resource kinds used to extend command-level cache invalidation\n// when a single mutation impacts multiple list resources.\nexport const WMS_INVENTORY_BALANCE_RESOURCE = 'wms.inventoryBalance'\nexport const WMS_INVENTORY_RESERVATION_RESOURCE = 'wms.inventoryReservation'\nexport const WMS_INVENTORY_MOVEMENT_RESOURCE = 'wms.inventoryMovement'\n\nexport { ensureOrganizationScope }\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,qBAAqB;AAC9B,SAAS,+BAA+B;AAExC,SAAS,SAAS;
|
|
4
|
+
"sourcesContent": ["import type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { ensureOrganizationScope } from '@open-mercato/shared/lib/commands/scope'\nimport type { CrudIndexerConfig, CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n InventoryBalance,\n InventoryMovement,\n InventoryReservation,\n Warehouse,\n WarehouseZone,\n} from '../data/entities'\n\nexport function ensureTenantScope(ctx: CommandRuntimeContext, tenantId: string): void {\n const currentTenant = ctx.auth?.tenantId ?? null\n if (currentTenant && currentTenant !== tenantId) {\n throw new CrudHttpError(403, { error: 'Forbidden' })\n }\n}\n\nexport function requireId(id: string | null | undefined, label: string): string {\n if (typeof id === 'string' && id.trim().length > 0) return id.trim()\n throw new CrudHttpError(400, { error: `${label} id is required.` })\n}\n\nexport function normalizeOptionalString(value: string | null | undefined): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\nexport function toNumericString(value: number | string | null | undefined, fallback = '0'): string {\n if (typeof value === 'string' && value.trim().length > 0) return value.trim()\n if (typeof value === 'number' && Number.isFinite(value)) return String(value)\n return fallback\n}\n\n// CRUD indexer configs \u2014 used by emitCrudSideEffects to drive query_index updates.\n// Cache invalidation cross-aliases (e.g. balance lists invalidated when a reservation mutates)\n// are declared in command-level metadata.context.cacheAliases so the command bus picks them up.\nexport const inventoryBalanceCrudIndexer: CrudIndexerConfig<InventoryBalance> = {\n entityType: E.wms.inventory_balance,\n}\n\nexport const inventoryReservationCrudIndexer: CrudIndexerConfig<InventoryReservation> = {\n entityType: E.wms.inventory_reservation,\n}\n\nexport const inventoryMovementCrudIndexer: CrudIndexerConfig<InventoryMovement> = {\n entityType: E.wms.inventory_movement,\n}\n\n// Zones are read through the hybrid query engine, which projects `cf:*` out of\n// `entity_indexes` rather than joining `custom_field_values`. Without this indexer the\n// zone commands write custom field values that no read path can ever see (#5239).\nexport const warehouseZoneCrudIndexer: CrudIndexerConfig<WarehouseZone> = {\n entityType: E.wms.warehouse_zone,\n}\n\n// Warehouse list/search goes through the hybrid query engine. Writing a custom\n// field upserts `entity_indexes`; delete must tombstone that row. A leftover\n// live index document makes `indexAnyRows` true and hides later warehouses that\n// were never indexed (empty combobox on the same integration shard).\nexport const warehouseCrudIndexer: CrudIndexerConfig<Warehouse> = {\n entityType: E.wms.warehouse,\n}\n\nexport const inventoryBalanceCrudEvents: CrudEventsConfig<InventoryBalance> = {\n module: 'wms',\n entity: 'inventory_balance',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\nexport const inventoryReservationCrudEvents: CrudEventsConfig<InventoryReservation> = {\n module: 'wms',\n entity: 'inventory_reservation',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\nexport const inventoryMovementCrudEvents: CrudEventsConfig<InventoryMovement> = {\n module: 'wms',\n entity: 'inventory_movement',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\n// Cache alias resource kinds used to extend command-level cache invalidation\n// when a single mutation impacts multiple list resources.\nexport const WMS_INVENTORY_BALANCE_RESOURCE = 'wms.inventoryBalance'\nexport const WMS_INVENTORY_RESERVATION_RESOURCE = 'wms.inventoryReservation'\nexport const WMS_INVENTORY_MOVEMENT_RESOURCE = 'wms.inventoryMovement'\n\nexport { ensureOrganizationScope }\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,qBAAqB;AAC9B,SAAS,+BAA+B;AAExC,SAAS,SAAS;AASX,SAAS,kBAAkB,KAA4B,UAAwB;AACpF,QAAM,gBAAgB,IAAI,MAAM,YAAY;AAC5C,MAAI,iBAAiB,kBAAkB,UAAU;AAC/C,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,YAAY,CAAC;AAAA,EACrD;AACF;AAEO,SAAS,UAAU,IAA+B,OAAuB;AAC9E,MAAI,OAAO,OAAO,YAAY,GAAG,KAAK,EAAE,SAAS,EAAG,QAAO,GAAG,KAAK;AACnE,QAAM,IAAI,cAAc,KAAK,EAAE,OAAO,GAAG,KAAK,mBAAmB,CAAC;AACpE;AAEO,SAAS,wBAAwB,OAAiD;AACvF,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,QAAQ,SAAS,IAAI,UAAU;AACxC;AAEO,SAAS,gBAAgB,OAA2C,WAAW,KAAa;AACjG,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,EAAG,QAAO,MAAM,KAAK;AAC5E,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO,OAAO,KAAK;AAC5E,SAAO;AACT;AAKO,MAAM,8BAAmE;AAAA,EAC9E,YAAY,EAAE,IAAI;AACpB;AAEO,MAAM,kCAA2E;AAAA,EACtF,YAAY,EAAE,IAAI;AACpB;AAEO,MAAM,+BAAqE;AAAA,EAChF,YAAY,EAAE,IAAI;AACpB;AAKO,MAAM,2BAA6D;AAAA,EACxE,YAAY,EAAE,IAAI;AACpB;AAMO,MAAM,uBAAqD;AAAA,EAChE,YAAY,EAAE,IAAI;AACpB;AAEO,MAAM,6BAAiE;AAAA,EAC5E,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,cAAc,CAAC,SAAS;AAAA,IACtB,IAAI,IAAI,YAAY;AAAA,IACpB,gBAAgB,IAAI,YAAY;AAAA,IAChC,UAAU,IAAI,YAAY;AAAA,EAC5B;AACF;AAEO,MAAM,iCAAyE;AAAA,EACpF,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,cAAc,CAAC,SAAS;AAAA,IACtB,IAAI,IAAI,YAAY;AAAA,IACpB,gBAAgB,IAAI,YAAY;AAAA,IAChC,UAAU,IAAI,YAAY;AAAA,EAC5B;AACF;AAEO,MAAM,8BAAmE;AAAA,EAC9E,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,cAAc,CAAC,SAAS;AAAA,IACtB,IAAI,IAAI,YAAY;AAAA,IACpB,gBAAgB,IAAI,YAAY;AAAA,IAChC,UAAU,IAAI,YAAY;AAAA,EAC5B;AACF;AAIO,MAAM,iCAAiC;AACvC,MAAM,qCAAqC;AAC3C,MAAM,kCAAkC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
|
|
6
|
+
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
7
|
+
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
8
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
9
|
+
import { raiseCrudError } from "@open-mercato/ui/backend/utils/serverErrors";
|
|
10
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@open-mercato/ui/primitives/dialog";
|
|
11
|
+
import { extractCustomFieldEntries } from "@open-mercato/shared/lib/crud/custom-fields-client";
|
|
12
|
+
import { useLocale, useT } from "@open-mercato/shared/lib/i18n/context";
|
|
13
|
+
import { E } from "../../../../generated/entities.ids.generated.js";
|
|
14
|
+
import { flashMutationError } from "../../lib/flashMutationError.js";
|
|
15
|
+
import {
|
|
16
|
+
countryOptionFromStored,
|
|
17
|
+
loadCountryOptions,
|
|
18
|
+
loadTimezoneOptions,
|
|
19
|
+
timezoneOptionFromStored
|
|
20
|
+
} from "./warehouseFormOptions.js";
|
|
21
|
+
const warehouseFormSchema = z.object({
|
|
22
|
+
name: z.string().trim().min(1),
|
|
23
|
+
code: z.string().trim().min(1),
|
|
24
|
+
city: z.string().trim().optional(),
|
|
25
|
+
country: z.string().trim().optional(),
|
|
26
|
+
timezone: z.string().trim().optional(),
|
|
27
|
+
isActive: z.boolean().default(true),
|
|
28
|
+
isPrimary: z.boolean().default(false)
|
|
29
|
+
}).passthrough();
|
|
30
|
+
function WarehouseEditDialog({ open, onOpenChange, mode, row, onSaved }) {
|
|
31
|
+
const t = useT();
|
|
32
|
+
const locale = useLocale();
|
|
33
|
+
const { runMutation } = useGuardedMutation({ contextId: "wms-config-warehouses" });
|
|
34
|
+
const [submitting, setSubmitting] = React.useState(false);
|
|
35
|
+
const countrySeedOptions = React.useMemo(() => {
|
|
36
|
+
if (mode !== "edit" || !row?.country?.trim()) return void 0;
|
|
37
|
+
return [countryOptionFromStored(row.country, locale)];
|
|
38
|
+
}, [locale, mode, row]);
|
|
39
|
+
const timezoneSeedOptions = React.useMemo(() => {
|
|
40
|
+
if (mode !== "edit" || !row?.timezone?.trim()) return void 0;
|
|
41
|
+
return [timezoneOptionFromStored(row.timezone)];
|
|
42
|
+
}, [mode, row]);
|
|
43
|
+
const fields = React.useMemo(() => [
|
|
44
|
+
{ id: "name", type: "text", label: t("wms.backend.config.warehouses.form.name", "Name"), required: true },
|
|
45
|
+
{ id: "code", type: "text", label: t("wms.backend.config.warehouses.form.code", "Code"), required: true },
|
|
46
|
+
{ id: "city", type: "text", label: t("wms.backend.config.warehouses.form.city", "City") },
|
|
47
|
+
{
|
|
48
|
+
id: "country",
|
|
49
|
+
type: "combobox",
|
|
50
|
+
label: t("wms.backend.config.warehouses.form.country", "Country"),
|
|
51
|
+
placeholder: t("wms.backend.config.warehouses.form.countryPlaceholder", "Search country"),
|
|
52
|
+
loadOptions: (query) => loadCountryOptions(query, locale),
|
|
53
|
+
allowCustomValues: false,
|
|
54
|
+
seedOptions: countrySeedOptions,
|
|
55
|
+
resolveLabel: (value) => countryOptionFromStored(value, locale).label
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "timezone",
|
|
59
|
+
type: "combobox",
|
|
60
|
+
label: t("wms.backend.config.warehouses.form.timezone", "Timezone"),
|
|
61
|
+
placeholder: t("wms.backend.config.warehouses.form.timezonePlaceholder", "Search timezone"),
|
|
62
|
+
loadOptions: loadTimezoneOptions,
|
|
63
|
+
allowCustomValues: false,
|
|
64
|
+
seedOptions: timezoneSeedOptions
|
|
65
|
+
},
|
|
66
|
+
{ id: "isPrimary", type: "checkbox", label: t("wms.backend.config.warehouses.form.primary", "Primary warehouse") },
|
|
67
|
+
{ id: "isActive", type: "checkbox", label: t("wms.backend.config.warehouses.form.active", "Active") }
|
|
68
|
+
], [countrySeedOptions, locale, t, timezoneSeedOptions]);
|
|
69
|
+
const initialValues = React.useMemo(() => {
|
|
70
|
+
if (mode === "edit" && row) {
|
|
71
|
+
return {
|
|
72
|
+
name: row.name || "",
|
|
73
|
+
code: row.code || "",
|
|
74
|
+
city: row.city || "",
|
|
75
|
+
country: row.country || "",
|
|
76
|
+
timezone: row.timezone || "",
|
|
77
|
+
isActive: row.is_active !== false,
|
|
78
|
+
isPrimary: row.is_primary === true,
|
|
79
|
+
...extractCustomFieldEntries(row)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
name: "",
|
|
84
|
+
code: "",
|
|
85
|
+
city: "",
|
|
86
|
+
country: "",
|
|
87
|
+
timezone: "",
|
|
88
|
+
isActive: true,
|
|
89
|
+
isPrimary: false
|
|
90
|
+
};
|
|
91
|
+
}, [mode, row]);
|
|
92
|
+
const handleSubmit = React.useCallback(async (values) => {
|
|
93
|
+
setSubmitting(true);
|
|
94
|
+
try {
|
|
95
|
+
const payload = mode === "edit" && row ? { id: row.id, ...values } : values;
|
|
96
|
+
const call = await runMutation({
|
|
97
|
+
operation: async () => {
|
|
98
|
+
const result = await apiCall(
|
|
99
|
+
"/api/wms/warehouses",
|
|
100
|
+
{
|
|
101
|
+
method: mode === "edit" ? "PUT" : "POST",
|
|
102
|
+
headers: { "x-om-forbidden-redirect": "0" },
|
|
103
|
+
body: JSON.stringify(payload)
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
if (!result.ok) {
|
|
107
|
+
await raiseCrudError(result.response, t("wms.backend.config.warehouses.errors.save", "Failed to save warehouse."));
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
},
|
|
111
|
+
context: {},
|
|
112
|
+
mutationPayload: payload
|
|
113
|
+
});
|
|
114
|
+
flash(
|
|
115
|
+
mode === "edit" ? t("wms.backend.config.warehouses.flash.updated", "Warehouse updated") : t("wms.backend.config.warehouses.flash.created", "Warehouse created"),
|
|
116
|
+
"success"
|
|
117
|
+
);
|
|
118
|
+
const resultBody = call?.result && typeof call.result === "object" ? call.result : null;
|
|
119
|
+
const createdId = mode === "create" && typeof resultBody?.id === "string" ? resultBody.id.trim() : void 0;
|
|
120
|
+
const updatedAt = typeof resultBody?.updatedAt === "string" && resultBody.updatedAt.trim() || typeof resultBody?.updated_at === "string" && resultBody.updated_at.trim() || void 0;
|
|
121
|
+
onOpenChange(false);
|
|
122
|
+
await onSaved?.({
|
|
123
|
+
mode,
|
|
124
|
+
id: createdId || row?.id,
|
|
125
|
+
values,
|
|
126
|
+
updatedAt: updatedAt || null
|
|
127
|
+
});
|
|
128
|
+
} catch (error) {
|
|
129
|
+
flashMutationError(error, t("wms.backend.config.warehouses.errors.save", "Failed to save warehouse."), t);
|
|
130
|
+
} finally {
|
|
131
|
+
setSubmitting(false);
|
|
132
|
+
}
|
|
133
|
+
}, [mode, onOpenChange, onSaved, row, runMutation, t]);
|
|
134
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-3xl", children: [
|
|
135
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: mode === "edit" ? t("wms.backend.config.warehouses.dialog.edit", "Edit warehouse") : t("wms.backend.config.warehouses.dialog.create", "Create warehouse") }) }),
|
|
136
|
+
/* @__PURE__ */ jsx(
|
|
137
|
+
CrudForm,
|
|
138
|
+
{
|
|
139
|
+
schema: warehouseFormSchema,
|
|
140
|
+
fields,
|
|
141
|
+
entityId: E.wms.warehouse,
|
|
142
|
+
initialValues,
|
|
143
|
+
submitLabel: t("common.save", "Save"),
|
|
144
|
+
onSubmit: handleSubmit,
|
|
145
|
+
embedded: true,
|
|
146
|
+
disableInitialFocus: true,
|
|
147
|
+
isLoading: submitting,
|
|
148
|
+
twoColumn: true,
|
|
149
|
+
optimisticLockUpdatedAt: mode === "edit" ? row?.updatedAt ?? row?.updated_at ?? null : void 0
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
] }) });
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
WarehouseEditDialog,
|
|
156
|
+
warehouseFormSchema
|
|
157
|
+
};
|
|
158
|
+
//# sourceMappingURL=WarehouseEditDialog.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/wms/components/backend/WarehouseEditDialog.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { CrudForm, type CrudField } from '@open-mercato/ui/backend/CrudForm'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { E } from '#generated/entities.ids.generated'\nimport { flashMutationError } from '../../lib/flashMutationError'\nimport {\n countryOptionFromStored,\n loadCountryOptions,\n loadTimezoneOptions,\n timezoneOptionFromStored,\n} from './warehouseFormOptions'\n\nexport type WarehouseDialogRow = {\n id: string\n name?: string | null\n code?: string | null\n city?: string | null\n country?: string | null\n timezone?: string | null\n is_active?: boolean | null\n is_primary?: boolean | null\n updated_at?: string | null\n updatedAt?: string | null\n customValues?: Record<string, unknown> | null\n}\n\nexport type WarehouseFormValues = {\n name: string\n code: string\n city?: string\n country?: string\n timezone?: string\n isActive: boolean\n isPrimary: boolean\n}\n\nexport const warehouseFormSchema = z.object({\n name: z.string().trim().min(1),\n code: z.string().trim().min(1),\n city: z.string().trim().optional(),\n country: z.string().trim().optional(),\n timezone: z.string().trim().optional(),\n isActive: z.boolean().default(true),\n isPrimary: z.boolean().default(false),\n}).passthrough()\n\ntype WarehouseEditDialogProps = {\n open: boolean\n onOpenChange: (open: boolean) => void\n mode: 'create' | 'edit'\n row?: WarehouseDialogRow | null\n onSaved?: (info: {\n mode: 'create' | 'edit'\n id?: string\n values: WarehouseFormValues\n updatedAt?: string | null\n }) => void | Promise<void>\n}\n\nexport function WarehouseEditDialog({ open, onOpenChange, mode, row, onSaved }: WarehouseEditDialogProps) {\n const t = useT()\n const locale = useLocale()\n const { runMutation } = useGuardedMutation<Record<string, unknown>>({ contextId: 'wms-config-warehouses' })\n const [submitting, setSubmitting] = React.useState(false)\n\n const countrySeedOptions = React.useMemo(() => {\n if (mode !== 'edit' || !row?.country?.trim()) return undefined\n return [countryOptionFromStored(row.country, locale)]\n }, [locale, mode, row])\n\n const timezoneSeedOptions = React.useMemo(() => {\n if (mode !== 'edit' || !row?.timezone?.trim()) return undefined\n return [timezoneOptionFromStored(row.timezone)]\n }, [mode, row])\n\n const fields = React.useMemo<CrudField[]>(() => [\n { id: 'name', type: 'text', label: t('wms.backend.config.warehouses.form.name', 'Name'), required: true },\n { id: 'code', type: 'text', label: t('wms.backend.config.warehouses.form.code', 'Code'), required: true },\n { id: 'city', type: 'text', label: t('wms.backend.config.warehouses.form.city', 'City') },\n {\n id: 'country',\n type: 'combobox',\n label: t('wms.backend.config.warehouses.form.country', 'Country'),\n placeholder: t('wms.backend.config.warehouses.form.countryPlaceholder', 'Search country'),\n loadOptions: (query) => loadCountryOptions(query, locale),\n allowCustomValues: false,\n seedOptions: countrySeedOptions,\n resolveLabel: (value) => countryOptionFromStored(value, locale).label,\n },\n {\n id: 'timezone',\n type: 'combobox',\n label: t('wms.backend.config.warehouses.form.timezone', 'Timezone'),\n placeholder: t('wms.backend.config.warehouses.form.timezonePlaceholder', 'Search timezone'),\n loadOptions: loadTimezoneOptions,\n allowCustomValues: false,\n seedOptions: timezoneSeedOptions,\n },\n { id: 'isPrimary', type: 'checkbox', label: t('wms.backend.config.warehouses.form.primary', 'Primary warehouse') },\n { id: 'isActive', type: 'checkbox', label: t('wms.backend.config.warehouses.form.active', 'Active') },\n ], [countrySeedOptions, locale, t, timezoneSeedOptions])\n\n const initialValues = React.useMemo<WarehouseFormValues>(() => {\n if (mode === 'edit' && row) {\n return {\n name: row.name || '',\n code: row.code || '',\n city: row.city || '',\n country: row.country || '',\n timezone: row.timezone || '',\n isActive: row.is_active !== false,\n isPrimary: row.is_primary === true,\n ...extractCustomFieldEntries(row as Record<string, unknown>),\n } as WarehouseFormValues\n }\n return {\n name: '',\n code: '',\n city: '',\n country: '',\n timezone: '',\n isActive: true,\n isPrimary: false,\n }\n }, [mode, row])\n\n const handleSubmit = React.useCallback(async (values: WarehouseFormValues) => {\n setSubmitting(true)\n try {\n const payload = mode === 'edit' && row ? { id: row.id, ...values } : values\n const call = await runMutation({\n operation: async () => {\n const result = await apiCall<{ id?: string | null; updatedAt?: string | null; updated_at?: string | null }>(\n '/api/wms/warehouses',\n {\n method: mode === 'edit' ? 'PUT' : 'POST',\n headers: { 'x-om-forbidden-redirect': '0' },\n body: JSON.stringify(payload),\n },\n )\n if (!result.ok) {\n await raiseCrudError(result.response, t('wms.backend.config.warehouses.errors.save', 'Failed to save warehouse.'))\n }\n return result\n },\n context: {},\n mutationPayload: payload,\n })\n flash(\n mode === 'edit'\n ? t('wms.backend.config.warehouses.flash.updated', 'Warehouse updated')\n : t('wms.backend.config.warehouses.flash.created', 'Warehouse created'),\n 'success',\n )\n const resultBody =\n call?.result && typeof call.result === 'object'\n ? (call.result as { id?: unknown; updatedAt?: unknown; updated_at?: unknown })\n : null\n const createdId =\n mode === 'create' && typeof resultBody?.id === 'string'\n ? resultBody.id.trim()\n : undefined\n const updatedAt =\n (typeof resultBody?.updatedAt === 'string' && resultBody.updatedAt.trim()) ||\n (typeof resultBody?.updated_at === 'string' && resultBody.updated_at.trim()) ||\n undefined\n onOpenChange(false)\n await onSaved?.({\n mode,\n id: createdId || row?.id,\n values,\n updatedAt: updatedAt || null,\n })\n } catch (error) {\n flashMutationError(error, t('wms.backend.config.warehouses.errors.save', 'Failed to save warehouse.'), t)\n } finally {\n setSubmitting(false)\n }\n }, [mode, onOpenChange, onSaved, row, runMutation, t])\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-3xl\">\n <DialogHeader>\n <DialogTitle>\n {mode === 'edit'\n ? t('wms.backend.config.warehouses.dialog.edit', 'Edit warehouse')\n : t('wms.backend.config.warehouses.dialog.create', 'Create warehouse')}\n </DialogTitle>\n </DialogHeader>\n <CrudForm<WarehouseFormValues>\n schema={warehouseFormSchema}\n fields={fields}\n entityId={E.wms.warehouse}\n initialValues={initialValues}\n submitLabel={t('common.save', 'Save')}\n onSubmit={handleSubmit}\n embedded\n disableInitialFocus\n isLoading={submitting}\n twoColumn\n optimisticLockUpdatedAt={mode === 'edit' ? (row?.updatedAt ?? row?.updated_at ?? null) : undefined}\n />\n </DialogContent>\n </Dialog>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -36,17 +36,10 @@ import {
|
|
|
36
36
|
inventoryRotationStrategyLabel
|
|
37
37
|
} from "../../lib/inventoryDisplayUi.js";
|
|
38
38
|
import { LocationEditDialog } from "./LocationEditDialog.js";
|
|
39
|
+
import { WarehouseEditDialog } from "./WarehouseEditDialog.js";
|
|
40
|
+
import { formatWarehouseCountryLabel } from "./warehouseFormOptions.js";
|
|
39
41
|
import { useWmsInventoryMutationAccess } from "./useWmsInventoryMutationAccess.js";
|
|
40
42
|
import { flashMutationError } from "../../lib/flashMutationError.js";
|
|
41
|
-
const warehouseFormSchema = z.object({
|
|
42
|
-
name: z.string().trim().min(1),
|
|
43
|
-
code: z.string().trim().min(1),
|
|
44
|
-
city: z.string().trim().optional(),
|
|
45
|
-
country: z.string().trim().optional(),
|
|
46
|
-
timezone: z.string().trim().optional(),
|
|
47
|
-
isActive: z.boolean().default(true),
|
|
48
|
-
isPrimary: z.boolean().default(false)
|
|
49
|
-
});
|
|
50
43
|
const zoneFormSchema = z.object({
|
|
51
44
|
warehouseId: z.string().uuid(),
|
|
52
45
|
code: z.string().trim().min(1).max(80),
|
|
@@ -79,7 +72,7 @@ const STRATEGY_OPTIONS = [
|
|
|
79
72
|
{ value: "lifo", label: "LIFO" },
|
|
80
73
|
{ value: "fefo", label: "FEFO" }
|
|
81
74
|
];
|
|
82
|
-
function mergeCreatedWarehouseIntoWarehousesCaches(queryClient, newId, values) {
|
|
75
|
+
function mergeCreatedWarehouseIntoWarehousesCaches(queryClient, newId, values, updatedAt) {
|
|
83
76
|
const row = {
|
|
84
77
|
id: newId,
|
|
85
78
|
name: values.name,
|
|
@@ -88,7 +81,9 @@ function mergeCreatedWarehouseIntoWarehousesCaches(queryClient, newId, values) {
|
|
|
88
81
|
country: values.country || null,
|
|
89
82
|
timezone: values.timezone || null,
|
|
90
83
|
is_active: values.isActive,
|
|
91
|
-
is_primary: values.isPrimary
|
|
84
|
+
is_primary: values.isPrimary,
|
|
85
|
+
updated_at: updatedAt ?? null,
|
|
86
|
+
updatedAt: updatedAt ?? null
|
|
92
87
|
};
|
|
93
88
|
const haystack = `${values.name}
|
|
94
89
|
${values.code}`.toLowerCase();
|
|
@@ -148,6 +143,7 @@ function SectionCard({
|
|
|
148
143
|
}
|
|
149
144
|
function WarehouseSection({ viewAllHref } = {}) {
|
|
150
145
|
const t = useT();
|
|
146
|
+
const locale = useLocale();
|
|
151
147
|
const queryClient = useQueryClient();
|
|
152
148
|
const { confirm, ConfirmDialogElement } = useConfirmDialog();
|
|
153
149
|
const { runMutation } = useGuardedMutation({ contextId: "wms-config-warehouses" });
|
|
@@ -155,7 +151,6 @@ function WarehouseSection({ viewAllHref } = {}) {
|
|
|
155
151
|
const [page, setPage] = React.useState(1);
|
|
156
152
|
const [search, setSearch] = React.useState("");
|
|
157
153
|
const [sorting, setSorting] = React.useState([{ id: "updatedAt", desc: true }]);
|
|
158
|
-
const [submitting, setSubmitting] = React.useState(false);
|
|
159
154
|
const [dialog, setDialog] = React.useState(null);
|
|
160
155
|
const handleSortingChange = React.useCallback((nextSorting) => {
|
|
161
156
|
setSorting(nextSorting);
|
|
@@ -183,15 +178,6 @@ function WarehouseSection({ viewAllHref } = {}) {
|
|
|
183
178
|
return call.result ?? { items: [], total: 0, totalPages: 1 };
|
|
184
179
|
}
|
|
185
180
|
});
|
|
186
|
-
const fields = React.useMemo(() => [
|
|
187
|
-
{ id: "name", type: "text", label: t("wms.backend.config.warehouses.form.name", "Name"), required: true },
|
|
188
|
-
{ id: "code", type: "text", label: t("wms.backend.config.warehouses.form.code", "Code"), required: true },
|
|
189
|
-
{ id: "city", type: "text", label: t("wms.backend.config.warehouses.form.city", "City") },
|
|
190
|
-
{ id: "country", type: "text", label: t("wms.backend.config.warehouses.form.country", "Country") },
|
|
191
|
-
{ id: "timezone", type: "text", label: t("wms.backend.config.warehouses.form.timezone", "Timezone") },
|
|
192
|
-
{ id: "isPrimary", type: "checkbox", label: t("wms.backend.config.warehouses.form.primary", "Primary warehouse") },
|
|
193
|
-
{ id: "isActive", type: "checkbox", label: t("wms.backend.config.warehouses.form.active", "Active") }
|
|
194
|
-
], [t]);
|
|
195
181
|
const columns = React.useMemo(() => [
|
|
196
182
|
{
|
|
197
183
|
accessorKey: "name",
|
|
@@ -201,7 +187,7 @@ function WarehouseSection({ viewAllHref } = {}) {
|
|
|
201
187
|
},
|
|
202
188
|
{ accessorKey: "code", header: t("wms.backend.config.warehouses.columns.code", "Code"), enableSorting: true },
|
|
203
189
|
{ accessorKey: "city", header: t("wms.backend.config.warehouses.columns.city", "City"), cell: ({ row }) => row.original.city || "\u2014" },
|
|
204
|
-
{ accessorKey: "country", header: t("wms.backend.config.warehouses.columns.country", "Country"), cell: ({ row }) => row.original.country
|
|
190
|
+
{ accessorKey: "country", header: t("wms.backend.config.warehouses.columns.country", "Country"), cell: ({ row }) => formatWarehouseCountryLabel(row.original.country, locale) },
|
|
205
191
|
{
|
|
206
192
|
accessorKey: "is_primary",
|
|
207
193
|
header: t("wms.backend.config.warehouses.columns.primary", "Primary"),
|
|
@@ -212,79 +198,24 @@ function WarehouseSection({ viewAllHref } = {}) {
|
|
|
212
198
|
header: t("wms.backend.config.warehouses.columns.status", "Status"),
|
|
213
199
|
cell: ({ row }) => row.original.is_active === false ? t("wms.common.inactive", "Inactive") : t("wms.common.active", "Active")
|
|
214
200
|
}
|
|
215
|
-
], [t]);
|
|
216
|
-
const initialValues = React.useMemo(() => {
|
|
217
|
-
if (dialog?.mode === "edit") {
|
|
218
|
-
return {
|
|
219
|
-
name: dialog.row.name || "",
|
|
220
|
-
code: dialog.row.code || "",
|
|
221
|
-
city: dialog.row.city || "",
|
|
222
|
-
country: dialog.row.country || "",
|
|
223
|
-
timezone: dialog.row.timezone || "",
|
|
224
|
-
isActive: dialog.row.is_active !== false,
|
|
225
|
-
isPrimary: dialog.row.is_primary === true
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
return {
|
|
229
|
-
name: "",
|
|
230
|
-
code: "",
|
|
231
|
-
city: "",
|
|
232
|
-
country: "",
|
|
233
|
-
timezone: "",
|
|
234
|
-
isActive: true,
|
|
235
|
-
isPrimary: false
|
|
236
|
-
};
|
|
237
|
-
}, [dialog]);
|
|
201
|
+
], [locale, t]);
|
|
238
202
|
const closeDialog = React.useCallback(() => {
|
|
239
203
|
setDialog(null);
|
|
240
|
-
setSubmitting(false);
|
|
241
204
|
}, []);
|
|
242
205
|
const refresh = React.useCallback(async () => {
|
|
243
206
|
await queryClient.cancelQueries({ queryKey: ["wms-config", "warehouses"] });
|
|
244
207
|
await queryClient.invalidateQueries({ queryKey: ["wms-config", "warehouses"] });
|
|
245
208
|
await queryClient.refetchQueries({ queryKey: ["wms-config", "warehouses"], type: "all" });
|
|
246
209
|
}, [queryClient]);
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
operation: async () => {
|
|
254
|
-
const result = await apiCall(
|
|
255
|
-
"/api/wms/warehouses",
|
|
256
|
-
{
|
|
257
|
-
method: submitMode === "edit" ? "PUT" : "POST",
|
|
258
|
-
body: JSON.stringify(
|
|
259
|
-
submitMode === "edit" ? { id: dialog.row.id, ...values } : values
|
|
260
|
-
)
|
|
261
|
-
}
|
|
262
|
-
);
|
|
263
|
-
if (!result.ok) {
|
|
264
|
-
await raiseCrudError(result.response, t("wms.backend.config.warehouses.errors.save", "Failed to save warehouse."));
|
|
265
|
-
}
|
|
266
|
-
return result;
|
|
267
|
-
},
|
|
268
|
-
context: {},
|
|
269
|
-
mutationPayload: submitMode === "edit" ? { id: dialog.row.id, ...values } : values
|
|
270
|
-
});
|
|
271
|
-
flash(
|
|
272
|
-
submitMode === "edit" ? t("wms.backend.config.warehouses.flash.updated", "Warehouse updated") : t("wms.backend.config.warehouses.flash.created", "Warehouse created"),
|
|
273
|
-
"success"
|
|
274
|
-
);
|
|
275
|
-
const createdId = submitMode === "create" && call?.result && typeof call.result === "object" && typeof call.result.id === "string" ? call.result.id.trim() : null;
|
|
276
|
-
closeDialog();
|
|
277
|
-
if (submitMode === "create" && createdId) {
|
|
278
|
-
mergeCreatedWarehouseIntoWarehousesCaches(queryClient, createdId, values);
|
|
279
|
-
setSearch("");
|
|
280
|
-
setPage(1);
|
|
281
|
-
}
|
|
282
|
-
await refresh();
|
|
283
|
-
} catch (error) {
|
|
284
|
-
flashMutationError(error, t("wms.backend.config.warehouses.errors.save", "Failed to save warehouse."), t);
|
|
285
|
-
setSubmitting(false);
|
|
210
|
+
const handleWarehouseSaved = React.useCallback(async (info) => {
|
|
211
|
+
closeDialog();
|
|
212
|
+
if (info.mode === "create" && info.id) {
|
|
213
|
+
mergeCreatedWarehouseIntoWarehousesCaches(queryClient, info.id, info.values, info.updatedAt);
|
|
214
|
+
setSearch("");
|
|
215
|
+
setPage(1);
|
|
286
216
|
}
|
|
287
|
-
|
|
217
|
+
await refresh();
|
|
218
|
+
}, [closeDialog, queryClient, refresh]);
|
|
288
219
|
const handleDelete = React.useCallback(async (row) => {
|
|
289
220
|
const confirmed = await confirm({
|
|
290
221
|
title: t("wms.backend.config.warehouses.confirmDelete", 'Archive warehouse "{name}"?', {
|
|
@@ -373,23 +304,18 @@ function WarehouseSection({ viewAllHref } = {}) {
|
|
|
373
304
|
)
|
|
374
305
|
}
|
|
375
306
|
),
|
|
376
|
-
/* @__PURE__ */ jsx(
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
{
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
isLoading: submitting,
|
|
389
|
-
twoColumn: true
|
|
390
|
-
}
|
|
391
|
-
)
|
|
392
|
-
] }) }),
|
|
307
|
+
/* @__PURE__ */ jsx(
|
|
308
|
+
WarehouseEditDialog,
|
|
309
|
+
{
|
|
310
|
+
open: dialog !== null,
|
|
311
|
+
onOpenChange: (next) => {
|
|
312
|
+
if (!next) closeDialog();
|
|
313
|
+
},
|
|
314
|
+
mode: dialog?.mode === "edit" ? "edit" : "create",
|
|
315
|
+
row: dialog?.mode === "edit" ? dialog.row : null,
|
|
316
|
+
onSaved: handleWarehouseSaved
|
|
317
|
+
}
|
|
318
|
+
),
|
|
393
319
|
ConfirmDialogElement
|
|
394
320
|
] });
|
|
395
321
|
}
|