@open-mercato/core 0.5.1-develop.2953.6647bb2c43 → 0.5.1-develop.2954.610bab2d08
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/dist/helpers/integration/salesUi.js +25 -23
- package/dist/helpers/integration/salesUi.js.map +2 -2
- package/dist/modules/api_docs/frontend/docs/api/Explorer.js +24 -24
- package/dist/modules/api_docs/frontend/docs/api/Explorer.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +15 -7
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
- package/dist/modules/attachments/fields/attachment.js +4 -6
- package/dist/modules/attachments/fields/attachment.js.map +2 -2
- package/dist/modules/auth/backend/users/create/page.js +26 -26
- package/dist/modules/auth/backend/users/create/page.js.map +2 -2
- package/dist/modules/business_rules/components/ActionRow.js +36 -25
- package/dist/modules/business_rules/components/ActionRow.js.map +2 -2
- package/dist/modules/business_rules/components/ConditionGroup.js +14 -5
- package/dist/modules/business_rules/components/ConditionGroup.js.map +2 -2
- package/dist/modules/business_rules/components/ConditionRow.js +19 -10
- package/dist/modules/business_rules/components/ConditionRow.js.map +2 -2
- package/dist/modules/business_rules/components/RuleSetMembers.js +16 -10
- package/dist/modules/business_rules/components/RuleSetMembers.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +30 -34
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +220 -223
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +20 -19
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductUomSection.js +42 -37
- package/dist/modules/catalog/components/products/ProductUomSection.js.map +2 -2
- package/dist/modules/catalog/components/products/VariantBuilder.js +22 -18
- package/dist/modules/catalog/components/products/VariantBuilder.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +18 -26
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +4 -6
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +5 -4
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +19 -7
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +24 -21
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/components/AddressEditor.js +24 -7
- package/dist/modules/customers/components/AddressEditor.js.map +2 -2
- package/dist/modules/customers/components/AddressFormatSettings.js +35 -25
- package/dist/modules/customers/components/AddressFormatSettings.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityForm.js +20 -12
- package/dist/modules/customers/components/detail/ActivityForm.js.map +2 -2
- package/dist/modules/customers/components/detail/AnnualRevenueField.js +2 -2
- package/dist/modules/customers/components/detail/AnnualRevenueField.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +19 -14
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js +16 -12
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js +3 -2
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.client.js +18 -10
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.client.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.client.js +3 -2
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.client.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.client.js +3 -2
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.client.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +27 -28
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.js +14 -6
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js +14 -6
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js +3 -2
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js +3 -2
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js +17 -8
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +40 -23
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js +15 -6
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
- package/dist/modules/dictionaries/components/AppearanceSelector.js +4 -4
- package/dist/modules/dictionaries/components/AppearanceSelector.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +4 -5
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntrySelect.js +22 -14
- package/dist/modules/dictionaries/components/DictionaryEntrySelect.js.map +2 -2
- package/dist/modules/dictionaries/fields/dictionary.js +18 -13
- package/dist/modules/dictionaries/fields/dictionary.js.map +2 -2
- package/dist/modules/entities/components/EncryptionManager.js +23 -19
- package/dist/modules/entities/components/EncryptionManager.js.map +2 -2
- package/dist/modules/feature_toggles/components/formConfig.js +17 -9
- package/dist/modules/feature_toggles/components/formConfig.js.map +2 -2
- package/dist/modules/feature_toggles/components/overrideFormConfig.js +17 -9
- package/dist/modules/feature_toggles/components/overrideFormConfig.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +15 -8
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +37 -22
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +22 -17
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +12 -6
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +19 -12
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/resources/components/ResourceCrudForm.js +15 -10
- package/dist/modules/resources/components/ResourceCrudForm.js.map +3 -3
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +15 -18
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/components/ProviderFieldInput.js +23 -20
- package/dist/modules/sales/components/ProviderFieldInput.js.map +2 -2
- package/dist/modules/sales/components/ShippingMethodsSettings.js +25 -17
- package/dist/modules/sales/components/ShippingMethodsSettings.js.map +3 -3
- package/dist/modules/sales/components/channels/ChannelOfferForm.js +35 -42
- package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +87 -90
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentDialog.js +17 -6
- package/dist/modules/sales/components/documents/AdjustmentDialog.js.map +3 -3
- package/dist/modules/sales/components/documents/LineItemDialog.js +42 -25
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentForm.js +96 -87
- package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
- package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js +20 -11
- package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js.map +2 -2
- package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js +20 -11
- package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/shipment-wizard/components/ConfigureStep.js +36 -22
- package/dist/modules/shipping_carriers/lib/shipment-wizard/components/ConfigureStep.js.map +2 -2
- package/dist/modules/staff/components/TeamMemberForm.js +14 -9
- package/dist/modules/staff/components/TeamMemberForm.js.map +3 -3
- package/dist/modules/workflows/backend/tasks/[id]/page.js +42 -21
- package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
- package/dist/modules/workflows/components/ActivitiesEditor.js +14 -6
- package/dist/modules/workflows/components/ActivitiesEditor.js.map +3 -3
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +25 -17
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +3 -3
- package/dist/modules/workflows/components/EdgeEditDialog.js +48 -45
- package/dist/modules/workflows/components/EdgeEditDialog.js.map +2 -2
- package/dist/modules/workflows/components/NodeEditDialog.js +90 -90
- package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
- package/dist/modules/workflows/components/StepsEditor.js +14 -6
- package/dist/modules/workflows/components/StepsEditor.js.map +3 -3
- package/dist/modules/workflows/components/TransitionsEditor.js +31 -26
- package/dist/modules/workflows/components/TransitionsEditor.js.map +3 -3
- package/dist/modules/workflows/components/fields/ActivityArrayEditor.js +19 -11
- package/dist/modules/workflows/components/fields/ActivityArrayEditor.js.map +3 -3
- package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js +12 -14
- package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js +24 -16
- package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js.map +3 -3
- package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js +12 -13
- package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/mobile/MobileTaskForm.js +12 -8
- package/dist/modules/workflows/components/mobile/MobileTaskForm.js.map +2 -2
- package/dist/modules/workflows/frontend/checkout-demo/page.js +43 -46
- package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
- package/package.json +3 -3
- package/src/helpers/integration/salesUi.ts +40 -30
- package/src/modules/api_docs/frontend/docs/api/Explorer.tsx +25 -19
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +21 -11
- package/src/modules/attachments/fields/attachment.tsx +4 -6
- package/src/modules/auth/backend/users/create/page.tsx +16 -20
- package/src/modules/business_rules/components/ActionRow.tsx +51 -32
- package/src/modules/business_rules/components/ConditionGroup.tsx +20 -9
- package/src/modules/business_rules/components/ConditionRow.tsx +24 -15
- package/src/modules/business_rules/components/RuleSetMembers.tsx +23 -13
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +47 -53
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +84 -87
- package/src/modules/catalog/components/PriceKindSettings.tsx +9 -9
- package/src/modules/catalog/components/products/ProductUomSection.tsx +85 -83
- package/src/modules/catalog/components/products/VariantBuilder.tsx +49 -33
- package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +12 -27
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +4 -6
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +5 -4
- package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +28 -15
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +37 -26
- package/src/modules/customers/components/AddressEditor.tsx +30 -16
- package/src/modules/customers/components/AddressFormatSettings.tsx +25 -19
- package/src/modules/customers/components/detail/ActivityForm.tsx +35 -23
- package/src/modules/customers/components/detail/AnnualRevenueField.tsx +2 -2
- package/src/modules/customers/components/detail/DealForm.tsx +33 -20
- package/src/modules/customers/components/formConfig.tsx +25 -17
- package/src/modules/customers/widgets/dashboard/customer-todos/widget.client.tsx +3 -2
- package/src/modules/customers/widgets/dashboard/new-customers/widget.client.tsx +21 -11
- package/src/modules/customers/widgets/dashboard/new-deals/widget.client.tsx +3 -2
- package/src/modules/customers/widgets/dashboard/next-interactions/widget.client.tsx +3 -2
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +17 -22
- package/src/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.tsx +17 -7
- package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.tsx +20 -10
- package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.tsx +3 -2
- package/src/modules/dashboards/widgets/dashboard/top-customers/widget.client.tsx +3 -2
- package/src/modules/dashboards/widgets/dashboard/top-products/widget.client.tsx +20 -9
- package/src/modules/data_sync/backend/data-sync/page.tsx +64 -38
- package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +18 -7
- package/src/modules/dictionaries/components/AppearanceSelector.tsx +4 -4
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +3 -4
- package/src/modules/dictionaries/components/DictionaryEntrySelect.tsx +27 -21
- package/src/modules/dictionaries/fields/dictionary.tsx +36 -23
- package/src/modules/entities/components/EncryptionManager.tsx +49 -33
- package/src/modules/feature_toggles/components/formConfig.tsx +20 -10
- package/src/modules/feature_toggles/components/overrideFormConfig.tsx +20 -10
- package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +19 -10
- package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +49 -26
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +20 -11
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +19 -9
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +34 -21
- package/src/modules/resources/components/ResourceCrudForm.tsx +24 -15
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +12 -15
- package/src/modules/sales/components/ProviderFieldInput.tsx +26 -17
- package/src/modules/sales/components/ShippingMethodsSettings.tsx +28 -20
- package/src/modules/sales/components/channels/ChannelOfferForm.tsx +51 -46
- package/src/modules/sales/components/documents/AddressesSection.tsx +78 -76
- package/src/modules/sales/components/documents/AdjustmentDialog.tsx +27 -15
- package/src/modules/sales/components/documents/LineItemDialog.tsx +69 -51
- package/src/modules/sales/components/documents/SalesDocumentForm.tsx +98 -87
- package/src/modules/sales/widgets/dashboard/new-orders/widget.client.tsx +23 -12
- package/src/modules/sales/widgets/dashboard/new-quotes/widget.client.tsx +23 -12
- package/src/modules/shipping_carriers/lib/shipment-wizard/components/ConfigureStep.tsx +35 -19
- package/src/modules/staff/components/TeamMemberForm.tsx +23 -14
- package/src/modules/workflows/backend/tasks/[id]/page.tsx +51 -23
- package/src/modules/workflows/components/ActivitiesEditor.tsx +20 -10
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +28 -18
- package/src/modules/workflows/components/EdgeEditDialog.tsx +51 -40
- package/src/modules/workflows/components/NodeEditDialog.tsx +81 -77
- package/src/modules/workflows/components/StepsEditor.tsx +20 -10
- package/src/modules/workflows/components/TransitionsEditor.tsx +61 -44
- package/src/modules/workflows/components/fields/ActivityArrayEditor.tsx +22 -12
- package/src/modules/workflows/components/fields/BusinessRuleConditionsEditor.tsx +9 -13
- package/src/modules/workflows/components/fields/FormFieldArrayEditor.tsx +27 -17
- package/src/modules/workflows/components/fields/StartPreConditionsEditor.tsx +9 -12
- package/src/modules/workflows/components/mobile/MobileTaskForm.tsx +19 -11
- package/src/modules/workflows/frontend/checkout-demo/page.tsx +71 -60
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/sales/widgets/dashboard/new-orders/widget.client.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\r\n\r\nimport * as React from 'react'\r\nimport Link from 'next/link'\r\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\r\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\r\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\r\nimport { Badge } from '@open-mercato/ui/primitives/badge'\r\nimport { formatRelativeTime } from '@open-mercato/shared/lib/time'\r\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\r\nimport { DEFAULT_SETTINGS, hydrateSalesNewOrdersSettings, type DatePeriodOption, type SalesNewOrdersSettings } from './config'\r\nimport { readString, toDateInputValue, openNativeDatePicker, formatAmount } from '../shared'\r\n\r\ntype NewOrderItem = {\r\n id: string\r\n orderNumber: string\r\n status: string | null\r\n customerName: string | null\r\n customerEntityId: string | null\r\n netAmount: string\r\n grossAmount: string\r\n currency: string | null\r\n createdAt: string\r\n}\r\n\r\ntype NewOrdersApiPayload = {\r\n items?: unknown[]\r\n error?: string\r\n}\r\n\r\nfunction parseNewOrderItems(payload: NewOrdersApiPayload | null): NewOrderItem[] {\r\n const rawItems = Array.isArray(payload?.items) ? payload?.items : []\r\n return rawItems\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null\r\n const data = item as Record<string, unknown>\r\n const id = readString(data.id)\r\n const orderNumber = readString(data.orderNumber)\r\n const createdAt = readString(data.createdAt)\r\n if (!id || !orderNumber || !createdAt) return null\r\n return {\r\n id,\r\n orderNumber,\r\n status: readString(data.status),\r\n customerName: readString(data.customerName),\r\n customerEntityId: readString(data.customerEntityId),\r\n netAmount: readString(data.netAmount) ?? '0',\r\n grossAmount: readString(data.grossAmount) ?? '0',\r\n currency: readString(data.currency),\r\n createdAt,\r\n }\r\n })\r\n .filter((item): item is NewOrderItem => !!item)\r\n}\r\n\r\nasync function loadNewOrders(settings: SalesNewOrdersSettings): Promise<NewOrderItem[]> {\r\n const params = new URLSearchParams({\r\n limit: String(settings.pageSize),\r\n datePeriod: settings.datePeriod,\r\n })\r\n if (settings.datePeriod === 'custom') {\r\n if (settings.customFrom) params.set('customFrom', settings.customFrom)\r\n if (settings.customTo) params.set('customTo', settings.customTo)\r\n }\r\n\r\n const call = await apiCall<NewOrdersApiPayload>(`/api/sales/dashboard/widgets/new-orders?${params.toString()}`)\r\n if (!call.ok) {\r\n const message =\r\n typeof (call.result as Record<string, unknown> | null)?.error === 'string'\r\n ? ((call.result as Record<string, unknown>).error as string)\r\n : `Request failed with status ${call.status}`\r\n throw new Error(message)\r\n }\r\n return parseNewOrderItems(call.result ?? null)\r\n}\r\n\r\nfunction resolveDetailHref(item: NewOrderItem): string | null {\r\n return item.id ? `/backend/sales/orders/${encodeURIComponent(item.id)}` : null\r\n}\r\n\r\n\r\nconst SalesNewOrdersWidget: React.FC<DashboardWidgetComponentProps<SalesNewOrdersSettings>> = ({\r\n mode,\r\n settings = DEFAULT_SETTINGS,\r\n onSettingsChange,\r\n refreshToken,\r\n onRefreshStateChange,\r\n}) => {\r\n const translate = useT()\r\n const hydrated = React.useMemo(() => hydrateSalesNewOrdersSettings(settings), [settings])\r\n const [items, setItems] = React.useState<NewOrderItem[]>([])\r\n const [loading, setLoading] = React.useState(true)\r\n const [error, setError] = React.useState<string | null>(null)\r\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\r\n\r\n React.useEffect(() => {\r\n if (typeof navigator !== 'undefined') {\r\n setLocale(navigator.language)\r\n }\r\n }, [])\r\n\r\n const refresh = React.useCallback(async () => {\r\n onRefreshStateChange?.(true)\r\n setLoading(true)\r\n setError(null)\r\n try {\r\n const data = await loadNewOrders(hydrated)\r\n setItems(data)\r\n } catch (err) {\r\n console.error('Failed to load new orders widget data', err)\r\n setError(translate('sales.widgets.newOrders.error', 'Failed to load orders'))\r\n } finally {\r\n setLoading(false)\r\n onRefreshStateChange?.(false)\r\n }\r\n }, [hydrated, onRefreshStateChange, translate])\r\n\r\n React.useEffect(() => {\r\n refresh().catch(() => {})\r\n }, [refresh, refreshToken])\r\n\r\n if (mode === 'settings') {\r\n return (\r\n <div className=\"space-y-4 text-sm\">\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-orders-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newOrders.settings.pageSize', 'Number of Orders')}\r\n </label>\r\n <input\r\n id=\"sales-new-orders-page-size\"\r\n type=\"number\"\r\n min={1}\r\n max={20}\r\n className=\"w-24 rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n value={hydrated.pageSize}\r\n onChange={(event) => {\r\n const next = Number(event.target.value)\r\n if (!Number.isFinite(next)) return\r\n const clamped = Math.min(20, Math.max(1, Math.floor(next)))\r\n onSettingsChange?.({ ...hydrated, pageSize: clamped })\r\n }}\r\n />\r\n </div>\r\n\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-orders-date-period\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newOrders.settings.datePeriod', 'Date Period')}\r\n </label>\r\n <select\r\n id=\"sales-new-orders-date-period\"\r\n value={hydrated.datePeriod}\r\n onChange={(event) => {\r\n onSettingsChange?.({ ...hydrated, datePeriod: event.target.value as DatePeriodOption })\r\n }}\r\n className=\"w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n >\r\n <option value=\"last24h\">{translate('sales.widgets.newOrders.settings.last24h', 'Last 24 hours')}</option>\r\n <option value=\"last7d\">{translate('sales.widgets.newOrders.settings.last7d', 'Last 7 days')}</option>\r\n <option value=\"last30d\">{translate('sales.widgets.newOrders.settings.last30d', 'Last 30 days')}</option>\r\n <option value=\"custom\">{translate('sales.widgets.newOrders.settings.custom', 'Custom range')}</option>\r\n </select>\r\n </div>\r\n\r\n {hydrated.datePeriod === 'custom' ? (\r\n <div className=\"grid gap-3\">\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-orders-custom-from\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newOrders.settings.customFrom', 'From')}\r\n </label>\r\n <input\r\n id=\"sales-new-orders-custom-from\"\r\n type=\"date\"\r\n value={toDateInputValue(hydrated.customFrom)}\r\n onChange={(event) => {\r\n onSettingsChange?.({ ...hydrated, customFrom: event.target.value })\r\n }}\r\n onFocus={openNativeDatePicker}\r\n onClick={openNativeDatePicker}\r\n className=\"w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n />\r\n </div>\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-orders-custom-to\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newOrders.settings.customTo', 'To')}\r\n </label>\r\n <input\r\n id=\"sales-new-orders-custom-to\"\r\n type=\"date\"\r\n value={toDateInputValue(hydrated.customTo)}\r\n onChange={(event) => {\r\n onSettingsChange?.({ ...hydrated, customTo: event.target.value })\r\n }}\r\n onFocus={openNativeDatePicker}\r\n onClick={openNativeDatePicker}\r\n className=\"w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n />\r\n </div>\r\n </div>\r\n ) : null}\r\n </div>\r\n )\r\n }\r\n\r\n if (error) {\r\n return <p className=\"text-sm text-destructive\">{error}</p>\r\n }\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex h-32 items-center justify-center\">\r\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\r\n </div>\r\n )\r\n }\r\n\r\n if (!items.length) {\r\n return <p className=\"text-sm text-muted-foreground\">{translate('sales.widgets.newOrders.empty', 'No orders found')}</p>\r\n }\r\n\r\n return (\r\n <ul className=\"space-y-3\">\r\n {items.map((item) => {\r\n const detailHref = resolveDetailHref(item)\r\n const amountLabel = formatAmount(item.grossAmount, item.currency, locale)\r\n const createdLabel = formatRelativeTime(item.createdAt) ?? ''\r\n return (\r\n <li key={item.id} className=\"rounded-md border p-3\">\r\n <div className=\"flex items-start justify-between gap-3\">\r\n <div className=\"space-y-1\">\r\n <div className=\"flex items-center gap-2\">\r\n {detailHref ? (\r\n <Link href={detailHref} className=\"text-sm font-semibold text-foreground hover:underline\">\r\n {item.orderNumber}\r\n </Link>\r\n ) : (\r\n <span className=\"text-sm font-semibold text-foreground\">{item.orderNumber}</span>\r\n )}\r\n {item.status ? (\r\n <Badge variant=\"outline\" className=\"text-xs\">\r\n {item.status}\r\n </Badge>\r\n ) : null}\r\n </div>\r\n <p className=\"text-xs text-muted-foreground\">\r\n {item.customerName ?? translate('sales.widgets.newOrders.noCustomer', 'No customer')}\r\n </p>\r\n <p className=\"text-xs text-muted-foreground\">{createdLabel}</p>\r\n </div>\r\n <div className=\"text-right\">\r\n <p className=\"text-sm font-semibold\">{amountLabel}</p>\r\n </div>\r\n </div>\r\n </li>\r\n )\r\n })}\r\n </ul>\r\n )\r\n}\r\n\r\nexport default SalesNewOrdersWidget\r\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\r\n\r\nimport * as React from 'react'\r\nimport Link from 'next/link'\r\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\r\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\r\nimport { Input } from '@open-mercato/ui/primitives/input'\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from '@open-mercato/ui/primitives/select'\r\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\r\nimport { Badge } from '@open-mercato/ui/primitives/badge'\r\nimport { formatRelativeTime } from '@open-mercato/shared/lib/time'\r\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\r\nimport { DEFAULT_SETTINGS, hydrateSalesNewOrdersSettings, type DatePeriodOption, type SalesNewOrdersSettings } from './config'\r\nimport { readString, toDateInputValue, openNativeDatePicker, formatAmount } from '../shared'\r\n\r\ntype NewOrderItem = {\r\n id: string\r\n orderNumber: string\r\n status: string | null\r\n customerName: string | null\r\n customerEntityId: string | null\r\n netAmount: string\r\n grossAmount: string\r\n currency: string | null\r\n createdAt: string\r\n}\r\n\r\ntype NewOrdersApiPayload = {\r\n items?: unknown[]\r\n error?: string\r\n}\r\n\r\nfunction parseNewOrderItems(payload: NewOrdersApiPayload | null): NewOrderItem[] {\r\n const rawItems = Array.isArray(payload?.items) ? payload?.items : []\r\n return rawItems\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null\r\n const data = item as Record<string, unknown>\r\n const id = readString(data.id)\r\n const orderNumber = readString(data.orderNumber)\r\n const createdAt = readString(data.createdAt)\r\n if (!id || !orderNumber || !createdAt) return null\r\n return {\r\n id,\r\n orderNumber,\r\n status: readString(data.status),\r\n customerName: readString(data.customerName),\r\n customerEntityId: readString(data.customerEntityId),\r\n netAmount: readString(data.netAmount) ?? '0',\r\n grossAmount: readString(data.grossAmount) ?? '0',\r\n currency: readString(data.currency),\r\n createdAt,\r\n }\r\n })\r\n .filter((item): item is NewOrderItem => !!item)\r\n}\r\n\r\nasync function loadNewOrders(settings: SalesNewOrdersSettings): Promise<NewOrderItem[]> {\r\n const params = new URLSearchParams({\r\n limit: String(settings.pageSize),\r\n datePeriod: settings.datePeriod,\r\n })\r\n if (settings.datePeriod === 'custom') {\r\n if (settings.customFrom) params.set('customFrom', settings.customFrom)\r\n if (settings.customTo) params.set('customTo', settings.customTo)\r\n }\r\n\r\n const call = await apiCall<NewOrdersApiPayload>(`/api/sales/dashboard/widgets/new-orders?${params.toString()}`)\r\n if (!call.ok) {\r\n const message =\r\n typeof (call.result as Record<string, unknown> | null)?.error === 'string'\r\n ? ((call.result as Record<string, unknown>).error as string)\r\n : `Request failed with status ${call.status}`\r\n throw new Error(message)\r\n }\r\n return parseNewOrderItems(call.result ?? null)\r\n}\r\n\r\nfunction resolveDetailHref(item: NewOrderItem): string | null {\r\n return item.id ? `/backend/sales/orders/${encodeURIComponent(item.id)}` : null\r\n}\r\n\r\n\r\nconst SalesNewOrdersWidget: React.FC<DashboardWidgetComponentProps<SalesNewOrdersSettings>> = ({\r\n mode,\r\n settings = DEFAULT_SETTINGS,\r\n onSettingsChange,\r\n refreshToken,\r\n onRefreshStateChange,\r\n}) => {\r\n const translate = useT()\r\n const hydrated = React.useMemo(() => hydrateSalesNewOrdersSettings(settings), [settings])\r\n const [items, setItems] = React.useState<NewOrderItem[]>([])\r\n const [loading, setLoading] = React.useState(true)\r\n const [error, setError] = React.useState<string | null>(null)\r\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\r\n\r\n React.useEffect(() => {\r\n if (typeof navigator !== 'undefined') {\r\n setLocale(navigator.language)\r\n }\r\n }, [])\r\n\r\n const refresh = React.useCallback(async () => {\r\n onRefreshStateChange?.(true)\r\n setLoading(true)\r\n setError(null)\r\n try {\r\n const data = await loadNewOrders(hydrated)\r\n setItems(data)\r\n } catch (err) {\r\n console.error('Failed to load new orders widget data', err)\r\n setError(translate('sales.widgets.newOrders.error', 'Failed to load orders'))\r\n } finally {\r\n setLoading(false)\r\n onRefreshStateChange?.(false)\r\n }\r\n }, [hydrated, onRefreshStateChange, translate])\r\n\r\n React.useEffect(() => {\r\n refresh().catch(() => {})\r\n }, [refresh, refreshToken])\r\n\r\n if (mode === 'settings') {\r\n return (\r\n <div className=\"space-y-4 text-sm\">\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-orders-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newOrders.settings.pageSize', 'Number of Orders')}\r\n </label>\r\n <Input\r\n id=\"sales-new-orders-page-size\"\r\n type=\"number\"\r\n min={1}\r\n max={20}\r\n className=\"w-24\"\r\n value={hydrated.pageSize}\r\n onChange={(event) => {\r\n const next = Number(event.target.value)\r\n if (!Number.isFinite(next)) return\r\n const clamped = Math.min(20, Math.max(1, Math.floor(next)))\r\n onSettingsChange?.({ ...hydrated, pageSize: clamped })\r\n }}\r\n />\r\n </div>\r\n\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-orders-date-period\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newOrders.settings.datePeriod', 'Date Period')}\r\n </label>\r\n <Select\r\n value={hydrated.datePeriod}\r\n onValueChange={(value) => {\r\n onSettingsChange?.({ ...hydrated, datePeriod: value as DatePeriodOption })\r\n }}\r\n >\r\n <SelectTrigger id=\"sales-new-orders-date-period\" size=\"sm\">\r\n <SelectValue />\r\n </SelectTrigger>\r\n <SelectContent>\r\n <SelectItem value=\"last24h\">{translate('sales.widgets.newOrders.settings.last24h', 'Last 24 hours')}</SelectItem>\r\n <SelectItem value=\"last7d\">{translate('sales.widgets.newOrders.settings.last7d', 'Last 7 days')}</SelectItem>\r\n <SelectItem value=\"last30d\">{translate('sales.widgets.newOrders.settings.last30d', 'Last 30 days')}</SelectItem>\r\n <SelectItem value=\"custom\">{translate('sales.widgets.newOrders.settings.custom', 'Custom range')}</SelectItem>\r\n </SelectContent>\r\n </Select>\r\n </div>\r\n\r\n {hydrated.datePeriod === 'custom' ? (\r\n <div className=\"grid gap-3\">\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-orders-custom-from\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newOrders.settings.customFrom', 'From')}\r\n </label>\r\n <input\r\n id=\"sales-new-orders-custom-from\"\r\n type=\"date\"\r\n value={toDateInputValue(hydrated.customFrom)}\r\n onChange={(event) => {\r\n onSettingsChange?.({ ...hydrated, customFrom: event.target.value })\r\n }}\r\n onFocus={openNativeDatePicker}\r\n onClick={openNativeDatePicker}\r\n className=\"w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n />\r\n </div>\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-orders-custom-to\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newOrders.settings.customTo', 'To')}\r\n </label>\r\n <input\r\n id=\"sales-new-orders-custom-to\"\r\n type=\"date\"\r\n value={toDateInputValue(hydrated.customTo)}\r\n onChange={(event) => {\r\n onSettingsChange?.({ ...hydrated, customTo: event.target.value })\r\n }}\r\n onFocus={openNativeDatePicker}\r\n onClick={openNativeDatePicker}\r\n className=\"w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n />\r\n </div>\r\n </div>\r\n ) : null}\r\n </div>\r\n )\r\n }\r\n\r\n if (error) {\r\n return <p className=\"text-sm text-destructive\">{error}</p>\r\n }\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex h-32 items-center justify-center\">\r\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\r\n </div>\r\n )\r\n }\r\n\r\n if (!items.length) {\r\n return <p className=\"text-sm text-muted-foreground\">{translate('sales.widgets.newOrders.empty', 'No orders found')}</p>\r\n }\r\n\r\n return (\r\n <ul className=\"space-y-3\">\r\n {items.map((item) => {\r\n const detailHref = resolveDetailHref(item)\r\n const amountLabel = formatAmount(item.grossAmount, item.currency, locale)\r\n const createdLabel = formatRelativeTime(item.createdAt) ?? ''\r\n return (\r\n <li key={item.id} className=\"rounded-md border p-3\">\r\n <div className=\"flex items-start justify-between gap-3\">\r\n <div className=\"space-y-1\">\r\n <div className=\"flex items-center gap-2\">\r\n {detailHref ? (\r\n <Link href={detailHref} className=\"text-sm font-semibold text-foreground hover:underline\">\r\n {item.orderNumber}\r\n </Link>\r\n ) : (\r\n <span className=\"text-sm font-semibold text-foreground\">{item.orderNumber}</span>\r\n )}\r\n {item.status ? (\r\n <Badge variant=\"outline\" className=\"text-xs\">\r\n {item.status}\r\n </Badge>\r\n ) : null}\r\n </div>\r\n <p className=\"text-xs text-muted-foreground\">\r\n {item.customerName ?? translate('sales.widgets.newOrders.noCustomer', 'No customer')}\r\n </p>\r\n <p className=\"text-xs text-muted-foreground\">{createdLabel}</p>\r\n </div>\r\n <div className=\"text-right\">\r\n <p className=\"text-sm font-semibold\">{amountLabel}</p>\r\n </div>\r\n </div>\r\n </li>\r\n )\r\n })}\r\n </ul>\r\n )\r\n}\r\n\r\nexport default SalesNewOrdersWidget\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,6 +3,14 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
6
|
+
import { Input } from "@open-mercato/ui/primitives/input";
|
|
7
|
+
import {
|
|
8
|
+
Select,
|
|
9
|
+
SelectContent,
|
|
10
|
+
SelectItem,
|
|
11
|
+
SelectTrigger,
|
|
12
|
+
SelectValue
|
|
13
|
+
} from "@open-mercato/ui/primitives/select";
|
|
6
14
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
7
15
|
import { Badge } from "@open-mercato/ui/primitives/badge";
|
|
8
16
|
import { formatRelativeTime } from "@open-mercato/shared/lib/time";
|
|
@@ -95,13 +103,13 @@ const SalesNewQuotesWidget = ({
|
|
|
95
103
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
96
104
|
/* @__PURE__ */ jsx("label", { htmlFor: "sales-new-quotes-page-size", className: "text-xs font-semibold uppercase text-muted-foreground", children: translate("sales.widgets.newQuotes.settings.pageSize", "Number of Quotes") }),
|
|
97
105
|
/* @__PURE__ */ jsx(
|
|
98
|
-
|
|
106
|
+
Input,
|
|
99
107
|
{
|
|
100
108
|
id: "sales-new-quotes-page-size",
|
|
101
109
|
type: "number",
|
|
102
110
|
min: 1,
|
|
103
111
|
max: 20,
|
|
104
|
-
className: "w-24
|
|
112
|
+
className: "w-24",
|
|
105
113
|
value: hydrated.pageSize,
|
|
106
114
|
onChange: (event) => {
|
|
107
115
|
const next = Number(event.target.value);
|
|
@@ -115,19 +123,20 @@ const SalesNewQuotesWidget = ({
|
|
|
115
123
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
116
124
|
/* @__PURE__ */ jsx("label", { htmlFor: "sales-new-quotes-date-period", className: "text-xs font-semibold uppercase text-muted-foreground", children: translate("sales.widgets.newQuotes.settings.datePeriod", "Date Period") }),
|
|
117
125
|
/* @__PURE__ */ jsxs(
|
|
118
|
-
|
|
126
|
+
Select,
|
|
119
127
|
{
|
|
120
|
-
id: "sales-new-quotes-date-period",
|
|
121
128
|
value: hydrated.datePeriod,
|
|
122
|
-
|
|
123
|
-
onSettingsChange?.({ ...hydrated, datePeriod:
|
|
129
|
+
onValueChange: (value) => {
|
|
130
|
+
onSettingsChange?.({ ...hydrated, datePeriod: value });
|
|
124
131
|
},
|
|
125
|
-
className: "w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
126
132
|
children: [
|
|
127
|
-
/* @__PURE__ */ jsx(
|
|
128
|
-
/* @__PURE__ */
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
/* @__PURE__ */ jsx(SelectTrigger, { id: "sales-new-quotes-date-period", size: "sm", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
134
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
135
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "last24h", children: translate("sales.widgets.newQuotes.settings.last24h", "Last 24 hours") }),
|
|
136
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "last7d", children: translate("sales.widgets.newQuotes.settings.last7d", "Last 7 days") }),
|
|
137
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "last30d", children: translate("sales.widgets.newQuotes.settings.last30d", "Last 30 days") }),
|
|
138
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "custom", children: translate("sales.widgets.newQuotes.settings.custom", "Custom range") })
|
|
139
|
+
] })
|
|
131
140
|
]
|
|
132
141
|
}
|
|
133
142
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/sales/widgets/dashboard/new-quotes/widget.client.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\r\n\r\nimport * as React from 'react'\r\nimport Link from 'next/link'\r\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\r\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\r\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\r\nimport { Badge } from '@open-mercato/ui/primitives/badge'\r\nimport { formatRelativeTime } from '@open-mercato/shared/lib/time'\r\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\r\nimport { DEFAULT_SETTINGS, hydrateSalesNewQuotesSettings, type DatePeriodOption, type SalesNewQuotesSettings } from './config'\r\nimport { readString, toDateInputValue, openNativeDatePicker, formatAmount } from '../shared'\r\n\r\ntype NewQuoteItem = {\r\n id: string\r\n quoteNumber: string\r\n status: string | null\r\n customerName: string | null\r\n customerEntityId: string | null\r\n netAmount: string\r\n grossAmount: string\r\n currency: string | null\r\n createdAt: string\r\n validFrom: string | null\r\n validUntil: string | null\r\n convertedOrderId: string | null\r\n}\r\n\r\ntype NewQuotesApiPayload = {\r\n items?: unknown[]\r\n error?: string\r\n}\r\n\r\nfunction parseNewQuoteItems(payload: NewQuotesApiPayload | null): NewQuoteItem[] {\r\n const rawItems = Array.isArray(payload?.items) ? payload?.items : []\r\n return rawItems\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null\r\n const data = item as Record<string, unknown>\r\n const id = readString(data.id)\r\n const quoteNumber = readString(data.quoteNumber)\r\n const createdAt = readString(data.createdAt)\r\n if (!id || !quoteNumber || !createdAt) return null\r\n return {\r\n id,\r\n quoteNumber,\r\n status: readString(data.status),\r\n customerName: readString(data.customerName),\r\n customerEntityId: readString(data.customerEntityId),\r\n netAmount: readString(data.netAmount) ?? '0',\r\n grossAmount: readString(data.grossAmount) ?? '0',\r\n currency: readString(data.currency),\r\n createdAt,\r\n validFrom: readString(data.validFrom),\r\n validUntil: readString(data.validUntil),\r\n convertedOrderId: readString(data.convertedOrderId),\r\n }\r\n })\r\n .filter((item): item is NewQuoteItem => !!item)\r\n}\r\n\r\nasync function loadNewQuotes(settings: SalesNewQuotesSettings): Promise<NewQuoteItem[]> {\r\n const params = new URLSearchParams({\r\n limit: String(settings.pageSize),\r\n datePeriod: settings.datePeriod,\r\n })\r\n if (settings.datePeriod === 'custom') {\r\n if (settings.customFrom) params.set('customFrom', settings.customFrom)\r\n if (settings.customTo) params.set('customTo', settings.customTo)\r\n }\r\n\r\n const call = await apiCall<NewQuotesApiPayload>(`/api/sales/dashboard/widgets/new-quotes?${params.toString()}`)\r\n if (!call.ok) {\r\n const message =\r\n typeof (call.result as Record<string, unknown> | null)?.error === 'string'\r\n ? ((call.result as Record<string, unknown>).error as string)\r\n : `Request failed with status ${call.status}`\r\n throw new Error(message)\r\n }\r\n return parseNewQuoteItems(call.result ?? null)\r\n}\r\n\r\nfunction resolveDetailHref(item: NewQuoteItem): string | null {\r\n return item.id ? `/backend/sales/quotes/${encodeURIComponent(item.id)}` : null\r\n}\r\n\r\n\r\nconst SalesNewQuotesWidget: React.FC<DashboardWidgetComponentProps<SalesNewQuotesSettings>> = ({\r\n mode,\r\n settings = DEFAULT_SETTINGS,\r\n onSettingsChange,\r\n refreshToken,\r\n onRefreshStateChange,\r\n}) => {\r\n const translate = useT()\r\n const hydrated = React.useMemo(() => hydrateSalesNewQuotesSettings(settings), [settings])\r\n const [items, setItems] = React.useState<NewQuoteItem[]>([])\r\n const [loading, setLoading] = React.useState(true)\r\n const [error, setError] = React.useState<string | null>(null)\r\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\r\n\r\n React.useEffect(() => {\r\n if (typeof navigator !== 'undefined') {\r\n setLocale(navigator.language)\r\n }\r\n }, [])\r\n\r\n const refresh = React.useCallback(async () => {\r\n onRefreshStateChange?.(true)\r\n setLoading(true)\r\n setError(null)\r\n try {\r\n const data = await loadNewQuotes(hydrated)\r\n setItems(data)\r\n } catch (err) {\r\n console.error('Failed to load new quotes widget data', err)\r\n setError(translate('sales.widgets.newQuotes.error', 'Failed to load quotes'))\r\n } finally {\r\n setLoading(false)\r\n onRefreshStateChange?.(false)\r\n }\r\n }, [hydrated, onRefreshStateChange, translate])\r\n\r\n React.useEffect(() => {\r\n refresh().catch(() => {})\r\n }, [refresh, refreshToken])\r\n\r\n if (mode === 'settings') {\r\n return (\r\n <div className=\"space-y-4 text-sm\">\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-quotes-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newQuotes.settings.pageSize', 'Number of Quotes')}\r\n </label>\r\n <input\r\n id=\"sales-new-quotes-page-size\"\r\n type=\"number\"\r\n min={1}\r\n max={20}\r\n className=\"w-24 rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n value={hydrated.pageSize}\r\n onChange={(event) => {\r\n const next = Number(event.target.value)\r\n if (!Number.isFinite(next)) return\r\n const clamped = Math.min(20, Math.max(1, Math.floor(next)))\r\n onSettingsChange?.({ ...hydrated, pageSize: clamped })\r\n }}\r\n />\r\n </div>\r\n\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-quotes-date-period\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newQuotes.settings.datePeriod', 'Date Period')}\r\n </label>\r\n <select\r\n id=\"sales-new-quotes-date-period\"\r\n value={hydrated.datePeriod}\r\n onChange={(event) => {\r\n onSettingsChange?.({ ...hydrated, datePeriod: event.target.value as DatePeriodOption })\r\n }}\r\n className=\"w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n >\r\n <option value=\"last24h\">{translate('sales.widgets.newQuotes.settings.last24h', 'Last 24 hours')}</option>\r\n <option value=\"last7d\">{translate('sales.widgets.newQuotes.settings.last7d', 'Last 7 days')}</option>\r\n <option value=\"last30d\">{translate('sales.widgets.newQuotes.settings.last30d', 'Last 30 days')}</option>\r\n <option value=\"custom\">{translate('sales.widgets.newQuotes.settings.custom', 'Custom range')}</option>\r\n </select>\r\n </div>\r\n\r\n {hydrated.datePeriod === 'custom' ? (\r\n <div className=\"grid gap-3\">\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-quotes-custom-from\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newQuotes.settings.customFrom', 'From')}\r\n </label>\r\n <input\r\n id=\"sales-new-quotes-custom-from\"\r\n type=\"date\"\r\n value={toDateInputValue(hydrated.customFrom)}\r\n onChange={(event) => {\r\n onSettingsChange?.({ ...hydrated, customFrom: event.target.value })\r\n }}\r\n onFocus={openNativeDatePicker}\r\n onClick={openNativeDatePicker}\r\n className=\"w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n />\r\n </div>\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-quotes-custom-to\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newQuotes.settings.customTo', 'To')}\r\n </label>\r\n <input\r\n id=\"sales-new-quotes-custom-to\"\r\n type=\"date\"\r\n value={toDateInputValue(hydrated.customTo)}\r\n onChange={(event) => {\r\n onSettingsChange?.({ ...hydrated, customTo: event.target.value })\r\n }}\r\n onFocus={openNativeDatePicker}\r\n onClick={openNativeDatePicker}\r\n className=\"w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n />\r\n </div>\r\n </div>\r\n ) : null}\r\n </div>\r\n )\r\n }\r\n\r\n if (error) {\r\n return <p className=\"text-sm text-destructive\">{error}</p>\r\n }\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex h-32 items-center justify-center\">\r\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\r\n </div>\r\n )\r\n }\r\n\r\n if (!items.length) {\r\n return <p className=\"text-sm text-muted-foreground\">{translate('sales.widgets.newQuotes.empty', 'No quotes found')}</p>\r\n }\r\n\r\n return (\r\n <ul className=\"space-y-3\">\r\n {items.map((item) => {\r\n const detailHref = resolveDetailHref(item)\r\n const amountLabel = formatAmount(item.grossAmount, item.currency, locale)\r\n const createdLabel = formatRelativeTime(item.createdAt) ?? ''\r\n return (\r\n <li key={item.id} className=\"rounded-md border p-3\">\r\n <div className=\"flex items-start justify-between gap-3\">\r\n <div className=\"space-y-1\">\r\n <div className=\"flex items-center gap-2\">\r\n {detailHref ? (\r\n <Link href={detailHref} className=\"text-sm font-semibold text-foreground hover:underline\">\r\n {item.quoteNumber}\r\n </Link>\r\n ) : (\r\n <span className=\"text-sm font-semibold text-foreground\">{item.quoteNumber}</span>\r\n )}\r\n {item.status ? (\r\n <Badge variant=\"outline\" className=\"text-xs\">\r\n {item.status}\r\n </Badge>\r\n ) : null}\r\n </div>\r\n <p className=\"text-xs text-muted-foreground\">\r\n {item.customerName ?? translate('sales.widgets.newQuotes.noCustomer', 'No customer')}\r\n </p>\r\n <p className=\"text-xs text-muted-foreground\">{createdLabel}</p>\r\n </div>\r\n <div className=\"text-right\">\r\n <p className=\"text-sm font-semibold\">{amountLabel}</p>\r\n </div>\r\n </div>\r\n </li>\r\n )\r\n })}\r\n </ul>\r\n )\r\n}\r\n\r\nexport default SalesNewQuotesWidget\r\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\r\n\r\nimport * as React from 'react'\r\nimport Link from 'next/link'\r\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\r\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\r\nimport { Input } from '@open-mercato/ui/primitives/input'\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from '@open-mercato/ui/primitives/select'\r\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\r\nimport { Badge } from '@open-mercato/ui/primitives/badge'\r\nimport { formatRelativeTime } from '@open-mercato/shared/lib/time'\r\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\r\nimport { DEFAULT_SETTINGS, hydrateSalesNewQuotesSettings, type DatePeriodOption, type SalesNewQuotesSettings } from './config'\r\nimport { readString, toDateInputValue, openNativeDatePicker, formatAmount } from '../shared'\r\n\r\ntype NewQuoteItem = {\r\n id: string\r\n quoteNumber: string\r\n status: string | null\r\n customerName: string | null\r\n customerEntityId: string | null\r\n netAmount: string\r\n grossAmount: string\r\n currency: string | null\r\n createdAt: string\r\n validFrom: string | null\r\n validUntil: string | null\r\n convertedOrderId: string | null\r\n}\r\n\r\ntype NewQuotesApiPayload = {\r\n items?: unknown[]\r\n error?: string\r\n}\r\n\r\nfunction parseNewQuoteItems(payload: NewQuotesApiPayload | null): NewQuoteItem[] {\r\n const rawItems = Array.isArray(payload?.items) ? payload?.items : []\r\n return rawItems\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null\r\n const data = item as Record<string, unknown>\r\n const id = readString(data.id)\r\n const quoteNumber = readString(data.quoteNumber)\r\n const createdAt = readString(data.createdAt)\r\n if (!id || !quoteNumber || !createdAt) return null\r\n return {\r\n id,\r\n quoteNumber,\r\n status: readString(data.status),\r\n customerName: readString(data.customerName),\r\n customerEntityId: readString(data.customerEntityId),\r\n netAmount: readString(data.netAmount) ?? '0',\r\n grossAmount: readString(data.grossAmount) ?? '0',\r\n currency: readString(data.currency),\r\n createdAt,\r\n validFrom: readString(data.validFrom),\r\n validUntil: readString(data.validUntil),\r\n convertedOrderId: readString(data.convertedOrderId),\r\n }\r\n })\r\n .filter((item): item is NewQuoteItem => !!item)\r\n}\r\n\r\nasync function loadNewQuotes(settings: SalesNewQuotesSettings): Promise<NewQuoteItem[]> {\r\n const params = new URLSearchParams({\r\n limit: String(settings.pageSize),\r\n datePeriod: settings.datePeriod,\r\n })\r\n if (settings.datePeriod === 'custom') {\r\n if (settings.customFrom) params.set('customFrom', settings.customFrom)\r\n if (settings.customTo) params.set('customTo', settings.customTo)\r\n }\r\n\r\n const call = await apiCall<NewQuotesApiPayload>(`/api/sales/dashboard/widgets/new-quotes?${params.toString()}`)\r\n if (!call.ok) {\r\n const message =\r\n typeof (call.result as Record<string, unknown> | null)?.error === 'string'\r\n ? ((call.result as Record<string, unknown>).error as string)\r\n : `Request failed with status ${call.status}`\r\n throw new Error(message)\r\n }\r\n return parseNewQuoteItems(call.result ?? null)\r\n}\r\n\r\nfunction resolveDetailHref(item: NewQuoteItem): string | null {\r\n return item.id ? `/backend/sales/quotes/${encodeURIComponent(item.id)}` : null\r\n}\r\n\r\n\r\nconst SalesNewQuotesWidget: React.FC<DashboardWidgetComponentProps<SalesNewQuotesSettings>> = ({\r\n mode,\r\n settings = DEFAULT_SETTINGS,\r\n onSettingsChange,\r\n refreshToken,\r\n onRefreshStateChange,\r\n}) => {\r\n const translate = useT()\r\n const hydrated = React.useMemo(() => hydrateSalesNewQuotesSettings(settings), [settings])\r\n const [items, setItems] = React.useState<NewQuoteItem[]>([])\r\n const [loading, setLoading] = React.useState(true)\r\n const [error, setError] = React.useState<string | null>(null)\r\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\r\n\r\n React.useEffect(() => {\r\n if (typeof navigator !== 'undefined') {\r\n setLocale(navigator.language)\r\n }\r\n }, [])\r\n\r\n const refresh = React.useCallback(async () => {\r\n onRefreshStateChange?.(true)\r\n setLoading(true)\r\n setError(null)\r\n try {\r\n const data = await loadNewQuotes(hydrated)\r\n setItems(data)\r\n } catch (err) {\r\n console.error('Failed to load new quotes widget data', err)\r\n setError(translate('sales.widgets.newQuotes.error', 'Failed to load quotes'))\r\n } finally {\r\n setLoading(false)\r\n onRefreshStateChange?.(false)\r\n }\r\n }, [hydrated, onRefreshStateChange, translate])\r\n\r\n React.useEffect(() => {\r\n refresh().catch(() => {})\r\n }, [refresh, refreshToken])\r\n\r\n if (mode === 'settings') {\r\n return (\r\n <div className=\"space-y-4 text-sm\">\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-quotes-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newQuotes.settings.pageSize', 'Number of Quotes')}\r\n </label>\r\n <Input\r\n id=\"sales-new-quotes-page-size\"\r\n type=\"number\"\r\n min={1}\r\n max={20}\r\n className=\"w-24\"\r\n value={hydrated.pageSize}\r\n onChange={(event) => {\r\n const next = Number(event.target.value)\r\n if (!Number.isFinite(next)) return\r\n const clamped = Math.min(20, Math.max(1, Math.floor(next)))\r\n onSettingsChange?.({ ...hydrated, pageSize: clamped })\r\n }}\r\n />\r\n </div>\r\n\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-quotes-date-period\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newQuotes.settings.datePeriod', 'Date Period')}\r\n </label>\r\n <Select\r\n value={hydrated.datePeriod}\r\n onValueChange={(value) => {\r\n onSettingsChange?.({ ...hydrated, datePeriod: value as DatePeriodOption })\r\n }}\r\n >\r\n <SelectTrigger id=\"sales-new-quotes-date-period\" size=\"sm\">\r\n <SelectValue />\r\n </SelectTrigger>\r\n <SelectContent>\r\n <SelectItem value=\"last24h\">{translate('sales.widgets.newQuotes.settings.last24h', 'Last 24 hours')}</SelectItem>\r\n <SelectItem value=\"last7d\">{translate('sales.widgets.newQuotes.settings.last7d', 'Last 7 days')}</SelectItem>\r\n <SelectItem value=\"last30d\">{translate('sales.widgets.newQuotes.settings.last30d', 'Last 30 days')}</SelectItem>\r\n <SelectItem value=\"custom\">{translate('sales.widgets.newQuotes.settings.custom', 'Custom range')}</SelectItem>\r\n </SelectContent>\r\n </Select>\r\n </div>\r\n\r\n {hydrated.datePeriod === 'custom' ? (\r\n <div className=\"grid gap-3\">\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-quotes-custom-from\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newQuotes.settings.customFrom', 'From')}\r\n </label>\r\n <input\r\n id=\"sales-new-quotes-custom-from\"\r\n type=\"date\"\r\n value={toDateInputValue(hydrated.customFrom)}\r\n onChange={(event) => {\r\n onSettingsChange?.({ ...hydrated, customFrom: event.target.value })\r\n }}\r\n onFocus={openNativeDatePicker}\r\n onClick={openNativeDatePicker}\r\n className=\"w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n />\r\n </div>\r\n <div className=\"space-y-1.5\">\r\n <label htmlFor=\"sales-new-quotes-custom-to\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\r\n {translate('sales.widgets.newQuotes.settings.customTo', 'To')}\r\n </label>\r\n <input\r\n id=\"sales-new-quotes-custom-to\"\r\n type=\"date\"\r\n value={toDateInputValue(hydrated.customTo)}\r\n onChange={(event) => {\r\n onSettingsChange?.({ ...hydrated, customTo: event.target.value })\r\n }}\r\n onFocus={openNativeDatePicker}\r\n onClick={openNativeDatePicker}\r\n className=\"w-full rounded-md border border-input bg-background px-2 py-1 text-sm text-foreground focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n />\r\n </div>\r\n </div>\r\n ) : null}\r\n </div>\r\n )\r\n }\r\n\r\n if (error) {\r\n return <p className=\"text-sm text-destructive\">{error}</p>\r\n }\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex h-32 items-center justify-center\">\r\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\r\n </div>\r\n )\r\n }\r\n\r\n if (!items.length) {\r\n return <p className=\"text-sm text-muted-foreground\">{translate('sales.widgets.newQuotes.empty', 'No quotes found')}</p>\r\n }\r\n\r\n return (\r\n <ul className=\"space-y-3\">\r\n {items.map((item) => {\r\n const detailHref = resolveDetailHref(item)\r\n const amountLabel = formatAmount(item.grossAmount, item.currency, locale)\r\n const createdLabel = formatRelativeTime(item.createdAt) ?? ''\r\n return (\r\n <li key={item.id} className=\"rounded-md border p-3\">\r\n <div className=\"flex items-start justify-between gap-3\">\r\n <div className=\"space-y-1\">\r\n <div className=\"flex items-center gap-2\">\r\n {detailHref ? (\r\n <Link href={detailHref} className=\"text-sm font-semibold text-foreground hover:underline\">\r\n {item.quoteNumber}\r\n </Link>\r\n ) : (\r\n <span className=\"text-sm font-semibold text-foreground\">{item.quoteNumber}</span>\r\n )}\r\n {item.status ? (\r\n <Badge variant=\"outline\" className=\"text-xs\">\r\n {item.status}\r\n </Badge>\r\n ) : null}\r\n </div>\r\n <p className=\"text-xs text-muted-foreground\">\r\n {item.customerName ?? translate('sales.widgets.newQuotes.noCustomer', 'No customer')}\r\n </p>\r\n <p className=\"text-xs text-muted-foreground\">{createdLabel}</p>\r\n </div>\r\n <div className=\"text-right\">\r\n <p className=\"text-sm font-semibold\">{amountLabel}</p>\r\n </div>\r\n </div>\r\n </li>\r\n )\r\n })}\r\n </ul>\r\n )\r\n}\r\n\r\nexport default SalesNewQuotesWidget\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
5
|
+
import { Input } from "@open-mercato/ui/primitives/input";
|
|
6
|
+
import {
|
|
7
|
+
Select,
|
|
8
|
+
SelectContent,
|
|
9
|
+
SelectItem,
|
|
10
|
+
SelectTrigger,
|
|
11
|
+
SelectValue
|
|
12
|
+
} from "@open-mercato/ui/primitives/select";
|
|
5
13
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
6
14
|
import { Card, CardContent, CardHeader, CardTitle } from "@open-mercato/ui/primitives/card";
|
|
7
15
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
@@ -62,14 +70,15 @@ const ConfigureStep = (props) => {
|
|
|
62
70
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
63
71
|
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-muted-foreground", children: t("shipping_carriers.create.field.phone", "Phone") }),
|
|
64
72
|
/* @__PURE__ */ jsx(
|
|
65
|
-
|
|
73
|
+
Input,
|
|
66
74
|
{
|
|
67
|
-
className: `w-full rounded border bg-background px-2 py-1.5 text-sm ${senderContactErrors.phone ? "border-destructive" : ""}`,
|
|
68
75
|
type: "tel",
|
|
76
|
+
size: "sm",
|
|
69
77
|
value: senderContact.phone,
|
|
70
78
|
onChange: (e) => onSenderContactChange({ ...senderContact, phone: e.target.value }),
|
|
71
79
|
disabled: isFetchingRates,
|
|
72
|
-
placeholder: "e.g. 500000000"
|
|
80
|
+
placeholder: "e.g. 500000000",
|
|
81
|
+
"aria-invalid": senderContactErrors.phone ? true : void 0
|
|
73
82
|
}
|
|
74
83
|
),
|
|
75
84
|
senderContactErrors.phone ? /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: senderContactErrors.phone }) : null
|
|
@@ -77,14 +86,15 @@ const ConfigureStep = (props) => {
|
|
|
77
86
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
78
87
|
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-muted-foreground", children: t("shipping_carriers.create.field.email", "Email") }),
|
|
79
88
|
/* @__PURE__ */ jsx(
|
|
80
|
-
|
|
89
|
+
Input,
|
|
81
90
|
{
|
|
82
|
-
className: `w-full rounded border bg-background px-2 py-1.5 text-sm ${senderContactErrors.email ? "border-destructive" : ""}`,
|
|
83
91
|
type: "email",
|
|
92
|
+
size: "sm",
|
|
84
93
|
value: senderContact.email,
|
|
85
94
|
onChange: (e) => onSenderContactChange({ ...senderContact, email: e.target.value }),
|
|
86
95
|
disabled: isFetchingRates,
|
|
87
|
-
placeholder: "e.g. sender@example.com"
|
|
96
|
+
placeholder: "e.g. sender@example.com",
|
|
97
|
+
"aria-invalid": senderContactErrors.email ? true : void 0
|
|
88
98
|
}
|
|
89
99
|
),
|
|
90
100
|
senderContactErrors.email ? /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: senderContactErrors.email }) : null
|
|
@@ -97,14 +107,15 @@ const ConfigureStep = (props) => {
|
|
|
97
107
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
98
108
|
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-muted-foreground", children: t("shipping_carriers.create.field.phone", "Phone") }),
|
|
99
109
|
/* @__PURE__ */ jsx(
|
|
100
|
-
|
|
110
|
+
Input,
|
|
101
111
|
{
|
|
102
|
-
className: `w-full rounded border bg-background px-2 py-1.5 text-sm ${receiverContactErrors.phone ? "border-destructive" : ""}`,
|
|
103
112
|
type: "tel",
|
|
113
|
+
size: "sm",
|
|
104
114
|
value: receiverContact.phone,
|
|
105
115
|
onChange: (e) => onReceiverContactChange({ ...receiverContact, phone: e.target.value }),
|
|
106
116
|
disabled: isFetchingRates,
|
|
107
|
-
placeholder: "e.g. 500000000"
|
|
117
|
+
placeholder: "e.g. 500000000",
|
|
118
|
+
"aria-invalid": receiverContactErrors.phone ? true : void 0
|
|
108
119
|
}
|
|
109
120
|
),
|
|
110
121
|
receiverContactErrors.phone ? /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: receiverContactErrors.phone }) : null
|
|
@@ -112,14 +123,15 @@ const ConfigureStep = (props) => {
|
|
|
112
123
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
113
124
|
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-muted-foreground", children: t("shipping_carriers.create.field.email", "Email") }),
|
|
114
125
|
/* @__PURE__ */ jsx(
|
|
115
|
-
|
|
126
|
+
Input,
|
|
116
127
|
{
|
|
117
|
-
className: `w-full rounded border bg-background px-2 py-1.5 text-sm ${receiverContactErrors.email ? "border-destructive" : ""}`,
|
|
118
128
|
type: "email",
|
|
129
|
+
size: "sm",
|
|
119
130
|
value: receiverContact.email,
|
|
120
131
|
onChange: (e) => onReceiverContactChange({ ...receiverContact, email: e.target.value }),
|
|
121
132
|
disabled: isFetchingRates,
|
|
122
|
-
placeholder: "e.g. receiver@example.com"
|
|
133
|
+
placeholder: "e.g. receiver@example.com",
|
|
134
|
+
"aria-invalid": receiverContactErrors.email ? true : void 0
|
|
123
135
|
}
|
|
124
136
|
),
|
|
125
137
|
receiverContactErrors.email ? /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: receiverContactErrors.email }) : null
|
|
@@ -132,17 +144,18 @@ const ConfigureStep = (props) => {
|
|
|
132
144
|
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
133
145
|
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-muted-foreground", children: t("shipping_carriers.create.field.c2cSendingMethod", "Sending method (applies to courier_c2c service only)") }),
|
|
134
146
|
/* @__PURE__ */ jsxs(
|
|
135
|
-
|
|
147
|
+
Select,
|
|
136
148
|
{
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
onChange: (e) => onC2cSendingMethodChange(e.target.value),
|
|
149
|
+
value: c2cSendingMethod || void 0,
|
|
150
|
+
onValueChange: (value) => onC2cSendingMethodChange(value ?? ""),
|
|
140
151
|
disabled: isFetchingRates,
|
|
141
152
|
children: [
|
|
142
|
-
/* @__PURE__ */ jsx(
|
|
143
|
-
/* @__PURE__ */
|
|
144
|
-
|
|
145
|
-
|
|
153
|
+
/* @__PURE__ */ jsx(SelectTrigger, { size: "sm", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("shipping_carriers.create.c2cSendingMethod.default", "Dispatch order (default)") }) }),
|
|
154
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
155
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "parcel_locker", children: t("shipping_carriers.create.c2cSendingMethod.parcel_locker", "Parcel locker") }),
|
|
156
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "pop", children: t("shipping_carriers.create.c2cSendingMethod.pop", "POP (parcel pickup point)") }),
|
|
157
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "any_point", children: t("shipping_carriers.create.c2cSendingMethod.any_point", "Any point") })
|
|
158
|
+
] })
|
|
146
159
|
]
|
|
147
160
|
}
|
|
148
161
|
)
|
|
@@ -169,9 +182,10 @@ const ConfigureStep = (props) => {
|
|
|
169
182
|
] }),
|
|
170
183
|
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
171
184
|
/* @__PURE__ */ jsx(
|
|
172
|
-
|
|
185
|
+
Input,
|
|
173
186
|
{
|
|
174
|
-
|
|
187
|
+
size: "sm",
|
|
188
|
+
className: "flex-1",
|
|
175
189
|
value: searchInput,
|
|
176
190
|
onChange: (e) => setSearchInput(e.target.value),
|
|
177
191
|
onKeyDown: (e) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/shipping_carriers/lib/shipment-wizard/components/ConfigureStep.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Card, CardContent, CardHeader, CardTitle } from '@open-mercato/ui/primitives/card'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { AddressFields } from './AddressFields'\nimport { PackageEditor } from './PackageEditor'\nimport type { Address, PackageDimension, LabelFormat, ContactInfo, DropOffPoint } from '../types'\n\nexport type ConfigureStepProps = {\n origin: Address\n destination: Address\n packages: PackageDimension[]\n labelFormat: LabelFormat\n senderContact: ContactInfo\n receiverContact: ContactInfo\n targetPoint: string\n c2cSendingMethod: string\n isFetchingRates: boolean\n canProceed: boolean\n senderContactErrors: { email: string | null; phone: string | null }\n receiverContactErrors: { email: string | null; phone: string | null }\n dropOffPointQuery: string\n dropOffPoints: DropOffPoint[]\n isFetchingDropOffPoints: boolean\n dropOffPointsError: string | null\n onOriginChange: (address: Address) => void\n onDestinationChange: (address: Address) => void\n onPackagesChange: (packages: PackageDimension[]) => void\n onLabelFormatChange: (format: LabelFormat) => void\n onSenderContactChange: (contact: ContactInfo) => void\n onReceiverContactChange: (contact: ContactInfo) => void\n onTargetPointChange: (point: string) => void\n onC2cSendingMethodChange: (method: string) => void\n onSearchDropOffPoints: (query: string) => void\n onBack: () => void\n onNext: () => void\n}\n\nconst LABEL_FORMATS: LabelFormat[] = ['pdf', 'zpl', 'png']\n\nexport const ConfigureStep = (props: ConfigureStepProps) => {\n const {\n origin, destination, packages, labelFormat,\n senderContact, receiverContact, targetPoint, c2cSendingMethod,\n isFetchingRates, canProceed,\n senderContactErrors, receiverContactErrors,\n dropOffPointQuery, dropOffPoints, isFetchingDropOffPoints, dropOffPointsError,\n onOriginChange, onDestinationChange, onPackagesChange, onLabelFormatChange,\n onSenderContactChange, onReceiverContactChange, onTargetPointChange, onC2cSendingMethodChange,\n onSearchDropOffPoints,\n onBack, onNext,\n } = props\n const t = useT()\n const [searchInput, setSearchInput] = React.useState(dropOffPointQuery)\n\n return (\n <section className=\"space-y-6\">\n <div className=\"grid gap-6 lg:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.origin', 'Origin address')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <AddressFields prefix=\"origin\" address={origin} onChange={onOriginChange} disabled={isFetchingRates} />\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.destination', 'Destination address')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <AddressFields prefix=\"dest\" address={destination} onChange={onDestinationChange} disabled={isFetchingRates} />\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.packages', 'Packages')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <PackageEditor packages={packages} onChange={onPackagesChange} disabled={isFetchingRates} />\n </CardContent>\n </Card>\n\n <div className=\"grid gap-6 lg:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.senderContact', 'Sender contact')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n {t('shipping_carriers.create.field.phone', 'Phone')}\n </label>\n <input\n className={`w-full rounded border bg-background px-2 py-1.5 text-sm ${senderContactErrors.phone ? 'border-destructive' : ''}`}\n type=\"tel\"\n value={senderContact.phone}\n onChange={(e) => onSenderContactChange({ ...senderContact, phone: e.target.value })}\n disabled={isFetchingRates}\n placeholder=\"e.g. 500000000\"\n />\n {senderContactErrors.phone ? (\n <p className=\"text-xs text-destructive\">{senderContactErrors.phone}</p>\n ) : null}\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n {t('shipping_carriers.create.field.email', 'Email')}\n </label>\n <input\n className={`w-full rounded border bg-background px-2 py-1.5 text-sm ${senderContactErrors.email ? 'border-destructive' : ''}`}\n type=\"email\"\n value={senderContact.email}\n onChange={(e) => onSenderContactChange({ ...senderContact, email: e.target.value })}\n disabled={isFetchingRates}\n placeholder=\"e.g. sender@example.com\"\n />\n {senderContactErrors.email ? (\n <p className=\"text-xs text-destructive\">{senderContactErrors.email}</p>\n ) : null}\n </div>\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.receiverContact', 'Receiver contact')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n {t('shipping_carriers.create.field.phone', 'Phone')}\n </label>\n <input\n className={`w-full rounded border bg-background px-2 py-1.5 text-sm ${receiverContactErrors.phone ? 'border-destructive' : ''}`}\n type=\"tel\"\n value={receiverContact.phone}\n onChange={(e) => onReceiverContactChange({ ...receiverContact, phone: e.target.value })}\n disabled={isFetchingRates}\n placeholder=\"e.g. 500000000\"\n />\n {receiverContactErrors.phone ? (\n <p className=\"text-xs text-destructive\">{receiverContactErrors.phone}</p>\n ) : null}\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n {t('shipping_carriers.create.field.email', 'Email')}\n </label>\n <input\n className={`w-full rounded border bg-background px-2 py-1.5 text-sm ${receiverContactErrors.email ? 'border-destructive' : ''}`}\n type=\"email\"\n value={receiverContact.email}\n onChange={(e) => onReceiverContactChange({ ...receiverContact, email: e.target.value })}\n disabled={isFetchingRates}\n placeholder=\"e.g. receiver@example.com\"\n />\n {receiverContactErrors.email ? (\n <p className=\"text-xs text-destructive\">{receiverContactErrors.email}</p>\n ) : null}\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.c2cSendingMethod', 'C2C sending method')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n {t('shipping_carriers.create.field.c2cSendingMethod', 'Sending method (applies to courier_c2c service only)')}\n </label>\n <select\n className=\"w-full rounded border bg-background px-2 py-1.5 text-sm\"\n value={c2cSendingMethod}\n onChange={(e) => onC2cSendingMethodChange(e.target.value)}\n disabled={isFetchingRates}\n >\n <option value=\"\">{t('shipping_carriers.create.c2cSendingMethod.default', 'Dispatch order (default)')}</option>\n <option value=\"parcel_locker\">{t('shipping_carriers.create.c2cSendingMethod.parcel_locker', 'Parcel locker')}</option>\n <option value=\"pop\">{t('shipping_carriers.create.c2cSendingMethod.pop', 'POP (parcel pickup point)')}</option>\n <option value=\"any_point\">{t('shipping_carriers.create.c2cSendingMethod.any_point', 'Any point')}</option>\n </select>\n </div>\n </CardContent>\n </Card>\n\n {(c2cSendingMethod === 'parcel_locker' || c2cSendingMethod === 'pop') && (\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.dropOffPoint', 'Drop-off / locker point')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {targetPoint && (\n <div className=\"rounded border border-primary bg-primary/5 px-3 py-2 text-sm\">\n <span className=\"font-medium text-xs text-muted-foreground mr-2\">\n {t('shipping_carriers.create.field.selectedPoint', 'Selected:')}\n </span>\n <span className=\"font-mono font-medium\">{targetPoint}</span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-2 h-auto py-0 text-xs\"\n onClick={() => onTargetPointChange('')}\n disabled={isFetchingRates}\n >\n {t('shipping_carriers.create.action.clearPoint', 'Clear')}\n </Button>\n </div>\n )}\n\n <div className=\"flex gap-2\">\n <input\n className=\"flex-1 rounded border bg-background px-2 py-1.5 text-sm\"\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault()\n onSearchDropOffPoints(searchInput)\n }\n }}\n disabled={isFetchingRates}\n placeholder={t('shipping_carriers.create.field.dropOffSearch', 'Postal code (e.g. 30-624) or point name (e.g. KRA012)')}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => onSearchDropOffPoints(searchInput)}\n disabled={isFetchingRates || isFetchingDropOffPoints || searchInput.trim().length === 0}\n >\n {isFetchingDropOffPoints ? (\n <Spinner className=\"h-4 w-4\" />\n ) : (\n t('shipping_carriers.create.action.searchPoints', 'Search')\n )}\n </Button>\n </div>\n\n {dropOffPointsError && (\n <p className=\"text-xs text-destructive\">{dropOffPointsError}</p>\n )}\n\n {dropOffPoints.length > 0 && (\n <ul className=\"max-h-60 overflow-y-auto divide-y rounded border text-sm\">\n {dropOffPoints.map((point) => (\n <li key={point.id}>\n <button\n type=\"button\"\n className={`w-full px-3 py-2 text-left hover:bg-accent ${targetPoint === point.id ? 'bg-primary/5 font-medium' : ''}`}\n onClick={() => onTargetPointChange(point.id)}\n disabled={isFetchingRates}\n >\n <span className=\"font-mono mr-2\">{point.name}</span>\n <span className=\"text-muted-foreground text-xs\">\n {[point.street, point.city, point.postalCode].filter(Boolean).join(', ')}\n </span>\n </button>\n </li>\n ))}\n </ul>\n )}\n\n {!isFetchingDropOffPoints && dropOffPoints.length === 0 && dropOffPointQuery && !dropOffPointsError && (\n <p className=\"text-xs text-muted-foreground\">\n {t('shipping_carriers.create.dropOffPoints.noResults', 'No drop-off points found for this search.')}\n </p>\n )}\n </CardContent>\n </Card>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.labelFormat', 'Label format')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex gap-3\">\n {LABEL_FORMATS.map((fmt) => (\n <Button\n key={fmt}\n type=\"button\"\n variant={labelFormat === fmt ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => onLabelFormatChange(fmt)}\n disabled={isFetchingRates}\n >\n {fmt.toUpperCase()}\n </Button>\n ))}\n </div>\n </CardContent>\n </Card>\n\n <div className=\"flex justify-between gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={onBack} disabled={isFetchingRates}>\n {t('shipping_carriers.create.back', 'Back')}\n </Button>\n <Button type=\"button\" onClick={onNext} disabled={!canProceed || isFetchingRates}>\n {isFetchingRates ? (\n <>\n <Spinner className=\"mr-2 h-4 w-4\" />\n {t('shipping_carriers.create.fetchingRates', 'Fetching rates...')}\n </>\n ) : (\n t('shipping_carriers.create.getQuotes', 'Get quotes')\n )}\n </Button>\n </div>\n </section>\n )\n}\n\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\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 { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Card, CardContent, CardHeader, CardTitle } from '@open-mercato/ui/primitives/card'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { AddressFields } from './AddressFields'\nimport { PackageEditor } from './PackageEditor'\nimport type { Address, PackageDimension, LabelFormat, ContactInfo, DropOffPoint } from '../types'\n\nexport type ConfigureStepProps = {\n origin: Address\n destination: Address\n packages: PackageDimension[]\n labelFormat: LabelFormat\n senderContact: ContactInfo\n receiverContact: ContactInfo\n targetPoint: string\n c2cSendingMethod: string\n isFetchingRates: boolean\n canProceed: boolean\n senderContactErrors: { email: string | null; phone: string | null }\n receiverContactErrors: { email: string | null; phone: string | null }\n dropOffPointQuery: string\n dropOffPoints: DropOffPoint[]\n isFetchingDropOffPoints: boolean\n dropOffPointsError: string | null\n onOriginChange: (address: Address) => void\n onDestinationChange: (address: Address) => void\n onPackagesChange: (packages: PackageDimension[]) => void\n onLabelFormatChange: (format: LabelFormat) => void\n onSenderContactChange: (contact: ContactInfo) => void\n onReceiverContactChange: (contact: ContactInfo) => void\n onTargetPointChange: (point: string) => void\n onC2cSendingMethodChange: (method: string) => void\n onSearchDropOffPoints: (query: string) => void\n onBack: () => void\n onNext: () => void\n}\n\nconst LABEL_FORMATS: LabelFormat[] = ['pdf', 'zpl', 'png']\n\nexport const ConfigureStep = (props: ConfigureStepProps) => {\n const {\n origin, destination, packages, labelFormat,\n senderContact, receiverContact, targetPoint, c2cSendingMethod,\n isFetchingRates, canProceed,\n senderContactErrors, receiverContactErrors,\n dropOffPointQuery, dropOffPoints, isFetchingDropOffPoints, dropOffPointsError,\n onOriginChange, onDestinationChange, onPackagesChange, onLabelFormatChange,\n onSenderContactChange, onReceiverContactChange, onTargetPointChange, onC2cSendingMethodChange,\n onSearchDropOffPoints,\n onBack, onNext,\n } = props\n const t = useT()\n const [searchInput, setSearchInput] = React.useState(dropOffPointQuery)\n\n return (\n <section className=\"space-y-6\">\n <div className=\"grid gap-6 lg:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.origin', 'Origin address')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <AddressFields prefix=\"origin\" address={origin} onChange={onOriginChange} disabled={isFetchingRates} />\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.destination', 'Destination address')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <AddressFields prefix=\"dest\" address={destination} onChange={onDestinationChange} disabled={isFetchingRates} />\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.packages', 'Packages')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <PackageEditor packages={packages} onChange={onPackagesChange} disabled={isFetchingRates} />\n </CardContent>\n </Card>\n\n <div className=\"grid gap-6 lg:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.senderContact', 'Sender contact')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n {t('shipping_carriers.create.field.phone', 'Phone')}\n </label>\n <Input\n type=\"tel\"\n size=\"sm\"\n value={senderContact.phone}\n onChange={(e) => onSenderContactChange({ ...senderContact, phone: e.target.value })}\n disabled={isFetchingRates}\n placeholder=\"e.g. 500000000\"\n aria-invalid={senderContactErrors.phone ? true : undefined}\n />\n {senderContactErrors.phone ? (\n <p className=\"text-xs text-destructive\">{senderContactErrors.phone}</p>\n ) : null}\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n {t('shipping_carriers.create.field.email', 'Email')}\n </label>\n <Input\n type=\"email\"\n size=\"sm\"\n value={senderContact.email}\n onChange={(e) => onSenderContactChange({ ...senderContact, email: e.target.value })}\n disabled={isFetchingRates}\n placeholder=\"e.g. sender@example.com\"\n aria-invalid={senderContactErrors.email ? true : undefined}\n />\n {senderContactErrors.email ? (\n <p className=\"text-xs text-destructive\">{senderContactErrors.email}</p>\n ) : null}\n </div>\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.receiverContact', 'Receiver contact')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n {t('shipping_carriers.create.field.phone', 'Phone')}\n </label>\n <Input\n type=\"tel\"\n size=\"sm\"\n value={receiverContact.phone}\n onChange={(e) => onReceiverContactChange({ ...receiverContact, phone: e.target.value })}\n disabled={isFetchingRates}\n placeholder=\"e.g. 500000000\"\n aria-invalid={receiverContactErrors.phone ? true : undefined}\n />\n {receiverContactErrors.phone ? (\n <p className=\"text-xs text-destructive\">{receiverContactErrors.phone}</p>\n ) : null}\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n {t('shipping_carriers.create.field.email', 'Email')}\n </label>\n <Input\n type=\"email\"\n size=\"sm\"\n value={receiverContact.email}\n onChange={(e) => onReceiverContactChange({ ...receiverContact, email: e.target.value })}\n disabled={isFetchingRates}\n placeholder=\"e.g. receiver@example.com\"\n aria-invalid={receiverContactErrors.email ? true : undefined}\n />\n {receiverContactErrors.email ? (\n <p className=\"text-xs text-destructive\">{receiverContactErrors.email}</p>\n ) : null}\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.c2cSendingMethod', 'C2C sending method')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n {t('shipping_carriers.create.field.c2cSendingMethod', 'Sending method (applies to courier_c2c service only)')}\n </label>\n <Select\n value={c2cSendingMethod || undefined}\n onValueChange={(value) => onC2cSendingMethodChange(value ?? '')}\n disabled={isFetchingRates}\n >\n <SelectTrigger size=\"sm\">\n <SelectValue placeholder={t('shipping_carriers.create.c2cSendingMethod.default', 'Dispatch order (default)')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"parcel_locker\">{t('shipping_carriers.create.c2cSendingMethod.parcel_locker', 'Parcel locker')}</SelectItem>\n <SelectItem value=\"pop\">{t('shipping_carriers.create.c2cSendingMethod.pop', 'POP (parcel pickup point)')}</SelectItem>\n <SelectItem value=\"any_point\">{t('shipping_carriers.create.c2cSendingMethod.any_point', 'Any point')}</SelectItem>\n </SelectContent>\n </Select>\n </div>\n </CardContent>\n </Card>\n\n {(c2cSendingMethod === 'parcel_locker' || c2cSendingMethod === 'pop') && (\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.dropOffPoint', 'Drop-off / locker point')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {targetPoint && (\n <div className=\"rounded border border-primary bg-primary/5 px-3 py-2 text-sm\">\n <span className=\"font-medium text-xs text-muted-foreground mr-2\">\n {t('shipping_carriers.create.field.selectedPoint', 'Selected:')}\n </span>\n <span className=\"font-mono font-medium\">{targetPoint}</span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-2 h-auto py-0 text-xs\"\n onClick={() => onTargetPointChange('')}\n disabled={isFetchingRates}\n >\n {t('shipping_carriers.create.action.clearPoint', 'Clear')}\n </Button>\n </div>\n )}\n\n <div className=\"flex gap-2\">\n <Input\n size=\"sm\"\n className=\"flex-1\"\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault()\n onSearchDropOffPoints(searchInput)\n }\n }}\n disabled={isFetchingRates}\n placeholder={t('shipping_carriers.create.field.dropOffSearch', 'Postal code (e.g. 30-624) or point name (e.g. KRA012)')}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => onSearchDropOffPoints(searchInput)}\n disabled={isFetchingRates || isFetchingDropOffPoints || searchInput.trim().length === 0}\n >\n {isFetchingDropOffPoints ? (\n <Spinner className=\"h-4 w-4\" />\n ) : (\n t('shipping_carriers.create.action.searchPoints', 'Search')\n )}\n </Button>\n </div>\n\n {dropOffPointsError && (\n <p className=\"text-xs text-destructive\">{dropOffPointsError}</p>\n )}\n\n {dropOffPoints.length > 0 && (\n <ul className=\"max-h-60 overflow-y-auto divide-y rounded border text-sm\">\n {dropOffPoints.map((point) => (\n <li key={point.id}>\n <button\n type=\"button\"\n className={`w-full px-3 py-2 text-left hover:bg-accent ${targetPoint === point.id ? 'bg-primary/5 font-medium' : ''}`}\n onClick={() => onTargetPointChange(point.id)}\n disabled={isFetchingRates}\n >\n <span className=\"font-mono mr-2\">{point.name}</span>\n <span className=\"text-muted-foreground text-xs\">\n {[point.street, point.city, point.postalCode].filter(Boolean).join(', ')}\n </span>\n </button>\n </li>\n ))}\n </ul>\n )}\n\n {!isFetchingDropOffPoints && dropOffPoints.length === 0 && dropOffPointQuery && !dropOffPointsError && (\n <p className=\"text-xs text-muted-foreground\">\n {t('shipping_carriers.create.dropOffPoints.noResults', 'No drop-off points found for this search.')}\n </p>\n )}\n </CardContent>\n </Card>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('shipping_carriers.create.section.labelFormat', 'Label format')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex gap-3\">\n {LABEL_FORMATS.map((fmt) => (\n <Button\n key={fmt}\n type=\"button\"\n variant={labelFormat === fmt ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => onLabelFormatChange(fmt)}\n disabled={isFetchingRates}\n >\n {fmt.toUpperCase()}\n </Button>\n ))}\n </div>\n </CardContent>\n </Card>\n\n <div className=\"flex justify-between gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={onBack} disabled={isFetchingRates}>\n {t('shipping_carriers.create.back', 'Back')}\n </Button>\n <Button type=\"button\" onClick={onNext} disabled={!canProceed || isFetchingRates}>\n {isFetchingRates ? (\n <>\n <Spinner className=\"mr-2 h-4 w-4\" />\n {t('shipping_carriers.create.fetchingRates', 'Fetching rates...')}\n </>\n ) : (\n t('shipping_carriers.create.getQuotes', 'Get quotes')\n )}\n </Button>\n </div>\n </section>\n )\n}\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -8,6 +8,13 @@ import { normalizeCustomFieldValues } from "@open-mercato/shared/lib/custom-fiel
|
|
|
8
8
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
9
9
|
import { LookupSelect } from "@open-mercato/ui/backend/inputs";
|
|
10
10
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
11
|
+
import {
|
|
12
|
+
Select,
|
|
13
|
+
SelectContent,
|
|
14
|
+
SelectItem,
|
|
15
|
+
SelectTrigger,
|
|
16
|
+
SelectValue
|
|
17
|
+
} from "@open-mercato/ui/primitives/select";
|
|
11
18
|
import { AttachmentsSection, TagsSection } from "@open-mercato/ui/backend/detail";
|
|
12
19
|
import { E } from "../../../generated/entities.ids.generated.js";
|
|
13
20
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
@@ -216,13 +223,12 @@ function TeamMemberForm(props) {
|
|
|
216
223
|
)
|
|
217
224
|
] }),
|
|
218
225
|
/* @__PURE__ */ jsxs(
|
|
219
|
-
|
|
226
|
+
Select,
|
|
220
227
|
{
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
const nextTeamId = event.target.value || null;
|
|
228
|
+
value: currentValue || void 0,
|
|
229
|
+
onValueChange: (value2) => {
|
|
230
|
+
const nextValue = value2 || void 0;
|
|
231
|
+
const nextTeamId = value2 || null;
|
|
226
232
|
setValue(nextValue);
|
|
227
233
|
setSelectedTeamId(nextTeamId);
|
|
228
234
|
if (!setFormValue) return;
|
|
@@ -233,11 +239,10 @@ function TeamMemberForm(props) {
|
|
|
233
239
|
setFormValue("roleIds", nextRoleIds);
|
|
234
240
|
}
|
|
235
241
|
},
|
|
236
|
-
"data-crud-focus-target": "",
|
|
237
242
|
disabled,
|
|
238
243
|
children: [
|
|
239
|
-
/* @__PURE__ */ jsx(
|
|
240
|
-
teamOptions.map((option) => /* @__PURE__ */ jsx(
|
|
244
|
+
/* @__PURE__ */ jsx(SelectTrigger, { "data-crud-focus-target": "", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: translate("ui.forms.select.emptyOption", "\u2014") }) }),
|
|
245
|
+
/* @__PURE__ */ jsx(SelectContent, { children: teamOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
|
|
241
246
|
]
|
|
242
247
|
}
|
|
243
248
|
)
|