@open-mercato/core 0.10.1-develop.7822.1.5d6a1d00a1 → 0.10.1-develop.7826.1.5e82b7c668

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.
@@ -313,25 +313,39 @@ function ReleaseReservationDialog({
313
313
  ) })
314
314
  ] }),
315
315
  /* @__PURE__ */ jsxs(DialogFooter, { bordered: false, className: "border-t px-6 py-4 sm:justify-between", children: [
316
- /* @__PURE__ */ jsxs("p", { className: "hidden text-xs text-muted-foreground sm:inline-flex sm:items-center sm:gap-1.5", children: [
317
- /* @__PURE__ */ jsx(KbdShortcut, { keys: ["\u2318", "Enter"] }),
318
- /* @__PURE__ */ jsx("span", { children: "/" }),
319
- /* @__PURE__ */ jsx(KbdShortcut, { keys: ["Ctrl", "Enter"] }),
320
- /* @__PURE__ */ jsx("span", { children: t("wms.backend.inventory.release.dialog.shortcutSave", "to confirm") })
321
- ] }),
322
- /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col-reverse gap-2 sm:w-auto sm:flex-row", children: [
323
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: closeDialog, disabled: submitting, children: t("common.cancel", "Cancel") }),
324
- /* @__PURE__ */ jsx(
325
- Button,
326
- {
327
- type: "submit",
328
- variant: "destructive-solid",
329
- disabled: submitDisabled,
330
- "data-testid": "wms-inventory-release-submit",
331
- children: t("wms.backend.inventory.release.dialog.submit", "Release reservation")
332
- }
333
- )
334
- ] })
316
+ /* @__PURE__ */ jsxs(
317
+ "p",
318
+ {
319
+ className: "hidden text-xs text-muted-foreground sm:inline-flex sm:min-w-0 sm:flex-wrap sm:items-center sm:gap-1.5",
320
+ "data-testid": "wms-inventory-release-shortcut-hint",
321
+ children: [
322
+ /* @__PURE__ */ jsx(KbdShortcut, { keys: ["\u2318", "Enter"] }),
323
+ /* @__PURE__ */ jsx("span", { children: "/" }),
324
+ /* @__PURE__ */ jsx(KbdShortcut, { keys: ["Ctrl", "Enter"] }),
325
+ /* @__PURE__ */ jsx("span", { children: t("wms.backend.inventory.release.dialog.shortcutSave", "to confirm") })
326
+ ]
327
+ }
328
+ ),
329
+ /* @__PURE__ */ jsxs(
330
+ "div",
331
+ {
332
+ className: "flex w-full flex-col-reverse gap-2 sm:w-auto sm:shrink-0 sm:flex-row",
333
+ "data-testid": "wms-inventory-release-actions",
334
+ children: [
335
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: closeDialog, disabled: submitting, children: t("common.cancel", "Cancel") }),
336
+ /* @__PURE__ */ jsx(
337
+ Button,
338
+ {
339
+ type: "submit",
340
+ variant: "destructive-solid",
341
+ disabled: submitDisabled,
342
+ "data-testid": "wms-inventory-release-submit",
343
+ children: t("wms.backend.inventory.release.dialog.submit", "Release reservation")
344
+ }
345
+ )
346
+ ]
347
+ }
348
+ )
335
349
  ] })
336
350
  ] })
337
351
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/wms/components/backend/ReleaseReservationDialog.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { ShieldOff } from 'lucide-react'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { flashMutationError } from '../../lib/flashMutationError'\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 { Button } from '@open-mercato/ui/primitives/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { FormField } from '@open-mercato/ui/primitives/form-field'\nimport { KbdShortcut } from '@open-mercato/ui/primitives/kbd'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n createInventoryQuantityFormatter,\n formatReservationSourceLabel,\n} from '../../lib/inventoryDisplayUi'\nimport { parseInventoryQuantity } from '../../lib/inventoryMutationUi'\nimport type { WmsInventoryMutationAccess } from './useWmsInventoryMutationAccess'\n\nconst RELEASE_REASON_CODES = ['order_cancelled', 'manual_release', 'correction', 'other'] as const\n\ntype ReleaseReasonCode = (typeof RELEASE_REASON_CODES)[number]\n\ntype ReservationSummary = {\n id: string\n warehouse_name?: string | null\n warehouse_code?: string | null\n variant_name?: string | null\n variant_sku?: string | null\n quantity?: string | number | null\n source_type?: string | null\n source_id?: string | null\n source_label?: string | null\n status?: string | null\n}\n\ntype ReleaseReservationDialogProps = {\n open: boolean\n onOpenChange: (open: boolean) => void\n access: WmsInventoryMutationAccess\n reservation: ReservationSummary | null\n onSuccess?: () => void\n}\n\nfunction formatVariantLabel(\n row: ReservationSummary,\n notAvailableLabel: string,\n): string {\n const name = (row.variant_name ?? '').trim()\n const sku = (row.variant_sku ?? '').trim()\n if (name && sku) return `${name} (${sku})`\n if (name) return name\n if (sku) return sku\n return notAvailableLabel\n}\n\nfunction formatWarehouseLabel(\n row: ReservationSummary,\n notAvailableLabel: string,\n): string {\n return (\n row.warehouse_name?.trim() ||\n row.warehouse_code?.trim() ||\n notAvailableLabel\n )\n}\n\nexport function ReleaseReservationDialog({\n open,\n onOpenChange,\n access,\n reservation,\n onSuccess,\n}: ReleaseReservationDialogProps) {\n const t = useT()\n const locale = useLocale()\n const quantityFormatter = React.useMemo(\n () => createInventoryQuantityFormatter(locale),\n [locale],\n )\n const notAvailableLabel = t('wms.backend.inventory.common.notAvailable', '\u2014')\n const queryClient = useQueryClient()\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: 'wms-inventory-release',\n })\n const mutationContext = React.useMemo(\n () => ({ retryLastMutation }),\n [retryLastMutation],\n )\n const releaseFormSchema = React.useMemo(\n () =>\n z.object({\n reasonCode: z.enum(RELEASE_REASON_CODES),\n notes: z.string().trim().max(500).optional(),\n }),\n [],\n )\n const [submitting, setSubmitting] = React.useState(false)\n const [reasonCode, setReasonCode] = React.useState<ReleaseReasonCode | ''>('')\n const [notes, setNotes] = React.useState('')\n const [fieldErrors, setFieldErrors] = React.useState<Record<string, string>>({})\n\n const reasonLabel = React.useCallback(\n (code: ReleaseReasonCode) => {\n const fallbacks: Record<ReleaseReasonCode, string> = {\n order_cancelled: 'Order cancelled',\n manual_release: 'Manual release',\n correction: 'Correction',\n other: 'Other',\n }\n return t(`wms.backend.inventory.release.reasons.${code}`, fallbacks[code])\n },\n [t],\n )\n\n const resetDialog = React.useCallback(() => {\n setReasonCode('')\n setNotes('')\n setFieldErrors({})\n setSubmitting(false)\n }, [])\n\n React.useEffect(() => {\n if (!open || !reservation?.id) return\n setReasonCode('manual_release')\n setNotes('')\n setFieldErrors({})\n setSubmitting(false)\n }, [open, reservation?.id])\n\n const closeDialog = React.useCallback(() => {\n onOpenChange(false)\n resetDialog()\n }, [onOpenChange, resetDialog])\n\n const handleSubmit = React.useCallback(\n async (event?: React.FormEvent) => {\n event?.preventDefault()\n if (!reservation?.id) {\n flash(\n t(\n 'wms.backend.inventory.release.errors.missingReservation',\n 'Reservation context is missing. Close the dialog and try again from the reservations table.',\n ),\n 'error',\n )\n return\n }\n\n const parsed = releaseFormSchema.safeParse({\n reasonCode,\n notes: notes.trim() || undefined,\n })\n if (!parsed.success) {\n const nextErrors: Record<string, string> = {}\n for (const issue of parsed.error.issues) {\n const key = String(issue.path[0] ?? 'form')\n if (!nextErrors[key]) nextErrors[key] = issue.message\n }\n setFieldErrors(nextErrors)\n return\n }\n\n if (!access.scopeReady || !access.organizationId || !access.tenantId) {\n flash(\n t(\n 'wms.backend.inventory.mutations.errors.scope',\n 'Select an organization and sign in before posting inventory changes.',\n ),\n 'error',\n )\n return\n }\n\n setSubmitting(true)\n try {\n const reasonParts = [reasonLabel(parsed.data.reasonCode)]\n if (parsed.data.notes?.trim()) reasonParts.push(parsed.data.notes.trim())\n const payload = {\n organizationId: access.organizationId,\n tenantId: access.tenantId,\n reservationId: reservation.id,\n reason: reasonParts.join(' \u2014 ').slice(0, 120),\n reasonCode: parsed.data.reasonCode,\n }\n\n await runMutation({\n operation: async () => {\n const call = await apiCall<{ ok?: boolean }>('/api/wms/inventory/release', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!call.ok) {\n if (call.response.status === 409 && (call.result as { error?: string } | null)?.error === 'balance_integrity_violation') {\n flash(\n t(\n 'wms.backend.inventory.release.errors.balanceIntegrityViolation',\n 'Balance integrity error \u2014 run \"mercato wms verify-balances --repair\" to diagnose and fix drift before retrying.',\n ),\n 'error',\n )\n return {}\n }\n await raiseCrudError(\n call.response,\n t('wms.backend.inventory.release.errors.submit', 'Failed to release reservation.'),\n )\n }\n return call.result ?? {}\n },\n context: mutationContext,\n mutationPayload: payload,\n })\n\n flash(t('wms.backend.inventory.release.flash.success', 'Reservation released'), 'success')\n await queryClient.invalidateQueries({ queryKey: ['wms-inventory-console'] })\n await queryClient.invalidateQueries({ queryKey: ['wms-sku-detail'] })\n await queryClient.invalidateQueries({ queryKey: ['wms-location-detail'] })\n await queryClient.invalidateQueries({ queryKey: ['wms-lot-detail'] })\n closeDialog()\n onSuccess?.()\n } catch (error) {\n flashMutationError(error, t('wms.backend.inventory.release.errors.submit', 'Failed to release reservation.'), t)\n } finally {\n setSubmitting(false)\n }\n },\n [\n access,\n closeDialog,\n mutationContext,\n notes,\n onSuccess,\n queryClient,\n reasonCode,\n reasonLabel,\n releaseFormSchema,\n reservation,\n runMutation,\n t,\n ],\n )\n\n const submitDisabled = submitting || access.loading || !access.scopeReady\n\n const handleDialogKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n closeDialog()\n return\n }\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n if (!submitDisabled) void handleSubmit()\n }\n },\n [closeDialog, handleSubmit, submitDisabled],\n )\n\n if (!reservation) return null\n\n return (\n <Dialog open={open} onOpenChange={(next) => (next ? onOpenChange(true) : closeDialog())}>\n <DialogContent\n className=\"max-w-lg gap-0 overflow-hidden p-0\"\n onKeyDown={handleDialogKeyDown}\n >\n <div className=\"border-b px-6 py-4 pr-12\">\n <DialogHeader className=\"space-y-1 text-left\">\n <DialogTitle>\n {t('wms.backend.inventory.release.dialog.title', 'Release reservation')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'wms.backend.inventory.release.dialog.description',\n 'Return reserved quantity to available stock for this bucket.',\n )}\n </DialogDescription>\n </DialogHeader>\n </div>\n\n <form onSubmit={handleSubmit} className=\"flex min-h-0 flex-1 flex-col\">\n <div className=\"flex flex-col gap-5 overflow-y-auto px-6 py-6\">\n <div className=\"rounded-lg border bg-muted/40 px-4 py-3.5\">\n <div className=\"flex items-start gap-3\">\n <ShieldOff className=\"mt-0.5 size-4 text-muted-foreground\" aria-hidden=\"true\" />\n <dl className=\"grid gap-2 text-sm\">\n <div className=\"flex flex-wrap gap-x-2\">\n <dt className=\"text-muted-foreground\">\n {t('wms.backend.inventory.release.summary.variant', 'Variant')}\n </dt>\n <dd className=\"font-medium\">\n {formatVariantLabel(reservation, notAvailableLabel)}\n </dd>\n </div>\n <div className=\"flex flex-wrap gap-x-2\">\n <dt className=\"text-muted-foreground\">\n {t('wms.backend.inventory.release.summary.warehouse', 'Warehouse')}\n </dt>\n <dd className=\"font-medium\">\n {formatWarehouseLabel(reservation, notAvailableLabel)}\n </dd>\n </div>\n <div className=\"flex flex-wrap gap-x-2\">\n <dt className=\"text-muted-foreground\">\n {t('wms.backend.inventory.release.summary.quantity', 'Quantity')}\n </dt>\n <dd className=\"font-medium tabular-nums\">\n {quantityFormatter.format(parseInventoryQuantity(reservation.quantity))}\n </dd>\n </div>\n <div className=\"flex flex-wrap gap-x-2\">\n <dt className=\"text-muted-foreground\">\n {t('wms.backend.inventory.release.summary.source', 'Source')}\n </dt>\n <dd className=\"font-medium\">\n {formatReservationSourceLabel(reservation, t) || notAvailableLabel}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n\n <p className=\"rounded-lg border border-status-warning-border bg-status-warning-bg px-3 py-2.5 text-sm text-status-warning-text\">\n {t(\n 'wms.backend.inventory.release.warning',\n 'This action cannot be undone \u2014 the reserved quantity will be released immediately.',\n )}\n </p>\n\n <FormField\n label={t('wms.backend.inventory.release.form.reason', 'Reason')}\n required\n error={fieldErrors.reasonCode}\n >\n <Select\n value={reasonCode || undefined}\n onValueChange={(next) => {\n setReasonCode(next as ReleaseReasonCode)\n setFieldErrors({})\n }}\n disabled={submitting}\n >\n <SelectTrigger>\n <SelectValue\n placeholder={t(\n 'wms.backend.inventory.release.form.reasonPlaceholder',\n 'Select reason',\n )}\n />\n </SelectTrigger>\n <SelectContent>\n {RELEASE_REASON_CODES.map((code) => (\n <SelectItem key={code} value={code}>\n {reasonLabel(code)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </FormField>\n\n <FormField label={t('wms.backend.inventory.release.form.notes', 'Notes')}>\n <Textarea\n value={notes}\n onChange={(event) => setNotes(event.target.value)}\n placeholder={t(\n 'wms.backend.inventory.release.form.notesPlaceholder',\n 'Optional \u2014 additional context',\n )}\n rows={3}\n disabled={submitting}\n />\n </FormField>\n </div>\n\n <DialogFooter bordered={false} className=\"border-t px-6 py-4 sm:justify-between\">\n <p className=\"hidden text-xs text-muted-foreground sm:inline-flex sm:items-center sm:gap-1.5\">\n <KbdShortcut keys={['\u2318', 'Enter']} />\n <span>/</span>\n <KbdShortcut keys={['Ctrl', 'Enter']} />\n <span>{t('wms.backend.inventory.release.dialog.shortcutSave', 'to confirm')}</span>\n </p>\n <div className=\"flex w-full flex-col-reverse gap-2 sm:w-auto sm:flex-row\">\n <Button type=\"button\" variant=\"outline\" onClick={closeDialog} disabled={submitting}>\n {t('common.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"submit\"\n variant=\"destructive-solid\"\n disabled={submitDisabled}\n data-testid=\"wms-inventory-release-submit\"\n >\n {t('wms.backend.inventory.release.dialog.submit', 'Release reservation')}\n </Button>\n </div>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { ShieldOff } from 'lucide-react'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { flashMutationError } from '../../lib/flashMutationError'\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 { Button } from '@open-mercato/ui/primitives/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { FormField } from '@open-mercato/ui/primitives/form-field'\nimport { KbdShortcut } from '@open-mercato/ui/primitives/kbd'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n createInventoryQuantityFormatter,\n formatReservationSourceLabel,\n} from '../../lib/inventoryDisplayUi'\nimport { parseInventoryQuantity } from '../../lib/inventoryMutationUi'\nimport type { WmsInventoryMutationAccess } from './useWmsInventoryMutationAccess'\n\nconst RELEASE_REASON_CODES = ['order_cancelled', 'manual_release', 'correction', 'other'] as const\n\ntype ReleaseReasonCode = (typeof RELEASE_REASON_CODES)[number]\n\ntype ReservationSummary = {\n id: string\n warehouse_name?: string | null\n warehouse_code?: string | null\n variant_name?: string | null\n variant_sku?: string | null\n quantity?: string | number | null\n source_type?: string | null\n source_id?: string | null\n source_label?: string | null\n status?: string | null\n}\n\ntype ReleaseReservationDialogProps = {\n open: boolean\n onOpenChange: (open: boolean) => void\n access: WmsInventoryMutationAccess\n reservation: ReservationSummary | null\n onSuccess?: () => void\n}\n\nfunction formatVariantLabel(\n row: ReservationSummary,\n notAvailableLabel: string,\n): string {\n const name = (row.variant_name ?? '').trim()\n const sku = (row.variant_sku ?? '').trim()\n if (name && sku) return `${name} (${sku})`\n if (name) return name\n if (sku) return sku\n return notAvailableLabel\n}\n\nfunction formatWarehouseLabel(\n row: ReservationSummary,\n notAvailableLabel: string,\n): string {\n return (\n row.warehouse_name?.trim() ||\n row.warehouse_code?.trim() ||\n notAvailableLabel\n )\n}\n\nexport function ReleaseReservationDialog({\n open,\n onOpenChange,\n access,\n reservation,\n onSuccess,\n}: ReleaseReservationDialogProps) {\n const t = useT()\n const locale = useLocale()\n const quantityFormatter = React.useMemo(\n () => createInventoryQuantityFormatter(locale),\n [locale],\n )\n const notAvailableLabel = t('wms.backend.inventory.common.notAvailable', '\u2014')\n const queryClient = useQueryClient()\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: 'wms-inventory-release',\n })\n const mutationContext = React.useMemo(\n () => ({ retryLastMutation }),\n [retryLastMutation],\n )\n const releaseFormSchema = React.useMemo(\n () =>\n z.object({\n reasonCode: z.enum(RELEASE_REASON_CODES),\n notes: z.string().trim().max(500).optional(),\n }),\n [],\n )\n const [submitting, setSubmitting] = React.useState(false)\n const [reasonCode, setReasonCode] = React.useState<ReleaseReasonCode | ''>('')\n const [notes, setNotes] = React.useState('')\n const [fieldErrors, setFieldErrors] = React.useState<Record<string, string>>({})\n\n const reasonLabel = React.useCallback(\n (code: ReleaseReasonCode) => {\n const fallbacks: Record<ReleaseReasonCode, string> = {\n order_cancelled: 'Order cancelled',\n manual_release: 'Manual release',\n correction: 'Correction',\n other: 'Other',\n }\n return t(`wms.backend.inventory.release.reasons.${code}`, fallbacks[code])\n },\n [t],\n )\n\n const resetDialog = React.useCallback(() => {\n setReasonCode('')\n setNotes('')\n setFieldErrors({})\n setSubmitting(false)\n }, [])\n\n React.useEffect(() => {\n if (!open || !reservation?.id) return\n setReasonCode('manual_release')\n setNotes('')\n setFieldErrors({})\n setSubmitting(false)\n }, [open, reservation?.id])\n\n const closeDialog = React.useCallback(() => {\n onOpenChange(false)\n resetDialog()\n }, [onOpenChange, resetDialog])\n\n const handleSubmit = React.useCallback(\n async (event?: React.FormEvent) => {\n event?.preventDefault()\n if (!reservation?.id) {\n flash(\n t(\n 'wms.backend.inventory.release.errors.missingReservation',\n 'Reservation context is missing. Close the dialog and try again from the reservations table.',\n ),\n 'error',\n )\n return\n }\n\n const parsed = releaseFormSchema.safeParse({\n reasonCode,\n notes: notes.trim() || undefined,\n })\n if (!parsed.success) {\n const nextErrors: Record<string, string> = {}\n for (const issue of parsed.error.issues) {\n const key = String(issue.path[0] ?? 'form')\n if (!nextErrors[key]) nextErrors[key] = issue.message\n }\n setFieldErrors(nextErrors)\n return\n }\n\n if (!access.scopeReady || !access.organizationId || !access.tenantId) {\n flash(\n t(\n 'wms.backend.inventory.mutations.errors.scope',\n 'Select an organization and sign in before posting inventory changes.',\n ),\n 'error',\n )\n return\n }\n\n setSubmitting(true)\n try {\n const reasonParts = [reasonLabel(parsed.data.reasonCode)]\n if (parsed.data.notes?.trim()) reasonParts.push(parsed.data.notes.trim())\n const payload = {\n organizationId: access.organizationId,\n tenantId: access.tenantId,\n reservationId: reservation.id,\n reason: reasonParts.join(' \u2014 ').slice(0, 120),\n reasonCode: parsed.data.reasonCode,\n }\n\n await runMutation({\n operation: async () => {\n const call = await apiCall<{ ok?: boolean }>('/api/wms/inventory/release', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!call.ok) {\n if (call.response.status === 409 && (call.result as { error?: string } | null)?.error === 'balance_integrity_violation') {\n flash(\n t(\n 'wms.backend.inventory.release.errors.balanceIntegrityViolation',\n 'Balance integrity error \u2014 run \"mercato wms verify-balances --repair\" to diagnose and fix drift before retrying.',\n ),\n 'error',\n )\n return {}\n }\n await raiseCrudError(\n call.response,\n t('wms.backend.inventory.release.errors.submit', 'Failed to release reservation.'),\n )\n }\n return call.result ?? {}\n },\n context: mutationContext,\n mutationPayload: payload,\n })\n\n flash(t('wms.backend.inventory.release.flash.success', 'Reservation released'), 'success')\n await queryClient.invalidateQueries({ queryKey: ['wms-inventory-console'] })\n await queryClient.invalidateQueries({ queryKey: ['wms-sku-detail'] })\n await queryClient.invalidateQueries({ queryKey: ['wms-location-detail'] })\n await queryClient.invalidateQueries({ queryKey: ['wms-lot-detail'] })\n closeDialog()\n onSuccess?.()\n } catch (error) {\n flashMutationError(error, t('wms.backend.inventory.release.errors.submit', 'Failed to release reservation.'), t)\n } finally {\n setSubmitting(false)\n }\n },\n [\n access,\n closeDialog,\n mutationContext,\n notes,\n onSuccess,\n queryClient,\n reasonCode,\n reasonLabel,\n releaseFormSchema,\n reservation,\n runMutation,\n t,\n ],\n )\n\n const submitDisabled = submitting || access.loading || !access.scopeReady\n\n const handleDialogKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n closeDialog()\n return\n }\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n if (!submitDisabled) void handleSubmit()\n }\n },\n [closeDialog, handleSubmit, submitDisabled],\n )\n\n if (!reservation) return null\n\n return (\n <Dialog open={open} onOpenChange={(next) => (next ? onOpenChange(true) : closeDialog())}>\n <DialogContent\n className=\"max-w-lg gap-0 overflow-hidden p-0\"\n onKeyDown={handleDialogKeyDown}\n >\n <div className=\"border-b px-6 py-4 pr-12\">\n <DialogHeader className=\"space-y-1 text-left\">\n <DialogTitle>\n {t('wms.backend.inventory.release.dialog.title', 'Release reservation')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'wms.backend.inventory.release.dialog.description',\n 'Return reserved quantity to available stock for this bucket.',\n )}\n </DialogDescription>\n </DialogHeader>\n </div>\n\n <form onSubmit={handleSubmit} className=\"flex min-h-0 flex-1 flex-col\">\n <div className=\"flex flex-col gap-5 overflow-y-auto px-6 py-6\">\n <div className=\"rounded-lg border bg-muted/40 px-4 py-3.5\">\n <div className=\"flex items-start gap-3\">\n <ShieldOff className=\"mt-0.5 size-4 text-muted-foreground\" aria-hidden=\"true\" />\n <dl className=\"grid gap-2 text-sm\">\n <div className=\"flex flex-wrap gap-x-2\">\n <dt className=\"text-muted-foreground\">\n {t('wms.backend.inventory.release.summary.variant', 'Variant')}\n </dt>\n <dd className=\"font-medium\">\n {formatVariantLabel(reservation, notAvailableLabel)}\n </dd>\n </div>\n <div className=\"flex flex-wrap gap-x-2\">\n <dt className=\"text-muted-foreground\">\n {t('wms.backend.inventory.release.summary.warehouse', 'Warehouse')}\n </dt>\n <dd className=\"font-medium\">\n {formatWarehouseLabel(reservation, notAvailableLabel)}\n </dd>\n </div>\n <div className=\"flex flex-wrap gap-x-2\">\n <dt className=\"text-muted-foreground\">\n {t('wms.backend.inventory.release.summary.quantity', 'Quantity')}\n </dt>\n <dd className=\"font-medium tabular-nums\">\n {quantityFormatter.format(parseInventoryQuantity(reservation.quantity))}\n </dd>\n </div>\n <div className=\"flex flex-wrap gap-x-2\">\n <dt className=\"text-muted-foreground\">\n {t('wms.backend.inventory.release.summary.source', 'Source')}\n </dt>\n <dd className=\"font-medium\">\n {formatReservationSourceLabel(reservation, t) || notAvailableLabel}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n\n <p className=\"rounded-lg border border-status-warning-border bg-status-warning-bg px-3 py-2.5 text-sm text-status-warning-text\">\n {t(\n 'wms.backend.inventory.release.warning',\n 'This action cannot be undone \u2014 the reserved quantity will be released immediately.',\n )}\n </p>\n\n <FormField\n label={t('wms.backend.inventory.release.form.reason', 'Reason')}\n required\n error={fieldErrors.reasonCode}\n >\n <Select\n value={reasonCode || undefined}\n onValueChange={(next) => {\n setReasonCode(next as ReleaseReasonCode)\n setFieldErrors({})\n }}\n disabled={submitting}\n >\n <SelectTrigger>\n <SelectValue\n placeholder={t(\n 'wms.backend.inventory.release.form.reasonPlaceholder',\n 'Select reason',\n )}\n />\n </SelectTrigger>\n <SelectContent>\n {RELEASE_REASON_CODES.map((code) => (\n <SelectItem key={code} value={code}>\n {reasonLabel(code)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </FormField>\n\n <FormField label={t('wms.backend.inventory.release.form.notes', 'Notes')}>\n <Textarea\n value={notes}\n onChange={(event) => setNotes(event.target.value)}\n placeholder={t(\n 'wms.backend.inventory.release.form.notesPlaceholder',\n 'Optional \u2014 additional context',\n )}\n rows={3}\n disabled={submitting}\n />\n </FormField>\n </div>\n\n <DialogFooter bordered={false} className=\"border-t px-6 py-4 sm:justify-between\">\n <p\n className=\"hidden text-xs text-muted-foreground sm:inline-flex sm:min-w-0 sm:flex-wrap sm:items-center sm:gap-1.5\"\n data-testid=\"wms-inventory-release-shortcut-hint\"\n >\n <KbdShortcut keys={['\u2318', 'Enter']} />\n <span>/</span>\n <KbdShortcut keys={['Ctrl', 'Enter']} />\n <span>{t('wms.backend.inventory.release.dialog.shortcutSave', 'to confirm')}</span>\n </p>\n <div\n className=\"flex w-full flex-col-reverse gap-2 sm:w-auto sm:shrink-0 sm:flex-row\"\n data-testid=\"wms-inventory-release-actions\"\n >\n <Button type=\"button\" variant=\"outline\" onClick={closeDialog} disabled={submitting}>\n {t('common.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"submit\"\n variant=\"destructive-solid\"\n disabled={submitDisabled}\n data-testid=\"wms-inventory-release-submit\"\n >\n {t('wms.backend.inventory.release.dialog.submit', 'Release reservation')}\n </Button>\n </div>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.10.1-develop.7822.1.5d6a1d00a1",
3
+ "version": "0.10.1-develop.7826.1.5e82b7c668",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -266,16 +266,16 @@
266
266
  "zod": "^4.6.6"
267
267
  },
268
268
  "peerDependencies": {
269
- "@open-mercato/ai-assistant": "0.10.1-develop.7822.1.5d6a1d00a1",
270
- "@open-mercato/shared": "0.10.1-develop.7822.1.5d6a1d00a1",
271
- "@open-mercato/ui": "0.10.1-develop.7822.1.5d6a1d00a1",
269
+ "@open-mercato/ai-assistant": "0.10.1-develop.7826.1.5e82b7c668",
270
+ "@open-mercato/shared": "0.10.1-develop.7826.1.5e82b7c668",
271
+ "@open-mercato/ui": "0.10.1-develop.7826.1.5e82b7c668",
272
272
  "react": "^19.0.0",
273
273
  "react-dom": "^19.0.0"
274
274
  },
275
275
  "devDependencies": {
276
- "@open-mercato/ai-assistant": "0.10.1-develop.7822.1.5d6a1d00a1",
277
- "@open-mercato/shared": "0.10.1-develop.7822.1.5d6a1d00a1",
278
- "@open-mercato/ui": "0.10.1-develop.7822.1.5d6a1d00a1",
276
+ "@open-mercato/ai-assistant": "0.10.1-develop.7826.1.5e82b7c668",
277
+ "@open-mercato/shared": "0.10.1-develop.7826.1.5e82b7c668",
278
+ "@open-mercato/ui": "0.10.1-develop.7826.1.5e82b7c668",
279
279
  "@testing-library/dom": "^10.4.1",
280
280
  "@testing-library/jest-dom": "^7.0.1",
281
281
  "@testing-library/react": "^16.3.3",
@@ -397,13 +397,19 @@ export function ReleaseReservationDialog({
397
397
  </div>
398
398
 
399
399
  <DialogFooter bordered={false} className="border-t px-6 py-4 sm:justify-between">
400
- <p className="hidden text-xs text-muted-foreground sm:inline-flex sm:items-center sm:gap-1.5">
400
+ <p
401
+ className="hidden text-xs text-muted-foreground sm:inline-flex sm:min-w-0 sm:flex-wrap sm:items-center sm:gap-1.5"
402
+ data-testid="wms-inventory-release-shortcut-hint"
403
+ >
401
404
  <KbdShortcut keys={['⌘', 'Enter']} />
402
405
  <span>/</span>
403
406
  <KbdShortcut keys={['Ctrl', 'Enter']} />
404
407
  <span>{t('wms.backend.inventory.release.dialog.shortcutSave', 'to confirm')}</span>
405
408
  </p>
406
- <div className="flex w-full flex-col-reverse gap-2 sm:w-auto sm:flex-row">
409
+ <div
410
+ className="flex w-full flex-col-reverse gap-2 sm:w-auto sm:shrink-0 sm:flex-row"
411
+ data-testid="wms-inventory-release-actions"
412
+ >
407
413
  <Button type="button" variant="outline" onClick={closeDialog} disabled={submitting}>
408
414
  {t('common.cancel', 'Cancel')}
409
415
  </Button>