@open-mercato/core 0.6.6-develop.6398.1.013efe913e → 0.6.6-develop.6399.1.93ba8ca030

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.
@@ -349,12 +349,10 @@ function ResourcesResourceDetailPage({ params }) {
349
349
  const handleTagsSave = React.useCallback(
350
350
  async ({ next, added, removed }) => {
351
351
  if (!resourceId) return;
352
- for (const tag of added) {
353
- await assignTag(tag.id);
354
- }
355
- for (const tag of removed) {
356
- await unassignTag(tag.id);
357
- }
352
+ await Promise.all([
353
+ ...added.map((tag) => assignTag(tag.id)),
354
+ ...removed.map((tag) => unassignTag(tag.id))
355
+ ]);
358
356
  setTags(next);
359
357
  flash(t("resources.resources.tags.success", "Tags updated."), "success");
360
358
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/resources/backend/resources/resources/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { ActivitiesSection, NotesSection, RecordNotFoundState, type SectionAction, type TagOption } from '@open-mercato/ui/backend/detail'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { VersionHistoryAction } from '@open-mercato/ui/backend/version-history'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { buildResourceScheduleItems } from '@open-mercato/core/modules/resources/lib/resourceSchedule'\nimport { RESOURCES_RESOURCE_FIELDSET_DEFAULT } from '@open-mercato/core/modules/resources/lib/resourceCustomFields'\nimport type { AvailabilityScheduleItemBuilder } from '@open-mercato/core/modules/planner/components/AvailabilityRulesEditor'\nimport { AvailabilityRulesEditor } from '@open-mercato/core/modules/planner/components/AvailabilityRulesEditor'\nimport { ResourcesResourceForm, useResourcesResourceFormConfig } from '@open-mercato/core/modules/resources/components/ResourceCrudForm'\nimport { renderDictionaryColor, renderDictionaryIcon, ICON_SUGGESTIONS } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { createResourceNotesAdapter } from '@open-mercato/core/modules/resources/components/detail/notesAdapter'\nimport { createResourceActivitiesAdapter } from '@open-mercato/core/modules/resources/components/detail/activitiesAdapter'\nimport {\n createResourceDictionaryEntry,\n loadResourceDictionary,\n type DictionaryEntryOption,\n} from '@open-mercato/core/modules/resources/components/detail/dictionaries'\nimport type { DictionarySelectLabels } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\n\ntype ResourceRecord = {\n id: string\n name: string\n description?: string | null\n resourceTypeId: string | null\n capacity: number | null\n capacityUnitValue: string | null\n capacityUnitName: string | null\n capacityUnitColor: string | null\n capacityUnitIcon: string | null\n tags?: TagOption[] | null\n isActive: boolean\n appearanceIcon?: string | null\n appearanceColor?: string | null\n resource_type_id?: string | null\n capacity_unit_value?: string | null\n capacity_unit_name?: string | null\n capacity_unit_color?: string | null\n capacity_unit_icon?: string | null\n appearance_icon?: string | null\n appearance_color?: string | null\n is_active?: boolean\n availabilityRuleSetId?: string | null\n availability_rule_set_id?: string | null\n} & Record<string, unknown>\n\ntype ResourceResponse = {\n items: ResourceRecord[]\n}\n\ntype ResourceDetailMutationContext = {\n formId: string\n resourceKind: string\n resourceId?: string\n data: Record<string, unknown> | null\n retryLastMutation: () => Promise<boolean>\n}\n\nfunction normalizeResourceRecord(record: ResourceRecord): ResourceRecord {\n return {\n ...record,\n resourceTypeId: record.resourceTypeId ?? record.resource_type_id ?? null,\n description: record.description ?? null,\n capacityUnitValue: record.capacityUnitValue ?? record.capacity_unit_value ?? null,\n capacityUnitName: record.capacityUnitName ?? record.capacity_unit_name ?? null,\n capacityUnitColor: record.capacityUnitColor ?? record.capacity_unit_color ?? null,\n capacityUnitIcon: record.capacityUnitIcon ?? record.capacity_unit_icon ?? null,\n appearanceIcon: record.appearanceIcon ?? record.appearance_icon ?? null,\n appearanceColor: record.appearanceColor ?? record.appearance_color ?? null,\n isActive: record.isActive ?? record.is_active ?? true,\n }\n}\n\nexport default function ResourcesResourceDetailPage({ params }: { params?: { id?: string } }) {\n const resourceId = params?.id\n const t = useT()\n const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])\n const router = useRouter()\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const [initialValues, setInitialValues] = React.useState<Record<string, unknown> | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n // Capture the record (incl. its optimistic-lock `updatedAt`) exactly ONCE per\n // resource. The load effect's deps include identity-unstable values (`t`,\n // `resolveFieldsetCode`), so without this guard a re-render would re-fetch and\n // overwrite `initialValues.updatedAt` with a newer server value mid-edit \u2014\n // silently defeating optimistic locking (a concurrent change would no longer be\n // detected) and making the conflict flaky.\n const loadedResourceIdRef = React.useRef<string | null>(null)\n const [tags, setTags] = React.useState<TagOption[]>([])\n const [activeTab, setActiveTab] = React.useState<'details' | 'availability'>('details')\n const [activeDetailTab, setActiveDetailTab] = React.useState<'notes' | 'activities'>('notes')\n const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)\n const [availabilityRuleSetId, setAvailabilityRuleSetId] = React.useState<string | null>(null)\n const [selectedCapacityUnit, setSelectedCapacityUnit] = React.useState<{\n value: string\n label: string\n color?: string | null\n icon?: string | null\n } | null>(null)\n const [activityDictionaryId, setActivityDictionaryId] = React.useState<string | null>(null)\n const [activityTypeEntries, setActivityTypeEntries] = React.useState<DictionaryEntryOption[]>([])\n const flashShownRef = React.useRef(false)\n\n const availabilityMode = 'availability'\n const mutationContextId = React.useMemo(\n () => (resourceId ? `resources.resource:${resourceId}` : 'resources.resource:pending'),\n [resourceId],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<ResourceDetailMutationContext>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const mutationContext = React.useMemo<ResourceDetailMutationContext>(\n () => ({\n formId: mutationContextId,\n resourceKind: 'resources.resource',\n resourceId,\n data: initialValues,\n retryLastMutation,\n }),\n [initialValues, mutationContextId, resourceId, retryLastMutation],\n )\n const runMutationWithContext = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload?: Record<string, unknown>): Promise<T> => (\n runMutation({\n operation,\n mutationPayload,\n context: mutationContext,\n })\n ),\n [mutationContext, runMutation],\n )\n const notesAdapter = React.useMemo(\n () => createResourceNotesAdapter(detailTranslator, { runMutation: runMutationWithContext }),\n [detailTranslator, runMutationWithContext],\n )\n const activitiesAdapter = React.useMemo(\n () => createResourceActivitiesAdapter(detailTranslator, { runMutation: runMutationWithContext }),\n [detailTranslator, runMutationWithContext],\n )\n\n const activityTypeLabels = React.useMemo<DictionarySelectLabels>(() => ({\n placeholder: t('resources.resources.detail.activities.dictionary.placeholder', 'Select an activity type'),\n addLabel: t('resources.resources.detail.activities.dictionary.add', 'Add type'),\n addPrompt: t('resources.resources.detail.activities.dictionary.prompt', 'Name the type'),\n dialogTitle: t('resources.resources.detail.activities.dictionary.dialogTitle', 'Add activity type'),\n valueLabel: t('resources.resources.detail.activities.dictionary.valueLabel', 'Name'),\n valuePlaceholder: t('resources.resources.detail.activities.dictionary.valuePlaceholder', 'Name'),\n labelLabel: t('resources.resources.detail.activities.dictionary.labelLabel', 'Label'),\n labelPlaceholder: t('resources.resources.detail.activities.dictionary.labelPlaceholder', 'Display name shown in UI'),\n emptyError: t('resources.resources.detail.activities.dictionary.emptyError', 'Please enter a name'),\n cancelLabel: t('resources.resources.detail.activities.dictionary.cancel', 'Cancel'),\n saveLabel: t('resources.resources.detail.activities.dictionary.save', 'Save'),\n saveShortcutHint: t('resources.resources.detail.activities.dictionary.saveShortcut', '\u2318/Ctrl + Enter'),\n errorLoad: t('resources.resources.detail.activities.dictionary.errorLoad', 'Failed to load options'),\n errorSave: t('resources.resources.detail.activities.dictionary.errorSave', 'Failed to save option'),\n loadingLabel: t('resources.resources.detail.activities.dictionary.loading', 'Loading\u2026'),\n manageTitle: t('resources.resources.detail.activities.dictionary.manage', 'Manage dictionary'),\n }), [t])\n\n const loadActivityOptions = React.useCallback(async () => {\n const { dictionary, entries } = await loadResourceDictionary('activityTypes')\n setActivityDictionaryId(dictionary?.id ?? null)\n setActivityTypeEntries(entries)\n return entries\n }, [])\n\n const createActivityOption = React.useCallback(\n async (input: { value: string; label?: string; color?: string | null; icon?: string | null }) => {\n const entry = await createResourceDictionaryEntry('activityTypes', input)\n if (!entry) {\n throw new Error(t('resources.resources.detail.activities.dictionary.errorSave', 'Failed to save option'))\n }\n return entry\n },\n [t],\n )\n\n React.useEffect(() => {\n loadActivityOptions().catch(() => {})\n }, [loadActivityOptions])\n\n const activityTypeMap = React.useMemo(\n () => new Map(activityTypeEntries.map((entry) => [entry.value, entry])),\n [activityTypeEntries],\n )\n\n const resolveActivityPresentation = React.useCallback(\n (activity: { activityType: string; appearanceIcon?: string | null; appearanceColor?: string | null }) => {\n const entry = activityTypeMap.get(activity.activityType)\n return {\n label: entry?.label ?? activity.activityType,\n icon: entry?.icon ?? activity.appearanceIcon ?? null,\n color: entry?.color ?? activity.appearanceColor ?? null,\n }\n },\n [activityTypeMap],\n )\n\n const manageActivityHref = React.useMemo(() => {\n if (!activityDictionaryId) return '/backend/config/dictionaries'\n return `/backend/config/dictionaries?dictionaryId=${encodeURIComponent(activityDictionaryId)}`\n }, [activityDictionaryId])\n\n const appearanceLabels = React.useMemo(() => ({\n colorLabel: t('resources.resources.detail.activities.appearance.colorLabel', 'Color'),\n colorHelp: t('resources.resources.detail.activities.appearance.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('resources.resources.detail.activities.appearance.colorClear', 'Remove color'),\n iconLabel: t('resources.resources.detail.activities.appearance.iconLabel', 'Icon or emoji'),\n iconPlaceholder: t('resources.resources.detail.activities.appearance.iconPlaceholder', 'Type an emoji or pick one of the suggestions.'),\n iconPickerTriggerLabel: t('resources.resources.detail.activities.appearance.iconBrowse', 'Browse icons and emojis'),\n iconSearchPlaceholder: t('resources.resources.detail.activities.appearance.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('resources.resources.detail.activities.appearance.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('resources.resources.detail.activities.appearance.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('resources.resources.detail.activities.appearance.iconClear', 'Remove icon'),\n previewEmptyLabel: t('resources.resources.detail.activities.appearance.previewEmpty', 'No appearance selected'),\n }), [t])\n\n const renderCustomFields = React.useCallback((activity: { id?: string; customFields?: Array<{ key: string; label?: string | null; value: unknown }> }) => {\n const entries = Array.isArray(activity.customFields) ? activity.customFields : []\n if (!entries.length) return null\n const emptyLabel = t('resources.resources.detail.activities.customFields.empty', 'Not provided')\n return (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {entries.map((entry, index) => {\n const label = entry.label ?? entry.key\n const value = entry.value\n const hasValue = !(value == null || value === '' || (Array.isArray(value) && value.length === 0))\n const content = hasValue\n ? Array.isArray(value)\n ? value.map((item) => String(item)).join(', ')\n : String(value)\n : emptyLabel\n return (\n <div\n key={`activity-${activity.id ?? 'row'}-custom-${index}`}\n className=\"rounded-md border border-border/70 bg-muted/30 px-3 py-2\"\n >\n <div className=\"text-xs font-medium text-muted-foreground\">{label}</div>\n <div className=\"mt-1 text-sm text-foreground\">{content}</div>\n </div>\n )\n })}\n </div>\n )\n }, [t])\n\n React.useEffect(() => {\n if (!searchParams) return\n const tabParam = searchParams.get('tab')\n if (tabParam === 'availability') {\n setActiveTab('availability')\n }\n const created = searchParams.get('created') === '1'\n if (created && !flashShownRef.current) {\n flashShownRef.current = true\n flash(t('resources.resources.flash.createdAvailability', 'Saved. You can now set availability.'), 'success')\n const nextParams = new URLSearchParams(searchParams.toString())\n nextParams.delete('created')\n const nextQuery = nextParams.toString()\n const nextPath = resourceId\n ? `/backend/resources/resources/${encodeURIComponent(resourceId)}${nextQuery ? `?${nextQuery}` : ''}`\n : `/backend/resources/resources${nextQuery ? `?${nextQuery}` : ''}`\n router.replace(nextPath)\n }\n }, [resourceId, router, searchParams, t])\n\n const buildScheduleItems = React.useCallback<AvailabilityScheduleItemBuilder>(\n ({ availabilityRules, translate }) => buildResourceScheduleItems({\n availabilityRules,\n isAvailableByDefault: false,\n translate,\n }),\n [],\n )\n\n const tagLabels = React.useMemo(\n () => ({\n loading: t('resources.resources.tags.loading', 'Loading tags...'),\n placeholder: t('resources.resources.tags.placeholder', 'Type to add tags'),\n empty: t('resources.resources.tags.placeholder', 'No tags yet. Add labels to keep resources organized.'),\n loadError: t('resources.resources.tags.loadError', 'Failed to load tags.'),\n createError: t('resources.resources.tags.createError', 'Failed to create tag.'),\n updateError: t('resources.resources.tags.updateError', 'Failed to update tags.'),\n labelRequired: t('resources.resources.tags.labelRequired', 'Tag name is required.'),\n saveShortcut: t('resources.resources.tags.saveShortcut', 'Save Cmd+Enter / Ctrl+Enter'),\n cancelShortcut: t('resources.resources.tags.cancelShortcut', 'Cancel (Esc)'),\n edit: t('ui.forms.actions.edit', 'Edit'),\n cancel: t('ui.forms.actions.cancel', 'Cancel'),\n success: t('resources.resources.tags.success', 'Tags updated.'),\n }),\n [t],\n )\n\n const handleSubmit = React.useCallback(async (values: Record<string, unknown>) => {\n if (!resourceId) return\n const appearance = values.appearance && typeof values.appearance === 'object'\n ? values.appearance as { icon?: string | null; color?: string | null }\n : {}\n const { appearance: _appearance, ...rest } = values\n const customFieldsetCode = typeof values.customFieldsetCode === 'string' && values.customFieldsetCode.trim().length\n ? values.customFieldsetCode.trim()\n : RESOURCES_RESOURCE_FIELDSET_DEFAULT\n const payload: Record<string, unknown> = {\n ...rest,\n id: resourceId,\n resourceTypeId: values.resourceTypeId || null,\n capacity: values.capacity ? Number(values.capacity) : null,\n capacityUnitValue: values.capacityUnitValue ? String(values.capacityUnitValue) : null,\n appearanceIcon: appearance.icon ?? null,\n appearanceColor: appearance.color ?? null,\n isActive: values.isActive ?? true,\n customFieldsetCode,\n ...collectCustomFieldValues(values),\n }\n if (!payload.name || String(payload.name).trim().length === 0) {\n throw createCrudFormError(t('resources.resources.form.errors.nameRequired', 'Name is required.'))\n }\n await updateCrud('resources/resources', payload, {\n errorMessage: t('resources.resources.form.errors.update', 'Failed to update resource.'),\n })\n flash(t('resources.resources.form.flash.updated', 'Resource updated.'), 'success')\n }, [resourceId, t])\n\n const tabs = React.useMemo(() => ([\n { id: 'details', label: t('resources.resources.tabs.details', 'Details') },\n { id: 'availability', label: t('resources.resources.tabs.availability', 'Availability') },\n ]), [t])\n const detailTabs = React.useMemo(() => ([\n { id: 'notes' as const, label: t('resources.resources.detail.tabs.notes', 'Notes') },\n { id: 'activities' as const, label: t('resources.resources.detail.tabs.activities', 'Activities') },\n ]), [t])\n\n const loadTagOptions = React.useCallback(\n async (query?: string): Promise<TagOption[]> => {\n const params = new URLSearchParams({ pageSize: '100' })\n if (query) params.set('search', query)\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/resources/tags?${params.toString()}`,\n undefined,\n { errorMessage: t('resources.resources.tags.loadError', 'Failed to load tags.') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items\n .map((item: unknown): TagOption | null => {\n if (!item || typeof item !== 'object') return null\n const raw = item as { id?: unknown; tagId?: unknown; label?: unknown; slug?: unknown; color?: unknown }\n const rawId =\n typeof raw.id === 'string'\n ? raw.id\n : typeof raw.tagId === 'string'\n ? raw.tagId\n : null\n if (!rawId) return null\n const labelValue =\n (typeof raw.label === 'string' && raw.label.trim().length && raw.label.trim()) ||\n (typeof raw.slug === 'string' && raw.slug.trim().length && raw.slug.trim()) ||\n rawId\n const color = typeof raw.color === 'string' && raw.color.trim().length ? raw.color.trim() : null\n return { id: rawId, label: labelValue, color }\n })\n .filter((entry): entry is TagOption => entry !== null)\n },\n [t],\n )\n\n const createTag = React.useCallback(\n async (label: string): Promise<TagOption> => {\n const trimmed = label.trim()\n if (!trimmed.length) {\n throw new Error(t('resources.resources.tags.labelRequired', 'Tag name is required.'))\n }\n const requestBody = { label: trimmed }\n const response = await runMutationWithContext(\n () => apiCallOrThrow<Record<string, unknown>>(\n '/api/resources/tags',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(requestBody),\n },\n { errorMessage: t('resources.resources.tags.createError', 'Failed to create tag.') },\n ),\n { operation: 'createTag', label: trimmed },\n )\n const payload = response.result ?? {}\n const id =\n typeof payload?.id === 'string'\n ? payload.id\n : typeof (payload as any)?.tagId === 'string'\n ? (payload as any).tagId\n : ''\n if (!id) throw new Error(t('resources.resources.tags.createError', 'Failed to create tag.'))\n const color = typeof (payload as any)?.color === 'string' && (payload as any).color.trim().length\n ? (payload as any).color.trim()\n : null\n return { id, label: trimmed, color }\n },\n [runMutationWithContext, t],\n )\n\n const assignTag = React.useCallback(async (tagId: string) => {\n if (!resourceId) return\n const requestBody = { tagId, resourceId }\n await runMutationWithContext(\n () => apiCallOrThrow(\n '/api/resources/resources/tags/assign',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(requestBody),\n },\n { errorMessage: t('resources.resources.tags.updateError', 'Failed to update tags.') },\n ),\n { operation: 'assignTag', resourceId, tagId },\n )\n }, [resourceId, runMutationWithContext, t])\n\n const unassignTag = React.useCallback(async (tagId: string) => {\n if (!resourceId) return\n const requestBody = { tagId, resourceId }\n await runMutationWithContext(\n () => apiCallOrThrow(\n '/api/resources/resources/tags/unassign',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(requestBody),\n },\n { errorMessage: t('resources.resources.tags.updateError', 'Failed to update tags.') },\n ),\n { operation: 'unassignTag', resourceId, tagId },\n )\n }, [resourceId, runMutationWithContext, t])\n\n const handleTagsSave = React.useCallback(\n async ({ next, added, removed }: { next: TagOption[]; added: TagOption[]; removed: TagOption[] }) => {\n if (!resourceId) return\n for (const tag of added) {\n await assignTag(tag.id)\n }\n for (const tag of removed) {\n await unassignTag(tag.id)\n }\n setTags(next)\n flash(t('resources.resources.tags.success', 'Tags updated.'), 'success')\n },\n [assignTag, resourceId, t, unassignTag],\n )\n\n const tagsSection = React.useMemo(\n () => ({\n title: t('resources.resources.tags.title', 'Tags'),\n tags,\n onChange: setTags,\n loadOptions: loadTagOptions,\n createTag,\n onSave: handleTagsSave,\n labels: tagLabels,\n }),\n [createTag, handleTagsSave, loadTagOptions, t, tagLabels, tags],\n )\n\n const formConfig = useResourcesResourceFormConfig({\n tagsSection,\n selectedResourceTypeId:\n typeof initialValues?.resourceTypeId === 'string' ? initialValues.resourceTypeId : null,\n selectedCapacityUnit:\n typeof initialValues?.capacityUnitValue === 'string' && initialValues.capacityUnitValue.length > 0\n ? selectedCapacityUnit\n : null,\n })\n const { resourceTypesLoaded, resolveFieldsetCode } = formConfig\n\n React.useEffect(() => {\n if (!resourceId || !resourceTypesLoaded) return\n // Load once per resource \u2014 never re-fetch (and thereby refresh the captured\n // optimistic-lock token) on subsequent re-renders. See loadedResourceIdRef.\n if (loadedResourceIdRef.current === resourceId) return\n setIsNotFound(false)\n let cancelled = false\n async function loadResource() {\n try {\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '1')\n if (resourceId) params.set('ids', resourceId)\n const record = await readApiResultOrThrow<ResourceResponse>(`/api/resources/resources?${params.toString()}`)\n const resourceRaw = Array.isArray(record?.items) ? record.items[0] : null\n const resource = resourceRaw ? normalizeResourceRecord(resourceRaw) : null\n if (!resource) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n if (!cancelled) {\n loadedResourceIdRef.current = resourceId ?? null\n const customValues = extractCustomFieldEntries(resource)\n setTags(Array.isArray(resource.tags) ? resource.tags : [])\n setAvailabilityRuleSetId(\n typeof resource.availabilityRuleSetId === 'string'\n ? resource.availabilityRuleSetId\n : typeof resource.availability_rule_set_id === 'string'\n ? resource.availability_rule_set_id\n : null,\n )\n setSelectedCapacityUnit(\n typeof resource.capacityUnitValue === 'string' && resource.capacityUnitValue.length > 0\n ? {\n value: resource.capacityUnitValue,\n label:\n typeof resource.capacityUnitName === 'string' && resource.capacityUnitName.length > 0\n ? resource.capacityUnitName\n : resource.capacityUnitValue,\n color: typeof resource.capacityUnitColor === 'string' ? resource.capacityUnitColor : null,\n icon: typeof resource.capacityUnitIcon === 'string' ? resource.capacityUnitIcon : null,\n }\n : null,\n )\n setInitialValues({\n id: resource.id,\n name: resource.name,\n description: resource.description ?? '',\n resourceTypeId: resource.resourceTypeId || '',\n capacity: resource.capacity ?? '',\n capacityUnitValue: resource.capacityUnitValue ?? '',\n appearance: { icon: resource.appearanceIcon ?? null, color: resource.appearanceColor ?? null },\n isActive: resource.isActive ?? true,\n updatedAt:\n typeof resource.updatedAt === 'string'\n ? resource.updatedAt\n : typeof resource.updated_at === 'string'\n ? resource.updated_at\n : null,\n customFieldsetCode: resource.resourceTypeId\n ? resolveFieldsetCode(resource.resourceTypeId)\n : RESOURCES_RESOURCE_FIELDSET_DEFAULT,\n ...customValues,\n })\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : t('resources.resources.form.errors.load', 'Failed to load resource.')\n flash(message, 'error')\n }\n }\n loadResource()\n return () => { cancelled = true }\n }, [resourceId, resourceTypesLoaded, resolveFieldsetCode, t])\n\n const handleDelete = React.useCallback(async () => {\n if (!resourceId) return\n const resourceOptimisticLockHeader = buildOptimisticLockHeader(\n typeof initialValues?.updatedAt === 'string' ? initialValues.updatedAt : null,\n )\n const deleteResource = () => deleteCrud('resources/resources', resourceId, {\n errorMessage: t('resources.resources.form.errors.delete', 'Failed to delete resource.'),\n })\n await runMutationWithContext(\n () => Object.keys(resourceOptimisticLockHeader).length > 0\n ? withScopedApiRequestHeaders(resourceOptimisticLockHeader, deleteResource)\n : deleteResource(),\n { operation: 'deleteResource', id: resourceId, updatedAt: initialValues?.updatedAt ?? null },\n )\n flash(t('resources.resources.form.flash.deleted', 'Resource deleted.'), 'success')\n router.push('/backend/resources/resources')\n }, [initialValues?.updatedAt, resourceId, router, runMutationWithContext, t])\n\n const handleRulesetChange = React.useCallback(async (nextId: string | null) => {\n if (!resourceId) return\n const updateSchedule = () => updateCrud('resources/resources', { id: resourceId, availabilityRuleSetId: nextId }, {\n errorMessage: t('resources.resources.availability.ruleset.updateError', 'Failed to update schedule.'),\n })\n const resourceOptimisticLockHeader = buildOptimisticLockHeader(\n typeof initialValues?.updatedAt === 'string' ? initialValues.updatedAt : null,\n )\n await runMutationWithContext(\n () => Object.keys(resourceOptimisticLockHeader).length > 0\n ? withScopedApiRequestHeaders(resourceOptimisticLockHeader, updateSchedule)\n : updateSchedule(),\n { operation: 'updateAvailabilityRuleSet', id: resourceId, availabilityRuleSetId: nextId },\n )\n setAvailabilityRuleSetId(nextId)\n flash(t('resources.resources.availability.ruleset.updateSuccess', 'Schedule updated.'), 'success')\n }, [initialValues?.updatedAt, resourceId, runMutationWithContext, t])\n\n const resourceTitle =\n typeof initialValues?.name === 'string' && initialValues.name.trim().length > 0\n ? initialValues.name.trim()\n : t('resources.resources.detail.untitled', 'Unnamed resource')\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `resources.resource` + id\n // explicitly. The resourceKind mirrors the VersionHistoryAction config / ResourceCrudForm\n // `versionHistory` so the held lock matches the save-time conflict surface for the resource.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'resources.resource',\n resourceId: resourceId || null,\n updatedAt: typeof initialValues?.updatedAt === 'string' ? initialValues.updatedAt : null,\n data: initialValues,\n path: pathname,\n }),\n )\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('resources.resources.form.errors.notFound', 'Resource not found.')}\n backHref=\"/backend/resources/resources\"\n backLabel={t('resources.resources.detail.back', 'Back to resources')}\n />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/resources/resources\"\n backLabel={t('resources.resources.detail.back', 'Back to resources')}\n utilityActions={(\n <>\n {resourceId ? (\n <SendObjectMessageDialog\n object={{\n entityModule: 'resources',\n entityType: 'resource',\n entityId: resourceId,\n previewData: {\n title: resourceTitle,\n },\n }}\n viewHref={`/backend/resources/resources/${resourceId}`}\n />\n ) : null}\n <VersionHistoryAction\n config={resourceId ? { resourceKind: 'resources.resource', resourceId, includeRelated: true } : null}\n t={t}\n />\n </>\n )}\n title={resourceTitle}\n subtitle={t('resources.resources.detail.subtitle', 'Resource profile and activity')}\n />\n\n <div className=\"border-b\">\n <nav className=\"flex flex-wrap items-center gap-5 text-sm\" aria-label={t('resources.resources.tabs.label', 'Resource sections')}>\n {tabs.map((tab) => (\n <Button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === tab.id}\n variant=\"ghost\"\n size=\"sm\"\n className={`relative -mb-px h-auto rounded-none border-b-2 px-0 py-2 font-medium ${\n activeTab === tab.id\n ? 'border-accent-indigo text-foreground'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n onClick={() => setActiveTab(tab.id as 'details' | 'availability')}\n >\n {tab.label}\n </Button>\n ))}\n </nav>\n </div>\n\n {activeTab === 'details' ? (\n <>\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex gap-2\">\n {detailTabs.map((tab) => (\n <Button\n key={tab.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={`relative -mb-px h-auto rounded-none border-b-2 px-0 py-1 font-medium ${\n activeDetailTab === tab.id\n ? 'border-accent-indigo text-foreground'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n onClick={() => setActiveDetailTab(tab.id)}\n >\n {tab.label}\n </Button>\n ))}\n </div>\n {sectionAction ? (\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={sectionAction.disabled}\n onClick={() => sectionAction.onClick()}\n >\n {sectionAction.icon ?? null}\n {sectionAction.label}\n </Button>\n ) : null}\n </div>\n {activeDetailTab === 'notes' ? (\n <NotesSection\n entityId={resourceId ?? null}\n emptyLabel={t('resources.resources.detail.notes.empty', 'No notes yet.')}\n viewerUserId={null}\n viewerName={null}\n viewerEmail={null}\n addActionLabel={t('resources.resources.detail.notes.add', 'Add note')}\n emptyState={{\n title: t('resources.resources.detail.notes.emptyTitle', 'Keep everyone in the loop'),\n actionLabel: t('resources.resources.detail.notes.emptyAction', 'Add a note'),\n }}\n onActionChange={setSectionAction}\n translator={detailTranslator}\n labelPrefix=\"resources.resources.detail.notes\"\n inlineLabelPrefix=\"resources.resources.detail.inline\"\n dataAdapter={notesAdapter}\n renderIcon={renderDictionaryIcon}\n renderColor={renderDictionaryColor}\n iconSuggestions={ICON_SUGGESTIONS}\n />\n ) : null}\n {activeDetailTab === 'activities' ? (\n <ActivitiesSection\n entityId={resourceId ?? null}\n addActionLabel={t('resources.resources.detail.activities.add', 'Log activity')}\n emptyState={{\n title: t('resources.resources.detail.activities.emptyTitle', 'No activities yet'),\n actionLabel: t('resources.resources.detail.activities.emptyAction', 'Add an activity'),\n }}\n onActionChange={setSectionAction}\n dataAdapter={activitiesAdapter}\n activityTypeLabels={activityTypeLabels}\n loadActivityOptions={loadActivityOptions}\n createActivityOption={createActivityOption}\n resolveActivityPresentation={resolveActivityPresentation}\n renderCustomFields={renderCustomFields}\n labelPrefix=\"resources.resources.detail.activities\"\n renderIcon={renderDictionaryIcon}\n renderColor={renderDictionaryColor}\n appearanceLabels={appearanceLabels}\n manageHref={manageActivityHref}\n customFieldEntityIds={['resources:resources_resource_activity']}\n />\n ) : null}\n </div>\n\n <div className=\"rounded-lg border bg-card p-4\">\n <h2 className=\"mb-4 text-sm font-semibold uppercase text-muted-foreground\">\n {t('resources.resources.detail.formTitle', 'Resource settings')}\n </h2>\n <ResourcesResourceForm\n embedded\n title={t('resources.resources.form.editTitle', 'Edit resource')}\n backHref=\"/backend/resources/resources\"\n cancelHref=\"/backend/resources/resources\"\n successRedirect=\"/backend/resources/resources\"\n formConfig={formConfig}\n initialValues={initialValues ?? undefined}\n optimisticLockUpdatedAt={\n typeof initialValues?.updatedAt === 'string'\n ? initialValues.updatedAt\n : null\n }\n onSubmit={handleSubmit}\n onDelete={handleDelete}\n isLoading={!initialValues}\n loadingMessage={t('resources.resources.form.loading', 'Loading resource...')}\n />\n </div>\n </>\n ) : (\n <AvailabilityRulesEditor\n subjectType=\"resource\"\n subjectId={resourceId ?? ''}\n labelPrefix=\"resources.resources\"\n mode={availabilityMode}\n rulesetId={availabilityRuleSetId}\n onRulesetChange={handleRulesetChange}\n buildScheduleItems={buildScheduleItems}\n />\n )}\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { ActivitiesSection, NotesSection, RecordNotFoundState, type SectionAction, type TagOption } from '@open-mercato/ui/backend/detail'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { VersionHistoryAction } from '@open-mercato/ui/backend/version-history'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { buildResourceScheduleItems } from '@open-mercato/core/modules/resources/lib/resourceSchedule'\nimport { RESOURCES_RESOURCE_FIELDSET_DEFAULT } from '@open-mercato/core/modules/resources/lib/resourceCustomFields'\nimport type { AvailabilityScheduleItemBuilder } from '@open-mercato/core/modules/planner/components/AvailabilityRulesEditor'\nimport { AvailabilityRulesEditor } from '@open-mercato/core/modules/planner/components/AvailabilityRulesEditor'\nimport { ResourcesResourceForm, useResourcesResourceFormConfig } from '@open-mercato/core/modules/resources/components/ResourceCrudForm'\nimport { renderDictionaryColor, renderDictionaryIcon, ICON_SUGGESTIONS } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { createResourceNotesAdapter } from '@open-mercato/core/modules/resources/components/detail/notesAdapter'\nimport { createResourceActivitiesAdapter } from '@open-mercato/core/modules/resources/components/detail/activitiesAdapter'\nimport {\n createResourceDictionaryEntry,\n loadResourceDictionary,\n type DictionaryEntryOption,\n} from '@open-mercato/core/modules/resources/components/detail/dictionaries'\nimport type { DictionarySelectLabels } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\n\ntype ResourceRecord = {\n id: string\n name: string\n description?: string | null\n resourceTypeId: string | null\n capacity: number | null\n capacityUnitValue: string | null\n capacityUnitName: string | null\n capacityUnitColor: string | null\n capacityUnitIcon: string | null\n tags?: TagOption[] | null\n isActive: boolean\n appearanceIcon?: string | null\n appearanceColor?: string | null\n resource_type_id?: string | null\n capacity_unit_value?: string | null\n capacity_unit_name?: string | null\n capacity_unit_color?: string | null\n capacity_unit_icon?: string | null\n appearance_icon?: string | null\n appearance_color?: string | null\n is_active?: boolean\n availabilityRuleSetId?: string | null\n availability_rule_set_id?: string | null\n} & Record<string, unknown>\n\ntype ResourceResponse = {\n items: ResourceRecord[]\n}\n\ntype ResourceDetailMutationContext = {\n formId: string\n resourceKind: string\n resourceId?: string\n data: Record<string, unknown> | null\n retryLastMutation: () => Promise<boolean>\n}\n\nfunction normalizeResourceRecord(record: ResourceRecord): ResourceRecord {\n return {\n ...record,\n resourceTypeId: record.resourceTypeId ?? record.resource_type_id ?? null,\n description: record.description ?? null,\n capacityUnitValue: record.capacityUnitValue ?? record.capacity_unit_value ?? null,\n capacityUnitName: record.capacityUnitName ?? record.capacity_unit_name ?? null,\n capacityUnitColor: record.capacityUnitColor ?? record.capacity_unit_color ?? null,\n capacityUnitIcon: record.capacityUnitIcon ?? record.capacity_unit_icon ?? null,\n appearanceIcon: record.appearanceIcon ?? record.appearance_icon ?? null,\n appearanceColor: record.appearanceColor ?? record.appearance_color ?? null,\n isActive: record.isActive ?? record.is_active ?? true,\n }\n}\n\nexport default function ResourcesResourceDetailPage({ params }: { params?: { id?: string } }) {\n const resourceId = params?.id\n const t = useT()\n const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])\n const router = useRouter()\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const [initialValues, setInitialValues] = React.useState<Record<string, unknown> | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n // Capture the record (incl. its optimistic-lock `updatedAt`) exactly ONCE per\n // resource. The load effect's deps include identity-unstable values (`t`,\n // `resolveFieldsetCode`), so without this guard a re-render would re-fetch and\n // overwrite `initialValues.updatedAt` with a newer server value mid-edit \u2014\n // silently defeating optimistic locking (a concurrent change would no longer be\n // detected) and making the conflict flaky.\n const loadedResourceIdRef = React.useRef<string | null>(null)\n const [tags, setTags] = React.useState<TagOption[]>([])\n const [activeTab, setActiveTab] = React.useState<'details' | 'availability'>('details')\n const [activeDetailTab, setActiveDetailTab] = React.useState<'notes' | 'activities'>('notes')\n const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)\n const [availabilityRuleSetId, setAvailabilityRuleSetId] = React.useState<string | null>(null)\n const [selectedCapacityUnit, setSelectedCapacityUnit] = React.useState<{\n value: string\n label: string\n color?: string | null\n icon?: string | null\n } | null>(null)\n const [activityDictionaryId, setActivityDictionaryId] = React.useState<string | null>(null)\n const [activityTypeEntries, setActivityTypeEntries] = React.useState<DictionaryEntryOption[]>([])\n const flashShownRef = React.useRef(false)\n\n const availabilityMode = 'availability'\n const mutationContextId = React.useMemo(\n () => (resourceId ? `resources.resource:${resourceId}` : 'resources.resource:pending'),\n [resourceId],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<ResourceDetailMutationContext>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const mutationContext = React.useMemo<ResourceDetailMutationContext>(\n () => ({\n formId: mutationContextId,\n resourceKind: 'resources.resource',\n resourceId,\n data: initialValues,\n retryLastMutation,\n }),\n [initialValues, mutationContextId, resourceId, retryLastMutation],\n )\n const runMutationWithContext = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload?: Record<string, unknown>): Promise<T> => (\n runMutation({\n operation,\n mutationPayload,\n context: mutationContext,\n })\n ),\n [mutationContext, runMutation],\n )\n const notesAdapter = React.useMemo(\n () => createResourceNotesAdapter(detailTranslator, { runMutation: runMutationWithContext }),\n [detailTranslator, runMutationWithContext],\n )\n const activitiesAdapter = React.useMemo(\n () => createResourceActivitiesAdapter(detailTranslator, { runMutation: runMutationWithContext }),\n [detailTranslator, runMutationWithContext],\n )\n\n const activityTypeLabels = React.useMemo<DictionarySelectLabels>(() => ({\n placeholder: t('resources.resources.detail.activities.dictionary.placeholder', 'Select an activity type'),\n addLabel: t('resources.resources.detail.activities.dictionary.add', 'Add type'),\n addPrompt: t('resources.resources.detail.activities.dictionary.prompt', 'Name the type'),\n dialogTitle: t('resources.resources.detail.activities.dictionary.dialogTitle', 'Add activity type'),\n valueLabel: t('resources.resources.detail.activities.dictionary.valueLabel', 'Name'),\n valuePlaceholder: t('resources.resources.detail.activities.dictionary.valuePlaceholder', 'Name'),\n labelLabel: t('resources.resources.detail.activities.dictionary.labelLabel', 'Label'),\n labelPlaceholder: t('resources.resources.detail.activities.dictionary.labelPlaceholder', 'Display name shown in UI'),\n emptyError: t('resources.resources.detail.activities.dictionary.emptyError', 'Please enter a name'),\n cancelLabel: t('resources.resources.detail.activities.dictionary.cancel', 'Cancel'),\n saveLabel: t('resources.resources.detail.activities.dictionary.save', 'Save'),\n saveShortcutHint: t('resources.resources.detail.activities.dictionary.saveShortcut', '\u2318/Ctrl + Enter'),\n errorLoad: t('resources.resources.detail.activities.dictionary.errorLoad', 'Failed to load options'),\n errorSave: t('resources.resources.detail.activities.dictionary.errorSave', 'Failed to save option'),\n loadingLabel: t('resources.resources.detail.activities.dictionary.loading', 'Loading\u2026'),\n manageTitle: t('resources.resources.detail.activities.dictionary.manage', 'Manage dictionary'),\n }), [t])\n\n const loadActivityOptions = React.useCallback(async () => {\n const { dictionary, entries } = await loadResourceDictionary('activityTypes')\n setActivityDictionaryId(dictionary?.id ?? null)\n setActivityTypeEntries(entries)\n return entries\n }, [])\n\n const createActivityOption = React.useCallback(\n async (input: { value: string; label?: string; color?: string | null; icon?: string | null }) => {\n const entry = await createResourceDictionaryEntry('activityTypes', input)\n if (!entry) {\n throw new Error(t('resources.resources.detail.activities.dictionary.errorSave', 'Failed to save option'))\n }\n return entry\n },\n [t],\n )\n\n React.useEffect(() => {\n loadActivityOptions().catch(() => {})\n }, [loadActivityOptions])\n\n const activityTypeMap = React.useMemo(\n () => new Map(activityTypeEntries.map((entry) => [entry.value, entry])),\n [activityTypeEntries],\n )\n\n const resolveActivityPresentation = React.useCallback(\n (activity: { activityType: string; appearanceIcon?: string | null; appearanceColor?: string | null }) => {\n const entry = activityTypeMap.get(activity.activityType)\n return {\n label: entry?.label ?? activity.activityType,\n icon: entry?.icon ?? activity.appearanceIcon ?? null,\n color: entry?.color ?? activity.appearanceColor ?? null,\n }\n },\n [activityTypeMap],\n )\n\n const manageActivityHref = React.useMemo(() => {\n if (!activityDictionaryId) return '/backend/config/dictionaries'\n return `/backend/config/dictionaries?dictionaryId=${encodeURIComponent(activityDictionaryId)}`\n }, [activityDictionaryId])\n\n const appearanceLabels = React.useMemo(() => ({\n colorLabel: t('resources.resources.detail.activities.appearance.colorLabel', 'Color'),\n colorHelp: t('resources.resources.detail.activities.appearance.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('resources.resources.detail.activities.appearance.colorClear', 'Remove color'),\n iconLabel: t('resources.resources.detail.activities.appearance.iconLabel', 'Icon or emoji'),\n iconPlaceholder: t('resources.resources.detail.activities.appearance.iconPlaceholder', 'Type an emoji or pick one of the suggestions.'),\n iconPickerTriggerLabel: t('resources.resources.detail.activities.appearance.iconBrowse', 'Browse icons and emojis'),\n iconSearchPlaceholder: t('resources.resources.detail.activities.appearance.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('resources.resources.detail.activities.appearance.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('resources.resources.detail.activities.appearance.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('resources.resources.detail.activities.appearance.iconClear', 'Remove icon'),\n previewEmptyLabel: t('resources.resources.detail.activities.appearance.previewEmpty', 'No appearance selected'),\n }), [t])\n\n const renderCustomFields = React.useCallback((activity: { id?: string; customFields?: Array<{ key: string; label?: string | null; value: unknown }> }) => {\n const entries = Array.isArray(activity.customFields) ? activity.customFields : []\n if (!entries.length) return null\n const emptyLabel = t('resources.resources.detail.activities.customFields.empty', 'Not provided')\n return (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {entries.map((entry, index) => {\n const label = entry.label ?? entry.key\n const value = entry.value\n const hasValue = !(value == null || value === '' || (Array.isArray(value) && value.length === 0))\n const content = hasValue\n ? Array.isArray(value)\n ? value.map((item) => String(item)).join(', ')\n : String(value)\n : emptyLabel\n return (\n <div\n key={`activity-${activity.id ?? 'row'}-custom-${index}`}\n className=\"rounded-md border border-border/70 bg-muted/30 px-3 py-2\"\n >\n <div className=\"text-xs font-medium text-muted-foreground\">{label}</div>\n <div className=\"mt-1 text-sm text-foreground\">{content}</div>\n </div>\n )\n })}\n </div>\n )\n }, [t])\n\n React.useEffect(() => {\n if (!searchParams) return\n const tabParam = searchParams.get('tab')\n if (tabParam === 'availability') {\n setActiveTab('availability')\n }\n const created = searchParams.get('created') === '1'\n if (created && !flashShownRef.current) {\n flashShownRef.current = true\n flash(t('resources.resources.flash.createdAvailability', 'Saved. You can now set availability.'), 'success')\n const nextParams = new URLSearchParams(searchParams.toString())\n nextParams.delete('created')\n const nextQuery = nextParams.toString()\n const nextPath = resourceId\n ? `/backend/resources/resources/${encodeURIComponent(resourceId)}${nextQuery ? `?${nextQuery}` : ''}`\n : `/backend/resources/resources${nextQuery ? `?${nextQuery}` : ''}`\n router.replace(nextPath)\n }\n }, [resourceId, router, searchParams, t])\n\n const buildScheduleItems = React.useCallback<AvailabilityScheduleItemBuilder>(\n ({ availabilityRules, translate }) => buildResourceScheduleItems({\n availabilityRules,\n isAvailableByDefault: false,\n translate,\n }),\n [],\n )\n\n const tagLabels = React.useMemo(\n () => ({\n loading: t('resources.resources.tags.loading', 'Loading tags...'),\n placeholder: t('resources.resources.tags.placeholder', 'Type to add tags'),\n empty: t('resources.resources.tags.placeholder', 'No tags yet. Add labels to keep resources organized.'),\n loadError: t('resources.resources.tags.loadError', 'Failed to load tags.'),\n createError: t('resources.resources.tags.createError', 'Failed to create tag.'),\n updateError: t('resources.resources.tags.updateError', 'Failed to update tags.'),\n labelRequired: t('resources.resources.tags.labelRequired', 'Tag name is required.'),\n saveShortcut: t('resources.resources.tags.saveShortcut', 'Save Cmd+Enter / Ctrl+Enter'),\n cancelShortcut: t('resources.resources.tags.cancelShortcut', 'Cancel (Esc)'),\n edit: t('ui.forms.actions.edit', 'Edit'),\n cancel: t('ui.forms.actions.cancel', 'Cancel'),\n success: t('resources.resources.tags.success', 'Tags updated.'),\n }),\n [t],\n )\n\n const handleSubmit = React.useCallback(async (values: Record<string, unknown>) => {\n if (!resourceId) return\n const appearance = values.appearance && typeof values.appearance === 'object'\n ? values.appearance as { icon?: string | null; color?: string | null }\n : {}\n const { appearance: _appearance, ...rest } = values\n const customFieldsetCode = typeof values.customFieldsetCode === 'string' && values.customFieldsetCode.trim().length\n ? values.customFieldsetCode.trim()\n : RESOURCES_RESOURCE_FIELDSET_DEFAULT\n const payload: Record<string, unknown> = {\n ...rest,\n id: resourceId,\n resourceTypeId: values.resourceTypeId || null,\n capacity: values.capacity ? Number(values.capacity) : null,\n capacityUnitValue: values.capacityUnitValue ? String(values.capacityUnitValue) : null,\n appearanceIcon: appearance.icon ?? null,\n appearanceColor: appearance.color ?? null,\n isActive: values.isActive ?? true,\n customFieldsetCode,\n ...collectCustomFieldValues(values),\n }\n if (!payload.name || String(payload.name).trim().length === 0) {\n throw createCrudFormError(t('resources.resources.form.errors.nameRequired', 'Name is required.'))\n }\n await updateCrud('resources/resources', payload, {\n errorMessage: t('resources.resources.form.errors.update', 'Failed to update resource.'),\n })\n flash(t('resources.resources.form.flash.updated', 'Resource updated.'), 'success')\n }, [resourceId, t])\n\n const tabs = React.useMemo(() => ([\n { id: 'details', label: t('resources.resources.tabs.details', 'Details') },\n { id: 'availability', label: t('resources.resources.tabs.availability', 'Availability') },\n ]), [t])\n const detailTabs = React.useMemo(() => ([\n { id: 'notes' as const, label: t('resources.resources.detail.tabs.notes', 'Notes') },\n { id: 'activities' as const, label: t('resources.resources.detail.tabs.activities', 'Activities') },\n ]), [t])\n\n const loadTagOptions = React.useCallback(\n async (query?: string): Promise<TagOption[]> => {\n const params = new URLSearchParams({ pageSize: '100' })\n if (query) params.set('search', query)\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/resources/tags?${params.toString()}`,\n undefined,\n { errorMessage: t('resources.resources.tags.loadError', 'Failed to load tags.') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items\n .map((item: unknown): TagOption | null => {\n if (!item || typeof item !== 'object') return null\n const raw = item as { id?: unknown; tagId?: unknown; label?: unknown; slug?: unknown; color?: unknown }\n const rawId =\n typeof raw.id === 'string'\n ? raw.id\n : typeof raw.tagId === 'string'\n ? raw.tagId\n : null\n if (!rawId) return null\n const labelValue =\n (typeof raw.label === 'string' && raw.label.trim().length && raw.label.trim()) ||\n (typeof raw.slug === 'string' && raw.slug.trim().length && raw.slug.trim()) ||\n rawId\n const color = typeof raw.color === 'string' && raw.color.trim().length ? raw.color.trim() : null\n return { id: rawId, label: labelValue, color }\n })\n .filter((entry): entry is TagOption => entry !== null)\n },\n [t],\n )\n\n const createTag = React.useCallback(\n async (label: string): Promise<TagOption> => {\n const trimmed = label.trim()\n if (!trimmed.length) {\n throw new Error(t('resources.resources.tags.labelRequired', 'Tag name is required.'))\n }\n const requestBody = { label: trimmed }\n const response = await runMutationWithContext(\n () => apiCallOrThrow<Record<string, unknown>>(\n '/api/resources/tags',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(requestBody),\n },\n { errorMessage: t('resources.resources.tags.createError', 'Failed to create tag.') },\n ),\n { operation: 'createTag', label: trimmed },\n )\n const payload = response.result ?? {}\n const id =\n typeof payload?.id === 'string'\n ? payload.id\n : typeof (payload as any)?.tagId === 'string'\n ? (payload as any).tagId\n : ''\n if (!id) throw new Error(t('resources.resources.tags.createError', 'Failed to create tag.'))\n const color = typeof (payload as any)?.color === 'string' && (payload as any).color.trim().length\n ? (payload as any).color.trim()\n : null\n return { id, label: trimmed, color }\n },\n [runMutationWithContext, t],\n )\n\n const assignTag = React.useCallback(async (tagId: string) => {\n if (!resourceId) return\n const requestBody = { tagId, resourceId }\n await runMutationWithContext(\n () => apiCallOrThrow(\n '/api/resources/resources/tags/assign',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(requestBody),\n },\n { errorMessage: t('resources.resources.tags.updateError', 'Failed to update tags.') },\n ),\n { operation: 'assignTag', resourceId, tagId },\n )\n }, [resourceId, runMutationWithContext, t])\n\n const unassignTag = React.useCallback(async (tagId: string) => {\n if (!resourceId) return\n const requestBody = { tagId, resourceId }\n await runMutationWithContext(\n () => apiCallOrThrow(\n '/api/resources/resources/tags/unassign',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(requestBody),\n },\n { errorMessage: t('resources.resources.tags.updateError', 'Failed to update tags.') },\n ),\n { operation: 'unassignTag', resourceId, tagId },\n )\n }, [resourceId, runMutationWithContext, t])\n\n const handleTagsSave = React.useCallback(\n async ({ next, added, removed }: { next: TagOption[]; added: TagOption[]; removed: TagOption[] }) => {\n if (!resourceId) return\n await Promise.all([\n ...added.map((tag) => assignTag(tag.id)),\n ...removed.map((tag) => unassignTag(tag.id)),\n ])\n setTags(next)\n flash(t('resources.resources.tags.success', 'Tags updated.'), 'success')\n },\n [assignTag, resourceId, t, unassignTag],\n )\n\n const tagsSection = React.useMemo(\n () => ({\n title: t('resources.resources.tags.title', 'Tags'),\n tags,\n onChange: setTags,\n loadOptions: loadTagOptions,\n createTag,\n onSave: handleTagsSave,\n labels: tagLabels,\n }),\n [createTag, handleTagsSave, loadTagOptions, t, tagLabels, tags],\n )\n\n const formConfig = useResourcesResourceFormConfig({\n tagsSection,\n selectedResourceTypeId:\n typeof initialValues?.resourceTypeId === 'string' ? initialValues.resourceTypeId : null,\n selectedCapacityUnit:\n typeof initialValues?.capacityUnitValue === 'string' && initialValues.capacityUnitValue.length > 0\n ? selectedCapacityUnit\n : null,\n })\n const { resourceTypesLoaded, resolveFieldsetCode } = formConfig\n\n React.useEffect(() => {\n if (!resourceId || !resourceTypesLoaded) return\n // Load once per resource \u2014 never re-fetch (and thereby refresh the captured\n // optimistic-lock token) on subsequent re-renders. See loadedResourceIdRef.\n if (loadedResourceIdRef.current === resourceId) return\n setIsNotFound(false)\n let cancelled = false\n async function loadResource() {\n try {\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '1')\n if (resourceId) params.set('ids', resourceId)\n const record = await readApiResultOrThrow<ResourceResponse>(`/api/resources/resources?${params.toString()}`)\n const resourceRaw = Array.isArray(record?.items) ? record.items[0] : null\n const resource = resourceRaw ? normalizeResourceRecord(resourceRaw) : null\n if (!resource) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n if (!cancelled) {\n loadedResourceIdRef.current = resourceId ?? null\n const customValues = extractCustomFieldEntries(resource)\n setTags(Array.isArray(resource.tags) ? resource.tags : [])\n setAvailabilityRuleSetId(\n typeof resource.availabilityRuleSetId === 'string'\n ? resource.availabilityRuleSetId\n : typeof resource.availability_rule_set_id === 'string'\n ? resource.availability_rule_set_id\n : null,\n )\n setSelectedCapacityUnit(\n typeof resource.capacityUnitValue === 'string' && resource.capacityUnitValue.length > 0\n ? {\n value: resource.capacityUnitValue,\n label:\n typeof resource.capacityUnitName === 'string' && resource.capacityUnitName.length > 0\n ? resource.capacityUnitName\n : resource.capacityUnitValue,\n color: typeof resource.capacityUnitColor === 'string' ? resource.capacityUnitColor : null,\n icon: typeof resource.capacityUnitIcon === 'string' ? resource.capacityUnitIcon : null,\n }\n : null,\n )\n setInitialValues({\n id: resource.id,\n name: resource.name,\n description: resource.description ?? '',\n resourceTypeId: resource.resourceTypeId || '',\n capacity: resource.capacity ?? '',\n capacityUnitValue: resource.capacityUnitValue ?? '',\n appearance: { icon: resource.appearanceIcon ?? null, color: resource.appearanceColor ?? null },\n isActive: resource.isActive ?? true,\n updatedAt:\n typeof resource.updatedAt === 'string'\n ? resource.updatedAt\n : typeof resource.updated_at === 'string'\n ? resource.updated_at\n : null,\n customFieldsetCode: resource.resourceTypeId\n ? resolveFieldsetCode(resource.resourceTypeId)\n : RESOURCES_RESOURCE_FIELDSET_DEFAULT,\n ...customValues,\n })\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : t('resources.resources.form.errors.load', 'Failed to load resource.')\n flash(message, 'error')\n }\n }\n loadResource()\n return () => { cancelled = true }\n }, [resourceId, resourceTypesLoaded, resolveFieldsetCode, t])\n\n const handleDelete = React.useCallback(async () => {\n if (!resourceId) return\n const resourceOptimisticLockHeader = buildOptimisticLockHeader(\n typeof initialValues?.updatedAt === 'string' ? initialValues.updatedAt : null,\n )\n const deleteResource = () => deleteCrud('resources/resources', resourceId, {\n errorMessage: t('resources.resources.form.errors.delete', 'Failed to delete resource.'),\n })\n await runMutationWithContext(\n () => Object.keys(resourceOptimisticLockHeader).length > 0\n ? withScopedApiRequestHeaders(resourceOptimisticLockHeader, deleteResource)\n : deleteResource(),\n { operation: 'deleteResource', id: resourceId, updatedAt: initialValues?.updatedAt ?? null },\n )\n flash(t('resources.resources.form.flash.deleted', 'Resource deleted.'), 'success')\n router.push('/backend/resources/resources')\n }, [initialValues?.updatedAt, resourceId, router, runMutationWithContext, t])\n\n const handleRulesetChange = React.useCallback(async (nextId: string | null) => {\n if (!resourceId) return\n const updateSchedule = () => updateCrud('resources/resources', { id: resourceId, availabilityRuleSetId: nextId }, {\n errorMessage: t('resources.resources.availability.ruleset.updateError', 'Failed to update schedule.'),\n })\n const resourceOptimisticLockHeader = buildOptimisticLockHeader(\n typeof initialValues?.updatedAt === 'string' ? initialValues.updatedAt : null,\n )\n await runMutationWithContext(\n () => Object.keys(resourceOptimisticLockHeader).length > 0\n ? withScopedApiRequestHeaders(resourceOptimisticLockHeader, updateSchedule)\n : updateSchedule(),\n { operation: 'updateAvailabilityRuleSet', id: resourceId, availabilityRuleSetId: nextId },\n )\n setAvailabilityRuleSetId(nextId)\n flash(t('resources.resources.availability.ruleset.updateSuccess', 'Schedule updated.'), 'success')\n }, [initialValues?.updatedAt, resourceId, runMutationWithContext, t])\n\n const resourceTitle =\n typeof initialValues?.name === 'string' && initialValues.name.trim().length > 0\n ? initialValues.name.trim()\n : t('resources.resources.detail.untitled', 'Unnamed resource')\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `resources.resource` + id\n // explicitly. The resourceKind mirrors the VersionHistoryAction config / ResourceCrudForm\n // `versionHistory` so the held lock matches the save-time conflict surface for the resource.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'resources.resource',\n resourceId: resourceId || null,\n updatedAt: typeof initialValues?.updatedAt === 'string' ? initialValues.updatedAt : null,\n data: initialValues,\n path: pathname,\n }),\n )\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('resources.resources.form.errors.notFound', 'Resource not found.')}\n backHref=\"/backend/resources/resources\"\n backLabel={t('resources.resources.detail.back', 'Back to resources')}\n />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/resources/resources\"\n backLabel={t('resources.resources.detail.back', 'Back to resources')}\n utilityActions={(\n <>\n {resourceId ? (\n <SendObjectMessageDialog\n object={{\n entityModule: 'resources',\n entityType: 'resource',\n entityId: resourceId,\n previewData: {\n title: resourceTitle,\n },\n }}\n viewHref={`/backend/resources/resources/${resourceId}`}\n />\n ) : null}\n <VersionHistoryAction\n config={resourceId ? { resourceKind: 'resources.resource', resourceId, includeRelated: true } : null}\n t={t}\n />\n </>\n )}\n title={resourceTitle}\n subtitle={t('resources.resources.detail.subtitle', 'Resource profile and activity')}\n />\n\n <div className=\"border-b\">\n <nav className=\"flex flex-wrap items-center gap-5 text-sm\" aria-label={t('resources.resources.tabs.label', 'Resource sections')}>\n {tabs.map((tab) => (\n <Button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === tab.id}\n variant=\"ghost\"\n size=\"sm\"\n className={`relative -mb-px h-auto rounded-none border-b-2 px-0 py-2 font-medium ${\n activeTab === tab.id\n ? 'border-accent-indigo text-foreground'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n onClick={() => setActiveTab(tab.id as 'details' | 'availability')}\n >\n {tab.label}\n </Button>\n ))}\n </nav>\n </div>\n\n {activeTab === 'details' ? (\n <>\n <div className=\"rounded-lg border bg-card p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex gap-2\">\n {detailTabs.map((tab) => (\n <Button\n key={tab.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={`relative -mb-px h-auto rounded-none border-b-2 px-0 py-1 font-medium ${\n activeDetailTab === tab.id\n ? 'border-accent-indigo text-foreground'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n onClick={() => setActiveDetailTab(tab.id)}\n >\n {tab.label}\n </Button>\n ))}\n </div>\n {sectionAction ? (\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={sectionAction.disabled}\n onClick={() => sectionAction.onClick()}\n >\n {sectionAction.icon ?? null}\n {sectionAction.label}\n </Button>\n ) : null}\n </div>\n {activeDetailTab === 'notes' ? (\n <NotesSection\n entityId={resourceId ?? null}\n emptyLabel={t('resources.resources.detail.notes.empty', 'No notes yet.')}\n viewerUserId={null}\n viewerName={null}\n viewerEmail={null}\n addActionLabel={t('resources.resources.detail.notes.add', 'Add note')}\n emptyState={{\n title: t('resources.resources.detail.notes.emptyTitle', 'Keep everyone in the loop'),\n actionLabel: t('resources.resources.detail.notes.emptyAction', 'Add a note'),\n }}\n onActionChange={setSectionAction}\n translator={detailTranslator}\n labelPrefix=\"resources.resources.detail.notes\"\n inlineLabelPrefix=\"resources.resources.detail.inline\"\n dataAdapter={notesAdapter}\n renderIcon={renderDictionaryIcon}\n renderColor={renderDictionaryColor}\n iconSuggestions={ICON_SUGGESTIONS}\n />\n ) : null}\n {activeDetailTab === 'activities' ? (\n <ActivitiesSection\n entityId={resourceId ?? null}\n addActionLabel={t('resources.resources.detail.activities.add', 'Log activity')}\n emptyState={{\n title: t('resources.resources.detail.activities.emptyTitle', 'No activities yet'),\n actionLabel: t('resources.resources.detail.activities.emptyAction', 'Add an activity'),\n }}\n onActionChange={setSectionAction}\n dataAdapter={activitiesAdapter}\n activityTypeLabels={activityTypeLabels}\n loadActivityOptions={loadActivityOptions}\n createActivityOption={createActivityOption}\n resolveActivityPresentation={resolveActivityPresentation}\n renderCustomFields={renderCustomFields}\n labelPrefix=\"resources.resources.detail.activities\"\n renderIcon={renderDictionaryIcon}\n renderColor={renderDictionaryColor}\n appearanceLabels={appearanceLabels}\n manageHref={manageActivityHref}\n customFieldEntityIds={['resources:resources_resource_activity']}\n />\n ) : null}\n </div>\n\n <div className=\"rounded-lg border bg-card p-4\">\n <h2 className=\"mb-4 text-sm font-semibold uppercase text-muted-foreground\">\n {t('resources.resources.detail.formTitle', 'Resource settings')}\n </h2>\n <ResourcesResourceForm\n embedded\n title={t('resources.resources.form.editTitle', 'Edit resource')}\n backHref=\"/backend/resources/resources\"\n cancelHref=\"/backend/resources/resources\"\n successRedirect=\"/backend/resources/resources\"\n formConfig={formConfig}\n initialValues={initialValues ?? undefined}\n optimisticLockUpdatedAt={\n typeof initialValues?.updatedAt === 'string'\n ? initialValues.updatedAt\n : null\n }\n onSubmit={handleSubmit}\n onDelete={handleDelete}\n isLoading={!initialValues}\n loadingMessage={t('resources.resources.form.loading', 'Loading resource...')}\n />\n </div>\n </>\n ) : (\n <AvailabilityRulesEditor\n subjectType=\"resource\"\n subjectId={resourceId ?? ''}\n labelPrefix=\"resources.resources\"\n mode={availabilityMode}\n rulesetId={availabilityRuleSetId}\n onRulesetChange={handleRulesetChange}\n buildScheduleItems={buildScheduleItems}\n />\n )}\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": ";AA2PY,SAsYE,UAlYA,KAJF;AAzPZ,YAAY,WAAW;AACvB,SAAS,aAAa,WAAW,uBAAuB;AACxD,SAAS,MAAM,gBAAgB;AAC/B,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AACvB,SAAS,gBAAgB,sBAAsB,mCAAmC;AAClF,SAAS,iCAAiC;AAC1C,SAAS,gCAAgC;AACzC,SAAS,2BAA2B;AACpC,SAAS,YAAY,kBAAkB;AACvC,SAAS,aAAa;AACtB,SAAS,mBAAmB,cAAc,2BAA+D;AACzG,SAAS,6BAA6B,2CAA2C;AACjF,SAAS,0BAA0B;AACnC,SAAS,4BAA4B;AACrC,SAAS,+BAA+B;AACxC,SAAS,YAAY;AACrB,SAAS,iCAAiC;AAC1C,SAAS,oCAAoC;AAC7C,SAAS,kCAAkC;AAC3C,SAAS,2CAA2C;AAEpD,SAAS,+BAA+B;AACxC,SAAS,uBAAuB,sCAAsC;AACtE,SAAS,uBAAuB,sBAAsB,wBAAwB;AAC9E,SAAS,kCAAkC;AAC3C,SAAS,uCAAuC;AAChD;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAyCP,SAAS,wBAAwB,QAAwC;AACvE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,gBAAgB,OAAO,kBAAkB,OAAO,oBAAoB;AAAA,IACpE,aAAa,OAAO,eAAe;AAAA,IACnC,mBAAmB,OAAO,qBAAqB,OAAO,uBAAuB;AAAA,IAC7E,kBAAkB,OAAO,oBAAoB,OAAO,sBAAsB;AAAA,IAC1E,mBAAmB,OAAO,qBAAqB,OAAO,uBAAuB;AAAA,IAC7E,kBAAkB,OAAO,oBAAoB,OAAO,sBAAsB;AAAA,IAC1E,gBAAgB,OAAO,kBAAkB,OAAO,mBAAmB;AAAA,IACnE,iBAAiB,OAAO,mBAAmB,OAAO,oBAAoB;AAAA,IACtE,UAAU,OAAO,YAAY,OAAO,aAAa;AAAA,EACnD;AACF;AAEe,SAAR,4BAA6C,EAAE,OAAO,GAAiC;AAC5F,QAAM,aAAa,QAAQ;AAC3B,QAAM,IAAI,KAAK;AACf,QAAM,mBAAmB,MAAM,QAAQ,MAAM,6BAA6B,CAAC,GAAG,CAAC,CAAC,CAAC;AACjF,QAAM,SAAS,UAAU;AACzB,QAAM,WAAW,YAAY;AAC7B,QAAM,eAAe,gBAAgB;AACrC,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAyC,IAAI;AAC7F,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AAOxD,QAAM,sBAAsB,MAAM,OAAsB,IAAI;AAC5D,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAsB,CAAC,CAAC;AACtD,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAqC,SAAS;AACtF,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,MAAM,SAAiC,OAAO;AAC5F,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAA+B,IAAI;AACnF,QAAM,CAAC,uBAAuB,wBAAwB,IAAI,MAAM,SAAwB,IAAI;AAC5F,QAAM,CAAC,sBAAsB,uBAAuB,IAAI,MAAM,SAKpD,IAAI;AACd,QAAM,CAAC,sBAAsB,uBAAuB,IAAI,MAAM,SAAwB,IAAI;AAC1F,QAAM,CAAC,qBAAqB,sBAAsB,IAAI,MAAM,SAAkC,CAAC,CAAC;AAChG,QAAM,gBAAgB,MAAM,OAAO,KAAK;AAExC,QAAM,mBAAmB;AACzB,QAAM,oBAAoB,MAAM;AAAA,IAC9B,MAAO,aAAa,sBAAsB,UAAU,KAAK;AAAA,IACzD,CAAC,UAAU;AAAA,EACb;AACA,QAAM,EAAE,aAAa,kBAAkB,IAAI,mBAAkD;AAAA,IAC3F,WAAW;AAAA,IACX,gBAAgB,EAAE,8BAA8B,4BAA4B;AAAA,EAC9E,CAAC;AACD,QAAM,kBAAkB,MAAM;AAAA,IAC5B,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,cAAc;AAAA,MACd;AAAA,MACA,MAAM;AAAA,MACN;AAAA,IACF;AAAA,IACA,CAAC,eAAe,mBAAmB,YAAY,iBAAiB;AAAA,EAClE;AACA,QAAM,yBAAyB,MAAM;AAAA,IACnC,OAAW,WAA6B,oBACtC,YAAY;AAAA,MACV;AAAA,MACA;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AAAA,IAEH,CAAC,iBAAiB,WAAW;AAAA,EAC/B;AACA,QAAM,eAAe,MAAM;AAAA,IACzB,MAAM,2BAA2B,kBAAkB,EAAE,aAAa,uBAAuB,CAAC;AAAA,IAC1F,CAAC,kBAAkB,sBAAsB;AAAA,EAC3C;AACA,QAAM,oBAAoB,MAAM;AAAA,IAC9B,MAAM,gCAAgC,kBAAkB,EAAE,aAAa,uBAAuB,CAAC;AAAA,IAC/F,CAAC,kBAAkB,sBAAsB;AAAA,EAC3C;AAEA,QAAM,qBAAqB,MAAM,QAAgC,OAAO;AAAA,IACtE,aAAa,EAAE,gEAAgE,yBAAyB;AAAA,IACxG,UAAU,EAAE,wDAAwD,UAAU;AAAA,IAC9E,WAAW,EAAE,2DAA2D,eAAe;AAAA,IACvF,aAAa,EAAE,gEAAgE,mBAAmB;AAAA,IAClG,YAAY,EAAE,+DAA+D,MAAM;AAAA,IACnF,kBAAkB,EAAE,qEAAqE,MAAM;AAAA,IAC/F,YAAY,EAAE,+DAA+D,OAAO;AAAA,IACpF,kBAAkB,EAAE,qEAAqE,0BAA0B;AAAA,IACnH,YAAY,EAAE,+DAA+D,qBAAqB;AAAA,IAClG,aAAa,EAAE,2DAA2D,QAAQ;AAAA,IAClF,WAAW,EAAE,yDAAyD,MAAM;AAAA,IAC5E,kBAAkB,EAAE,iEAAiE,qBAAgB;AAAA,IACrG,WAAW,EAAE,8DAA8D,wBAAwB;AAAA,IACnG,WAAW,EAAE,8DAA8D,uBAAuB;AAAA,IAClG,cAAc,EAAE,4DAA4D,eAAU;AAAA,IACtF,aAAa,EAAE,2DAA2D,mBAAmB;AAAA,EAC/F,IAAI,CAAC,CAAC,CAAC;AAEP,QAAM,sBAAsB,MAAM,YAAY,YAAY;AACxD,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,uBAAuB,eAAe;AAC5E,4BAAwB,YAAY,MAAM,IAAI;AAC9C,2BAAuB,OAAO;AAC9B,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,uBAAuB,MAAM;AAAA,IACjC,OAAO,UAA0F;AAC/F,YAAM,QAAQ,MAAM,8BAA8B,iBAAiB,KAAK;AACxE,UAAI,CAAC,OAAO;AACV,cAAM,IAAI,MAAM,EAAE,8DAA8D,uBAAuB,CAAC;AAAA,MAC1G;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,UAAU,MAAM;AACpB,wBAAoB,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACtC,GAAG,CAAC,mBAAmB,CAAC;AAExB,QAAM,kBAAkB,MAAM;AAAA,IAC5B,MAAM,IAAI,IAAI,oBAAoB,IAAI,CAAC,UAAU,CAAC,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IACtE,CAAC,mBAAmB;AAAA,EACtB;AAEA,QAAM,8BAA8B,MAAM;AAAA,IACxC,CAAC,aAAwG;AACvG,YAAM,QAAQ,gBAAgB,IAAI,SAAS,YAAY;AACvD,aAAO;AAAA,QACL,OAAO,OAAO,SAAS,SAAS;AAAA,QAChC,MAAM,OAAO,QAAQ,SAAS,kBAAkB;AAAA,QAChD,OAAO,OAAO,SAAS,SAAS,mBAAmB;AAAA,MACrD;AAAA,IACF;AAAA,IACA,CAAC,eAAe;AAAA,EAClB;AAEA,QAAM,qBAAqB,MAAM,QAAQ,MAAM;AAC7C,QAAI,CAAC,qBAAsB,QAAO;AAClC,WAAO,6CAA6C,mBAAmB,oBAAoB,CAAC;AAAA,EAC9F,GAAG,CAAC,oBAAoB,CAAC;AAEzB,QAAM,mBAAmB,MAAM,QAAQ,OAAO;AAAA,IAC5C,YAAY,EAAE,+DAA+D,OAAO;AAAA,IACpF,WAAW,EAAE,8DAA8D,wCAAwC;AAAA,IACnH,iBAAiB,EAAE,+DAA+D,cAAc;AAAA,IAChG,WAAW,EAAE,8DAA8D,eAAe;AAAA,IAC1F,iBAAiB,EAAE,oEAAoE,+CAA+C;AAAA,IACtI,wBAAwB,EAAE,+DAA+D,yBAAyB;AAAA,IAClH,uBAAuB,EAAE,0EAA0E,8BAAyB;AAAA,IAC5H,sBAAsB,EAAE,oEAAoE,6BAA6B;AAAA,IACzH,sBAAsB,EAAE,oEAAoE,aAAa;AAAA,IACzG,gBAAgB,EAAE,8DAA8D,aAAa;AAAA,IAC7F,mBAAmB,EAAE,iEAAiE,wBAAwB;AAAA,EAChH,IAAI,CAAC,CAAC,CAAC;AAEP,QAAM,qBAAqB,MAAM,YAAY,CAAC,aAA4G;AACxJ,UAAM,UAAU,MAAM,QAAQ,SAAS,YAAY,IAAI,SAAS,eAAe,CAAC;AAChF,QAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,UAAM,aAAa,EAAE,4DAA4D,cAAc;AAC/F,WACE,oBAAC,SAAI,WAAU,6BACZ,kBAAQ,IAAI,CAAC,OAAO,UAAU;AAC7B,YAAM,QAAQ,MAAM,SAAS,MAAM;AACnC,YAAM,QAAQ,MAAM;AACpB,YAAM,WAAW,EAAE,SAAS,QAAQ,UAAU,MAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW;AAC9F,YAAM,UAAU,WACZ,MAAM,QAAQ,KAAK,IACjB,MAAM,IAAI,CAAC,SAAS,OAAO,IAAI,CAAC,EAAE,KAAK,IAAI,IAC3C,OAAO,KAAK,IACd;AACJ,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAEV;AAAA,gCAAC,SAAI,WAAU,6CAA6C,iBAAM;AAAA,YAClE,oBAAC,SAAI,WAAU,gCAAgC,mBAAQ;AAAA;AAAA;AAAA,QAJlD,YAAY,SAAS,MAAM,KAAK,WAAW,KAAK;AAAA,MAKvD;AAAA,IAEJ,CAAC,GACH;AAAA,EAEJ,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,aAAc;AACnB,UAAM,WAAW,aAAa,IAAI,KAAK;AACvC,QAAI,aAAa,gBAAgB;AAC/B,mBAAa,cAAc;AAAA,IAC7B;AACA,UAAM,UAAU,aAAa,IAAI,SAAS,MAAM;AAChD,QAAI,WAAW,CAAC,cAAc,SAAS;AACrC,oBAAc,UAAU;AACxB,YAAM,EAAE,iDAAiD,sCAAsC,GAAG,SAAS;AAC3G,YAAM,aAAa,IAAI,gBAAgB,aAAa,SAAS,CAAC;AAC9D,iBAAW,OAAO,SAAS;AAC3B,YAAM,YAAY,WAAW,SAAS;AACtC,YAAM,WAAW,aACb,gCAAgC,mBAAmB,UAAU,CAAC,GAAG,YAAY,IAAI,SAAS,KAAK,EAAE,KACjG,+BAA+B,YAAY,IAAI,SAAS,KAAK,EAAE;AACnE,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,YAAY,QAAQ,cAAc,CAAC,CAAC;AAExC,QAAM,qBAAqB,MAAM;AAAA,IAC/B,CAAC,EAAE,mBAAmB,UAAU,MAAM,2BAA2B;AAAA,MAC/D;AAAA,MACA,sBAAsB;AAAA,MACtB;AAAA,IACF,CAAC;AAAA,IACD,CAAC;AAAA,EACH;AAEA,QAAM,YAAY,MAAM;AAAA,IACtB,OAAO;AAAA,MACL,SAAS,EAAE,oCAAoC,iBAAiB;AAAA,MAChE,aAAa,EAAE,wCAAwC,kBAAkB;AAAA,MACzE,OAAO,EAAE,wCAAwC,sDAAsD;AAAA,MACvG,WAAW,EAAE,sCAAsC,sBAAsB;AAAA,MACzE,aAAa,EAAE,wCAAwC,uBAAuB;AAAA,MAC9E,aAAa,EAAE,wCAAwC,wBAAwB;AAAA,MAC/E,eAAe,EAAE,0CAA0C,uBAAuB;AAAA,MAClF,cAAc,EAAE,yCAAyC,6BAA6B;AAAA,MACtF,gBAAgB,EAAE,2CAA2C,cAAc;AAAA,MAC3E,MAAM,EAAE,yBAAyB,MAAM;AAAA,MACvC,QAAQ,EAAE,2BAA2B,QAAQ;AAAA,MAC7C,SAAS,EAAE,oCAAoC,eAAe;AAAA,IAChE;AAAA,IACA,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,eAAe,MAAM,YAAY,OAAO,WAAoC;AAChF,QAAI,CAAC,WAAY;AACjB,UAAM,aAAa,OAAO,cAAc,OAAO,OAAO,eAAe,WACjE,OAAO,aACP,CAAC;AACL,UAAM,EAAE,YAAY,aAAa,GAAG,KAAK,IAAI;AAC7C,UAAM,qBAAqB,OAAO,OAAO,uBAAuB,YAAY,OAAO,mBAAmB,KAAK,EAAE,SACzG,OAAO,mBAAmB,KAAK,IAC/B;AACJ,UAAM,UAAmC;AAAA,MACvC,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,gBAAgB,OAAO,kBAAkB;AAAA,MACzC,UAAU,OAAO,WAAW,OAAO,OAAO,QAAQ,IAAI;AAAA,MACtD,mBAAmB,OAAO,oBAAoB,OAAO,OAAO,iBAAiB,IAAI;AAAA,MACjF,gBAAgB,WAAW,QAAQ;AAAA,MACnC,iBAAiB,WAAW,SAAS;AAAA,MACrC,UAAU,OAAO,YAAY;AAAA,MAC7B;AAAA,MACA,GAAG,yBAAyB,MAAM;AAAA,IACpC;AACA,QAAI,CAAC,QAAQ,QAAQ,OAAO,QAAQ,IAAI,EAAE,KAAK,EAAE,WAAW,GAAG;AAC7D,YAAM,oBAAoB,EAAE,gDAAgD,mBAAmB,CAAC;AAAA,IAClG;AACA,UAAM,WAAW,uBAAuB,SAAS;AAAA,MAC/C,cAAc,EAAE,0CAA0C,4BAA4B;AAAA,IACxF,CAAC;AACD,UAAM,EAAE,0CAA0C,mBAAmB,GAAG,SAAS;AAAA,EACnF,GAAG,CAAC,YAAY,CAAC,CAAC;AAElB,QAAM,OAAO,MAAM,QAAQ,MAAO;AAAA,IAChC,EAAE,IAAI,WAAW,OAAO,EAAE,oCAAoC,SAAS,EAAE;AAAA,IACzE,EAAE,IAAI,gBAAgB,OAAO,EAAE,yCAAyC,cAAc,EAAE;AAAA,EAC1F,GAAI,CAAC,CAAC,CAAC;AACP,QAAM,aAAa,MAAM,QAAQ,MAAO;AAAA,IACtC,EAAE,IAAI,SAAkB,OAAO,EAAE,yCAAyC,OAAO,EAAE;AAAA,IACnF,EAAE,IAAI,cAAuB,OAAO,EAAE,8CAA8C,YAAY,EAAE;AAAA,EACpG,GAAI,CAAC,CAAC,CAAC;AAEP,QAAM,iBAAiB,MAAM;AAAA,IAC3B,OAAO,UAAyC;AAC9C,YAAMA,UAAS,IAAI,gBAAgB,EAAE,UAAU,MAAM,CAAC;AACtD,UAAI,MAAO,CAAAA,QAAO,IAAI,UAAU,KAAK;AACrC,YAAM,UAAU,MAAM;AAAA,QACpB,uBAAuBA,QAAO,SAAS,CAAC;AAAA,QACxC;AAAA,QACA,EAAE,cAAc,EAAE,sCAAsC,sBAAsB,EAAE;AAAA,MAClF;AACA,YAAM,QAAQ,MAAM,QAAQ,SAAS,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC/D,aAAO,MACJ,IAAI,CAAC,SAAoC;AACxC,YAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,cAAM,MAAM;AACZ,cAAM,QACJ,OAAO,IAAI,OAAO,WACd,IAAI,KACJ,OAAO,IAAI,UAAU,WACnB,IAAI,QACJ;AACR,YAAI,CAAC,MAAO,QAAO;AACnB,cAAM,aACH,OAAO,IAAI,UAAU,YAAY,IAAI,MAAM,KAAK,EAAE,UAAU,IAAI,MAAM,KAAK,KAC3E,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,KAAK,EAAE,UAAU,IAAI,KAAK,KAAK,KACzE;AACF,cAAM,QAAQ,OAAO,IAAI,UAAU,YAAY,IAAI,MAAM,KAAK,EAAE,SAAS,IAAI,MAAM,KAAK,IAAI;AAC5F,eAAO,EAAE,IAAI,OAAO,OAAO,YAAY,MAAM;AAAA,MAC/C,CAAC,EACA,OAAO,CAAC,UAA8B,UAAU,IAAI;AAAA,IACzD;AAAA,IACA,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,YAAY,MAAM;AAAA,IACtB,OAAO,UAAsC;AAC3C,YAAM,UAAU,MAAM,KAAK;AAC3B,UAAI,CAAC,QAAQ,QAAQ;AACnB,cAAM,IAAI,MAAM,EAAE,0CAA0C,uBAAuB,CAAC;AAAA,MACtF;AACA,YAAM,cAAc,EAAE,OAAO,QAAQ;AACrC,YAAM,WAAW,MAAM;AAAA,QACrB,MAAM;AAAA,UACJ;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,YAC9C,MAAM,KAAK,UAAU,WAAW;AAAA,UAClC;AAAA,UACA,EAAE,cAAc,EAAE,wCAAwC,uBAAuB,EAAE;AAAA,QACrF;AAAA,QACA,EAAE,WAAW,aAAa,OAAO,QAAQ;AAAA,MAC3C;AACA,YAAM,UAAU,SAAS,UAAU,CAAC;AACpC,YAAM,KACJ,OAAO,SAAS,OAAO,WACnB,QAAQ,KACR,OAAQ,SAAiB,UAAU,WAChC,QAAgB,QACjB;AACR,UAAI,CAAC,GAAI,OAAM,IAAI,MAAM,EAAE,wCAAwC,uBAAuB,CAAC;AAC3F,YAAM,QAAQ,OAAQ,SAAiB,UAAU,YAAa,QAAgB,MAAM,KAAK,EAAE,SACtF,QAAgB,MAAM,KAAK,IAC5B;AACJ,aAAO,EAAE,IAAI,OAAO,SAAS,MAAM;AAAA,IACrC;AAAA,IACA,CAAC,wBAAwB,CAAC;AAAA,EAC5B;AAEA,QAAM,YAAY,MAAM,YAAY,OAAO,UAAkB;AAC3D,QAAI,CAAC,WAAY;AACjB,UAAM,cAAc,EAAE,OAAO,WAAW;AACxC,UAAM;AAAA,MACJ,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,WAAW;AAAA,QAClC;AAAA,QACA,EAAE,cAAc,EAAE,wCAAwC,wBAAwB,EAAE;AAAA,MACtF;AAAA,MACA,EAAE,WAAW,aAAa,YAAY,MAAM;AAAA,IAC9C;AAAA,EACF,GAAG,CAAC,YAAY,wBAAwB,CAAC,CAAC;AAE1C,QAAM,cAAc,MAAM,YAAY,OAAO,UAAkB;AAC7D,QAAI,CAAC,WAAY;AACjB,UAAM,cAAc,EAAE,OAAO,WAAW;AACxC,UAAM;AAAA,MACJ,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,WAAW;AAAA,QAClC;AAAA,QACA,EAAE,cAAc,EAAE,wCAAwC,wBAAwB,EAAE;AAAA,MACtF;AAAA,MACA,EAAE,WAAW,eAAe,YAAY,MAAM;AAAA,IAChD;AAAA,EACF,GAAG,CAAC,YAAY,wBAAwB,CAAC,CAAC;AAE1C,QAAM,iBAAiB,MAAM;AAAA,IAC3B,OAAO,EAAE,MAAM,OAAO,QAAQ,MAAuE;AACnG,UAAI,CAAC,WAAY;AACjB,YAAM,QAAQ,IAAI;AAAA,QAChB,GAAG,MAAM,IAAI,CAAC,QAAQ,UAAU,IAAI,EAAE,CAAC;AAAA,QACvC,GAAG,QAAQ,IAAI,CAAC,QAAQ,YAAY,IAAI,EAAE,CAAC;AAAA,MAC7C,CAAC;AACD,cAAQ,IAAI;AACZ,YAAM,EAAE,oCAAoC,eAAe,GAAG,SAAS;AAAA,IACzE;AAAA,IACA,CAAC,WAAW,YAAY,GAAG,WAAW;AAAA,EACxC;AAEA,QAAM,cAAc,MAAM;AAAA,IACxB,OAAO;AAAA,MACL,OAAO,EAAE,kCAAkC,MAAM;AAAA,MACjD;AAAA,MACA,UAAU;AAAA,MACV,aAAa;AAAA,MACb;AAAA,MACA,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAAA,IACA,CAAC,WAAW,gBAAgB,gBAAgB,GAAG,WAAW,IAAI;AAAA,EAChE;AAEA,QAAM,aAAa,+BAA+B;AAAA,IAChD;AAAA,IACA,wBACE,OAAO,eAAe,mBAAmB,WAAW,cAAc,iBAAiB;AAAA,IACrF,sBACE,OAAO,eAAe,sBAAsB,YAAY,cAAc,kBAAkB,SAAS,IAC7F,uBACA;AAAA,EACR,CAAC;AACD,QAAM,EAAE,qBAAqB,oBAAoB,IAAI;AAErD,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,cAAc,CAAC,oBAAqB;AAGzC,QAAI,oBAAoB,YAAY,WAAY;AAChD,kBAAc,KAAK;AACnB,QAAI,YAAY;AAChB,mBAAe,eAAe;AAC5B,UAAI;AACF,cAAMA,UAAS,IAAI,gBAAgB;AACnC,QAAAA,QAAO,IAAI,QAAQ,GAAG;AACtB,QAAAA,QAAO,IAAI,YAAY,GAAG;AAC1B,YAAI,WAAY,CAAAA,QAAO,IAAI,OAAO,UAAU;AAC5C,cAAM,SAAS,MAAM,qBAAuC,4BAA4BA,QAAO,SAAS,CAAC,EAAE;AAC3G,cAAM,cAAc,MAAM,QAAQ,QAAQ,KAAK,IAAI,OAAO,MAAM,CAAC,IAAI;AACrE,cAAM,WAAW,cAAc,wBAAwB,WAAW,IAAI;AACtE,YAAI,CAAC,UAAU;AACb,cAAI,CAAC,UAAW,eAAc,IAAI;AAClC;AAAA,QACF;AACA,YAAI,CAAC,WAAW;AACd,8BAAoB,UAAU,cAAc;AAC5C,gBAAM,eAAe,0BAA0B,QAAQ;AACvD,kBAAQ,MAAM,QAAQ,SAAS,IAAI,IAAI,SAAS,OAAO,CAAC,CAAC;AACzD;AAAA,YACE,OAAO,SAAS,0BAA0B,WACtC,SAAS,wBACT,OAAO,SAAS,6BAA6B,WAC3C,SAAS,2BACT;AAAA,UACR;AACA;AAAA,YACE,OAAO,SAAS,sBAAsB,YAAY,SAAS,kBAAkB,SAAS,IAClF;AAAA,cACE,OAAO,SAAS;AAAA,cAChB,OACE,OAAO,SAAS,qBAAqB,YAAY,SAAS,iBAAiB,SAAS,IAChF,SAAS,mBACT,SAAS;AAAA,cACf,OAAO,OAAO,SAAS,sBAAsB,WAAW,SAAS,oBAAoB;AAAA,cACrF,MAAM,OAAO,SAAS,qBAAqB,WAAW,SAAS,mBAAmB;AAAA,YACpF,IACA;AAAA,UACN;AACA,2BAAiB;AAAA,YACf,IAAI,SAAS;AAAA,YACb,MAAM,SAAS;AAAA,YACf,aAAa,SAAS,eAAe;AAAA,YACrC,gBAAgB,SAAS,kBAAkB;AAAA,YAC3C,UAAU,SAAS,YAAY;AAAA,YAC/B,mBAAmB,SAAS,qBAAqB;AAAA,YACjD,YAAY,EAAE,MAAM,SAAS,kBAAkB,MAAM,OAAO,SAAS,mBAAmB,KAAK;AAAA,YAC7F,UAAU,SAAS,YAAY;AAAA,YAC/B,WACE,OAAO,SAAS,cAAc,WAC1B,SAAS,YACT,OAAO,SAAS,eAAe,WAC7B,SAAS,aACT;AAAA,YACR,oBAAoB,SAAS,iBACzB,oBAAoB,SAAS,cAAc,IAC3C;AAAA,YACJ,GAAG;AAAA,UACL,CAAC;AAAA,QACH;AAAA,MACF,SAAS,OAAO;AACd,cAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,EAAE,wCAAwC,0BAA0B;AAC7H,cAAM,SAAS,OAAO;AAAA,MACxB;AAAA,IACF;AACA,iBAAa;AACb,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAK;AAAA,EAClC,GAAG,CAAC,YAAY,qBAAqB,qBAAqB,CAAC,CAAC;AAE5D,QAAM,eAAe,MAAM,YAAY,YAAY;AACjD,QAAI,CAAC,WAAY;AACjB,UAAM,+BAA+B;AAAA,MACnC,OAAO,eAAe,cAAc,WAAW,cAAc,YAAY;AAAA,IAC3E;AACA,UAAM,iBAAiB,MAAM,WAAW,uBAAuB,YAAY;AAAA,MACzE,cAAc,EAAE,0CAA0C,4BAA4B;AAAA,IACxF,CAAC;AACD,UAAM;AAAA,MACJ,MAAM,OAAO,KAAK,4BAA4B,EAAE,SAAS,IACrD,4BAA4B,8BAA8B,cAAc,IACxE,eAAe;AAAA,MACnB,EAAE,WAAW,kBAAkB,IAAI,YAAY,WAAW,eAAe,aAAa,KAAK;AAAA,IAC7F;AACA,UAAM,EAAE,0CAA0C,mBAAmB,GAAG,SAAS;AACjF,WAAO,KAAK,8BAA8B;AAAA,EAC5C,GAAG,CAAC,eAAe,WAAW,YAAY,QAAQ,wBAAwB,CAAC,CAAC;AAE5E,QAAM,sBAAsB,MAAM,YAAY,OAAO,WAA0B;AAC7E,QAAI,CAAC,WAAY;AACjB,UAAM,iBAAiB,MAAM,WAAW,uBAAuB,EAAE,IAAI,YAAY,uBAAuB,OAAO,GAAG;AAAA,MAChH,cAAc,EAAE,wDAAwD,4BAA4B;AAAA,IACtG,CAAC;AACD,UAAM,+BAA+B;AAAA,MACnC,OAAO,eAAe,cAAc,WAAW,cAAc,YAAY;AAAA,IAC3E;AACA,UAAM;AAAA,MACJ,MAAM,OAAO,KAAK,4BAA4B,EAAE,SAAS,IACrD,4BAA4B,8BAA8B,cAAc,IACxE,eAAe;AAAA,MACnB,EAAE,WAAW,6BAA6B,IAAI,YAAY,uBAAuB,OAAO;AAAA,IAC1F;AACA,6BAAyB,MAAM;AAC/B,UAAM,EAAE,0DAA0D,mBAAmB,GAAG,SAAS;AAAA,EACnG,GAAG,CAAC,eAAe,WAAW,YAAY,wBAAwB,CAAC,CAAC;AAEpE,QAAM,gBACJ,OAAO,eAAe,SAAS,YAAY,cAAc,KAAK,KAAK,EAAE,SAAS,IAC1E,cAAc,KAAK,KAAK,IACxB,EAAE,uCAAuC,kBAAkB;AAMjE;AAAA,IACE,4BAA4B;AAAA,MAC1B,cAAc;AAAA,MACd,YAAY,cAAc;AAAA,MAC1B,WAAW,OAAO,eAAe,cAAc,WAAW,cAAc,YAAY;AAAA,MACpF,MAAM;AAAA,MACN,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAEA,MAAI,YAAY;AACd,WACE,oBAAC,QACC,8BAAC,YACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,4CAA4C,qBAAqB;AAAA,QAC1E,UAAS;AAAA,QACT,WAAW,EAAE,mCAAmC,mBAAmB;AAAA;AAAA,IACrE,GACF,GACF;AAAA,EAEJ;AAEA,SACE,oBAAC,QACC,8BAAC,YACC,+BAAC,SAAI,WAAU,aACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAS;AAAA,QACT,WAAW,EAAE,mCAAmC,mBAAmB;AAAA,QACnE,gBACE,iCACG;AAAA,uBACC;AAAA,YAAC;AAAA;AAAA,cACC,QAAQ;AAAA,gBACN,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,UAAU;AAAA,gBACV,aAAa;AAAA,kBACX,OAAO;AAAA,gBACT;AAAA,cACF;AAAA,cACA,UAAU,gCAAgC,UAAU;AAAA;AAAA,UACtD,IACE;AAAA,UACJ;AAAA,YAAC;AAAA;AAAA,cACC,QAAQ,aAAa,EAAE,cAAc,sBAAsB,YAAY,gBAAgB,KAAK,IAAI;AAAA,cAChG;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEF,OAAO;AAAA,QACP,UAAU,EAAE,uCAAuC,+BAA+B;AAAA;AAAA,IACpF;AAAA,IAEA,oBAAC,SAAI,WAAU,YACb,8BAAC,SAAI,WAAU,6CAA4C,cAAY,EAAE,kCAAkC,mBAAmB,GAC3H,eAAK,IAAI,CAAC,QACT;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,MAAK;AAAA,QACL,iBAAe,cAAc,IAAI;AAAA,QACjC,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,WAAW,wEACT,cAAc,IAAI,KACd,yCACA,gEACN;AAAA,QACA,SAAS,MAAM,aAAa,IAAI,EAAgC;AAAA,QAE/D,cAAI;AAAA;AAAA,MAbA,IAAI;AAAA,IAcX,CACD,GACH,GACF;AAAA,IAEC,cAAc,YACb,iCACE;AAAA,2BAAC,SAAI,WAAU,iCACb;AAAA,6BAAC,SAAI,WAAU,qDACb;AAAA,8BAAC,SAAI,WAAU,cACZ,qBAAW,IAAI,CAAC,QACf;AAAA,YAAC;AAAA;AAAA,cAEC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,WAAW,wEACT,oBAAoB,IAAI,KACpB,yCACA,gEACN;AAAA,cACA,SAAS,MAAM,mBAAmB,IAAI,EAAE;AAAA,cAEvC,cAAI;AAAA;AAAA,YAXA,IAAI;AAAA,UAYX,CACD,GACH;AAAA,UACC,gBACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,MAAK;AAAA,cACL,UAAU,cAAc;AAAA,cACxB,SAAS,MAAM,cAAc,QAAQ;AAAA,cAEpC;AAAA,8BAAc,QAAQ;AAAA,gBACtB,cAAc;AAAA;AAAA;AAAA,UACjB,IACE;AAAA,WACN;AAAA,QACC,oBAAoB,UACnB;AAAA,UAAC;AAAA;AAAA,YACC,UAAU,cAAc;AAAA,YACxB,YAAY,EAAE,0CAA0C,eAAe;AAAA,YACvE,cAAc;AAAA,YACd,YAAY;AAAA,YACZ,aAAa;AAAA,YACb,gBAAgB,EAAE,wCAAwC,UAAU;AAAA,YACpE,YAAY;AAAA,cACV,OAAO,EAAE,+CAA+C,2BAA2B;AAAA,cACnF,aAAa,EAAE,gDAAgD,YAAY;AAAA,YAC7E;AAAA,YACA,gBAAgB;AAAA,YAChB,YAAY;AAAA,YACZ,aAAY;AAAA,YACZ,mBAAkB;AAAA,YAClB,aAAa;AAAA,YACb,YAAY;AAAA,YACZ,aAAa;AAAA,YACb,iBAAiB;AAAA;AAAA,QACnB,IACE;AAAA,QACH,oBAAoB,eACnB;AAAA,UAAC;AAAA;AAAA,YACC,UAAU,cAAc;AAAA,YACxB,gBAAgB,EAAE,6CAA6C,cAAc;AAAA,YAC7E,YAAY;AAAA,cACV,OAAO,EAAE,oDAAoD,mBAAmB;AAAA,cAChF,aAAa,EAAE,qDAAqD,iBAAiB;AAAA,YACvF;AAAA,YACA,gBAAgB;AAAA,YAChB,aAAa;AAAA,YACb;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,aAAY;AAAA,YACZ,YAAY;AAAA,YACZ,aAAa;AAAA,YACb;AAAA,YACA,YAAY;AAAA,YACZ,sBAAsB,CAAC,uCAAuC;AAAA;AAAA,QAChE,IACE;AAAA,SACN;AAAA,MAEA,qBAAC,SAAI,WAAU,iCACb;AAAA,4BAAC,QAAG,WAAU,8DACX,YAAE,wCAAwC,mBAAmB,GAChE;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,UAAQ;AAAA,YACR,OAAO,EAAE,sCAAsC,eAAe;AAAA,YAC9D,UAAS;AAAA,YACT,YAAW;AAAA,YACX,iBAAgB;AAAA,YAChB;AAAA,YACA,eAAe,iBAAiB;AAAA,YAChC,yBACE,OAAO,eAAe,cAAc,WAChC,cAAc,YACd;AAAA,YAEN,UAAU;AAAA,YACV,UAAU;AAAA,YACV,WAAW,CAAC;AAAA,YACZ,gBAAgB,EAAE,oCAAoC,qBAAqB;AAAA;AAAA,QAC7E;AAAA,SACF;AAAA,OACF,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,aAAY;AAAA,QACZ,WAAW,cAAc;AAAA,QACzB,aAAY;AAAA,QACZ,MAAM;AAAA,QACN,WAAW;AAAA,QACX,iBAAiB;AAAA,QACjB;AAAA;AAAA,IACF;AAAA,KAEJ,GACF,GACF;AAEJ;",
6
6
  "names": ["params"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.6-develop.6398.1.013efe913e",
3
+ "version": "0.6.6-develop.6399.1.93ba8ca030",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -248,16 +248,16 @@
248
248
  "zod": "^4.4.3"
249
249
  },
250
250
  "peerDependencies": {
251
- "@open-mercato/ai-assistant": "0.6.6-develop.6398.1.013efe913e",
252
- "@open-mercato/shared": "0.6.6-develop.6398.1.013efe913e",
253
- "@open-mercato/ui": "0.6.6-develop.6398.1.013efe913e",
251
+ "@open-mercato/ai-assistant": "0.6.6-develop.6399.1.93ba8ca030",
252
+ "@open-mercato/shared": "0.6.6-develop.6399.1.93ba8ca030",
253
+ "@open-mercato/ui": "0.6.6-develop.6399.1.93ba8ca030",
254
254
  "react": "^19.0.0",
255
255
  "react-dom": "^19.0.0"
256
256
  },
257
257
  "devDependencies": {
258
- "@open-mercato/ai-assistant": "0.6.6-develop.6398.1.013efe913e",
259
- "@open-mercato/shared": "0.6.6-develop.6398.1.013efe913e",
260
- "@open-mercato/ui": "0.6.6-develop.6398.1.013efe913e",
258
+ "@open-mercato/ai-assistant": "0.6.6-develop.6399.1.93ba8ca030",
259
+ "@open-mercato/shared": "0.6.6-develop.6399.1.93ba8ca030",
260
+ "@open-mercato/ui": "0.6.6-develop.6399.1.93ba8ca030",
261
261
  "@testing-library/dom": "^10.4.1",
262
262
  "@testing-library/jest-dom": "^6.9.1",
263
263
  "@testing-library/react": "^16.3.1",
@@ -453,12 +453,10 @@ export default function ResourcesResourceDetailPage({ params }: { params?: { id?
453
453
  const handleTagsSave = React.useCallback(
454
454
  async ({ next, added, removed }: { next: TagOption[]; added: TagOption[]; removed: TagOption[] }) => {
455
455
  if (!resourceId) return
456
- for (const tag of added) {
457
- await assignTag(tag.id)
458
- }
459
- for (const tag of removed) {
460
- await unassignTag(tag.id)
461
- }
456
+ await Promise.all([
457
+ ...added.map((tag) => assignTag(tag.id)),
458
+ ...removed.map((tag) => unassignTag(tag.id)),
459
+ ])
462
460
  setTags(next)
463
461
  flash(t('resources.resources.tags.success', 'Tags updated.'), 'success')
464
462
  },