@open-mercato/core 0.6.7-develop.6828.1.ab1620a63e → 0.6.7-develop.6842.1.8cd8a8883c
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/attachments/fields/attachment.js +1 -1
- package/dist/modules/attachments/fields/attachment.js.map +2 -2
- package/dist/modules/auth/components/UserConsentsPanel.js +9 -9
- package/dist/modules/auth/components/UserConsentsPanel.js.map +2 -2
- package/dist/modules/auth/frontend/reset.js +2 -2
- package/dist/modules/auth/frontend/reset.js.map +2 -2
- package/dist/modules/business_rules/components/ActionRow.js +1 -1
- package/dist/modules/business_rules/components/ActionRow.js.map +1 -1
- package/dist/modules/business_rules/components/ConditionRow.js +8 -4
- package/dist/modules/business_rules/components/ConditionRow.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +4 -4
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +5 -5
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +3 -3
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductCategorizeSection.js +3 -3
- package/dist/modules/catalog/components/products/ProductCategorizeSection.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductMediaManager.js +1 -1
- package/dist/modules/catalog/components/products/ProductMediaManager.js.map +2 -2
- package/dist/modules/catalog/components/products/VariantBuilder.js +5 -5
- package/dist/modules/catalog/components/products/VariantBuilder.js.map +2 -2
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +1 -1
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivitiesDayStrip.js +2 -3
- package/dist/modules/customers/components/detail/ActivitiesDayStrip.js.map +2 -2
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js +1 -1
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js.map +1 -1
- package/dist/modules/dashboards/api/widgets/data/schema.js +26 -17
- package/dist/modules/dashboards/api/widgets/data/schema.js.map +2 -2
- package/dist/modules/dashboards/lib/aggregations.js +20 -6
- package/dist/modules/dashboards/lib/aggregations.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/detail.js +8 -8
- package/dist/modules/design_system/gallery/entries/detail.js.map +1 -1
- package/dist/modules/design_system/gallery/entries/overlays.js +2 -2
- package/dist/modules/design_system/gallery/entries/overlays.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/scaffolding.js +8 -8
- package/dist/modules/design_system/gallery/entries/scaffolding.js.map +1 -1
- package/dist/modules/dictionaries/components/DictionaryEntrySelect.js +1 -1
- package/dist/modules/dictionaries/components/DictionaryEntrySelect.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +6 -6
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +3 -3
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/dialogs.js +1 -1
- package/dist/modules/messages/components/message-detail/panels/dialogs.js.map +1 -1
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +4 -4
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/shipment-wizard/components/PackageEditor.js +1 -1
- package/dist/modules/shipping_carriers/lib/shipment-wizard/components/PackageEditor.js.map +1 -1
- package/dist/modules/wms/components/backend/ReleaseReservationDialog.js +1 -1
- package/dist/modules/wms/components/backend/ReleaseReservationDialog.js.map +1 -1
- package/dist/modules/workflows/backend/definitions/page.js +1 -1
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +1 -1
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +8 -8
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +6 -6
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/components/ActivitiesEditor.js +2 -2
- package/dist/modules/workflows/components/ActivitiesEditor.js.map +2 -2
- package/dist/modules/workflows/components/BusinessRulesSelector.js +1 -1
- package/dist/modules/workflows/components/BusinessRulesSelector.js.map +2 -2
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +2 -2
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +2 -2
- package/dist/modules/workflows/components/EdgeEditDialogCrudForm.js +1 -2
- package/dist/modules/workflows/components/EdgeEditDialogCrudForm.js.map +2 -2
- package/dist/modules/workflows/components/NodeEditDialogCrudForm.js +1 -2
- package/dist/modules/workflows/components/NodeEditDialogCrudForm.js.map +2 -2
- package/dist/modules/workflows/components/StepsEditor.js +2 -2
- package/dist/modules/workflows/components/StepsEditor.js.map +2 -2
- package/dist/modules/workflows/components/TransitionsEditor.js +3 -3
- package/dist/modules/workflows/components/TransitionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowLegend.js +1 -1
- package/dist/modules/workflows/components/WorkflowLegend.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowSelector.js +1 -1
- package/dist/modules/workflows/components/WorkflowSelector.js.map +2 -2
- package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js +1 -1
- package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js +1 -1
- package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/MappingArrayEditor.js +1 -1
- package/dist/modules/workflows/components/fields/MappingArrayEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js +1 -1
- package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/WorkflowSelectorField.js +4 -4
- package/dist/modules/workflows/components/fields/WorkflowSelectorField.js.map +2 -2
- package/package.json +8 -8
- package/src/modules/api_keys/i18n/ko.json +42 -0
- package/src/modules/attachments/fields/attachment.tsx +1 -1
- package/src/modules/attachments/i18n/ko.json +172 -0
- package/src/modules/audit_logs/i18n/ko.json +66 -0
- package/src/modules/auth/components/UserConsentsPanel.tsx +9 -9
- package/src/modules/auth/frontend/reset.tsx +2 -2
- package/src/modules/auth/i18n/ko.json +255 -0
- package/src/modules/business_rules/components/ActionRow.tsx +1 -1
- package/src/modules/business_rules/components/ConditionRow.tsx +9 -6
- package/src/modules/business_rules/i18n/ko.json +396 -0
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +4 -4
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +5 -5
- package/src/modules/catalog/components/PriceKindSettings.tsx +3 -3
- package/src/modules/catalog/components/products/ProductCategorizeSection.tsx +3 -3
- package/src/modules/catalog/components/products/ProductMediaManager.tsx +1 -1
- package/src/modules/catalog/components/products/VariantBuilder.tsx +5 -5
- package/src/modules/catalog/i18n/ko.json +723 -0
- package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +1 -1
- package/src/modules/communication_channels/i18n/ko.json +138 -0
- package/src/modules/configs/i18n/ko.json +197 -0
- package/src/modules/currencies/i18n/de.json +1 -0
- package/src/modules/currencies/i18n/en.json +1 -0
- package/src/modules/currencies/i18n/es.json +1 -0
- package/src/modules/currencies/i18n/ko.json +160 -0
- package/src/modules/currencies/i18n/pl.json +1 -0
- package/src/modules/customer_accounts/i18n/ko.json +354 -0
- package/src/modules/customers/components/detail/ActivitiesDayStrip.tsx +2 -3
- package/src/modules/customers/components/detail/ConfirmDealLostDialog.tsx +1 -1
- package/src/modules/customers/i18n/de.json +10 -0
- package/src/modules/customers/i18n/en.json +10 -0
- package/src/modules/customers/i18n/es.json +10 -0
- package/src/modules/customers/i18n/ko.json +2855 -0
- package/src/modules/customers/i18n/pl.json +10 -0
- package/src/modules/dashboards/api/widgets/data/schema.ts +48 -19
- package/src/modules/dashboards/i18n/ko.json +118 -0
- package/src/modules/dashboards/lib/aggregations.ts +42 -6
- package/src/modules/data_sync/i18n/ko.json +125 -0
- package/src/modules/design_system/gallery/entries/detail.tsx +8 -8
- package/src/modules/design_system/gallery/entries/overlays.tsx +2 -2
- package/src/modules/design_system/gallery/entries/scaffolding.tsx +8 -8
- package/src/modules/design_system/i18n/de.json +12 -0
- package/src/modules/design_system/i18n/en.json +12 -0
- package/src/modules/design_system/i18n/es.json +12 -0
- package/src/modules/design_system/i18n/ko.json +58 -0
- package/src/modules/design_system/i18n/pl.json +12 -0
- package/src/modules/dictionaries/components/DictionaryEntrySelect.tsx +1 -1
- package/src/modules/dictionaries/i18n/ko.json +130 -0
- package/src/modules/directory/i18n/ko.json +105 -0
- package/src/modules/entities/i18n/ko.json +260 -0
- package/src/modules/feature_toggles/i18n/ko.json +96 -0
- package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +6 -6
- package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +3 -3
- package/src/modules/inbox_ops/i18n/ko.json +196 -0
- package/src/modules/integrations/i18n/ko.json +129 -0
- package/src/modules/messages/components/message-detail/panels/dialogs.tsx +1 -1
- package/src/modules/messages/i18n/ko.json +263 -0
- package/src/modules/notifications/i18n/ko.json +55 -0
- package/src/modules/payment_gateways/i18n/ko.json +87 -0
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +4 -4
- package/src/modules/planner/i18n/ko.json +565 -0
- package/src/modules/portal/i18n/ko.json +143 -0
- package/src/modules/progress/i18n/ko.json +20 -0
- package/src/modules/query_index/i18n/ko.json +69 -0
- package/src/modules/resources/i18n/ko.json +770 -0
- package/src/modules/sales/i18n/ko.json +1442 -0
- package/src/modules/shipping_carriers/i18n/ko.json +85 -0
- package/src/modules/shipping_carriers/lib/shipment-wizard/components/PackageEditor.tsx +1 -1
- package/src/modules/staff/i18n/ko.json +1162 -0
- package/src/modules/sync_excel/i18n/ko.json +107 -0
- package/src/modules/translations/i18n/ko.json +45 -0
- package/src/modules/wms/components/backend/ReleaseReservationDialog.tsx +1 -1
- package/src/modules/wms/i18n/ko.json +1053 -0
- package/src/modules/workflows/backend/definitions/page.tsx +1 -1
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +1 -1
- package/src/modules/workflows/backend/instances/page.tsx +8 -8
- package/src/modules/workflows/backend/tasks/page.tsx +6 -6
- package/src/modules/workflows/components/ActivitiesEditor.tsx +2 -2
- package/src/modules/workflows/components/BusinessRulesSelector.tsx +1 -1
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +2 -2
- package/src/modules/workflows/components/EdgeEditDialogCrudForm.tsx +1 -2
- package/src/modules/workflows/components/NodeEditDialogCrudForm.tsx +1 -2
- package/src/modules/workflows/components/StepsEditor.tsx +2 -2
- package/src/modules/workflows/components/TransitionsEditor.tsx +3 -3
- package/src/modules/workflows/components/WorkflowLegend.tsx +1 -1
- package/src/modules/workflows/components/WorkflowSelector.tsx +1 -1
- package/src/modules/workflows/components/fields/BusinessRuleConditionsEditor.tsx +1 -1
- package/src/modules/workflows/components/fields/FormFieldArrayEditor.tsx +1 -1
- package/src/modules/workflows/components/fields/MappingArrayEditor.tsx +1 -1
- package/src/modules/workflows/components/fields/StartPreConditionsEditor.tsx +1 -1
- package/src/modules/workflows/components/fields/WorkflowSelectorField.tsx +4 -4
- package/src/modules/workflows/i18n/ko.json +1203 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/catalog/components/products/VariantBuilder.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { flushSync } from 'react-dom'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { ProductMediaManager } from './ProductMediaManager'\nimport { MetadataEditor } from './MetadataEditor'\nimport type { PriceKindSummary, TaxRateSummary } from './productForm'\nimport { formatTaxRateLabel } from './productForm'\nimport type { OptionDefinition, VariantFormValues, VariantPriceDraft } from './variantForm'\nimport { CATALOG_GTIN_TYPES } from '../../data/types'\nimport { E } from '#generated/entities.ids.generated'\n\ntype VariantBuilderProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n errors: Record<string, string>\n optionDefinitions: OptionDefinition[]\n priceKinds: PriceKindSummary[]\n taxRates: TaxRateSummary[]\n}\n\ntype VariantSectionBaseProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n errors: Record<string, string>\n}\n\ntype VariantOptionValuesSectionProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n optionDefinitions: OptionDefinition[]\n showHeading?: boolean\n}\n\ntype VariantDimensionsSectionProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n showHeading?: boolean\n}\n\ntype VariantMetadataSectionProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n showIntro?: boolean\n embedded?: boolean\n}\n\ntype VariantPricesSectionProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n priceKinds: PriceKindSummary[]\n taxRates: TaxRateSummary[]\n showHeader?: boolean\n embedded?: boolean\n}\n\ntype VariantMediaSectionProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n showLabel?: boolean\n}\n\nexport function VariantBuilder({\n values,\n setValue,\n errors,\n optionDefinitions,\n priceKinds,\n taxRates,\n}: VariantBuilderProps) {\n return (\n <div className=\"space-y-6\">\n <VariantBasicsSection values={values} setValue={setValue} errors={errors} />\n <VariantOptionValuesSection values={values} setValue={setValue} optionDefinitions={optionDefinitions} />\n <VariantDimensionsSection values={values} setValue={setValue} />\n <VariantMetadataSection values={values} setValue={setValue} />\n <VariantPricesSection values={values} setValue={setValue} priceKinds={priceKinds} taxRates={taxRates} />\n <VariantMediaSection values={values} setValue={setValue} />\n </div>\n )\n}\n\nexport function VariantBasicsSection({ values, setValue, errors }: VariantSectionBaseProps) {\n const t = useT()\n return (\n <div className=\"space-y-6\">\n <div className=\"space-y-2\">\n <Label className=\"flex items-center gap-1\">\n {t('catalog.variants.form.nameLabel', 'Name')}\n <span className=\"text-red-600\">*</span>\n </Label>\n <Input\n value={values.name}\n onChange={(event) => setValue('name', event.target.value)}\n placeholder={t('catalog.variants.form.namePlaceholder', 'e.g., Blue / Small')}\n />\n {errors.name ? <p className=\"text-xs text-red-600\">{errors.name}</p> : null}\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>{t('catalog.variants.form.skuLabel', 'SKU')}</Label>\n <Input\n value={values.sku}\n onChange={(event) => setValue('sku', event.target.value)}\n placeholder={t('catalog.variants.form.skuPlaceholder', 'Unique identifier')}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>{t('catalog.variants.form.barcodeLabel', 'Barcode')}</Label>\n <Input\n value={values.barcode}\n onChange={(event) => setValue('barcode', event.target.value)}\n placeholder={t('catalog.variants.form.barcodePlaceholder', 'EAN, UPC, etc.')}\n />\n {errors.barcode ? <p className=\"text-xs text-destructive\">{errors.barcode}</p> : null}\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-variant-gtin-type\">\n {t('catalog.variants.form.gtinTypeLabel', 'Identifier type (GTIN)')}\n </Label>\n <Select\n value={values.gtinType ?? 'none'}\n onValueChange={(value) => setValue('gtinType', value === 'none' ? null : value)}\n >\n <SelectTrigger id=\"catalog-variant-gtin-type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"none\">{t('catalog.variants.form.gtinTypeNone', 'Untyped')}</SelectItem>\n {CATALOG_GTIN_TYPES.map((type) => (\n <SelectItem key={type} value={type}>\n {t(`catalog.variants.form.gtinTypes.${type}`, type.toUpperCase())}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'catalog.variants.form.gtinTypeHint',\n 'Typed barcodes are validated and kept unique per organization.',\n )}\n </p>\n {errors.gtinType ? <p className=\"text-xs text-destructive\">{errors.gtinType}</p> : null}\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-variant-hs-code\">\n {t('catalog.variants.form.hsCodeLabel', 'HS code (customs tariff)')}\n </Label>\n <Input\n id=\"catalog-variant-hs-code\"\n value={values.hsCode}\n onChange={(event) => setValue('hsCode', event.target.value)}\n />\n {errors.hsCode ? <p className=\"text-xs text-destructive\">{errors.hsCode}</p> : null}\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <label className=\"flex items-center justify-between gap-2 rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{t('catalog.variants.form.isDefaultLabel', 'Default variant')}</p>\n <p className=\"text-xs text-muted-foreground\">{t('catalog.variants.form.isDefaultHint', 'Used in storefronts')}</p>\n </div>\n <Switch checked={values.isDefault} onCheckedChange={(next) => setValue('isDefault', next)} />\n </label>\n <label className=\"flex items-center justify-between gap-2 rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{t('catalog.variants.form.isActiveLabel', 'Active')}</p>\n <p className=\"text-xs text-muted-foreground\">{t('catalog.variants.form.isActiveHint', 'Inactive variants stay hidden')}</p>\n </div>\n <Switch checked={values.isActive !== false} onCheckedChange={(next) => setValue('isActive', next)} />\n </label>\n </div>\n </div>\n )\n}\n\nexport function VariantOptionValuesSection({\n values,\n setValue,\n optionDefinitions,\n showHeading = true,\n}: VariantOptionValuesSectionProps) {\n const t = useT()\n\n const handleOptionChange = React.useCallback(\n (code: string, next: string) => {\n setValue('optionValues', { ...(values.optionValues ?? {}), [code]: next })\n },\n [setValue, values.optionValues],\n )\n\n if (!optionDefinitions.length) return null\n\n return (\n <div className=\"space-y-3\">\n {showHeading ? <h3 className=\"text-sm font-semibold\">{t('catalog.variants.form.options', 'Option values')}</h3> : null}\n <div className=\"grid gap-4 md:grid-cols-2\">\n {optionDefinitions.map((option) => (\n <div key={option.code} className=\"space-y-2\">\n <Label className=\"text-xs uppercase text-muted-foreground\">{option.label}</Label>\n <Select\n value={values.optionValues?.[option.code] || undefined}\n onValueChange={(value) => handleOptionChange(option.code, value ?? '')}\n >\n <SelectTrigger>\n <SelectValue placeholder={t('catalog.variants.form.optionPlaceholder', 'Select value')} />\n </SelectTrigger>\n <SelectContent>\n {option.values.map((value) => (\n <SelectItem key={value.id} value={value.label}>\n {value.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ))}\n </div>\n </div>\n )\n}\n\nexport function VariantDimensionsSection({ values, setValue, showHeading = true }: VariantDimensionsSectionProps) {\n const t = useT()\n const metadata = normalizeMetadata(values.metadata)\n const dimensionValues = normalizeDimensions(metadata)\n const weightValues = normalizeWeight(metadata)\n const dimensionUnitPlaceholder = t('catalog.variants.form.dimensionUnitPlaceholder', 'cm')\n const weightUnitPlaceholder = t('catalog.variants.form.weightUnitPlaceholder', 'kg')\n\n return (\n <div className=\"space-y-4\">\n {showHeading ? <h3 className=\"text-sm font-semibold\">{t('catalog.variants.form.dimensions', 'Dimensions & weight')}</h3> : null}\n <div className=\"grid gap-4 md:grid-cols-2\">\n <DimensionInput\n label={t('catalog.variants.form.width', 'Width')}\n value={dimensionValues.width ?? ''}\n onChange={(value) => setValue('metadata', applyDimension(metadata, 'width', value))}\n />\n <DimensionInput\n label={t('catalog.variants.form.height', 'Height')}\n value={dimensionValues.height ?? ''}\n onChange={(value) => setValue('metadata', applyDimension(metadata, 'height', value))}\n />\n <DimensionInput\n label={t('catalog.variants.form.depth', 'Depth')}\n value={dimensionValues.depth ?? ''}\n onChange={(value) => setValue('metadata', applyDimension(metadata, 'depth', value))}\n />\n <DimensionInput\n label={t('catalog.variants.form.dimensionUnit', 'Size unit')}\n value={dimensionValues.unit ?? ''}\n placeholder={dimensionUnitPlaceholder}\n onChange={(value) => setValue('metadata', applyDimension(metadata, 'unit', value))}\n />\n <DimensionInput\n label={t('catalog.variants.form.weight', 'Weight')}\n value={weightValues.value ?? ''}\n onChange={(value) => setValue('metadata', applyWeight(metadata, 'value', value))}\n />\n <DimensionInput\n label={t('catalog.variants.form.weightUnit', 'Weight unit')}\n value={weightValues.unit ?? ''}\n placeholder={weightUnitPlaceholder}\n onChange={(value) => setValue('metadata', applyWeight(metadata, 'unit', value))}\n />\n </div>\n </div>\n )\n}\n\nexport function VariantMetadataSection({\n values,\n setValue,\n showIntro = true,\n embedded = false,\n}: VariantMetadataSectionProps) {\n const metadata = normalizeMetadata(values.metadata)\n const systemMetadata = React.useMemo(() => extractSystemMetadata(metadata), [metadata])\n const customMetadata = React.useMemo(() => stripSystemMetadata(metadata), [metadata])\n\n const handleMetadataChange = React.useCallback(\n (next: Record<string, unknown>) => {\n const merged: Record<string, unknown> = {}\n Object.entries(systemMetadata).forEach(([key, value]) => {\n merged[key] = value\n })\n Object.entries(next).forEach(([key, value]) => {\n merged[key] = value\n })\n setValue('metadata', merged)\n },\n [setValue, systemMetadata],\n )\n\n return (\n <MetadataEditor\n value={customMetadata}\n onChange={handleMetadataChange}\n title={showIntro ? undefined : ''}\n description={showIntro ? undefined : ''}\n embedded={embedded}\n />\n )\n}\n\nexport function VariantPricesSection({\n values,\n setValue,\n priceKinds,\n taxRates,\n showHeader = true,\n embedded = false,\n}: VariantPricesSectionProps) {\n const t = useT()\n const pricesRef = React.useRef(values.prices)\n\n React.useEffect(() => {\n pricesRef.current = values.prices\n }, [values.prices])\n\n const updatePrice = React.useCallback(\n (priceKindId: string, patch: Partial<VariantPriceDraft>) => {\n const currentPrices = pricesRef.current ?? {}\n const prev = currentPrices[priceKindId] ?? { priceKindId, amount: '', displayMode: 'excluding-tax' }\n const nextPrices = { ...currentPrices, [priceKindId]: { ...prev, ...patch, priceKindId } }\n pricesRef.current = nextPrices\n flushSync(() => setValue('prices', nextPrices))\n },\n [setValue],\n )\n\n const containerClass = embedded ? 'space-y-4' : 'space-y-4 rounded-lg border p-4'\n const selectedTaxRate = values.taxRateId\n ? taxRates.find((rate) => rate.id === values.taxRateId) ?? null\n : null\n const fallbackSelectedTaxRate =\n values.taxRateId && !selectedTaxRate\n ? {\n id: values.taxRateId,\n name: values.taxRateId,\n code: null,\n rate: null,\n isDefault: false,\n }\n : null\n const displayedSelectedTaxRate = selectedTaxRate ?? fallbackSelectedTaxRate\n const displayedTaxRates = fallbackSelectedTaxRate\n ? [fallbackSelectedTaxRate, ...taxRates]\n : taxRates\n const taxRateOptionsKey = displayedTaxRates.map((rate) => `${rate.id}:${formatTaxRateLabel(rate)}`).join('\\0')\n const taxRateSelectKey = `variant-tax-rate:${values.taxRateId ?? ''}:${taxRateOptionsKey}`\n\n return (\n <div className={containerClass}>\n {showHeader ? (\n <div className=\"flex items-center justify-between gap-2\">\n <div>\n <h3 className=\"text-sm font-semibold\">{t('catalog.variants.form.pricesLabel', 'Prices')}</h3>\n <p className=\"text-xs text-muted-foreground\">\n {t('catalog.variants.form.pricesHint', 'Populate list prices per price kind.')}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <Select\n key={taxRateSelectKey}\n value={values.taxRateId || undefined}\n onValueChange={(value) => {\n if (value) setValue('taxRateId', value)\n }}\n >\n <SelectTrigger>\n <SelectValue placeholder={t('catalog.variants.form.pricesTaxNone', 'No tax override')}>\n {displayedSelectedTaxRate ? formatTaxRateLabel(displayedSelectedTaxRate) : undefined}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {displayedTaxRates.map((rate) => (\n <SelectItem key={rate.id} value={rate.id}>\n {formatTaxRateLabel(rate)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n ) : (\n <div className=\"flex justify-end\">\n <Select\n key={taxRateSelectKey}\n value={values.taxRateId || undefined}\n onValueChange={(value) => {\n if (value) setValue('taxRateId', value)\n }}\n >\n <SelectTrigger>\n <SelectValue placeholder={t('catalog.variants.form.pricesTaxNone', 'No tax override')}>\n {displayedSelectedTaxRate ? formatTaxRateLabel(displayedSelectedTaxRate) : undefined}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {displayedTaxRates.map((rate) => (\n <SelectItem key={rate.id} value={rate.id}>\n {formatTaxRateLabel(rate)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n <div className=\"space-y-3\">\n {priceKinds.length ? (\n priceKinds.map((kind) => {\n const draft = values.prices?.[kind.id]\n return (\n <div key={kind.id} className=\"rounded bg-muted/50 p-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-sm font-semibold\">{kind.title}</p>\n <p className=\"text-xs text-muted-foreground\">\n {kind.currencyCode\n ? `${kind.currencyCode.toUpperCase()} \u2022 ${kind.displayMode === 'including-tax' ? t('catalog.priceKinds.form.displayMode.include', 'Including tax') : t('catalog.priceKinds.form.displayMode.exclude', 'Excluding tax')}`\n : t('catalog.variants.form.priceMissingCurrency', 'No currency configured')}\n </p>\n </div>\n </div>\n <Input\n className=\"mt-3\"\n value={draft?.amount ?? ''}\n onInput={(event) => updatePrice(kind.id, { amount: event.currentTarget.value })}\n onChange={(event) => updatePrice(kind.id, { amount: event.target.value })}\n placeholder=\"0.00\"\n />\n </div>\n )\n })\n ) : (\n <p className=\"text-xs text-muted-foreground\">{t('catalog.variants.form.pricesEmpty', 'No price kinds configured yet.')}</p>\n )}\n </div>\n </div>\n )\n}\n\nexport function VariantMediaSection({ values, setValue, showLabel = true }: VariantMediaSectionProps) {\n const t = useT()\n return (\n <div className=\"space-y-2\">\n {showLabel ? <Label>{t('catalog.variants.form.media', 'Media')}</Label> : null}\n <ProductMediaManager\n entityId={E.catalog.catalog_product_variant}\n draftRecordId={values.mediaDraftId}\n items={Array.isArray(values.mediaItems) ? values.mediaItems : []}\n defaultMediaId={values.defaultMediaId}\n onItemsChange={(next) => setValue('mediaItems', next)}\n onDefaultChange={(next) => setValue('defaultMediaId', next)}\n />\n </div>\n )\n}\n\nfunction DimensionInput({\n label,\n value,\n onChange,\n placeholder = '0',\n}: {\n label: string\n value: string | number | undefined\n onChange: (next: string) => void\n placeholder?: string\n}) {\n return (\n <div className=\"space-y-2\">\n <Label className=\"text-xs uppercase text-muted-foreground\">{label}</Label>\n <Input value={value ?? ''} onChange={(event) => onChange(event.target.value)} placeholder={placeholder} />\n </div>\n )\n}\n\nfunction normalizeMetadata(input: unknown): Record<string, any> {\n return typeof input === 'object' && input ? { ...(input as Record<string, unknown>) } : {}\n}\n\nfunction normalizeDimensions(metadata: Record<string, any>) {\n const raw = metadata.dimensions\n if (!raw || typeof raw !== 'object') return {}\n return {\n width: typeof raw.width === 'number' ? raw.width : undefined,\n height: typeof raw.height === 'number' ? raw.height : undefined,\n depth: typeof raw.depth === 'number' ? raw.depth : undefined,\n unit: typeof raw.unit === 'string' ? raw.unit : undefined,\n }\n}\n\nfunction normalizeWeight(metadata: Record<string, any>) {\n const raw = metadata.weight\n if (!raw || typeof raw !== 'object') return {}\n return {\n value: typeof raw.value === 'number' ? raw.value : undefined,\n unit: typeof raw.unit === 'string' ? raw.unit : undefined,\n }\n}\n\nfunction applyDimension(metadata: Record<string, any>, field: 'width' | 'height' | 'depth' | 'unit', raw: string) {\n const dims = normalizeDimensions(metadata)\n if (field === 'unit') {\n dims.unit = raw\n } else {\n const numeric = Number(raw)\n dims[field] = Number.isNaN(numeric) ? undefined : numeric\n }\n const clean = cleanupDimensions(dims)\n if (clean) return { ...metadata, dimensions: clean }\n const copy = { ...metadata }\n delete copy.dimensions\n return copy\n}\n\nfunction applyWeight(metadata: Record<string, any>, field: 'value' | 'unit', raw: string) {\n const weight = normalizeWeight(metadata)\n if (field === 'unit') weight.unit = raw\n else {\n const numeric = Number(raw)\n weight.value = Number.isNaN(numeric) ? undefined : numeric\n }\n const clean = cleanupWeight(weight)\n if (clean) return { ...metadata, weight: clean }\n const copy = { ...metadata }\n delete copy.weight\n return copy\n}\n\nfunction cleanupDimensions(dims: { width?: number; height?: number; depth?: number; unit?: string }) {\n const clean: Record<string, unknown> = {}\n if (typeof dims.width === 'number' && Number.isFinite(dims.width)) clean.width = dims.width\n if (typeof dims.height === 'number' && Number.isFinite(dims.height)) clean.height = dims.height\n if (typeof dims.depth === 'number' && Number.isFinite(dims.depth)) clean.depth = dims.depth\n if (typeof dims.unit === 'string' && dims.unit.trim().length) clean.unit = dims.unit\n return Object.keys(clean).length ? clean : null\n}\n\nfunction cleanupWeight(weight: { value?: number; unit?: string }) {\n const clean: Record<string, unknown> = {}\n if (typeof weight.value === 'number' && Number.isFinite(weight.value)) clean.value = weight.value\n if (typeof weight.unit === 'string' && weight.unit.trim().length) clean.unit = weight.unit\n return Object.keys(clean).length ? clean : null\n}\n\nfunction stripSystemMetadata(metadata: Record<string, any>) {\n const copy: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(metadata)) {\n if (key === 'dimensions' || key === 'weight') continue\n copy[key] = value\n }\n return copy\n}\n\nfunction extractSystemMetadata(metadata: Record<string, any>) {\n const system: Record<string, unknown> = {}\n if (metadata.dimensions) system.dimensions = metadata.dimensions\n if (metadata.weight) system.weight = metadata.weight\n return system\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { flushSync } from 'react-dom'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { ProductMediaManager } from './ProductMediaManager'\nimport { MetadataEditor } from './MetadataEditor'\nimport type { PriceKindSummary, TaxRateSummary } from './productForm'\nimport { formatTaxRateLabel } from './productForm'\nimport type { OptionDefinition, VariantFormValues, VariantPriceDraft } from './variantForm'\nimport { CATALOG_GTIN_TYPES } from '../../data/types'\nimport { E } from '#generated/entities.ids.generated'\n\ntype VariantBuilderProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n errors: Record<string, string>\n optionDefinitions: OptionDefinition[]\n priceKinds: PriceKindSummary[]\n taxRates: TaxRateSummary[]\n}\n\ntype VariantSectionBaseProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n errors: Record<string, string>\n}\n\ntype VariantOptionValuesSectionProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n optionDefinitions: OptionDefinition[]\n showHeading?: boolean\n}\n\ntype VariantDimensionsSectionProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n showHeading?: boolean\n}\n\ntype VariantMetadataSectionProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n showIntro?: boolean\n embedded?: boolean\n}\n\ntype VariantPricesSectionProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n priceKinds: PriceKindSummary[]\n taxRates: TaxRateSummary[]\n showHeader?: boolean\n embedded?: boolean\n}\n\ntype VariantMediaSectionProps = {\n values: VariantFormValues\n setValue: (id: string, value: unknown) => void\n showLabel?: boolean\n}\n\nexport function VariantBuilder({\n values,\n setValue,\n errors,\n optionDefinitions,\n priceKinds,\n taxRates,\n}: VariantBuilderProps) {\n return (\n <div className=\"space-y-6\">\n <VariantBasicsSection values={values} setValue={setValue} errors={errors} />\n <VariantOptionValuesSection values={values} setValue={setValue} optionDefinitions={optionDefinitions} />\n <VariantDimensionsSection values={values} setValue={setValue} />\n <VariantMetadataSection values={values} setValue={setValue} />\n <VariantPricesSection values={values} setValue={setValue} priceKinds={priceKinds} taxRates={taxRates} />\n <VariantMediaSection values={values} setValue={setValue} />\n </div>\n )\n}\n\nexport function VariantBasicsSection({ values, setValue, errors }: VariantSectionBaseProps) {\n const t = useT()\n return (\n <div className=\"space-y-6\">\n <div className=\"space-y-2\">\n <Label className=\"flex items-center gap-1\">\n {t('catalog.variants.form.nameLabel', 'Name')}\n <span className=\"text-status-error-text\">*</span>\n </Label>\n <Input\n value={values.name}\n onChange={(event) => setValue('name', event.target.value)}\n placeholder={t('catalog.variants.form.namePlaceholder', 'e.g., Blue / Small')}\n />\n {errors.name ? <p className=\"text-xs text-status-error-text\">{errors.name}</p> : null}\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>{t('catalog.variants.form.skuLabel', 'SKU')}</Label>\n <Input\n value={values.sku}\n onChange={(event) => setValue('sku', event.target.value)}\n placeholder={t('catalog.variants.form.skuPlaceholder', 'Unique identifier')}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>{t('catalog.variants.form.barcodeLabel', 'Barcode')}</Label>\n <Input\n value={values.barcode}\n onChange={(event) => setValue('barcode', event.target.value)}\n placeholder={t('catalog.variants.form.barcodePlaceholder', 'EAN, UPC, etc.')}\n />\n {errors.barcode ? <p className=\"text-xs text-status-error-text\">{errors.barcode}</p> : null}\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-variant-gtin-type\">\n {t('catalog.variants.form.gtinTypeLabel', 'Identifier type (GTIN)')}\n </Label>\n <Select\n value={values.gtinType ?? 'none'}\n onValueChange={(value) => setValue('gtinType', value === 'none' ? null : value)}\n >\n <SelectTrigger id=\"catalog-variant-gtin-type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"none\">{t('catalog.variants.form.gtinTypeNone', 'Untyped')}</SelectItem>\n {CATALOG_GTIN_TYPES.map((type) => (\n <SelectItem key={type} value={type}>\n {t(`catalog.variants.form.gtinTypes.${type}`, type.toUpperCase())}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'catalog.variants.form.gtinTypeHint',\n 'Typed barcodes are validated and kept unique per organization.',\n )}\n </p>\n {errors.gtinType ? <p className=\"text-xs text-status-error-text\">{errors.gtinType}</p> : null}\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"catalog-variant-hs-code\">\n {t('catalog.variants.form.hsCodeLabel', 'HS code (customs tariff)')}\n </Label>\n <Input\n id=\"catalog-variant-hs-code\"\n value={values.hsCode}\n onChange={(event) => setValue('hsCode', event.target.value)}\n />\n {errors.hsCode ? <p className=\"text-xs text-status-error-text\">{errors.hsCode}</p> : null}\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <label className=\"flex items-center justify-between gap-2 rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{t('catalog.variants.form.isDefaultLabel', 'Default variant')}</p>\n <p className=\"text-xs text-muted-foreground\">{t('catalog.variants.form.isDefaultHint', 'Used in storefronts')}</p>\n </div>\n <Switch checked={values.isDefault} onCheckedChange={(next) => setValue('isDefault', next)} />\n </label>\n <label className=\"flex items-center justify-between gap-2 rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{t('catalog.variants.form.isActiveLabel', 'Active')}</p>\n <p className=\"text-xs text-muted-foreground\">{t('catalog.variants.form.isActiveHint', 'Inactive variants stay hidden')}</p>\n </div>\n <Switch checked={values.isActive !== false} onCheckedChange={(next) => setValue('isActive', next)} />\n </label>\n </div>\n </div>\n )\n}\n\nexport function VariantOptionValuesSection({\n values,\n setValue,\n optionDefinitions,\n showHeading = true,\n}: VariantOptionValuesSectionProps) {\n const t = useT()\n\n const handleOptionChange = React.useCallback(\n (code: string, next: string) => {\n setValue('optionValues', { ...(values.optionValues ?? {}), [code]: next })\n },\n [setValue, values.optionValues],\n )\n\n if (!optionDefinitions.length) return null\n\n return (\n <div className=\"space-y-3\">\n {showHeading ? <h3 className=\"text-sm font-semibold\">{t('catalog.variants.form.options', 'Option values')}</h3> : null}\n <div className=\"grid gap-4 md:grid-cols-2\">\n {optionDefinitions.map((option) => (\n <div key={option.code} className=\"space-y-2\">\n <Label className=\"text-xs uppercase text-muted-foreground\">{option.label}</Label>\n <Select\n value={values.optionValues?.[option.code] || undefined}\n onValueChange={(value) => handleOptionChange(option.code, value ?? '')}\n >\n <SelectTrigger>\n <SelectValue placeholder={t('catalog.variants.form.optionPlaceholder', 'Select value')} />\n </SelectTrigger>\n <SelectContent>\n {option.values.map((value) => (\n <SelectItem key={value.id} value={value.label}>\n {value.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ))}\n </div>\n </div>\n )\n}\n\nexport function VariantDimensionsSection({ values, setValue, showHeading = true }: VariantDimensionsSectionProps) {\n const t = useT()\n const metadata = normalizeMetadata(values.metadata)\n const dimensionValues = normalizeDimensions(metadata)\n const weightValues = normalizeWeight(metadata)\n const dimensionUnitPlaceholder = t('catalog.variants.form.dimensionUnitPlaceholder', 'cm')\n const weightUnitPlaceholder = t('catalog.variants.form.weightUnitPlaceholder', 'kg')\n\n return (\n <div className=\"space-y-4\">\n {showHeading ? <h3 className=\"text-sm font-semibold\">{t('catalog.variants.form.dimensions', 'Dimensions & weight')}</h3> : null}\n <div className=\"grid gap-4 md:grid-cols-2\">\n <DimensionInput\n label={t('catalog.variants.form.width', 'Width')}\n value={dimensionValues.width ?? ''}\n onChange={(value) => setValue('metadata', applyDimension(metadata, 'width', value))}\n />\n <DimensionInput\n label={t('catalog.variants.form.height', 'Height')}\n value={dimensionValues.height ?? ''}\n onChange={(value) => setValue('metadata', applyDimension(metadata, 'height', value))}\n />\n <DimensionInput\n label={t('catalog.variants.form.depth', 'Depth')}\n value={dimensionValues.depth ?? ''}\n onChange={(value) => setValue('metadata', applyDimension(metadata, 'depth', value))}\n />\n <DimensionInput\n label={t('catalog.variants.form.dimensionUnit', 'Size unit')}\n value={dimensionValues.unit ?? ''}\n placeholder={dimensionUnitPlaceholder}\n onChange={(value) => setValue('metadata', applyDimension(metadata, 'unit', value))}\n />\n <DimensionInput\n label={t('catalog.variants.form.weight', 'Weight')}\n value={weightValues.value ?? ''}\n onChange={(value) => setValue('metadata', applyWeight(metadata, 'value', value))}\n />\n <DimensionInput\n label={t('catalog.variants.form.weightUnit', 'Weight unit')}\n value={weightValues.unit ?? ''}\n placeholder={weightUnitPlaceholder}\n onChange={(value) => setValue('metadata', applyWeight(metadata, 'unit', value))}\n />\n </div>\n </div>\n )\n}\n\nexport function VariantMetadataSection({\n values,\n setValue,\n showIntro = true,\n embedded = false,\n}: VariantMetadataSectionProps) {\n const metadata = normalizeMetadata(values.metadata)\n const systemMetadata = React.useMemo(() => extractSystemMetadata(metadata), [metadata])\n const customMetadata = React.useMemo(() => stripSystemMetadata(metadata), [metadata])\n\n const handleMetadataChange = React.useCallback(\n (next: Record<string, unknown>) => {\n const merged: Record<string, unknown> = {}\n Object.entries(systemMetadata).forEach(([key, value]) => {\n merged[key] = value\n })\n Object.entries(next).forEach(([key, value]) => {\n merged[key] = value\n })\n setValue('metadata', merged)\n },\n [setValue, systemMetadata],\n )\n\n return (\n <MetadataEditor\n value={customMetadata}\n onChange={handleMetadataChange}\n title={showIntro ? undefined : ''}\n description={showIntro ? undefined : ''}\n embedded={embedded}\n />\n )\n}\n\nexport function VariantPricesSection({\n values,\n setValue,\n priceKinds,\n taxRates,\n showHeader = true,\n embedded = false,\n}: VariantPricesSectionProps) {\n const t = useT()\n const pricesRef = React.useRef(values.prices)\n\n React.useEffect(() => {\n pricesRef.current = values.prices\n }, [values.prices])\n\n const updatePrice = React.useCallback(\n (priceKindId: string, patch: Partial<VariantPriceDraft>) => {\n const currentPrices = pricesRef.current ?? {}\n const prev = currentPrices[priceKindId] ?? { priceKindId, amount: '', displayMode: 'excluding-tax' }\n const nextPrices = { ...currentPrices, [priceKindId]: { ...prev, ...patch, priceKindId } }\n pricesRef.current = nextPrices\n flushSync(() => setValue('prices', nextPrices))\n },\n [setValue],\n )\n\n const containerClass = embedded ? 'space-y-4' : 'space-y-4 rounded-lg border p-4'\n const selectedTaxRate = values.taxRateId\n ? taxRates.find((rate) => rate.id === values.taxRateId) ?? null\n : null\n const fallbackSelectedTaxRate =\n values.taxRateId && !selectedTaxRate\n ? {\n id: values.taxRateId,\n name: values.taxRateId,\n code: null,\n rate: null,\n isDefault: false,\n }\n : null\n const displayedSelectedTaxRate = selectedTaxRate ?? fallbackSelectedTaxRate\n const displayedTaxRates = fallbackSelectedTaxRate\n ? [fallbackSelectedTaxRate, ...taxRates]\n : taxRates\n const taxRateOptionsKey = displayedTaxRates.map((rate) => `${rate.id}:${formatTaxRateLabel(rate)}`).join('\\0')\n const taxRateSelectKey = `variant-tax-rate:${values.taxRateId ?? ''}:${taxRateOptionsKey}`\n\n return (\n <div className={containerClass}>\n {showHeader ? (\n <div className=\"flex items-center justify-between gap-2\">\n <div>\n <h3 className=\"text-sm font-semibold\">{t('catalog.variants.form.pricesLabel', 'Prices')}</h3>\n <p className=\"text-xs text-muted-foreground\">\n {t('catalog.variants.form.pricesHint', 'Populate list prices per price kind.')}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <Select\n key={taxRateSelectKey}\n value={values.taxRateId || undefined}\n onValueChange={(value) => {\n if (value) setValue('taxRateId', value)\n }}\n >\n <SelectTrigger>\n <SelectValue placeholder={t('catalog.variants.form.pricesTaxNone', 'No tax override')}>\n {displayedSelectedTaxRate ? formatTaxRateLabel(displayedSelectedTaxRate) : undefined}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {displayedTaxRates.map((rate) => (\n <SelectItem key={rate.id} value={rate.id}>\n {formatTaxRateLabel(rate)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n ) : (\n <div className=\"flex justify-end\">\n <Select\n key={taxRateSelectKey}\n value={values.taxRateId || undefined}\n onValueChange={(value) => {\n if (value) setValue('taxRateId', value)\n }}\n >\n <SelectTrigger>\n <SelectValue placeholder={t('catalog.variants.form.pricesTaxNone', 'No tax override')}>\n {displayedSelectedTaxRate ? formatTaxRateLabel(displayedSelectedTaxRate) : undefined}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {displayedTaxRates.map((rate) => (\n <SelectItem key={rate.id} value={rate.id}>\n {formatTaxRateLabel(rate)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n <div className=\"space-y-3\">\n {priceKinds.length ? (\n priceKinds.map((kind) => {\n const draft = values.prices?.[kind.id]\n return (\n <div key={kind.id} className=\"rounded bg-muted/50 p-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-sm font-semibold\">{kind.title}</p>\n <p className=\"text-xs text-muted-foreground\">\n {kind.currencyCode\n ? `${kind.currencyCode.toUpperCase()} \u2022 ${kind.displayMode === 'including-tax' ? t('catalog.priceKinds.form.displayMode.include', 'Including tax') : t('catalog.priceKinds.form.displayMode.exclude', 'Excluding tax')}`\n : t('catalog.variants.form.priceMissingCurrency', 'No currency configured')}\n </p>\n </div>\n </div>\n <Input\n className=\"mt-3\"\n value={draft?.amount ?? ''}\n onInput={(event) => updatePrice(kind.id, { amount: event.currentTarget.value })}\n onChange={(event) => updatePrice(kind.id, { amount: event.target.value })}\n placeholder=\"0.00\"\n />\n </div>\n )\n })\n ) : (\n <p className=\"text-xs text-muted-foreground\">{t('catalog.variants.form.pricesEmpty', 'No price kinds configured yet.')}</p>\n )}\n </div>\n </div>\n )\n}\n\nexport function VariantMediaSection({ values, setValue, showLabel = true }: VariantMediaSectionProps) {\n const t = useT()\n return (\n <div className=\"space-y-2\">\n {showLabel ? <Label>{t('catalog.variants.form.media', 'Media')}</Label> : null}\n <ProductMediaManager\n entityId={E.catalog.catalog_product_variant}\n draftRecordId={values.mediaDraftId}\n items={Array.isArray(values.mediaItems) ? values.mediaItems : []}\n defaultMediaId={values.defaultMediaId}\n onItemsChange={(next) => setValue('mediaItems', next)}\n onDefaultChange={(next) => setValue('defaultMediaId', next)}\n />\n </div>\n )\n}\n\nfunction DimensionInput({\n label,\n value,\n onChange,\n placeholder = '0',\n}: {\n label: string\n value: string | number | undefined\n onChange: (next: string) => void\n placeholder?: string\n}) {\n return (\n <div className=\"space-y-2\">\n <Label className=\"text-xs uppercase text-muted-foreground\">{label}</Label>\n <Input value={value ?? ''} onChange={(event) => onChange(event.target.value)} placeholder={placeholder} />\n </div>\n )\n}\n\nfunction normalizeMetadata(input: unknown): Record<string, any> {\n return typeof input === 'object' && input ? { ...(input as Record<string, unknown>) } : {}\n}\n\nfunction normalizeDimensions(metadata: Record<string, any>) {\n const raw = metadata.dimensions\n if (!raw || typeof raw !== 'object') return {}\n return {\n width: typeof raw.width === 'number' ? raw.width : undefined,\n height: typeof raw.height === 'number' ? raw.height : undefined,\n depth: typeof raw.depth === 'number' ? raw.depth : undefined,\n unit: typeof raw.unit === 'string' ? raw.unit : undefined,\n }\n}\n\nfunction normalizeWeight(metadata: Record<string, any>) {\n const raw = metadata.weight\n if (!raw || typeof raw !== 'object') return {}\n return {\n value: typeof raw.value === 'number' ? raw.value : undefined,\n unit: typeof raw.unit === 'string' ? raw.unit : undefined,\n }\n}\n\nfunction applyDimension(metadata: Record<string, any>, field: 'width' | 'height' | 'depth' | 'unit', raw: string) {\n const dims = normalizeDimensions(metadata)\n if (field === 'unit') {\n dims.unit = raw\n } else {\n const numeric = Number(raw)\n dims[field] = Number.isNaN(numeric) ? undefined : numeric\n }\n const clean = cleanupDimensions(dims)\n if (clean) return { ...metadata, dimensions: clean }\n const copy = { ...metadata }\n delete copy.dimensions\n return copy\n}\n\nfunction applyWeight(metadata: Record<string, any>, field: 'value' | 'unit', raw: string) {\n const weight = normalizeWeight(metadata)\n if (field === 'unit') weight.unit = raw\n else {\n const numeric = Number(raw)\n weight.value = Number.isNaN(numeric) ? undefined : numeric\n }\n const clean = cleanupWeight(weight)\n if (clean) return { ...metadata, weight: clean }\n const copy = { ...metadata }\n delete copy.weight\n return copy\n}\n\nfunction cleanupDimensions(dims: { width?: number; height?: number; depth?: number; unit?: string }) {\n const clean: Record<string, unknown> = {}\n if (typeof dims.width === 'number' && Number.isFinite(dims.width)) clean.width = dims.width\n if (typeof dims.height === 'number' && Number.isFinite(dims.height)) clean.height = dims.height\n if (typeof dims.depth === 'number' && Number.isFinite(dims.depth)) clean.depth = dims.depth\n if (typeof dims.unit === 'string' && dims.unit.trim().length) clean.unit = dims.unit\n return Object.keys(clean).length ? clean : null\n}\n\nfunction cleanupWeight(weight: { value?: number; unit?: string }) {\n const clean: Record<string, unknown> = {}\n if (typeof weight.value === 'number' && Number.isFinite(weight.value)) clean.value = weight.value\n if (typeof weight.unit === 'string' && weight.unit.trim().length) clean.unit = weight.unit\n return Object.keys(clean).length ? clean : null\n}\n\nfunction stripSystemMetadata(metadata: Record<string, any>) {\n const copy: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(metadata)) {\n if (key === 'dimensions' || key === 'weight') continue\n copy[key] = value\n }\n return copy\n}\n\nfunction extractSystemMetadata(metadata: Record<string, any>) {\n const system: Record<string, unknown> = {}\n if (metadata.dimensions) system.dimensions = metadata.dimensions\n if (metadata.weight) system.weight = metadata.weight\n return system\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -709,7 +709,7 @@ function DisconnectChannelDialog({
|
|
|
709
709
|
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
710
710
|
/* @__PURE__ */ jsx("span", { className: "mr-auto text-xs text-muted-foreground", children: /* @__PURE__ */ jsx(KbdShortcut, { keys: ["\u2318", "Enter"] }) }),
|
|
711
711
|
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: onClose, disabled: submitting, children: t("communication_channels.profile.disconnect.cancel", "Cancel") }),
|
|
712
|
-
/* @__PURE__ */ jsx(Button, { type: "button", variant: "destructive", onClick: () => void handleConfirm(), disabled: submitting, children: submitting ? t("communication_channels.profile.disconnect.submitting", "Disconnecting\u2026") : t("communication_channels.profile.disconnect.confirm", "Disconnect") })
|
|
712
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "destructive-solid", onClick: () => void handleConfirm(), disabled: submitting, children: submitting ? t("communication_channels.profile.disconnect.submitting", "Disconnecting\u2026") : t("communication_channels.profile.disconnect.confirm", "Disconnect") })
|
|
713
713
|
] })
|
|
714
714
|
] }) });
|
|
715
715
|
}
|
package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/communication_channels/backend/profile/communication-channels/page.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/communication_channels/extension-points'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { KbdShortcut } from '@open-mercato/ui/primitives/kbd'\nimport { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype ChannelRow = {\n id: string\n providerKey: string\n channelType: string\n displayName: string\n externalIdentifier: string | null\n isPrimary: boolean\n isActive: boolean\n status: 'connected' | 'requires_reauth' | 'error' | 'disconnected'\n lastError: string | null\n pollIntervalSeconds: number | null\n lastPolledAt: string | null\n /** Spec C \u2014 push delivery state (null when provider doesn't support push). */\n pushStatus: 'active' | 'inactive' | 'failed' | null\n lastPushError: { code: string | null; message: string | null; at: string | null } | null\n createdAt: string | null\n}\n\nconst PROFILE_CHANNELS_MUTATION_CONTEXT_ID = 'communication-channels-profile'\nconst IMPORT_HISTORY_MUTATION_CONTEXT_ID = 'communication-channels-import-history'\nconst DISCONNECT_MUTATION_CONTEXT_ID = 'communication-channels-disconnect'\n\ntype ChannelMutationContext = {\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n}\n\nexport default function ProfileCommunicationChannelsPage() {\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const flashType = searchParams?.get('flash')\n const flashCode = searchParams?.get('code')\n const flashProvider = searchParams?.get('provider')\n\n const [rows, setRows] = React.useState<ChannelRow[]>([])\n const [isLoading, setIsLoading] = React.useState(true)\n const [errorMessage, setErrorMessage] = React.useState<string | null>(null)\n const [reloadKey, setReloadKey] = React.useState(0)\n const [importChannel, setImportChannel] = React.useState<ChannelRow | null>(null)\n const [disconnectChannel, setDisconnectChannel] = React.useState<ChannelRow | null>(null)\n const { runMutation, retryLastMutation } = useGuardedMutation<ChannelMutationContext>({\n contextId: PROFILE_CHANNELS_MUTATION_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n React.useEffect(() => {\n if (flashType === 'connected') {\n flash(\n flashProvider\n ? t('communication_channels.profile.flash.connectedWithProvider', 'Channel connected ({provider}).', {\n provider: flashProvider,\n })\n : t('communication_channels.profile.flash.connected', 'Channel connected.'),\n 'success',\n )\n } else if (flashType === 'error') {\n flash(\n flashCode === 'oauth_client_not_configured'\n ? t(\n 'communication_channels.profile.connect.notConfigured',\n 'This provider is not configured yet. Ask an administrator to add the OAuth Client ID and Secret under Integrations before connecting a mailbox.',\n )\n : flashCode === 'mailbox_already_connected'\n ? t(\n 'communication_channels.profile.connect.mailboxAlreadyConnected',\n 'This mailbox is already connected through another provider. Disconnect it first to reconnect it with a different one.',\n )\n : flashCode\n ? t('communication_channels.profile.flash.errorWithCode', 'Failed to connect channel \u2014 {code}.', {\n code: flashCode,\n })\n : t('communication_channels.profile.flash.error', 'Failed to connect channel.'),\n 'error',\n )\n }\n }, [flashType, flashCode, flashProvider, t])\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setIsLoading(true)\n setErrorMessage(null)\n const response = await apiCall<{ items?: ChannelRow[] }>(\n '/api/communication_channels/me/channels',\n ).catch((err: unknown) => ({\n ok: false,\n result: { error: err instanceof Error ? err.message : 'Failed to load channels' },\n }))\n if (cancelled) return\n if (!response.ok) {\n const body = response.result as { error?: string } | undefined\n setErrorMessage(\n body?.error ?? t('communication_channels.errors.loadList', 'Failed to load channels'),\n )\n setRows([])\n } else {\n const data = (response.result ?? {}) as { items?: ChannelRow[] }\n setRows(Array.isArray(data.items) ? data.items : [])\n }\n setIsLoading(false)\n }\n void load()\n return () => {\n cancelled = true\n }\n }, [reloadKey, t])\n\n const reauthRows = rows.filter((r) => r.status === 'requires_reauth')\n\n const onSetPrimary = React.useCallback(\n async (channelId: string) => {\n let response\n try {\n response = await runMutation({\n operation: () => apiCall(\n `/api/communication_channels/channels/${encodeURIComponent(channelId)}/set-primary`,\n { method: 'POST' },\n ),\n context: {\n formId: PROFILE_CHANNELS_MUTATION_CONTEXT_ID,\n resourceKind: 'communication_channels.channel',\n resourceId: channelId,\n retryLastMutation,\n },\n mutationPayload: { isPrimary: true },\n })\n } catch (err) {\n flash(err instanceof Error ? err.message : t('communication_channels.profile.actions.setPrimaryFailed', 'Failed to set as primary'), 'error')\n return\n }\n if (!response.ok) {\n const body = response.result as { error?: string } | undefined\n flash(\n body?.error ?? t('communication_channels.profile.actions.setPrimaryFailed', 'Failed to set as primary'),\n 'error',\n )\n return\n }\n flash(\n t('communication_channels.profile.actions.setPrimarySuccess', 'Marked as primary.'),\n 'success',\n )\n setReloadKey((k) => k + 1)\n },\n [retryLastMutation, runMutation, t],\n )\n\n const onRegisterPush = React.useCallback(\n async (channelId: string) => {\n let response\n try {\n response = await runMutation({\n operation: () => apiCall<{ pushStatus?: string; error?: { code: string; message: string } }>(\n `/api/communication_channels/channels/${encodeURIComponent(channelId)}/push/register`,\n { method: 'POST' },\n ),\n context: {\n formId: PROFILE_CHANNELS_MUTATION_CONTEXT_ID,\n resourceKind: 'communication_channels.channel',\n resourceId: channelId,\n retryLastMutation,\n },\n mutationPayload: { action: 'push-register' },\n })\n } catch (err) {\n flash(err instanceof Error ? err.message : t('communication_channels.push.button.reregister', 'Re-register push'), 'error')\n return\n }\n if (!response.ok) {\n const body = response.result as { error?: string } | undefined\n flash(body?.error ?? t('communication_channels.push.flash.registerFailed', 'Failed to register push'), 'error')\n return\n }\n const result = (response.result ?? {}) as { pushStatus?: string }\n if (result.pushStatus === 'active') {\n flash(t('communication_channels.push.status.active', 'Push active'), 'success')\n } else {\n flash(\n t(\n 'communication_channels.push.status.failed',\n 'Push registration returned a non-active status \u2014 falling back to polling.',\n ),\n 'error',\n )\n }\n setReloadKey((k) => k + 1)\n },\n [retryLastMutation, runMutation, t],\n )\n\n const onPollNow = React.useCallback(\n async (channelId: string) => {\n let response\n try {\n response = await runMutation({\n operation: () => apiCall(\n `/api/communication_channels/channels/${encodeURIComponent(channelId)}/poll-now`,\n { method: 'POST' },\n ),\n context: {\n formId: PROFILE_CHANNELS_MUTATION_CONTEXT_ID,\n resourceKind: 'communication_channels.channel',\n resourceId: channelId,\n retryLastMutation,\n },\n mutationPayload: { action: 'poll-now' },\n })\n } catch (err) {\n flash(err instanceof Error ? err.message : t('communication_channels.profile.actions.pollNowFailed', 'Failed to trigger poll'), 'error')\n return\n }\n if (!response.ok) {\n const body = response.result as { error?: string } | undefined\n flash(\n body?.error ?? t('communication_channels.profile.actions.pollNowFailed', 'Failed to trigger poll'),\n 'error',\n )\n return\n }\n flash(\n t(\n 'communication_channels.profile.actions.pollNowSuccess',\n 'Poll triggered \u2014 new messages will appear on linked Person timelines in a few seconds.',\n ),\n 'success',\n )\n // Give the worker a moment to fetch + ingest, then refetch our channel list\n // so `lastPolledAt` updates in the UI.\n setTimeout(() => setReloadKey((k) => k + 1), 1500)\n },\n [retryLastMutation, runMutation, t],\n )\n\n const columns = React.useMemo<ColumnDef<ChannelRow>[]>(\n () => [\n {\n header: t('communication_channels.columns.displayName', 'Channel'),\n accessorKey: 'displayName',\n },\n {\n header: t('communication_channels.columns.provider', 'Provider'),\n accessorKey: 'providerKey',\n cell: ({ row }) => (\n <Tag variant=\"info\">\n {t(\n `communication_channels.channel.providers.${row.original.providerKey}`,\n row.original.providerKey,\n )}\n </Tag>\n ),\n },\n {\n header: t('communication_channels.columns.identifier', 'Email / username'),\n accessorKey: 'externalIdentifier',\n cell: ({ row }) => row.original.externalIdentifier ?? '\u2014',\n meta: { truncate: true, maxWidth: 240 },\n },\n {\n header: t('communication_channels.profile.columns.primary', 'Primary'),\n accessorKey: 'isPrimary',\n cell: ({ row }) =>\n row.original.isPrimary ? (\n <Tag variant=\"success\" dot>\n {t('communication_channels.profile.primary', 'Primary')}\n </Tag>\n ) : (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void onSetPrimary(row.original.id)}\n aria-label={t('communication_channels.profile.actions.setPrimary', 'Set as primary')}\n >\n {t('communication_channels.profile.actions.setPrimary', 'Set as primary')}\n </Button>\n ),\n },\n {\n header: t('communication_channels.columns.status', 'Status'),\n accessorKey: 'status',\n cell: ({ row }) => statusTag(row.original.status, t),\n },\n {\n id: 'pushStatus',\n header: t('communication_channels.push.status.active', 'Push'),\n cell: ({ row }) => {\n const supportsPush = row.original.providerKey === 'gmail'\n if (!supportsPush) {\n return (\n <span className=\"text-xs text-muted-foreground\">\n {t('communication_channels.push.status.inactive', 'Polling only')}\n </span>\n )\n }\n const ps = row.original.pushStatus\n if (ps === 'active') {\n return (\n <Tag variant=\"success\" dot>\n {t('communication_channels.push.status.active', 'Push active')}\n </Tag>\n )\n }\n if (ps === 'failed') {\n const errorMsg = row.original.lastPushError?.message ?? null\n return (\n <div className=\"flex items-center gap-2\">\n <Tag variant=\"error\" dot>\n {t('communication_channels.push.status.failed', 'Push failed \u2014 using polling')}\n </Tag>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void onRegisterPush(row.original.id)}\n aria-label={t('communication_channels.push.button.reregister', 'Re-register push')}\n title={errorMsg ?? undefined}\n >\n {t('communication_channels.push.button.reregister', 'Re-register push')}\n </Button>\n </div>\n )\n }\n // null or 'inactive' \u2014 provider supports push but not registered yet.\n return (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-muted-foreground\">\n {t('communication_channels.push.status.inactive', 'Polling only')}\n </span>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void onRegisterPush(row.original.id)}\n aria-label={t('communication_channels.push.button.reregister', 'Re-register push')}\n >\n {t('communication_channels.push.button.reregister', 'Re-register push')}\n </Button>\n </div>\n )\n },\n },\n {\n header: t('communication_channels.profile.columns.lastPolled', 'Last synced'),\n accessorKey: 'lastPolledAt',\n cell: ({ row }) =>\n row.original.lastPolledAt\n ? new Date(row.original.lastPolledAt).toLocaleString()\n : '\u2014',\n },\n {\n id: 'importHistory',\n header: t('communication_channels.profile.columns.importHistory', 'History'),\n cell: ({ row }) => {\n const eligible =\n row.original.isActive &&\n row.original.status === 'connected' &&\n row.original.channelType === 'email'\n const label = t('communication_channels.profile.actions.importHistory', 'Import history')\n return (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setImportChannel(row.original)}\n disabled={!eligible}\n aria-label={label}\n >\n {label}\n </Button>\n )\n },\n },\n {\n id: 'pollNow',\n header: t('communication_channels.profile.columns.pollNow', 'Sync'),\n cell: ({ row }) => {\n // Allowed from 'connected' AND 'error' \u2014 the latter lets the user\n // recover a stuck channel without disconnecting + reconnecting.\n // 'requires_reauth' and 'disconnected' are owned by other flows.\n const pollable =\n row.original.isActive &&\n (row.original.status === 'connected' || row.original.status === 'error')\n const label =\n row.original.status === 'error'\n ? t('communication_channels.profile.actions.retryPoll', 'Retry')\n : t('communication_channels.profile.actions.pollNow', 'Poll now')\n return (\n <Button\n type=\"button\"\n variant={row.original.status === 'error' ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => void onPollNow(row.original.id)}\n disabled={!pollable}\n aria-label={label}\n >\n {label}\n </Button>\n )\n },\n },\n {\n id: 'disconnect',\n header: t('communication_channels.profile.columns.disconnect', 'Connection'),\n cell: ({ row }) => {\n const label = t('communication_channels.profile.actions.disconnect', 'Disconnect')\n return (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setDisconnectChannel(row.original)}\n aria-label={label}\n >\n {label}\n </Button>\n )\n },\n },\n ],\n [onSetPrimary, onPollNow, onRegisterPush, t],\n )\n\n return (\n <Page>\n <PageBody>\n <header className=\"mb-4 flex items-baseline justify-between\">\n <div>\n <h2 className=\"text-2xl font-semibold\">\n {t('communication_channels.profile.title', 'My communication channels')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\n 'communication_channels.profile.subtitle',\n 'Connect your personal mailbox so outbound messages come from your address and inbound emails land in your unified inbox.',\n )}\n </p>\n </div>\n {/* Provider connect entry points injected by each channel-* package\n (channel-gmail, channel-imap) via UMES. */}\n <InjectionSpot\n spotId={extensionPoints.hosts.profileConnect.spotId}\n context={{ reload: () => setReloadKey((k) => k + 1) }}\n data={{}}\n />\n </header>\n\n {reauthRows.length > 0 ? (\n <Alert variant=\"warning\" className=\"mb-4\">\n <AlertDescription>\n {t(\n 'communication_channels.profile.alerts.requiresReauth',\n '{count} channel(s) need reconnection. Click \"Reconnect\" on the affected channel below.',\n { count: reauthRows.length },\n )}\n </AlertDescription>\n </Alert>\n ) : null}\n\n <DataTable<ChannelRow>\n title={t('communication_channels.profile.tableTitle', 'Your channels')}\n extensionTableId={extensionPoints.hosts.profileChannelsTable.tableId}\n columns={columns}\n data={rows}\n isLoading={isLoading}\n error={errorMessage}\n emptyState={t(\n 'communication_channels.profile.empty',\n 'You have no connected channels yet. Use the \"Connect channel\" entry above to add Gmail or IMAP.',\n )}\n />\n <ImportHistoryDialog\n channel={importChannel}\n onClose={() => setImportChannel(null)}\n onQueued={() => {\n setImportChannel(null)\n router.refresh()\n }}\n />\n <DisconnectChannelDialog\n channel={disconnectChannel}\n onClose={() => setDisconnectChannel(null)}\n onDisconnected={() => {\n setDisconnectChannel(null)\n setReloadKey((k) => k + 1)\n }}\n />\n </PageBody>\n </Page>\n )\n}\n\ntype ImportHistoryDialogProps = {\n channel: ChannelRow | null\n onClose: () => void\n onQueued: () => void\n}\n\nfunction ImportHistoryDialog({ channel, onClose, onQueued }: ImportHistoryDialogProps): React.JSX.Element {\n const t = useT()\n const [sinceDays, setSinceDays] = React.useState('30')\n const [contactEmails, setContactEmails] = React.useState('')\n const [maxMessages, setMaxMessages] = React.useState('500')\n const [fieldErrors, setFieldErrors] = React.useState<Record<string, string>>({})\n const [submitting, setSubmitting] = React.useState(false)\n const { runMutation, retryLastMutation } = useGuardedMutation<ChannelMutationContext>({\n contextId: IMPORT_HISTORY_MUTATION_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n React.useEffect(() => {\n if (channel) {\n setSinceDays('30')\n setContactEmails('')\n setMaxMessages('500')\n setFieldErrors({})\n setSubmitting(false)\n }\n }, [channel?.id])\n\n const handleSubmit = React.useCallback(async () => {\n if (!channel || submitting) return\n const sinceNum = Number.parseInt(sinceDays, 10)\n const maxNum = Number.parseInt(maxMessages, 10)\n const errors: Record<string, string> = {}\n if (!Number.isFinite(sinceNum) || sinceNum < 1 || sinceNum > 365) {\n errors.sinceDays = t(\n 'communication_channels.profile.importHistory.errors.sinceDays',\n 'Choose a number between 1 and 365 days.',\n )\n }\n if (!Number.isFinite(maxNum) || maxNum < 1 || maxNum > 5000) {\n errors.maxMessages = t(\n 'communication_channels.profile.importHistory.errors.maxMessages',\n 'Choose a number between 1 and 5000 messages.',\n )\n }\n const parsedEmails = contactEmails\n .split(/[\\s,;]+/)\n .map((s) => s.trim())\n .filter(Boolean)\n if (parsedEmails.length > 0 && parsedEmails.some((s) => !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(s))) {\n errors.contactEmails = t(\n 'communication_channels.profile.importHistory.errors.contactEmails',\n 'One or more entries is not a valid email address.',\n )\n }\n if (Object.keys(errors).length > 0) {\n setFieldErrors(errors)\n return\n }\n setFieldErrors({})\n setSubmitting(true)\n const mutationPayload = {\n sinceDays: sinceNum,\n maxMessages: maxNum,\n ...(parsedEmails.length > 0 ? { contactEmails: parsedEmails } : {}),\n }\n let response\n try {\n response = await runMutation({\n operation: () => apiCall<{ progressJobId?: string }>(\n `/api/communication_channels/channels/${encodeURIComponent(channel.id)}/import-history`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(mutationPayload),\n },\n ),\n context: {\n formId: IMPORT_HISTORY_MUTATION_CONTEXT_ID,\n resourceKind: 'communication_channels.channel',\n resourceId: channel.id,\n retryLastMutation,\n },\n mutationPayload,\n })\n } catch (err) {\n setSubmitting(false)\n flash(\n err instanceof Error\n ? err.message\n : t('communication_channels.profile.importHistory.flash.error', 'Failed to queue history import.'),\n 'error',\n )\n return\n }\n setSubmitting(false)\n if (!response.ok) {\n const body = response.result as { error?: string; fieldErrors?: Record<string, string> } | undefined\n if (body?.fieldErrors && Object.keys(body.fieldErrors).length > 0) {\n setFieldErrors(body.fieldErrors)\n return\n }\n flash(\n body?.error ??\n t(\n 'communication_channels.profile.importHistory.flash.error',\n 'Failed to queue history import.',\n ),\n 'error',\n )\n return\n }\n flash(\n t(\n 'communication_channels.profile.importHistory.flash.success',\n 'History import queued \u2014 track progress in the top bar.',\n ),\n 'success',\n )\n onQueued()\n }, [channel, sinceDays, maxMessages, contactEmails, submitting, t, onQueued, retryLastMutation, runMutation])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n void handleSubmit()\n }\n },\n [handleSubmit],\n )\n\n return (\n <Dialog open={channel !== null} onOpenChange={(open) => { if (!open) onClose() }}>\n <DialogContent onKeyDown={handleKeyDown}>\n <DialogHeader>\n <DialogTitle>\n {t('communication_channels.profile.importHistory.title', 'Import channel history')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'communication_channels.profile.importHistory.description',\n 'Pull older messages this channel never observed at connect-time. Filters narrow the search server-side.',\n )}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-1\">\n <Label htmlFor=\"import-history-since\">\n {t('communication_channels.profile.importHistory.fields.sinceDays', 'Look back (days)')}\n </Label>\n <Input\n id=\"import-history-since\"\n type=\"number\"\n min={1}\n max={365}\n value={sinceDays}\n onChange={(e) => setSinceDays(e.target.value)}\n aria-invalid={Boolean(fieldErrors.sinceDays)}\n />\n {fieldErrors.sinceDays ? (\n <p className=\"text-xs text-status-error-text\">{fieldErrors.sinceDays}</p>\n ) : null}\n </div>\n\n <div className=\"space-y-1\">\n <Label htmlFor=\"import-history-emails\">\n {t(\n 'communication_channels.profile.importHistory.fields.contactEmails',\n 'Filter by sender (optional)',\n )}\n </Label>\n <Textarea\n id=\"import-history-emails\"\n rows={3}\n value={contactEmails}\n onChange={(e) => setContactEmails(e.target.value)}\n placeholder={t(\n 'communication_channels.profile.importHistory.fields.contactEmailsPlaceholder',\n 'alice@example.com, bob@example.com',\n )}\n aria-invalid={Boolean(fieldErrors.contactEmails)}\n />\n {fieldErrors.contactEmails ? (\n <p className=\"text-xs text-status-error-text\">{fieldErrors.contactEmails}</p>\n ) : (\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'communication_channels.profile.importHistory.fields.contactEmailsHint',\n 'Leave empty to scan all senders in the window.',\n )}\n </p>\n )}\n </div>\n\n <div className=\"space-y-1\">\n <Label htmlFor=\"import-history-max\">\n {t('communication_channels.profile.importHistory.fields.maxMessages', 'Maximum messages')}\n </Label>\n <Input\n id=\"import-history-max\"\n type=\"number\"\n min={1}\n max={5000}\n value={maxMessages}\n onChange={(e) => setMaxMessages(e.target.value)}\n aria-invalid={Boolean(fieldErrors.maxMessages)}\n />\n {fieldErrors.maxMessages ? (\n <p className=\"text-xs text-status-error-text\">{fieldErrors.maxMessages}</p>\n ) : null}\n </div>\n\n {fieldErrors.channelId ? (\n <Alert variant=\"warning\">\n <AlertDescription>{fieldErrors.channelId}</AlertDescription>\n </Alert>\n ) : null}\n </div>\n\n <DialogFooter>\n <span className=\"mr-auto text-xs text-muted-foreground\">\n <KbdShortcut keys={['\u2318', 'Enter']} />\n </span>\n <Button type=\"button\" variant=\"outline\" onClick={onClose} disabled={submitting}>\n {t('communication_channels.profile.importHistory.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={() => void handleSubmit()} disabled={submitting}>\n {submitting\n ? t('communication_channels.profile.importHistory.submitting', 'Queueing\u2026')\n : t('communication_channels.profile.importHistory.submit', 'Start import')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n\ntype DisconnectChannelDialogProps = {\n channel: ChannelRow | null\n onClose: () => void\n onDisconnected: () => void\n}\n\nfunction DisconnectChannelDialog({\n channel,\n onClose,\n onDisconnected,\n}: DisconnectChannelDialogProps): React.JSX.Element {\n const t = useT()\n const [submitting, setSubmitting] = React.useState(false)\n const { runMutation, retryLastMutation } = useGuardedMutation<ChannelMutationContext>({\n contextId: DISCONNECT_MUTATION_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n React.useEffect(() => {\n if (channel) setSubmitting(false)\n }, [channel?.id])\n\n const handleConfirm = React.useCallback(async () => {\n if (!channel || submitting) return\n setSubmitting(true)\n let response\n try {\n response = await runMutation({\n // optimistic-lock-exempt: self-service connect/disconnect of the\n // signed-in operator's OWN communication channel (an integration link),\n // not a shared multi-editor record. Disconnect is a terminal action\n // keyed by channel id; there is no concurrent-edit lost-update window to\n // guard, and the row carries no client-surfaced `updatedAt` round-trip.\n operation: () => apiCall(\n `/api/communication_channels/channels/${encodeURIComponent(channel.id)}`,\n { method: 'DELETE' },\n ),\n context: {\n formId: DISCONNECT_MUTATION_CONTEXT_ID,\n resourceKind: 'communication_channels.channel',\n resourceId: channel.id,\n retryLastMutation,\n },\n mutationPayload: { action: 'disconnect' },\n })\n } catch (err) {\n setSubmitting(false)\n flash(\n err instanceof Error\n ? err.message\n : t('communication_channels.profile.actions.disconnectFailed', 'Failed to disconnect channel'),\n 'error',\n )\n return\n }\n setSubmitting(false)\n if (!response.ok) {\n const body = response.result as { error?: string } | undefined\n flash(\n body?.error ??\n t('communication_channels.profile.actions.disconnectFailed', 'Failed to disconnect channel'),\n 'error',\n )\n return\n }\n flash(\n t(\n 'communication_channels.profile.actions.disconnectSuccess',\n 'Channel disconnected. You can reconnect it anytime.',\n ),\n 'success',\n )\n onDisconnected()\n }, [channel, submitting, runMutation, retryLastMutation, t, onDisconnected])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n void handleConfirm()\n }\n },\n [handleConfirm],\n )\n\n return (\n <Dialog open={channel !== null} onOpenChange={(open) => { if (!open) onClose() }}>\n <DialogContent onKeyDown={handleKeyDown}>\n <DialogHeader>\n <DialogTitle>\n {t('communication_channels.profile.disconnect.title', 'Disconnect channel')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'communication_channels.profile.disconnect.description',\n 'This removes the connection and stops syncing. Emails already imported stay on your timelines. You can reconnect anytime.',\n )}\n </DialogDescription>\n </DialogHeader>\n\n {channel ? (\n <p className=\"text-sm font-medium\">{channel.externalIdentifier ?? channel.displayName}</p>\n ) : null}\n\n <DialogFooter>\n <span className=\"mr-auto text-xs text-muted-foreground\">\n <KbdShortcut keys={['\u2318', 'Enter']} />\n </span>\n <Button type=\"button\" variant=\"outline\" onClick={onClose} disabled={submitting}>\n {t('communication_channels.profile.disconnect.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"destructive\" onClick={() => void handleConfirm()} disabled={submitting}>\n {submitting\n ? t('communication_channels.profile.disconnect.submitting', 'Disconnecting\u2026')\n : t('communication_channels.profile.disconnect.confirm', 'Disconnect')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n\nfunction statusTag(\n status: ChannelRow['status'],\n t: (key: string, fallback?: string) => string,\n): React.ReactNode {\n switch (status) {\n case 'connected':\n return (\n <Tag variant=\"success\" dot>\n {t('communication_channels.status.connected', 'Connected')}\n </Tag>\n )\n case 'requires_reauth':\n return (\n <Tag variant=\"warning\" dot>\n {t('communication_channels.status.requiresReauth', 'Needs reconnection')}\n </Tag>\n )\n case 'error':\n return (\n <Tag variant=\"error\" dot>\n {t('communication_channels.status.error', 'Error')}\n </Tag>\n )\n case 'disconnected':\n return <Tag variant=\"neutral\">{t('communication_channels.status.disconnected', 'Disconnected')}</Tag>\n default:\n return <Tag variant=\"neutral\">{status}</Tag>\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/communication_channels/extension-points'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { KbdShortcut } from '@open-mercato/ui/primitives/kbd'\nimport { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype ChannelRow = {\n id: string\n providerKey: string\n channelType: string\n displayName: string\n externalIdentifier: string | null\n isPrimary: boolean\n isActive: boolean\n status: 'connected' | 'requires_reauth' | 'error' | 'disconnected'\n lastError: string | null\n pollIntervalSeconds: number | null\n lastPolledAt: string | null\n /** Spec C \u2014 push delivery state (null when provider doesn't support push). */\n pushStatus: 'active' | 'inactive' | 'failed' | null\n lastPushError: { code: string | null; message: string | null; at: string | null } | null\n createdAt: string | null\n}\n\nconst PROFILE_CHANNELS_MUTATION_CONTEXT_ID = 'communication-channels-profile'\nconst IMPORT_HISTORY_MUTATION_CONTEXT_ID = 'communication-channels-import-history'\nconst DISCONNECT_MUTATION_CONTEXT_ID = 'communication-channels-disconnect'\n\ntype ChannelMutationContext = {\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n}\n\nexport default function ProfileCommunicationChannelsPage() {\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const flashType = searchParams?.get('flash')\n const flashCode = searchParams?.get('code')\n const flashProvider = searchParams?.get('provider')\n\n const [rows, setRows] = React.useState<ChannelRow[]>([])\n const [isLoading, setIsLoading] = React.useState(true)\n const [errorMessage, setErrorMessage] = React.useState<string | null>(null)\n const [reloadKey, setReloadKey] = React.useState(0)\n const [importChannel, setImportChannel] = React.useState<ChannelRow | null>(null)\n const [disconnectChannel, setDisconnectChannel] = React.useState<ChannelRow | null>(null)\n const { runMutation, retryLastMutation } = useGuardedMutation<ChannelMutationContext>({\n contextId: PROFILE_CHANNELS_MUTATION_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n React.useEffect(() => {\n if (flashType === 'connected') {\n flash(\n flashProvider\n ? t('communication_channels.profile.flash.connectedWithProvider', 'Channel connected ({provider}).', {\n provider: flashProvider,\n })\n : t('communication_channels.profile.flash.connected', 'Channel connected.'),\n 'success',\n )\n } else if (flashType === 'error') {\n flash(\n flashCode === 'oauth_client_not_configured'\n ? t(\n 'communication_channels.profile.connect.notConfigured',\n 'This provider is not configured yet. Ask an administrator to add the OAuth Client ID and Secret under Integrations before connecting a mailbox.',\n )\n : flashCode === 'mailbox_already_connected'\n ? t(\n 'communication_channels.profile.connect.mailboxAlreadyConnected',\n 'This mailbox is already connected through another provider. Disconnect it first to reconnect it with a different one.',\n )\n : flashCode\n ? t('communication_channels.profile.flash.errorWithCode', 'Failed to connect channel \u2014 {code}.', {\n code: flashCode,\n })\n : t('communication_channels.profile.flash.error', 'Failed to connect channel.'),\n 'error',\n )\n }\n }, [flashType, flashCode, flashProvider, t])\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setIsLoading(true)\n setErrorMessage(null)\n const response = await apiCall<{ items?: ChannelRow[] }>(\n '/api/communication_channels/me/channels',\n ).catch((err: unknown) => ({\n ok: false,\n result: { error: err instanceof Error ? err.message : 'Failed to load channels' },\n }))\n if (cancelled) return\n if (!response.ok) {\n const body = response.result as { error?: string } | undefined\n setErrorMessage(\n body?.error ?? t('communication_channels.errors.loadList', 'Failed to load channels'),\n )\n setRows([])\n } else {\n const data = (response.result ?? {}) as { items?: ChannelRow[] }\n setRows(Array.isArray(data.items) ? data.items : [])\n }\n setIsLoading(false)\n }\n void load()\n return () => {\n cancelled = true\n }\n }, [reloadKey, t])\n\n const reauthRows = rows.filter((r) => r.status === 'requires_reauth')\n\n const onSetPrimary = React.useCallback(\n async (channelId: string) => {\n let response\n try {\n response = await runMutation({\n operation: () => apiCall(\n `/api/communication_channels/channels/${encodeURIComponent(channelId)}/set-primary`,\n { method: 'POST' },\n ),\n context: {\n formId: PROFILE_CHANNELS_MUTATION_CONTEXT_ID,\n resourceKind: 'communication_channels.channel',\n resourceId: channelId,\n retryLastMutation,\n },\n mutationPayload: { isPrimary: true },\n })\n } catch (err) {\n flash(err instanceof Error ? err.message : t('communication_channels.profile.actions.setPrimaryFailed', 'Failed to set as primary'), 'error')\n return\n }\n if (!response.ok) {\n const body = response.result as { error?: string } | undefined\n flash(\n body?.error ?? t('communication_channels.profile.actions.setPrimaryFailed', 'Failed to set as primary'),\n 'error',\n )\n return\n }\n flash(\n t('communication_channels.profile.actions.setPrimarySuccess', 'Marked as primary.'),\n 'success',\n )\n setReloadKey((k) => k + 1)\n },\n [retryLastMutation, runMutation, t],\n )\n\n const onRegisterPush = React.useCallback(\n async (channelId: string) => {\n let response\n try {\n response = await runMutation({\n operation: () => apiCall<{ pushStatus?: string; error?: { code: string; message: string } }>(\n `/api/communication_channels/channels/${encodeURIComponent(channelId)}/push/register`,\n { method: 'POST' },\n ),\n context: {\n formId: PROFILE_CHANNELS_MUTATION_CONTEXT_ID,\n resourceKind: 'communication_channels.channel',\n resourceId: channelId,\n retryLastMutation,\n },\n mutationPayload: { action: 'push-register' },\n })\n } catch (err) {\n flash(err instanceof Error ? err.message : t('communication_channels.push.button.reregister', 'Re-register push'), 'error')\n return\n }\n if (!response.ok) {\n const body = response.result as { error?: string } | undefined\n flash(body?.error ?? t('communication_channels.push.flash.registerFailed', 'Failed to register push'), 'error')\n return\n }\n const result = (response.result ?? {}) as { pushStatus?: string }\n if (result.pushStatus === 'active') {\n flash(t('communication_channels.push.status.active', 'Push active'), 'success')\n } else {\n flash(\n t(\n 'communication_channels.push.status.failed',\n 'Push registration returned a non-active status \u2014 falling back to polling.',\n ),\n 'error',\n )\n }\n setReloadKey((k) => k + 1)\n },\n [retryLastMutation, runMutation, t],\n )\n\n const onPollNow = React.useCallback(\n async (channelId: string) => {\n let response\n try {\n response = await runMutation({\n operation: () => apiCall(\n `/api/communication_channels/channels/${encodeURIComponent(channelId)}/poll-now`,\n { method: 'POST' },\n ),\n context: {\n formId: PROFILE_CHANNELS_MUTATION_CONTEXT_ID,\n resourceKind: 'communication_channels.channel',\n resourceId: channelId,\n retryLastMutation,\n },\n mutationPayload: { action: 'poll-now' },\n })\n } catch (err) {\n flash(err instanceof Error ? err.message : t('communication_channels.profile.actions.pollNowFailed', 'Failed to trigger poll'), 'error')\n return\n }\n if (!response.ok) {\n const body = response.result as { error?: string } | undefined\n flash(\n body?.error ?? t('communication_channels.profile.actions.pollNowFailed', 'Failed to trigger poll'),\n 'error',\n )\n return\n }\n flash(\n t(\n 'communication_channels.profile.actions.pollNowSuccess',\n 'Poll triggered \u2014 new messages will appear on linked Person timelines in a few seconds.',\n ),\n 'success',\n )\n // Give the worker a moment to fetch + ingest, then refetch our channel list\n // so `lastPolledAt` updates in the UI.\n setTimeout(() => setReloadKey((k) => k + 1), 1500)\n },\n [retryLastMutation, runMutation, t],\n )\n\n const columns = React.useMemo<ColumnDef<ChannelRow>[]>(\n () => [\n {\n header: t('communication_channels.columns.displayName', 'Channel'),\n accessorKey: 'displayName',\n },\n {\n header: t('communication_channels.columns.provider', 'Provider'),\n accessorKey: 'providerKey',\n cell: ({ row }) => (\n <Tag variant=\"info\">\n {t(\n `communication_channels.channel.providers.${row.original.providerKey}`,\n row.original.providerKey,\n )}\n </Tag>\n ),\n },\n {\n header: t('communication_channels.columns.identifier', 'Email / username'),\n accessorKey: 'externalIdentifier',\n cell: ({ row }) => row.original.externalIdentifier ?? '\u2014',\n meta: { truncate: true, maxWidth: 240 },\n },\n {\n header: t('communication_channels.profile.columns.primary', 'Primary'),\n accessorKey: 'isPrimary',\n cell: ({ row }) =>\n row.original.isPrimary ? (\n <Tag variant=\"success\" dot>\n {t('communication_channels.profile.primary', 'Primary')}\n </Tag>\n ) : (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void onSetPrimary(row.original.id)}\n aria-label={t('communication_channels.profile.actions.setPrimary', 'Set as primary')}\n >\n {t('communication_channels.profile.actions.setPrimary', 'Set as primary')}\n </Button>\n ),\n },\n {\n header: t('communication_channels.columns.status', 'Status'),\n accessorKey: 'status',\n cell: ({ row }) => statusTag(row.original.status, t),\n },\n {\n id: 'pushStatus',\n header: t('communication_channels.push.status.active', 'Push'),\n cell: ({ row }) => {\n const supportsPush = row.original.providerKey === 'gmail'\n if (!supportsPush) {\n return (\n <span className=\"text-xs text-muted-foreground\">\n {t('communication_channels.push.status.inactive', 'Polling only')}\n </span>\n )\n }\n const ps = row.original.pushStatus\n if (ps === 'active') {\n return (\n <Tag variant=\"success\" dot>\n {t('communication_channels.push.status.active', 'Push active')}\n </Tag>\n )\n }\n if (ps === 'failed') {\n const errorMsg = row.original.lastPushError?.message ?? null\n return (\n <div className=\"flex items-center gap-2\">\n <Tag variant=\"error\" dot>\n {t('communication_channels.push.status.failed', 'Push failed \u2014 using polling')}\n </Tag>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void onRegisterPush(row.original.id)}\n aria-label={t('communication_channels.push.button.reregister', 'Re-register push')}\n title={errorMsg ?? undefined}\n >\n {t('communication_channels.push.button.reregister', 'Re-register push')}\n </Button>\n </div>\n )\n }\n // null or 'inactive' \u2014 provider supports push but not registered yet.\n return (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-muted-foreground\">\n {t('communication_channels.push.status.inactive', 'Polling only')}\n </span>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void onRegisterPush(row.original.id)}\n aria-label={t('communication_channels.push.button.reregister', 'Re-register push')}\n >\n {t('communication_channels.push.button.reregister', 'Re-register push')}\n </Button>\n </div>\n )\n },\n },\n {\n header: t('communication_channels.profile.columns.lastPolled', 'Last synced'),\n accessorKey: 'lastPolledAt',\n cell: ({ row }) =>\n row.original.lastPolledAt\n ? new Date(row.original.lastPolledAt).toLocaleString()\n : '\u2014',\n },\n {\n id: 'importHistory',\n header: t('communication_channels.profile.columns.importHistory', 'History'),\n cell: ({ row }) => {\n const eligible =\n row.original.isActive &&\n row.original.status === 'connected' &&\n row.original.channelType === 'email'\n const label = t('communication_channels.profile.actions.importHistory', 'Import history')\n return (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setImportChannel(row.original)}\n disabled={!eligible}\n aria-label={label}\n >\n {label}\n </Button>\n )\n },\n },\n {\n id: 'pollNow',\n header: t('communication_channels.profile.columns.pollNow', 'Sync'),\n cell: ({ row }) => {\n // Allowed from 'connected' AND 'error' \u2014 the latter lets the user\n // recover a stuck channel without disconnecting + reconnecting.\n // 'requires_reauth' and 'disconnected' are owned by other flows.\n const pollable =\n row.original.isActive &&\n (row.original.status === 'connected' || row.original.status === 'error')\n const label =\n row.original.status === 'error'\n ? t('communication_channels.profile.actions.retryPoll', 'Retry')\n : t('communication_channels.profile.actions.pollNow', 'Poll now')\n return (\n <Button\n type=\"button\"\n variant={row.original.status === 'error' ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => void onPollNow(row.original.id)}\n disabled={!pollable}\n aria-label={label}\n >\n {label}\n </Button>\n )\n },\n },\n {\n id: 'disconnect',\n header: t('communication_channels.profile.columns.disconnect', 'Connection'),\n cell: ({ row }) => {\n const label = t('communication_channels.profile.actions.disconnect', 'Disconnect')\n return (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setDisconnectChannel(row.original)}\n aria-label={label}\n >\n {label}\n </Button>\n )\n },\n },\n ],\n [onSetPrimary, onPollNow, onRegisterPush, t],\n )\n\n return (\n <Page>\n <PageBody>\n <header className=\"mb-4 flex items-baseline justify-between\">\n <div>\n <h2 className=\"text-2xl font-semibold\">\n {t('communication_channels.profile.title', 'My communication channels')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\n 'communication_channels.profile.subtitle',\n 'Connect your personal mailbox so outbound messages come from your address and inbound emails land in your unified inbox.',\n )}\n </p>\n </div>\n {/* Provider connect entry points injected by each channel-* package\n (channel-gmail, channel-imap) via UMES. */}\n <InjectionSpot\n spotId={extensionPoints.hosts.profileConnect.spotId}\n context={{ reload: () => setReloadKey((k) => k + 1) }}\n data={{}}\n />\n </header>\n\n {reauthRows.length > 0 ? (\n <Alert variant=\"warning\" className=\"mb-4\">\n <AlertDescription>\n {t(\n 'communication_channels.profile.alerts.requiresReauth',\n '{count} channel(s) need reconnection. Click \"Reconnect\" on the affected channel below.',\n { count: reauthRows.length },\n )}\n </AlertDescription>\n </Alert>\n ) : null}\n\n <DataTable<ChannelRow>\n title={t('communication_channels.profile.tableTitle', 'Your channels')}\n extensionTableId={extensionPoints.hosts.profileChannelsTable.tableId}\n columns={columns}\n data={rows}\n isLoading={isLoading}\n error={errorMessage}\n emptyState={t(\n 'communication_channels.profile.empty',\n 'You have no connected channels yet. Use the \"Connect channel\" entry above to add Gmail or IMAP.',\n )}\n />\n <ImportHistoryDialog\n channel={importChannel}\n onClose={() => setImportChannel(null)}\n onQueued={() => {\n setImportChannel(null)\n router.refresh()\n }}\n />\n <DisconnectChannelDialog\n channel={disconnectChannel}\n onClose={() => setDisconnectChannel(null)}\n onDisconnected={() => {\n setDisconnectChannel(null)\n setReloadKey((k) => k + 1)\n }}\n />\n </PageBody>\n </Page>\n )\n}\n\ntype ImportHistoryDialogProps = {\n channel: ChannelRow | null\n onClose: () => void\n onQueued: () => void\n}\n\nfunction ImportHistoryDialog({ channel, onClose, onQueued }: ImportHistoryDialogProps): React.JSX.Element {\n const t = useT()\n const [sinceDays, setSinceDays] = React.useState('30')\n const [contactEmails, setContactEmails] = React.useState('')\n const [maxMessages, setMaxMessages] = React.useState('500')\n const [fieldErrors, setFieldErrors] = React.useState<Record<string, string>>({})\n const [submitting, setSubmitting] = React.useState(false)\n const { runMutation, retryLastMutation } = useGuardedMutation<ChannelMutationContext>({\n contextId: IMPORT_HISTORY_MUTATION_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n React.useEffect(() => {\n if (channel) {\n setSinceDays('30')\n setContactEmails('')\n setMaxMessages('500')\n setFieldErrors({})\n setSubmitting(false)\n }\n }, [channel?.id])\n\n const handleSubmit = React.useCallback(async () => {\n if (!channel || submitting) return\n const sinceNum = Number.parseInt(sinceDays, 10)\n const maxNum = Number.parseInt(maxMessages, 10)\n const errors: Record<string, string> = {}\n if (!Number.isFinite(sinceNum) || sinceNum < 1 || sinceNum > 365) {\n errors.sinceDays = t(\n 'communication_channels.profile.importHistory.errors.sinceDays',\n 'Choose a number between 1 and 365 days.',\n )\n }\n if (!Number.isFinite(maxNum) || maxNum < 1 || maxNum > 5000) {\n errors.maxMessages = t(\n 'communication_channels.profile.importHistory.errors.maxMessages',\n 'Choose a number between 1 and 5000 messages.',\n )\n }\n const parsedEmails = contactEmails\n .split(/[\\s,;]+/)\n .map((s) => s.trim())\n .filter(Boolean)\n if (parsedEmails.length > 0 && parsedEmails.some((s) => !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(s))) {\n errors.contactEmails = t(\n 'communication_channels.profile.importHistory.errors.contactEmails',\n 'One or more entries is not a valid email address.',\n )\n }\n if (Object.keys(errors).length > 0) {\n setFieldErrors(errors)\n return\n }\n setFieldErrors({})\n setSubmitting(true)\n const mutationPayload = {\n sinceDays: sinceNum,\n maxMessages: maxNum,\n ...(parsedEmails.length > 0 ? { contactEmails: parsedEmails } : {}),\n }\n let response\n try {\n response = await runMutation({\n operation: () => apiCall<{ progressJobId?: string }>(\n `/api/communication_channels/channels/${encodeURIComponent(channel.id)}/import-history`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(mutationPayload),\n },\n ),\n context: {\n formId: IMPORT_HISTORY_MUTATION_CONTEXT_ID,\n resourceKind: 'communication_channels.channel',\n resourceId: channel.id,\n retryLastMutation,\n },\n mutationPayload,\n })\n } catch (err) {\n setSubmitting(false)\n flash(\n err instanceof Error\n ? err.message\n : t('communication_channels.profile.importHistory.flash.error', 'Failed to queue history import.'),\n 'error',\n )\n return\n }\n setSubmitting(false)\n if (!response.ok) {\n const body = response.result as { error?: string; fieldErrors?: Record<string, string> } | undefined\n if (body?.fieldErrors && Object.keys(body.fieldErrors).length > 0) {\n setFieldErrors(body.fieldErrors)\n return\n }\n flash(\n body?.error ??\n t(\n 'communication_channels.profile.importHistory.flash.error',\n 'Failed to queue history import.',\n ),\n 'error',\n )\n return\n }\n flash(\n t(\n 'communication_channels.profile.importHistory.flash.success',\n 'History import queued \u2014 track progress in the top bar.',\n ),\n 'success',\n )\n onQueued()\n }, [channel, sinceDays, maxMessages, contactEmails, submitting, t, onQueued, retryLastMutation, runMutation])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n void handleSubmit()\n }\n },\n [handleSubmit],\n )\n\n return (\n <Dialog open={channel !== null} onOpenChange={(open) => { if (!open) onClose() }}>\n <DialogContent onKeyDown={handleKeyDown}>\n <DialogHeader>\n <DialogTitle>\n {t('communication_channels.profile.importHistory.title', 'Import channel history')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'communication_channels.profile.importHistory.description',\n 'Pull older messages this channel never observed at connect-time. Filters narrow the search server-side.',\n )}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-1\">\n <Label htmlFor=\"import-history-since\">\n {t('communication_channels.profile.importHistory.fields.sinceDays', 'Look back (days)')}\n </Label>\n <Input\n id=\"import-history-since\"\n type=\"number\"\n min={1}\n max={365}\n value={sinceDays}\n onChange={(e) => setSinceDays(e.target.value)}\n aria-invalid={Boolean(fieldErrors.sinceDays)}\n />\n {fieldErrors.sinceDays ? (\n <p className=\"text-xs text-status-error-text\">{fieldErrors.sinceDays}</p>\n ) : null}\n </div>\n\n <div className=\"space-y-1\">\n <Label htmlFor=\"import-history-emails\">\n {t(\n 'communication_channels.profile.importHistory.fields.contactEmails',\n 'Filter by sender (optional)',\n )}\n </Label>\n <Textarea\n id=\"import-history-emails\"\n rows={3}\n value={contactEmails}\n onChange={(e) => setContactEmails(e.target.value)}\n placeholder={t(\n 'communication_channels.profile.importHistory.fields.contactEmailsPlaceholder',\n 'alice@example.com, bob@example.com',\n )}\n aria-invalid={Boolean(fieldErrors.contactEmails)}\n />\n {fieldErrors.contactEmails ? (\n <p className=\"text-xs text-status-error-text\">{fieldErrors.contactEmails}</p>\n ) : (\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'communication_channels.profile.importHistory.fields.contactEmailsHint',\n 'Leave empty to scan all senders in the window.',\n )}\n </p>\n )}\n </div>\n\n <div className=\"space-y-1\">\n <Label htmlFor=\"import-history-max\">\n {t('communication_channels.profile.importHistory.fields.maxMessages', 'Maximum messages')}\n </Label>\n <Input\n id=\"import-history-max\"\n type=\"number\"\n min={1}\n max={5000}\n value={maxMessages}\n onChange={(e) => setMaxMessages(e.target.value)}\n aria-invalid={Boolean(fieldErrors.maxMessages)}\n />\n {fieldErrors.maxMessages ? (\n <p className=\"text-xs text-status-error-text\">{fieldErrors.maxMessages}</p>\n ) : null}\n </div>\n\n {fieldErrors.channelId ? (\n <Alert variant=\"warning\">\n <AlertDescription>{fieldErrors.channelId}</AlertDescription>\n </Alert>\n ) : null}\n </div>\n\n <DialogFooter>\n <span className=\"mr-auto text-xs text-muted-foreground\">\n <KbdShortcut keys={['\u2318', 'Enter']} />\n </span>\n <Button type=\"button\" variant=\"outline\" onClick={onClose} disabled={submitting}>\n {t('communication_channels.profile.importHistory.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={() => void handleSubmit()} disabled={submitting}>\n {submitting\n ? t('communication_channels.profile.importHistory.submitting', 'Queueing\u2026')\n : t('communication_channels.profile.importHistory.submit', 'Start import')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n\ntype DisconnectChannelDialogProps = {\n channel: ChannelRow | null\n onClose: () => void\n onDisconnected: () => void\n}\n\nfunction DisconnectChannelDialog({\n channel,\n onClose,\n onDisconnected,\n}: DisconnectChannelDialogProps): React.JSX.Element {\n const t = useT()\n const [submitting, setSubmitting] = React.useState(false)\n const { runMutation, retryLastMutation } = useGuardedMutation<ChannelMutationContext>({\n contextId: DISCONNECT_MUTATION_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n React.useEffect(() => {\n if (channel) setSubmitting(false)\n }, [channel?.id])\n\n const handleConfirm = React.useCallback(async () => {\n if (!channel || submitting) return\n setSubmitting(true)\n let response\n try {\n response = await runMutation({\n // optimistic-lock-exempt: self-service connect/disconnect of the\n // signed-in operator's OWN communication channel (an integration link),\n // not a shared multi-editor record. Disconnect is a terminal action\n // keyed by channel id; there is no concurrent-edit lost-update window to\n // guard, and the row carries no client-surfaced `updatedAt` round-trip.\n operation: () => apiCall(\n `/api/communication_channels/channels/${encodeURIComponent(channel.id)}`,\n { method: 'DELETE' },\n ),\n context: {\n formId: DISCONNECT_MUTATION_CONTEXT_ID,\n resourceKind: 'communication_channels.channel',\n resourceId: channel.id,\n retryLastMutation,\n },\n mutationPayload: { action: 'disconnect' },\n })\n } catch (err) {\n setSubmitting(false)\n flash(\n err instanceof Error\n ? err.message\n : t('communication_channels.profile.actions.disconnectFailed', 'Failed to disconnect channel'),\n 'error',\n )\n return\n }\n setSubmitting(false)\n if (!response.ok) {\n const body = response.result as { error?: string } | undefined\n flash(\n body?.error ??\n t('communication_channels.profile.actions.disconnectFailed', 'Failed to disconnect channel'),\n 'error',\n )\n return\n }\n flash(\n t(\n 'communication_channels.profile.actions.disconnectSuccess',\n 'Channel disconnected. You can reconnect it anytime.',\n ),\n 'success',\n )\n onDisconnected()\n }, [channel, submitting, runMutation, retryLastMutation, t, onDisconnected])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n void handleConfirm()\n }\n },\n [handleConfirm],\n )\n\n return (\n <Dialog open={channel !== null} onOpenChange={(open) => { if (!open) onClose() }}>\n <DialogContent onKeyDown={handleKeyDown}>\n <DialogHeader>\n <DialogTitle>\n {t('communication_channels.profile.disconnect.title', 'Disconnect channel')}\n </DialogTitle>\n <DialogDescription>\n {t(\n 'communication_channels.profile.disconnect.description',\n 'This removes the connection and stops syncing. Emails already imported stay on your timelines. You can reconnect anytime.',\n )}\n </DialogDescription>\n </DialogHeader>\n\n {channel ? (\n <p className=\"text-sm font-medium\">{channel.externalIdentifier ?? channel.displayName}</p>\n ) : null}\n\n <DialogFooter>\n <span className=\"mr-auto text-xs text-muted-foreground\">\n <KbdShortcut keys={['\u2318', 'Enter']} />\n </span>\n <Button type=\"button\" variant=\"outline\" onClick={onClose} disabled={submitting}>\n {t('communication_channels.profile.disconnect.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"destructive-solid\" onClick={() => void handleConfirm()} disabled={submitting}>\n {submitting\n ? t('communication_channels.profile.disconnect.submitting', 'Disconnecting\u2026')\n : t('communication_channels.profile.disconnect.confirm', 'Disconnect')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n\nfunction statusTag(\n status: ChannelRow['status'],\n t: (key: string, fallback?: string) => string,\n): React.ReactNode {\n switch (status) {\n case 'connected':\n return (\n <Tag variant=\"success\" dot>\n {t('communication_channels.status.connected', 'Connected')}\n </Tag>\n )\n case 'requires_reauth':\n return (\n <Tag variant=\"warning\" dot>\n {t('communication_channels.status.requiresReauth', 'Needs reconnection')}\n </Tag>\n )\n case 'error':\n return (\n <Tag variant=\"error\" dot>\n {t('communication_channels.status.error', 'Error')}\n </Tag>\n )\n case 'disconnected':\n return <Tag variant=\"neutral\">{t('communication_channels.status.disconnected', 'Disconnected')}</Tag>\n default:\n return <Tag variant=\"neutral\">{status}</Tag>\n }\n}\n"],
|
|
5
|
+
"mappings": ";AAmRU,cA8DI,YA9DJ;AAjRV,YAAY,WAAW;AACvB,SAAS,uBAAuB;AAEhC,SAAS,WAAW,uBAAuB;AAC3C,SAAS,MAAM,gBAAgB;AAC/B,SAAS,iBAAiB;AAC1B,SAAS,WAAW;AACpB,SAAS,cAAc;AACvB,SAAS,OAAO,wBAAwB;AACxC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AACxB,SAAS,0BAA0B;AACnC,SAAS,aAAa;AACtB,SAAS,YAAY;AAoBrB,MAAM,uCAAuC;AAC7C,MAAM,qCAAqC;AAC3C,MAAM,iCAAiC;AASxB,SAAR,mCAAoD;AACzD,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,eAAe,gBAAgB;AACrC,QAAM,YAAY,cAAc,IAAI,OAAO;AAC3C,QAAM,YAAY,cAAc,IAAI,MAAM;AAC1C,QAAM,gBAAgB,cAAc,IAAI,UAAU;AAElD,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAuB,CAAC,CAAC;AACvD,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,IAAI;AACrD,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAwB,IAAI;AAC1E,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,CAAC;AAClD,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAA4B,IAAI;AAChF,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,MAAM,SAA4B,IAAI;AACxF,QAAM,EAAE,aAAa,kBAAkB,IAAI,mBAA2C;AAAA,IACpF,WAAW;AAAA,IACX,gBAAgB,EAAE,8BAA8B,4BAA4B;AAAA,EAC9E,CAAC;AAED,QAAM,UAAU,MAAM;AACpB,QAAI,cAAc,aAAa;AAC7B;AAAA,QACE,gBACI,EAAE,8DAA8D,mCAAmC;AAAA,UACjG,UAAU;AAAA,QACZ,CAAC,IACD,EAAE,kDAAkD,oBAAoB;AAAA,QAC5E;AAAA,MACF;AAAA,IACF,WAAW,cAAc,SAAS;AAChC;AAAA,QACE,cAAc,gCACV;AAAA,UACE;AAAA,UACA;AAAA,QACF,IACA,cAAc,8BACZ;AAAA,UACE;AAAA,UACA;AAAA,QACF,IACA,YACE,EAAE,sDAAsD,4CAAuC;AAAA,UAC7F,MAAM;AAAA,QACR,CAAC,IACD,EAAE,8CAA8C,4BAA4B;AAAA,QACpF;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,WAAW,WAAW,eAAe,CAAC,CAAC;AAE3C,QAAM,UAAU,MAAM;AACpB,QAAI,YAAY;AAChB,mBAAe,OAAO;AACpB,mBAAa,IAAI;AACjB,sBAAgB,IAAI;AACpB,YAAM,WAAW,MAAM;AAAA,QACrB;AAAA,MACF,EAAE,MAAM,CAAC,SAAkB;AAAA,QACzB,IAAI;AAAA,QACJ,QAAQ,EAAE,OAAO,eAAe,QAAQ,IAAI,UAAU,0BAA0B;AAAA,MAClF,EAAE;AACF,UAAI,UAAW;AACf,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,OAAO,SAAS;AACtB;AAAA,UACE,MAAM,SAAS,EAAE,0CAA0C,yBAAyB;AAAA,QACtF;AACA,gBAAQ,CAAC,CAAC;AAAA,MACZ,OAAO;AACL,cAAM,OAAQ,SAAS,UAAU,CAAC;AAClC,gBAAQ,MAAM,QAAQ,KAAK,KAAK,IAAI,KAAK,QAAQ,CAAC,CAAC;AAAA,MACrD;AACA,mBAAa,KAAK;AAAA,IACpB;AACA,SAAK,KAAK;AACV,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,WAAW,CAAC,CAAC;AAEjB,QAAM,aAAa,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,iBAAiB;AAEpE,QAAM,eAAe,MAAM;AAAA,IACzB,OAAO,cAAsB;AAC3B,UAAI;AACJ,UAAI;AACF,mBAAW,MAAM,YAAY;AAAA,UAC3B,WAAW,MAAM;AAAA,YACf,wCAAwC,mBAAmB,SAAS,CAAC;AAAA,YACrE,EAAE,QAAQ,OAAO;AAAA,UACnB;AAAA,UACA,SAAS;AAAA,YACP,QAAQ;AAAA,YACR,cAAc;AAAA,YACd,YAAY;AAAA,YACZ;AAAA,UACF;AAAA,UACA,iBAAiB,EAAE,WAAW,KAAK;AAAA,QACrC,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,cAAM,eAAe,QAAQ,IAAI,UAAU,EAAE,2DAA2D,0BAA0B,GAAG,OAAO;AAC5I;AAAA,MACF;AACA,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,OAAO,SAAS;AACtB;AAAA,UACE,MAAM,SAAS,EAAE,2DAA2D,0BAA0B;AAAA,UACtG;AAAA,QACF;AACA;AAAA,MACF;AACA;AAAA,QACE,EAAE,4DAA4D,oBAAoB;AAAA,QAClF;AAAA,MACF;AACA,mBAAa,CAAC,MAAM,IAAI,CAAC;AAAA,IAC3B;AAAA,IACA,CAAC,mBAAmB,aAAa,CAAC;AAAA,EACpC;AAEA,QAAM,iBAAiB,MAAM;AAAA,IAC3B,OAAO,cAAsB;AAC3B,UAAI;AACJ,UAAI;AACF,mBAAW,MAAM,YAAY;AAAA,UAC3B,WAAW,MAAM;AAAA,YACf,wCAAwC,mBAAmB,SAAS,CAAC;AAAA,YACrE,EAAE,QAAQ,OAAO;AAAA,UACnB;AAAA,UACA,SAAS;AAAA,YACP,QAAQ;AAAA,YACR,cAAc;AAAA,YACd,YAAY;AAAA,YACZ;AAAA,UACF;AAAA,UACA,iBAAiB,EAAE,QAAQ,gBAAgB;AAAA,QAC7C,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,cAAM,eAAe,QAAQ,IAAI,UAAU,EAAE,iDAAiD,kBAAkB,GAAG,OAAO;AAC1H;AAAA,MACF;AACA,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,OAAO,SAAS;AACtB,cAAM,MAAM,SAAS,EAAE,oDAAoD,yBAAyB,GAAG,OAAO;AAC9G;AAAA,MACF;AACA,YAAM,SAAU,SAAS,UAAU,CAAC;AACpC,UAAI,OAAO,eAAe,UAAU;AAClC,cAAM,EAAE,6CAA6C,aAAa,GAAG,SAAS;AAAA,MAChF,OAAO;AACL;AAAA,UACE;AAAA,YACE;AAAA,YACA;AAAA,UACF;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,mBAAa,CAAC,MAAM,IAAI,CAAC;AAAA,IAC3B;AAAA,IACA,CAAC,mBAAmB,aAAa,CAAC;AAAA,EACpC;AAEA,QAAM,YAAY,MAAM;AAAA,IACtB,OAAO,cAAsB;AAC3B,UAAI;AACJ,UAAI;AACF,mBAAW,MAAM,YAAY;AAAA,UAC3B,WAAW,MAAM;AAAA,YACf,wCAAwC,mBAAmB,SAAS,CAAC;AAAA,YACrE,EAAE,QAAQ,OAAO;AAAA,UACnB;AAAA,UACA,SAAS;AAAA,YACP,QAAQ;AAAA,YACR,cAAc;AAAA,YACd,YAAY;AAAA,YACZ;AAAA,UACF;AAAA,UACA,iBAAiB,EAAE,QAAQ,WAAW;AAAA,QACxC,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,cAAM,eAAe,QAAQ,IAAI,UAAU,EAAE,wDAAwD,wBAAwB,GAAG,OAAO;AACvI;AAAA,MACF;AACA,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,OAAO,SAAS;AACtB;AAAA,UACE,MAAM,SAAS,EAAE,wDAAwD,wBAAwB;AAAA,UACjG;AAAA,QACF;AACA;AAAA,MACF;AACA;AAAA,QACE;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAGA,iBAAW,MAAM,aAAa,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI;AAAA,IACnD;AAAA,IACA,CAAC,mBAAmB,aAAa,CAAC;AAAA,EACpC;AAEA,QAAM,UAAU,MAAM;AAAA,IACpB,MAAM;AAAA,MACJ;AAAA,QACE,QAAQ,EAAE,8CAA8C,SAAS;AAAA,QACjE,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,QAAQ,EAAE,2CAA2C,UAAU;AAAA,QAC/D,aAAa;AAAA,QACb,MAAM,CAAC,EAAE,IAAI,MACX,oBAAC,OAAI,SAAQ,QACV;AAAA,UACC,4CAA4C,IAAI,SAAS,WAAW;AAAA,UACpE,IAAI,SAAS;AAAA,QACf,GACF;AAAA,MAEJ;AAAA,MACA;AAAA,QACE,QAAQ,EAAE,6CAA6C,kBAAkB;AAAA,QACzE,aAAa;AAAA,QACb,MAAM,CAAC,EAAE,IAAI,MAAM,IAAI,SAAS,sBAAsB;AAAA,QACtD,MAAM,EAAE,UAAU,MAAM,UAAU,IAAI;AAAA,MACxC;AAAA,MACA;AAAA,QACE,QAAQ,EAAE,kDAAkD,SAAS;AAAA,QACrE,aAAa;AAAA,QACb,MAAM,CAAC,EAAE,IAAI,MACX,IAAI,SAAS,YACX,oBAAC,OAAI,SAAQ,WAAU,KAAG,MACvB,YAAE,0CAA0C,SAAS,GACxD,IAEA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,MAAM,KAAK,aAAa,IAAI,SAAS,EAAE;AAAA,YAChD,cAAY,EAAE,qDAAqD,gBAAgB;AAAA,YAElF,YAAE,qDAAqD,gBAAgB;AAAA;AAAA,QAC1E;AAAA,MAEN;AAAA,MACA;AAAA,QACE,QAAQ,EAAE,yCAAyC,QAAQ;AAAA,QAC3D,aAAa;AAAA,QACb,MAAM,CAAC,EAAE,IAAI,MAAM,UAAU,IAAI,SAAS,QAAQ,CAAC;AAAA,MACrD;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,QAAQ,EAAE,6CAA6C,MAAM;AAAA,QAC7D,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,eAAe,IAAI,SAAS,gBAAgB;AAClD,cAAI,CAAC,cAAc;AACjB,mBACE,oBAAC,UAAK,WAAU,iCACb,YAAE,+CAA+C,cAAc,GAClE;AAAA,UAEJ;AACA,gBAAM,KAAK,IAAI,SAAS;AACxB,cAAI,OAAO,UAAU;AACnB,mBACE,oBAAC,OAAI,SAAQ,WAAU,KAAG,MACvB,YAAE,6CAA6C,aAAa,GAC/D;AAAA,UAEJ;AACA,cAAI,OAAO,UAAU;AACnB,kBAAM,WAAW,IAAI,SAAS,eAAe,WAAW;AACxD,mBACE,qBAAC,SAAI,WAAU,2BACb;AAAA,kCAAC,OAAI,SAAQ,SAAQ,KAAG,MACrB,YAAE,6CAA6C,kCAA6B,GAC/E;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,SAAS,MAAM,KAAK,eAAe,IAAI,SAAS,EAAE;AAAA,kBAClD,cAAY,EAAE,iDAAiD,kBAAkB;AAAA,kBACjF,OAAO,YAAY;AAAA,kBAElB,YAAE,iDAAiD,kBAAkB;AAAA;AAAA,cACxE;AAAA,eACF;AAAA,UAEJ;AAEA,iBACE,qBAAC,SAAI,WAAU,2BACb;AAAA,gCAAC,UAAK,WAAU,iCACb,YAAE,+CAA+C,cAAc,GAClE;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,SAAS,MAAM,KAAK,eAAe,IAAI,SAAS,EAAE;AAAA,gBAClD,cAAY,EAAE,iDAAiD,kBAAkB;AAAA,gBAEhF,YAAE,iDAAiD,kBAAkB;AAAA;AAAA,YACxE;AAAA,aACF;AAAA,QAEJ;AAAA,MACF;AAAA,MACA;AAAA,QACE,QAAQ,EAAE,qDAAqD,aAAa;AAAA,QAC5E,aAAa;AAAA,QACb,MAAM,CAAC,EAAE,IAAI,MACX,IAAI,SAAS,eACT,IAAI,KAAK,IAAI,SAAS,YAAY,EAAE,eAAe,IACnD;AAAA,MACR;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,QAAQ,EAAE,wDAAwD,SAAS;AAAA,QAC3E,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,WACJ,IAAI,SAAS,YACb,IAAI,SAAS,WAAW,eACxB,IAAI,SAAS,gBAAgB;AAC/B,gBAAM,QAAQ,EAAE,wDAAwD,gBAAgB;AACxF,iBACE;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM,iBAAiB,IAAI,QAAQ;AAAA,cAC5C,UAAU,CAAC;AAAA,cACX,cAAY;AAAA,cAEX;AAAA;AAAA,UACH;AAAA,QAEJ;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,QAAQ,EAAE,kDAAkD,MAAM;AAAA,QAClE,MAAM,CAAC,EAAE,IAAI,MAAM;AAIjB,gBAAM,WACJ,IAAI,SAAS,aACZ,IAAI,SAAS,WAAW,eAAe,IAAI,SAAS,WAAW;AAClE,gBAAM,QACJ,IAAI,SAAS,WAAW,UACpB,EAAE,oDAAoD,OAAO,IAC7D,EAAE,kDAAkD,UAAU;AACpE,iBACE;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,IAAI,SAAS,WAAW,UAAU,YAAY;AAAA,cACvD,MAAK;AAAA,cACL,SAAS,MAAM,KAAK,UAAU,IAAI,SAAS,EAAE;AAAA,cAC7C,UAAU,CAAC;AAAA,cACX,cAAY;AAAA,cAEX;AAAA;AAAA,UACH;AAAA,QAEJ;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,QAAQ,EAAE,qDAAqD,YAAY;AAAA,QAC3E,MAAM,CAAC,EAAE,IAAI,MAAM;AACjB,gBAAM,QAAQ,EAAE,qDAAqD,YAAY;AACjF,iBACE;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM,qBAAqB,IAAI,QAAQ;AAAA,cAChD,cAAY;AAAA,cAEX;AAAA;AAAA,UACH;AAAA,QAEJ;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,cAAc,WAAW,gBAAgB,CAAC;AAAA,EAC7C;AAEA,SACE,oBAAC,QACC,+BAAC,YACC;AAAA,yBAAC,YAAO,WAAU,4CAChB;AAAA,2BAAC,SACC;AAAA,4BAAC,QAAG,WAAU,0BACX,YAAE,wCAAwC,2BAA2B,GACxE;AAAA,QACA,oBAAC,OAAE,WAAU,iCACV;AAAA,UACC;AAAA,UACA;AAAA,QACF,GACF;AAAA,SACF;AAAA,MAGA;AAAA,QAAC;AAAA;AAAA,UACC,QAAQ,gBAAgB,MAAM,eAAe;AAAA,UAC7C,SAAS,EAAE,QAAQ,MAAM,aAAa,CAAC,MAAM,IAAI,CAAC,EAAE;AAAA,UACpD,MAAM,CAAC;AAAA;AAAA,MACT;AAAA,OACF;AAAA,IAEC,WAAW,SAAS,IACnB,oBAAC,SAAM,SAAQ,WAAU,WAAU,QACjC,8BAAC,oBACE;AAAA,MACC;AAAA,MACA;AAAA,MACA,EAAE,OAAO,WAAW,OAAO;AAAA,IAC7B,GACF,GACF,IACE;AAAA,IAEJ;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,6CAA6C,eAAe;AAAA,QACrE,kBAAkB,gBAAgB,MAAM,qBAAqB;AAAA,QAC7D;AAAA,QACA,MAAM;AAAA,QACN;AAAA,QACA,OAAO;AAAA,QACP,YAAY;AAAA,UACV;AAAA,UACA;AAAA,QACF;AAAA;AAAA,IACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,SAAS,MAAM,iBAAiB,IAAI;AAAA,QACpC,UAAU,MAAM;AACd,2BAAiB,IAAI;AACrB,iBAAO,QAAQ;AAAA,QACjB;AAAA;AAAA,IACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,SAAS,MAAM,qBAAqB,IAAI;AAAA,QACxC,gBAAgB,MAAM;AACpB,+BAAqB,IAAI;AACzB,uBAAa,CAAC,MAAM,IAAI,CAAC;AAAA,QAC3B;AAAA;AAAA,IACF;AAAA,KACF,GACF;AAEJ;AAQA,SAAS,oBAAoB,EAAE,SAAS,SAAS,SAAS,GAAgD;AACxG,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,IAAI;AACrD,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAS,EAAE;AAC3D,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAS,KAAK;AAC1D,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAiC,CAAC,CAAC;AAC/E,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,EAAE,aAAa,kBAAkB,IAAI,mBAA2C;AAAA,IACpF,WAAW;AAAA,IACX,gBAAgB,EAAE,8BAA8B,4BAA4B;AAAA,EAC9E,CAAC;AAED,QAAM,UAAU,MAAM;AACpB,QAAI,SAAS;AACX,mBAAa,IAAI;AACjB,uBAAiB,EAAE;AACnB,qBAAe,KAAK;AACpB,qBAAe,CAAC,CAAC;AACjB,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,SAAS,EAAE,CAAC;AAEhB,QAAM,eAAe,MAAM,YAAY,YAAY;AACjD,QAAI,CAAC,WAAW,WAAY;AAC5B,UAAM,WAAW,OAAO,SAAS,WAAW,EAAE;AAC9C,UAAM,SAAS,OAAO,SAAS,aAAa,EAAE;AAC9C,UAAM,SAAiC,CAAC;AACxC,QAAI,CAAC,OAAO,SAAS,QAAQ,KAAK,WAAW,KAAK,WAAW,KAAK;AAChE,aAAO,YAAY;AAAA,QACjB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,OAAO,SAAS,MAAM,KAAK,SAAS,KAAK,SAAS,KAAM;AAC3D,aAAO,cAAc;AAAA,QACnB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,UAAM,eAAe,cAClB,MAAM,SAAS,EACf,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,OAAO;AACjB,QAAI,aAAa,SAAS,KAAK,aAAa,KAAK,CAAC,MAAM,CAAC,6BAA6B,KAAK,CAAC,CAAC,GAAG;AAC9F,aAAO,gBAAgB;AAAA,QACrB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,QAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,qBAAe,MAAM;AACrB;AAAA,IACF;AACA,mBAAe,CAAC,CAAC;AACjB,kBAAc,IAAI;AAClB,UAAM,kBAAkB;AAAA,MACtB,WAAW;AAAA,MACX,aAAa;AAAA,MACb,GAAI,aAAa,SAAS,IAAI,EAAE,eAAe,aAAa,IAAI,CAAC;AAAA,IACnE;AACA,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,YAAY;AAAA,QAC3B,WAAW,MAAM;AAAA,UACf,wCAAwC,mBAAmB,QAAQ,EAAE,CAAC;AAAA,UACtE;AAAA,YACE,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,YAC9C,MAAM,KAAK,UAAU,eAAe;AAAA,UACtC;AAAA,QACF;AAAA,QACA,SAAS;AAAA,UACP,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,YAAY,QAAQ;AAAA,UACpB;AAAA,QACF;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,oBAAc,KAAK;AACnB;AAAA,QACE,eAAe,QACX,IAAI,UACJ,EAAE,4DAA4D,iCAAiC;AAAA,QACnG;AAAA,MACF;AACA;AAAA,IACF;AACA,kBAAc,KAAK;AACnB,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OAAO,SAAS;AACtB,UAAI,MAAM,eAAe,OAAO,KAAK,KAAK,WAAW,EAAE,SAAS,GAAG;AACjE,uBAAe,KAAK,WAAW;AAC/B;AAAA,MACF;AACA;AAAA,QACE,MAAM,SACJ;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AACA;AAAA,MACE;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,IACF;AACA,aAAS;AAAA,EACX,GAAG,CAAC,SAAS,WAAW,aAAa,eAAe,YAAY,GAAG,UAAU,mBAAmB,WAAW,CAAC;AAE5G,QAAM,gBAAgB,MAAM;AAAA,IAC1B,CAAC,UAA+B;AAC9B,UAAI,MAAM,QAAQ,YAAY,MAAM,WAAW,MAAM,UAAU;AAC7D,cAAM,eAAe;AACrB,aAAK,aAAa;AAAA,MACpB;AAAA,IACF;AAAA,IACA,CAAC,YAAY;AAAA,EACf;AAEA,SACE,oBAAC,UAAO,MAAM,YAAY,MAAM,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,KAAM,SAAQ;AAAA,EAAE,GAC7E,+BAAC,iBAAc,WAAW,eACxB;AAAA,yBAAC,gBACC;AAAA,0BAAC,eACE,YAAE,sDAAsD,wBAAwB,GACnF;AAAA,MACA,oBAAC,qBACE;AAAA,QACC;AAAA,QACA;AAAA,MACF,GACF;AAAA,OACF;AAAA,IAEA,qBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,SAAI,WAAU,aACb;AAAA,4BAAC,SAAM,SAAQ,wBACZ,YAAE,iEAAiE,kBAAkB,GACxF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,KAAK;AAAA,YACL,KAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,aAAa,EAAE,OAAO,KAAK;AAAA,YAC5C,gBAAc,QAAQ,YAAY,SAAS;AAAA;AAAA,QAC7C;AAAA,QACC,YAAY,YACX,oBAAC,OAAE,WAAU,kCAAkC,sBAAY,WAAU,IACnE;AAAA,SACN;AAAA,MAEA,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,SAAM,SAAQ,yBACZ;AAAA,UACC;AAAA,UACA;AAAA,QACF,GACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAM;AAAA,YACN,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,iBAAiB,EAAE,OAAO,KAAK;AAAA,YAChD,aAAa;AAAA,cACX;AAAA,cACA;AAAA,YACF;AAAA,YACA,gBAAc,QAAQ,YAAY,aAAa;AAAA;AAAA,QACjD;AAAA,QACC,YAAY,gBACX,oBAAC,OAAE,WAAU,kCAAkC,sBAAY,eAAc,IAEzE,oBAAC,OAAE,WAAU,iCACV;AAAA,UACC;AAAA,UACA;AAAA,QACF,GACF;AAAA,SAEJ;AAAA,MAEA,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,SAAM,SAAQ,sBACZ,YAAE,mEAAmE,kBAAkB,GAC1F;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,KAAK;AAAA,YACL,KAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,YAC9C,gBAAc,QAAQ,YAAY,WAAW;AAAA;AAAA,QAC/C;AAAA,QACC,YAAY,cACX,oBAAC,OAAE,WAAU,kCAAkC,sBAAY,aAAY,IACrE;AAAA,SACN;AAAA,MAEC,YAAY,YACX,oBAAC,SAAM,SAAQ,WACb,8BAAC,oBAAkB,sBAAY,WAAU,GAC3C,IACE;AAAA,OACN;AAAA,IAEA,qBAAC,gBACC;AAAA,0BAAC,UAAK,WAAU,yCACd,8BAAC,eAAY,MAAM,CAAC,UAAK,OAAO,GAAG,GACrC;AAAA,MACA,oBAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,SAAS,SAAS,UAAU,YACjE,YAAE,uDAAuD,QAAQ,GACpE;AAAA,MACA,oBAAC,UAAO,MAAK,UAAS,SAAS,MAAM,KAAK,aAAa,GAAG,UAAU,YACjE,uBACG,EAAE,2DAA2D,gBAAW,IACxE,EAAE,uDAAuD,cAAc,GAC7E;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAQA,SAAS,wBAAwB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACF,GAAoD;AAClD,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,EAAE,aAAa,kBAAkB,IAAI,mBAA2C;AAAA,IACpF,WAAW;AAAA,IACX,gBAAgB,EAAE,8BAA8B,4BAA4B;AAAA,EAC9E,CAAC;AAED,QAAM,UAAU,MAAM;AACpB,QAAI,QAAS,eAAc,KAAK;AAAA,EAClC,GAAG,CAAC,SAAS,EAAE,CAAC;AAEhB,QAAM,gBAAgB,MAAM,YAAY,YAAY;AAClD,QAAI,CAAC,WAAW,WAAY;AAC5B,kBAAc,IAAI;AAClB,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAM3B,WAAW,MAAM;AAAA,UACf,wCAAwC,mBAAmB,QAAQ,EAAE,CAAC;AAAA,UACtE,EAAE,QAAQ,SAAS;AAAA,QACrB;AAAA,QACA,SAAS;AAAA,UACP,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,YAAY,QAAQ;AAAA,UACpB;AAAA,QACF;AAAA,QACA,iBAAiB,EAAE,QAAQ,aAAa;AAAA,MAC1C,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,oBAAc,KAAK;AACnB;AAAA,QACE,eAAe,QACX,IAAI,UACJ,EAAE,2DAA2D,8BAA8B;AAAA,QAC/F;AAAA,MACF;AACA;AAAA,IACF;AACA,kBAAc,KAAK;AACnB,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OAAO,SAAS;AACtB;AAAA,QACE,MAAM,SACJ,EAAE,2DAA2D,8BAA8B;AAAA,QAC7F;AAAA,MACF;AACA;AAAA,IACF;AACA;AAAA,MACE;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,IACF;AACA,mBAAe;AAAA,EACjB,GAAG,CAAC,SAAS,YAAY,aAAa,mBAAmB,GAAG,cAAc,CAAC;AAE3E,QAAM,gBAAgB,MAAM;AAAA,IAC1B,CAAC,UAA+B;AAC9B,UAAI,MAAM,QAAQ,YAAY,MAAM,WAAW,MAAM,UAAU;AAC7D,cAAM,eAAe;AACrB,aAAK,cAAc;AAAA,MACrB;AAAA,IACF;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,SACE,oBAAC,UAAO,MAAM,YAAY,MAAM,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,KAAM,SAAQ;AAAA,EAAE,GAC7E,+BAAC,iBAAc,WAAW,eACxB;AAAA,yBAAC,gBACC;AAAA,0BAAC,eACE,YAAE,mDAAmD,oBAAoB,GAC5E;AAAA,MACA,oBAAC,qBACE;AAAA,QACC;AAAA,QACA;AAAA,MACF,GACF;AAAA,OACF;AAAA,IAEC,UACC,oBAAC,OAAE,WAAU,uBAAuB,kBAAQ,sBAAsB,QAAQ,aAAY,IACpF;AAAA,IAEJ,qBAAC,gBACC;AAAA,0BAAC,UAAK,WAAU,yCACd,8BAAC,eAAY,MAAM,CAAC,UAAK,OAAO,GAAG,GACrC;AAAA,MACA,oBAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,SAAS,SAAS,UAAU,YACjE,YAAE,oDAAoD,QAAQ,GACjE;AAAA,MACA,oBAAC,UAAO,MAAK,UAAS,SAAQ,qBAAoB,SAAS,MAAM,KAAK,cAAc,GAAG,UAAU,YAC9F,uBACG,EAAE,wDAAwD,qBAAgB,IAC1E,EAAE,qDAAqD,YAAY,GACzE;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAEA,SAAS,UACP,QACA,GACiB;AACjB,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aACE,oBAAC,OAAI,SAAQ,WAAU,KAAG,MACvB,YAAE,2CAA2C,WAAW,GAC3D;AAAA,IAEJ,KAAK;AACH,aACE,oBAAC,OAAI,SAAQ,WAAU,KAAG,MACvB,YAAE,gDAAgD,oBAAoB,GACzE;AAAA,IAEJ,KAAK;AACH,aACE,oBAAC,OAAI,SAAQ,SAAQ,KAAG,MACrB,YAAE,uCAAuC,OAAO,GACnD;AAAA,IAEJ,KAAK;AACH,aAAO,oBAAC,OAAI,SAAQ,WAAW,YAAE,8CAA8C,cAAc,GAAE;AAAA,IACjG;AACE,aAAO,oBAAC,OAAI,SAAQ,WAAW,kBAAO;AAAA,EAC1C;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -180,9 +180,8 @@ function ActivitiesDayStrip({ entityId, selectedDate, onSelectDate, refreshKey =
|
|
|
180
180
|
);
|
|
181
181
|
setFetchedEvents(Array.isArray(payload?.items) ? payload.items : []);
|
|
182
182
|
} catch (err) {
|
|
183
|
-
if (err?.name
|
|
184
|
-
|
|
185
|
-
}
|
|
183
|
+
if (err?.name === "AbortError") return;
|
|
184
|
+
logger.warn("failed to load interactions", { component: "ActivitiesDayStrip", err });
|
|
186
185
|
setFetchedEvents([]);
|
|
187
186
|
}
|
|
188
187
|
})();
|