@open-mercato/core 0.9.1-develop.7532.1.8eac7e198f → 0.9.1-develop.7536.1.f9a5776a07
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/logout.js +8 -5
- package/dist/modules/auth/api/logout.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/[id]/page.js +5 -2
- package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
- package/dist/modules/currencies/commands/currencies.js +399 -137
- package/dist/modules/currencies/commands/currencies.js.map +2 -2
- package/dist/modules/currencies/lib/seeds.js +2 -0
- package/dist/modules/currencies/lib/seeds.js.map +2 -2
- package/dist/modules/customers/commands/companies.js +10 -3
- package/dist/modules/customers/commands/companies.js.map +2 -2
- package/dist/modules/customers/commands/interactionRestoreDetails.js +75 -0
- package/dist/modules/customers/commands/interactionRestoreDetails.js.map +7 -0
- package/dist/modules/customers/commands/people.js +10 -3
- package/dist/modules/customers/commands/people.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/auth/api/logout.ts +9 -5
- package/src/modules/currencies/backend/currencies/[id]/page.tsx +5 -1
- package/src/modules/currencies/commands/currencies.ts +475 -168
- package/src/modules/currencies/i18n/de.json +4 -0
- package/src/modules/currencies/i18n/en.json +4 -0
- package/src/modules/currencies/i18n/es.json +4 -0
- package/src/modules/currencies/i18n/ko.json +4 -0
- package/src/modules/currencies/i18n/pl.json +4 -0
- package/src/modules/currencies/lib/seeds.ts +2 -0
- package/src/modules/customers/commands/companies.ts +16 -4
- package/src/modules/customers/commands/interactionRestoreDetails.ts +110 -0
- package/src/modules/customers/commands/people.ts +16 -4
package/.turbo/turbo-build.log
CHANGED
|
@@ -2,6 +2,7 @@ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
|
2
2
|
import { verifyJwt } from "@open-mercato/shared/lib/auth/jwt";
|
|
3
3
|
import { buildSafeRedirectResponse } from "@open-mercato/core/modules/auth/lib/requestRedirect";
|
|
4
4
|
import { emitAuthEvent } from "@open-mercato/core/modules/auth/events";
|
|
5
|
+
import { getTelemetryRuntime } from "@open-mercato/shared/lib/telemetry/runtime";
|
|
5
6
|
const emptyAuthTokenClaims = Object.freeze({
|
|
6
7
|
userId: null,
|
|
7
8
|
sessionId: null,
|
|
@@ -26,7 +27,7 @@ function extractAuthTokenClaims(token) {
|
|
|
26
27
|
if (!token) return emptyAuthTokenClaims;
|
|
27
28
|
try {
|
|
28
29
|
const payload = verifyJwt(token);
|
|
29
|
-
if (!payload) return emptyAuthTokenClaims;
|
|
30
|
+
if (!payload || payload.type === "customer") return emptyAuthTokenClaims;
|
|
30
31
|
return {
|
|
31
32
|
userId: readStringClaim(payload, "sub"),
|
|
32
33
|
sessionId: readStringClaim(payload, "sid"),
|
|
@@ -40,6 +41,7 @@ function extractAuthTokenClaims(token) {
|
|
|
40
41
|
async function POST(req) {
|
|
41
42
|
const sessToken = parseCookie(req, "session_token");
|
|
42
43
|
const authToken = parseCookie(req, "auth_token");
|
|
44
|
+
if (!sessToken && !authToken) return buildSafeRedirectResponse(req, "/login");
|
|
43
45
|
const claims = extractAuthTokenClaims(authToken);
|
|
44
46
|
let sessionRevoked = false;
|
|
45
47
|
if (sessToken || claims.sessionId) {
|
|
@@ -53,7 +55,8 @@ async function POST(req) {
|
|
|
53
55
|
await auth.deleteSessionByToken(sessToken);
|
|
54
56
|
}
|
|
55
57
|
sessionRevoked = true;
|
|
56
|
-
} catch {
|
|
58
|
+
} catch (error) {
|
|
59
|
+
getTelemetryRuntime()?.reportError(error, { module: "auth", code: "auth.logout_revoke_failed" });
|
|
57
60
|
}
|
|
58
61
|
}
|
|
59
62
|
if (claims.userId) {
|
|
@@ -72,7 +75,7 @@ async function POST(req) {
|
|
|
72
75
|
return res;
|
|
73
76
|
}
|
|
74
77
|
const metadata = {
|
|
75
|
-
POST: { requireAuth:
|
|
78
|
+
POST: { requireAuth: false }
|
|
76
79
|
};
|
|
77
80
|
const openApi = {
|
|
78
81
|
tag: "Authentication & Accounts",
|
|
@@ -80,9 +83,9 @@ const openApi = {
|
|
|
80
83
|
methods: {
|
|
81
84
|
POST: {
|
|
82
85
|
summary: "Invalidate session and redirect",
|
|
83
|
-
description: "
|
|
86
|
+
description: "Revokes the session identified by the `auth_token` sid claim and the `session_token` cookie, clears both cookies, and redirects the browser to the login page. A valid access token is not required, so a logout submitted after the access token expired still revokes the remember-me refresh session. A request that carries neither cookie is only redirected.",
|
|
84
87
|
responses: [
|
|
85
|
-
{ status:
|
|
88
|
+
{ status: 307, description: "Redirect to login after successful logout", mediaType: "text/html" }
|
|
86
89
|
]
|
|
87
90
|
}
|
|
88
91
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/auth/api/logout.ts"],
|
|
4
|
-
"sourcesContent": ["import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { AuthService } from '@open-mercato/core/modules/auth/services/authService'\nimport { verifyJwt } from '@open-mercato/shared/lib/auth/jwt'\nimport { buildSafeRedirectResponse } from '@open-mercato/core/modules/auth/lib/requestRedirect'\nimport { emitAuthEvent } from '@open-mercato/core/modules/auth/events'\n\ntype AuthTokenClaims = {\n userId: string | null\n sessionId: string | null\n tenantId: string | null\n organizationId: string | null\n}\n\nconst emptyAuthTokenClaims: AuthTokenClaims = Object.freeze({\n userId: null,\n sessionId: null,\n tenantId: null,\n organizationId: null,\n})\n\nfunction parseCookie(req: Request, name: string): string | null {\n const cookie = req.headers.get('cookie') || ''\n const m = cookie.match(new RegExp('(?:^|;\\\\s*)' + name + '=([^;]+)'))\n if (!m) return null\n try {\n return decodeURIComponent(m[1])\n } catch {\n return null\n }\n}\n\nfunction readStringClaim(payload: Record<string, unknown>, key: string): string | null {\n const value = payload[key]\n return typeof value === 'string' && value.length > 0 ? value : null\n}\n\nfunction extractAuthTokenClaims(token: string | null): AuthTokenClaims {\n if (!token) return emptyAuthTokenClaims\n try {\n const payload = verifyJwt(token) as Record<string, unknown> | null\n if (!payload) return emptyAuthTokenClaims\n return {\n userId: readStringClaim(payload, 'sub'),\n sessionId: readStringClaim(payload, 'sid'),\n tenantId: readStringClaim(payload, 'tenantId'),\n organizationId: readStringClaim(payload, 'orgId'),\n }\n } catch {\n return emptyAuthTokenClaims\n }\n}\n\nexport async function POST(req: Request) {\n const sessToken = parseCookie(req, 'session_token')\n const authToken = parseCookie(req, 'auth_token')\n const claims = extractAuthTokenClaims(authToken)\n let sessionRevoked = false\n if (sessToken || claims.sessionId) {\n try {\n const c = await createRequestContainer()\n const auth = c.resolve<AuthService>('authService')\n if (claims.sessionId) {\n await auth.deleteSessionById(claims.sessionId)\n }\n if (sessToken) {\n await auth.deleteSessionByToken(sessToken)\n }\n sessionRevoked = true\n } catch {}\n }\n if (claims.userId) {\n void emitAuthEvent('auth.logout', {\n id: claims.userId,\n tenantId: claims.tenantId,\n organizationId: claims.organizationId,\n sessionId: claims.sessionId,\n sessionRevoked,\n at: new Date().toISOString(),\n }, { persistent: true }).catch(() => undefined)\n }\n const res = buildSafeRedirectResponse(req, '/login')\n res.cookies.set('auth_token', '', { path: '/', maxAge: 0 })\n res.cookies.set('session_token', '', { path: '/', maxAge: 0 })\n return res\n}\n\nexport const metadata = {\n POST: { requireAuth:
|
|
5
|
-
"mappings": "AACA,SAAS,8BAA8B;AAEvC,SAAS,iBAAiB;AAC1B,SAAS,iCAAiC;AAC1C,SAAS,qBAAqB;
|
|
4
|
+
"sourcesContent": ["import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { AuthService } from '@open-mercato/core/modules/auth/services/authService'\nimport { verifyJwt } from '@open-mercato/shared/lib/auth/jwt'\nimport { buildSafeRedirectResponse } from '@open-mercato/core/modules/auth/lib/requestRedirect'\nimport { emitAuthEvent } from '@open-mercato/core/modules/auth/events'\nimport { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'\n\ntype AuthTokenClaims = {\n userId: string | null\n sessionId: string | null\n tenantId: string | null\n organizationId: string | null\n}\n\nconst emptyAuthTokenClaims: AuthTokenClaims = Object.freeze({\n userId: null,\n sessionId: null,\n tenantId: null,\n organizationId: null,\n})\n\nfunction parseCookie(req: Request, name: string): string | null {\n const cookie = req.headers.get('cookie') || ''\n const m = cookie.match(new RegExp('(?:^|;\\\\s*)' + name + '=([^;]+)'))\n if (!m) return null\n try {\n return decodeURIComponent(m[1])\n } catch {\n return null\n }\n}\n\nfunction readStringClaim(payload: Record<string, unknown>, key: string): string | null {\n const value = payload[key]\n return typeof value === 'string' && value.length > 0 ? value : null\n}\n\nfunction extractAuthTokenClaims(token: string | null): AuthTokenClaims {\n if (!token) return emptyAuthTokenClaims\n try {\n const payload = verifyJwt(token) as Record<string, unknown> | null\n if (!payload || payload.type === 'customer') return emptyAuthTokenClaims\n return {\n userId: readStringClaim(payload, 'sub'),\n sessionId: readStringClaim(payload, 'sid'),\n tenantId: readStringClaim(payload, 'tenantId'),\n organizationId: readStringClaim(payload, 'orgId'),\n }\n } catch {\n return emptyAuthTokenClaims\n }\n}\n\nexport async function POST(req: Request) {\n const sessToken = parseCookie(req, 'session_token')\n const authToken = parseCookie(req, 'auth_token')\n if (!sessToken && !authToken) return buildSafeRedirectResponse(req, '/login')\n const claims = extractAuthTokenClaims(authToken)\n let sessionRevoked = false\n if (sessToken || claims.sessionId) {\n try {\n const c = await createRequestContainer()\n const auth = c.resolve<AuthService>('authService')\n if (claims.sessionId) {\n await auth.deleteSessionById(claims.sessionId)\n }\n if (sessToken) {\n await auth.deleteSessionByToken(sessToken)\n }\n sessionRevoked = true\n } catch (error) {\n getTelemetryRuntime()?.reportError(error, { module: 'auth', code: 'auth.logout_revoke_failed' })\n }\n }\n if (claims.userId) {\n void emitAuthEvent('auth.logout', {\n id: claims.userId,\n tenantId: claims.tenantId,\n organizationId: claims.organizationId,\n sessionId: claims.sessionId,\n sessionRevoked,\n at: new Date().toISOString(),\n }, { persistent: true }).catch(() => undefined)\n }\n const res = buildSafeRedirectResponse(req, '/login')\n res.cookies.set('auth_token', '', { path: '/', maxAge: 0 })\n res.cookies.set('session_token', '', { path: '/', maxAge: 0 })\n return res\n}\n\nexport const metadata = {\n POST: { requireAuth: false },\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Authentication & Accounts',\n summary: 'Log out current session',\n methods: {\n POST: {\n summary: 'Invalidate session and redirect',\n description: 'Revokes the session identified by the `auth_token` sid claim and the `session_token` cookie, clears both cookies, and redirects the browser to the login page. A valid access token is not required, so a logout submitted after the access token expired still revokes the remember-me refresh session. A request that carries neither cookie is only redirected.',\n responses: [\n { status: 307, description: 'Redirect to login after successful logout', mediaType: 'text/html' },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -49,6 +49,7 @@ function EditCurrencyPage({ params }) {
|
|
|
49
49
|
}
|
|
50
50
|
loadCurrency();
|
|
51
51
|
}, [params, t]);
|
|
52
|
+
const isCurrentBase = currency?.isBase === true;
|
|
52
53
|
const groups = React.useMemo(
|
|
53
54
|
() => [
|
|
54
55
|
{
|
|
@@ -109,7 +110,9 @@ function EditCurrencyPage({ params }) {
|
|
|
109
110
|
{
|
|
110
111
|
id: "isBase",
|
|
111
112
|
type: "checkbox",
|
|
112
|
-
label: t("currencies.form.field.isBase")
|
|
113
|
+
label: t("currencies.form.field.isBase"),
|
|
114
|
+
disabled: isCurrentBase,
|
|
115
|
+
description: isCurrentBase ? t("currencies.form.field.isBaseLocked") : void 0
|
|
113
116
|
},
|
|
114
117
|
{
|
|
115
118
|
id: "isActive",
|
|
@@ -119,7 +122,7 @@ function EditCurrencyPage({ params }) {
|
|
|
119
122
|
]
|
|
120
123
|
}
|
|
121
124
|
],
|
|
122
|
-
[t]
|
|
125
|
+
[t, isCurrentBase]
|
|
123
126
|
);
|
|
124
127
|
const handleDelete = React.useCallback(async () => {
|
|
125
128
|
if (!currency) return;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/currencies/backend/currencies/%5Bid%5D/page.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useRouter, usePathname } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport { DataLoader } from '@open-mercato/ui/primitives/DataLoader'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\n\ntype CurrencyData = {\n id: string\n code: string\n name: string\n symbol: string | null\n decimalPlaces: number\n thousandsSeparator: string | null\n decimalSeparator: string | null\n isBase: boolean\n isActive: boolean\n organizationId: string\n tenantId: string\n updatedAt?: string | null\n updated_at?: string | null\n}\n\nexport default function EditCurrencyPage({ params }: { params?: { id?: string } }) {\n const t = useT()\n const router = useRouter()\n const pathname = usePathname()\n const { confirm: confirmDialog, ConfirmDialogElement } = useConfirmDialog()\n const mutationContextId = 'currencies-edit:delete'\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const [currency, setCurrency] = React.useState<CurrencyData | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n\n React.useEffect(() => {\n async function loadCurrency() {\n try {\n const response = await apiCall<{ items: CurrencyData[] }>(`/api/currencies/currencies?id=${params?.id}`)\n if (response.ok && response.result && response.result.items.length > 0) {\n setCurrency(response.result.items[0])\n } else if (!response.ok) {\n setError(t('currencies.form.errors.load'))\n } else {\n setIsNotFound(true)\n }\n } catch (err) {\n setError(t('currencies.form.errors.load'))\n } finally {\n setLoading(false)\n }\n }\n loadCurrency()\n }, [params, t])\n\n const groups = React.useMemo<CrudFormGroup[]>(\n () => [\n {\n id: 'basic',\n column: 1,\n title: t('currencies.form.group.details'),\n fields: [\n {\n id: 'code',\n type: 'text',\n label: t('currencies.form.field.code'),\n placeholder: t('currencies.form.field.codePlaceholder'),\n required: true,\n maxLength: 3,\n helpText: t('currencies.form.field.codeHelp'),\n },\n {\n id: 'name',\n type: 'text',\n label: t('currencies.form.field.name'),\n placeholder: t('currencies.form.field.namePlaceholder'),\n required: true,\n },\n {\n id: 'symbol',\n type: 'text',\n label: t('currencies.form.field.symbol'),\n placeholder: t('currencies.form.field.symbolPlaceholder'),\n },\n ],\n },\n {\n id: 'formatting',\n column: 2,\n title: t('currencies.form.group.formatting'),\n fields: [\n {\n id: 'decimalPlaces',\n type: 'number',\n label: t('currencies.form.field.decimalPlaces'),\n min: 0,\n max: 8,\n },\n {\n id: 'thousandsSeparator',\n type: 'text',\n label: t('currencies.form.field.thousandsSeparator'),\n placeholder: ',',\n maxLength: 5,\n },\n {\n id: 'decimalSeparator',\n type: 'text',\n label: t('currencies.form.field.decimalSeparator'),\n placeholder: '.',\n maxLength: 5,\n },\n {\n id: 'isBase',\n type: 'checkbox',\n label: t('currencies.form.field.isBase'),\n },\n {\n id: 'isActive',\n type: 'checkbox',\n label: t('currencies.form.field.isActive'),\n },\n ],\n },\n ],\n [t]\n )\n\n const handleDelete = React.useCallback(async () => {\n if (!currency) return\n\n const confirmed = await confirmDialog({\n title: t('currencies.list.confirmDelete', { code: currency.code }),\n variant: 'destructive',\n })\n if (!confirmed) return\n\n try {\n await runMutation({\n operation: async () => {\n const headers = buildOptimisticLockHeader(currency.updatedAt ?? currency.updated_at ?? null)\n const call = await withScopedApiRequestHeaders(headers, () => (\n apiCall('/api/currencies/currencies', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: currency.id, organizationId: currency.organizationId, tenantId: currency.tenantId }),\n })\n ))\n if (!call.ok) {\n throw Object.assign(new Error('[internal] currencies.delete failed'), {\n status: call.status,\n ...((call.result as Record<string, unknown> | null) ?? {}),\n })\n }\n return call\n },\n context: {\n formId: mutationContextId,\n resourceKind: 'currencies.currency',\n resourceId: currency.id,\n retryLastMutation,\n },\n mutationPayload: { id: currency.id },\n })\n\n flash(t('currencies.flash.deleted'), 'success')\n router.push('/backend/currencies')\n } catch (error) {\n if (surfaceRecordConflict(error, t)) return\n flash(t('currencies.flash.deleteError'), 'error')\n }\n }, [currency, t, router, confirmDialog, mutationContextId, retryLastMutation, runMutation])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `currencies.currency` + id\n // explicitly. The resourceKind mirrors the CrudForm `versionHistory` so the held\n // lock matches the save-time conflict surface for the same currency.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'currencies.currency',\n resourceId: currency?.id ?? null,\n updatedAt: currency?.updatedAt ?? currency?.updated_at ?? null,\n data: currency as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (loading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex items-center justify-center p-8\">\n <div className=\"text-muted-foreground\">{t('currencies.form.loading')}</div>\n </div>\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('currencies.form.errors.notFound', 'Currency not found.')}\n backHref=\"/backend/currencies\"\n backLabel={t('currencies.form.actions.backToList', 'Back to currencies')}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n }\n\n if (error || !currency) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error ?? t('currencies.form.errors.notFound', 'Currency not found.')} />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={t('currencies.edit.title')}\n titleHeadingLevel={1}\n backHref=\"/backend/currencies\"\n versionHistory={{ resourceKind: 'currencies.currency', resourceId: currency.id }}\n extraActions={(\n <SendObjectMessageDialog\n object={{\n entityModule: 'currencies',\n entityType: 'currency',\n entityId: currency.id,\n previewData: {\n title: currency.name,\n subtitle: currency.code,\n metadata: {\n [t('currencies.form.field.code')]: currency.code,\n [t('currencies.form.field.name')]: currency.name,\n [t('currencies.form.field.symbol')]: currency.symbol || '-',\n },\n },\n }}\n viewHref={`/backend/currencies/${currency.id}`}\n />\n )}\n fields={[]}\n groups={groups}\n optimisticLockUpdatedAt={currency.updatedAt ?? currency.updated_at ?? null}\n initialValues={{\n code: currency.code,\n name: currency.name,\n symbol: currency.symbol || '',\n decimalPlaces: currency.decimalPlaces,\n thousandsSeparator: currency.thousandsSeparator || '',\n decimalSeparator: currency.decimalSeparator || '',\n isBase: currency.isBase,\n isActive: currency.isActive,\n }}\n submitLabel={t('currencies.form.action.save')}\n cancelHref=\"/backend/currencies\"\n onSubmit={async (values) => {\n // Validate currency code\n const code = String(values.code || '').trim().toUpperCase()\n if (!/^[A-Z]{3}$/.test(code)) {\n throw createCrudFormError(t('currencies.form.errors.codeFormat'), {\n code: t('currencies.form.errors.codeFormat'),\n })\n }\n\n const payload = {\n id: currency.id,\n code,\n name: String(values.name || '').trim(),\n symbol: values.symbol ? String(values.symbol).trim() : null,\n decimalPlaces: values.decimalPlaces ? parseInt(String(values.decimalPlaces)) : 2,\n thousandsSeparator: values.thousandsSeparator ? String(values.thousandsSeparator) : null,\n decimalSeparator: values.decimalSeparator ? String(values.decimalSeparator) : null,\n isBase: !!values.isBase,\n isActive: values.isActive !== false,\n }\n\n await updateCrud('currencies/currencies', payload)\n\n flash(t('currencies.flash.updated'), 'success')\n router.push('/backend/currencies')\n }}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useRouter, usePathname } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport { DataLoader } from '@open-mercato/ui/primitives/DataLoader'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\n\ntype CurrencyData = {\n id: string\n code: string\n name: string\n symbol: string | null\n decimalPlaces: number\n thousandsSeparator: string | null\n decimalSeparator: string | null\n isBase: boolean\n isActive: boolean\n organizationId: string\n tenantId: string\n updatedAt?: string | null\n updated_at?: string | null\n}\n\nexport default function EditCurrencyPage({ params }: { params?: { id?: string } }) {\n const t = useT()\n const router = useRouter()\n const pathname = usePathname()\n const { confirm: confirmDialog, ConfirmDialogElement } = useConfirmDialog()\n const mutationContextId = 'currencies-edit:delete'\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const [currency, setCurrency] = React.useState<CurrencyData | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n\n React.useEffect(() => {\n async function loadCurrency() {\n try {\n const response = await apiCall<{ items: CurrencyData[] }>(`/api/currencies/currencies?id=${params?.id}`)\n if (response.ok && response.result && response.result.items.length > 0) {\n setCurrency(response.result.items[0])\n } else if (!response.ok) {\n setError(t('currencies.form.errors.load'))\n } else {\n setIsNotFound(true)\n }\n } catch (err) {\n setError(t('currencies.form.errors.load'))\n } finally {\n setLoading(false)\n }\n }\n loadCurrency()\n }, [params, t])\n\n const isCurrentBase = currency?.isBase === true\n\n const groups = React.useMemo<CrudFormGroup[]>(\n () => [\n {\n id: 'basic',\n column: 1,\n title: t('currencies.form.group.details'),\n fields: [\n {\n id: 'code',\n type: 'text',\n label: t('currencies.form.field.code'),\n placeholder: t('currencies.form.field.codePlaceholder'),\n required: true,\n maxLength: 3,\n helpText: t('currencies.form.field.codeHelp'),\n },\n {\n id: 'name',\n type: 'text',\n label: t('currencies.form.field.name'),\n placeholder: t('currencies.form.field.namePlaceholder'),\n required: true,\n },\n {\n id: 'symbol',\n type: 'text',\n label: t('currencies.form.field.symbol'),\n placeholder: t('currencies.form.field.symbolPlaceholder'),\n },\n ],\n },\n {\n id: 'formatting',\n column: 2,\n title: t('currencies.form.group.formatting'),\n fields: [\n {\n id: 'decimalPlaces',\n type: 'number',\n label: t('currencies.form.field.decimalPlaces'),\n min: 0,\n max: 8,\n },\n {\n id: 'thousandsSeparator',\n type: 'text',\n label: t('currencies.form.field.thousandsSeparator'),\n placeholder: ',',\n maxLength: 5,\n },\n {\n id: 'decimalSeparator',\n type: 'text',\n label: t('currencies.form.field.decimalSeparator'),\n placeholder: '.',\n maxLength: 5,\n },\n {\n id: 'isBase',\n type: 'checkbox',\n label: t('currencies.form.field.isBase'),\n disabled: isCurrentBase,\n description: isCurrentBase ? t('currencies.form.field.isBaseLocked') : undefined,\n },\n {\n id: 'isActive',\n type: 'checkbox',\n label: t('currencies.form.field.isActive'),\n },\n ],\n },\n ],\n [t, isCurrentBase]\n )\n\n const handleDelete = React.useCallback(async () => {\n if (!currency) return\n\n const confirmed = await confirmDialog({\n title: t('currencies.list.confirmDelete', { code: currency.code }),\n variant: 'destructive',\n })\n if (!confirmed) return\n\n try {\n await runMutation({\n operation: async () => {\n const headers = buildOptimisticLockHeader(currency.updatedAt ?? currency.updated_at ?? null)\n const call = await withScopedApiRequestHeaders(headers, () => (\n apiCall('/api/currencies/currencies', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: currency.id, organizationId: currency.organizationId, tenantId: currency.tenantId }),\n })\n ))\n if (!call.ok) {\n throw Object.assign(new Error('[internal] currencies.delete failed'), {\n status: call.status,\n ...((call.result as Record<string, unknown> | null) ?? {}),\n })\n }\n return call\n },\n context: {\n formId: mutationContextId,\n resourceKind: 'currencies.currency',\n resourceId: currency.id,\n retryLastMutation,\n },\n mutationPayload: { id: currency.id },\n })\n\n flash(t('currencies.flash.deleted'), 'success')\n router.push('/backend/currencies')\n } catch (error) {\n if (surfaceRecordConflict(error, t)) return\n flash(t('currencies.flash.deleteError'), 'error')\n }\n }, [currency, t, router, confirmDialog, mutationContextId, retryLastMutation, runMutation])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `currencies.currency` + id\n // explicitly. The resourceKind mirrors the CrudForm `versionHistory` so the held\n // lock matches the save-time conflict surface for the same currency.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'currencies.currency',\n resourceId: currency?.id ?? null,\n updatedAt: currency?.updatedAt ?? currency?.updated_at ?? null,\n data: currency as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (loading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex items-center justify-center p-8\">\n <div className=\"text-muted-foreground\">{t('currencies.form.loading')}</div>\n </div>\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('currencies.form.errors.notFound', 'Currency not found.')}\n backHref=\"/backend/currencies\"\n backLabel={t('currencies.form.actions.backToList', 'Back to currencies')}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n }\n\n if (error || !currency) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error ?? t('currencies.form.errors.notFound', 'Currency not found.')} />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={t('currencies.edit.title')}\n titleHeadingLevel={1}\n backHref=\"/backend/currencies\"\n versionHistory={{ resourceKind: 'currencies.currency', resourceId: currency.id }}\n extraActions={(\n <SendObjectMessageDialog\n object={{\n entityModule: 'currencies',\n entityType: 'currency',\n entityId: currency.id,\n previewData: {\n title: currency.name,\n subtitle: currency.code,\n metadata: {\n [t('currencies.form.field.code')]: currency.code,\n [t('currencies.form.field.name')]: currency.name,\n [t('currencies.form.field.symbol')]: currency.symbol || '-',\n },\n },\n }}\n viewHref={`/backend/currencies/${currency.id}`}\n />\n )}\n fields={[]}\n groups={groups}\n optimisticLockUpdatedAt={currency.updatedAt ?? currency.updated_at ?? null}\n initialValues={{\n code: currency.code,\n name: currency.name,\n symbol: currency.symbol || '',\n decimalPlaces: currency.decimalPlaces,\n thousandsSeparator: currency.thousandsSeparator || '',\n decimalSeparator: currency.decimalSeparator || '',\n isBase: currency.isBase,\n isActive: currency.isActive,\n }}\n submitLabel={t('currencies.form.action.save')}\n cancelHref=\"/backend/currencies\"\n onSubmit={async (values) => {\n // Validate currency code\n const code = String(values.code || '').trim().toUpperCase()\n if (!/^[A-Z]{3}$/.test(code)) {\n throw createCrudFormError(t('currencies.form.errors.codeFormat'), {\n code: t('currencies.form.errors.codeFormat'),\n })\n }\n\n const payload = {\n id: currency.id,\n code,\n name: String(values.name || '').trim(),\n symbol: values.symbol ? String(values.symbol).trim() : null,\n decimalPlaces: values.decimalPlaces ? parseInt(String(values.decimalPlaces)) : 2,\n thousandsSeparator: values.thousandsSeparator ? String(values.thousandsSeparator) : null,\n decimalSeparator: values.decimalSeparator ? String(values.decimalSeparator) : null,\n isBase: !!values.isBase,\n isActive: values.isActive !== false,\n }\n\n await updateCrud('currencies/currencies', payload)\n\n flash(t('currencies.flash.updated'), 'success')\n router.push('/backend/currencies')\n }}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["error"]
|
|
7
7
|
}
|