@dainamite/cpq 0.6.0 → 0.7.0
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/CHANGELOG.md +16 -0
- package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js +3 -9
- package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js +21 -25
- package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js +48 -47
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/page.meta.js +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/shared.js +37 -2
- package/dist/modules/cpq/backend/cpq/inventory/shared.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js +154 -178
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js +168 -143
- package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/offerings/page.js +36 -34
- package/dist/modules/cpq/backend/cpq/offerings/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/orders/[id]/page.js +69 -66
- package/dist/modules/cpq/backend/cpq/orders/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/orders/page.js +6 -6
- package/dist/modules/cpq/backend/cpq/orders/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js +41 -36
- package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js +76 -72
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/page.js +18 -15
- package/dist/modules/cpq/backend/cpq/price-rules/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js +23 -21
- package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js +22 -50
- package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js +74 -52
- package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js +20 -17
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/page.js +1 -1
- package/dist/modules/cpq/backend/cpq/pricing/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js +115 -123
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js +6 -3
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js +129 -94
- package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/page.js +23 -19
- package/dist/modules/cpq/backend/cpq/quotes/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js +19 -15
- package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js +171 -178
- package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/page.js +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js +60 -50
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js +22 -18
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/page.js +1 -1
- package/dist/modules/cpq/backend/cpq/wizards/page.js.map +2 -2
- package/dist/modules/cpq/components/ArcLineDiff.js +2 -2
- package/dist/modules/cpq/components/ArcLineDiff.js.map +2 -2
- package/dist/modules/cpq/components/ChargeBreakdownTable.js +4 -10
- package/dist/modules/cpq/components/ChargeBreakdownTable.js.map +2 -2
- package/dist/modules/cpq/components/PriceWaterfall.js +3 -1
- package/dist/modules/cpq/components/PriceWaterfall.js.map +2 -2
- package/dist/modules/cpq/components/PricingSummaryCard.js +1 -6
- package/dist/modules/cpq/components/PricingSummaryCard.js.map +2 -2
- package/dist/modules/cpq/components/StatusPath.js +5 -3
- package/dist/modules/cpq/components/StatusPath.js.map +2 -2
- package/dist/modules/cpq/components/useCpqRowActions.js +10 -22
- package/dist/modules/cpq/components/useCpqRowActions.js.map +2 -2
- package/dist/modules/cpq/i18n/de.json +1220 -0
- package/dist/modules/cpq/i18n/en.json +1220 -0
- package/dist/modules/cpq/i18n/es.json +1220 -0
- package/dist/modules/cpq/i18n/pl.json +1220 -0
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js +39 -31
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js +13 -5
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js +41 -21
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection-table.js +2 -2
- package/dist/modules/cpq/widgets/injection-table.js.map +2 -2
- package/dist/modules/cpq/workflows/WizardRunner.js +10 -8
- package/dist/modules/cpq/workflows/WizardRunner.js.map +2 -2
- package/dist/modules/cpq/workflows/WizardTrigger.js +15 -9
- package/dist/modules/cpq/workflows/WizardTrigger.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js +9 -7
- package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/InventorySelectStep.js +9 -4
- package/dist/modules/cpq/workflows/steps/InventorySelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ItemListStep.js +16 -19
- package/dist/modules/cpq/workflows/steps/ItemListStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js +19 -32
- package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js +8 -6
- package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ReviewStep.js +32 -30
- package/dist/modules/cpq/workflows/steps/ReviewStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/index.js +12 -0
- package/dist/modules/cpq/workflows/steps/index.js.map +2 -2
- package/package.json +1 -1
- package/src/modules/cpq/__tests__/i18n/dictionaries.test.ts +62 -0
- package/src/modules/cpq/__tests__/i18n/hardcodedStrings.test.ts +35 -0
- package/src/modules/cpq/__tests__/i18n/sourceScan.ts +109 -0
- package/src/modules/cpq/backend/cpq/inventory/AssetsTable.tsx +3 -9
- package/src/modules/cpq/backend/cpq/inventory/SubscriptionsTable.tsx +22 -26
- package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.tsx +43 -46
- package/src/modules/cpq/backend/cpq/inventory/page.meta.ts +2 -2
- package/src/modules/cpq/backend/cpq/inventory/shared.tsx +37 -1
- package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.tsx +134 -112
- package/src/modules/cpq/backend/cpq/offerings/[id]/page.tsx +169 -130
- package/src/modules/cpq/backend/cpq/offerings/page.tsx +34 -24
- package/src/modules/cpq/backend/cpq/orders/[id]/page.tsx +66 -43
- package/src/modules/cpq/backend/cpq/orders/page.tsx +6 -6
- package/src/modules/cpq/backend/cpq/price-rules/PriceRuleForm.tsx +48 -34
- package/src/modules/cpq/backend/cpq/price-rules/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/price-rules/[id]/page.tsx +76 -70
- package/src/modules/cpq/backend/cpq/price-rules/page.tsx +25 -16
- package/src/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.tsx +24 -18
- package/src/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.tsx +29 -19
- package/src/modules/cpq/backend/cpq/pricing/[id]/page.tsx +95 -47
- package/src/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.ts +23 -15
- package/src/modules/cpq/backend/cpq/pricing/page.tsx +1 -1
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.tsx +111 -88
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.tsx +3 -3
- package/src/modules/cpq/backend/cpq/quotes/[id]/page.tsx +134 -89
- package/src/modules/cpq/backend/cpq/quotes/page.tsx +29 -21
- package/src/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.tsx +19 -15
- package/src/modules/cpq/backend/cpq/specifications/[id]/page.tsx +171 -171
- package/src/modules/cpq/backend/cpq/specifications/page.tsx +2 -2
- package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.tsx +51 -41
- package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/page.tsx +17 -13
- package/src/modules/cpq/backend/cpq/wizards/page.tsx +1 -1
- package/src/modules/cpq/components/ArcLineDiff.tsx +2 -2
- package/src/modules/cpq/components/ChargeBreakdownTable.tsx +4 -2
- package/src/modules/cpq/components/PriceWaterfall.tsx +4 -2
- package/src/modules/cpq/components/PricingSummaryCard.tsx +1 -1
- package/src/modules/cpq/components/StatusPath.tsx +7 -4
- package/src/modules/cpq/components/useCpqRowActions.tsx +17 -25
- package/src/modules/cpq/i18n/de.json +1220 -0
- package/src/modules/cpq/i18n/en.json +1220 -0
- package/src/modules/cpq/i18n/es.json +1220 -0
- package/src/modules/cpq/i18n/pl.json +1220 -0
- package/src/modules/cpq/widgets/injection/customer-inventory/widget.client.tsx +38 -31
- package/src/modules/cpq/widgets/injection/order-cpq-tab/widget.client.tsx +7 -5
- package/src/modules/cpq/widgets/injection/quote-configurator/widget.client.tsx +36 -21
- package/src/modules/cpq/widgets/injection-table.ts +8 -2
- package/src/modules/cpq/workflows/WizardRunner.tsx +8 -5
- package/src/modules/cpq/workflows/WizardTrigger.tsx +15 -9
- package/src/modules/cpq/workflows/steps/CustomerSelectStep.tsx +11 -7
- package/src/modules/cpq/workflows/steps/InventorySelectStep.tsx +9 -5
- package/src/modules/cpq/workflows/steps/ItemListStep.tsx +18 -12
- package/src/modules/cpq/workflows/steps/OfferingSelectStep.tsx +20 -16
- package/src/modules/cpq/workflows/steps/ProductConfigureStep.tsx +8 -6
- package/src/modules/cpq/workflows/steps/ReviewStep.tsx +33 -18
- package/src/modules/cpq/workflows/steps/index.ts +12 -0
- package/src/modules/cpq/workflows/types.ts +4 -0
|
@@ -70,8 +70,8 @@ type CustomerPickerProps = {
|
|
|
70
70
|
error: string | null
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
function getCustomerLabel(c: Customer) {
|
|
74
|
-
return c.display_name || c.displayName || c.name || c.companyName ||
|
|
73
|
+
function getCustomerLabel(c: Customer, unnamedLabel: string) {
|
|
74
|
+
return c.display_name || c.displayName || c.name || c.companyName || unnamedLabel
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
function getCustomerEmail(c: Customer) {
|
|
@@ -79,6 +79,8 @@ function getCustomerEmail(c: Customer) {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
function CustomerPickerModal({ open, onClose, onSelect, creating, error }: CustomerPickerProps) {
|
|
82
|
+
const t = useT()
|
|
83
|
+
const unnamedLabel = t('cpq.quotes.customerPicker.unnamed', 'Unnamed')
|
|
82
84
|
const [customers, setCustomers] = React.useState<Customer[]>([])
|
|
83
85
|
const [customersLoading, setCustomersLoading] = React.useState(false)
|
|
84
86
|
const [search, setSearch] = React.useState('')
|
|
@@ -110,7 +112,7 @@ function CustomerPickerModal({ open, onClose, onSelect, creating, error }: Custo
|
|
|
110
112
|
if (!search.trim()) return true
|
|
111
113
|
const q = search.toLowerCase()
|
|
112
114
|
return (
|
|
113
|
-
getCustomerLabel(c).toLowerCase().includes(q) ||
|
|
115
|
+
getCustomerLabel(c, unnamedLabel).toLowerCase().includes(q) ||
|
|
114
116
|
getCustomerEmail(c).toLowerCase().includes(q) ||
|
|
115
117
|
c.id.toLowerCase().includes(q)
|
|
116
118
|
)
|
|
@@ -126,14 +128,16 @@ function CustomerPickerModal({ open, onClose, onSelect, creating, error }: Custo
|
|
|
126
128
|
onClick={(e) => e.stopPropagation()}
|
|
127
129
|
>
|
|
128
130
|
<div className="flex items-center justify-between border-b px-4 py-3">
|
|
129
|
-
<h3 className="text-sm font-medium">
|
|
131
|
+
<h3 className="text-sm font-medium">
|
|
132
|
+
{t('cpq.quotes.customerPicker.title', 'Select Customer for New Quote')}
|
|
133
|
+
</h3>
|
|
130
134
|
<button
|
|
131
135
|
type="button"
|
|
132
136
|
onClick={onClose}
|
|
133
137
|
disabled={creating}
|
|
134
138
|
className="text-muted-foreground hover:text-foreground text-lg font-bold leading-none cursor-pointer disabled:cursor-not-allowed"
|
|
135
139
|
>
|
|
136
|
-
|
|
140
|
+
{'\u00d7'}
|
|
137
141
|
</button>
|
|
138
142
|
</div>
|
|
139
143
|
<div className="p-4 space-y-3">
|
|
@@ -141,7 +145,7 @@ function CustomerPickerModal({ open, onClose, onSelect, creating, error }: Custo
|
|
|
141
145
|
<div className="relative">
|
|
142
146
|
<SearchIcon className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
|
143
147
|
<Input
|
|
144
|
-
placeholder=
|
|
148
|
+
placeholder={t('cpq.quotes.customerPicker.searchPlaceholder', 'Search customers…')}
|
|
145
149
|
value={search}
|
|
146
150
|
onChange={(e) => setSearch(e.target.value)}
|
|
147
151
|
autoFocus
|
|
@@ -151,11 +155,13 @@ function CustomerPickerModal({ open, onClose, onSelect, creating, error }: Custo
|
|
|
151
155
|
<div className="max-h-72 overflow-y-auto space-y-1">
|
|
152
156
|
{customersLoading ? (
|
|
153
157
|
<div className="py-8 text-center text-sm text-muted-foreground">
|
|
154
|
-
Loading customers…
|
|
158
|
+
{t('cpq.quotes.customerPicker.loading', 'Loading customers…')}
|
|
155
159
|
</div>
|
|
156
160
|
) : filtered.length === 0 ? (
|
|
157
161
|
<div className="py-8 text-center text-sm text-muted-foreground">
|
|
158
|
-
{search
|
|
162
|
+
{search
|
|
163
|
+
? t('cpq.quotes.customerPicker.noMatch', 'No customers match your search.')
|
|
164
|
+
: t('cpq.quotes.customerPicker.empty', 'No customers found.')}
|
|
159
165
|
</div>
|
|
160
166
|
) : (
|
|
161
167
|
filtered.map((c) => (
|
|
@@ -166,7 +172,7 @@ function CustomerPickerModal({ open, onClose, onSelect, creating, error }: Custo
|
|
|
166
172
|
disabled={creating}
|
|
167
173
|
className="w-full rounded-md border px-3 py-2.5 text-left hover:border-primary hover:bg-primary/5 transition-colors disabled:opacity-50 cursor-pointer disabled:cursor-not-allowed"
|
|
168
174
|
>
|
|
169
|
-
<p className="text-sm font-medium">{getCustomerLabel(c)}</p>
|
|
175
|
+
<p className="text-sm font-medium">{getCustomerLabel(c, unnamedLabel)}</p>
|
|
170
176
|
{getCustomerEmail(c) && (
|
|
171
177
|
<p className="text-xs text-muted-foreground mt-0.5">{getCustomerEmail(c)}</p>
|
|
172
178
|
)}
|
|
@@ -200,17 +206,17 @@ export default function CpqQuotesListPage() {
|
|
|
200
206
|
|
|
201
207
|
const statusOptions = React.useMemo(
|
|
202
208
|
() => [
|
|
203
|
-
{ value: 'new', label: 'New' },
|
|
204
|
-
{ value: 'incomplete', label: 'Incomplete' },
|
|
205
|
-
{ value: 'ready', label: 'Ready' },
|
|
206
|
-
{ value: 'in_approval', label: 'In Approval' },
|
|
207
|
-
{ value: 'approved', label: 'Approved' },
|
|
208
|
-
{ value: 'with_customer', label: 'With Customer' },
|
|
209
|
-
{ value: 'accepted', label: 'Accepted' },
|
|
210
|
-
{ value: 'rejected', label: 'Rejected' },
|
|
211
|
-
{ value: 'cancelled', label: 'Cancelled' },
|
|
209
|
+
{ value: 'new', label: t('cpq.quotes.status.new', 'New') },
|
|
210
|
+
{ value: 'incomplete', label: t('cpq.quotes.status.incomplete', 'Incomplete') },
|
|
211
|
+
{ value: 'ready', label: t('cpq.quotes.status.ready', 'Ready') },
|
|
212
|
+
{ value: 'in_approval', label: t('cpq.quotes.status.in_approval', 'In Approval') },
|
|
213
|
+
{ value: 'approved', label: t('cpq.quotes.status.approved', 'Approved') },
|
|
214
|
+
{ value: 'with_customer', label: t('cpq.quotes.status.with_customer', 'With Customer') },
|
|
215
|
+
{ value: 'accepted', label: t('cpq.quotes.status.accepted', 'Accepted') },
|
|
216
|
+
{ value: 'rejected', label: t('cpq.quotes.status.rejected', 'Rejected') },
|
|
217
|
+
{ value: 'cancelled', label: t('cpq.quotes.status.cancelled', 'Cancelled') },
|
|
212
218
|
],
|
|
213
|
-
[],
|
|
219
|
+
[t],
|
|
214
220
|
)
|
|
215
221
|
|
|
216
222
|
const filters = React.useMemo<FilterDef[]>(
|
|
@@ -245,7 +251,9 @@ export default function CpqQuotesListPage() {
|
|
|
245
251
|
setShowCustomerPicker(false)
|
|
246
252
|
router.push(`/backend/cpq/quotes/${body.id}`)
|
|
247
253
|
} else {
|
|
248
|
-
setCreateError(
|
|
254
|
+
setCreateError(
|
|
255
|
+
body.error ?? t('cpq.quotes.create.error', 'Failed to create quote ({status})', { status: res.status }),
|
|
256
|
+
)
|
|
249
257
|
}
|
|
250
258
|
} catch (err) {
|
|
251
259
|
setCreateError((err as Error).message)
|
|
@@ -253,7 +261,7 @@ export default function CpqQuotesListPage() {
|
|
|
253
261
|
setCreating(false)
|
|
254
262
|
}
|
|
255
263
|
},
|
|
256
|
-
[router],
|
|
264
|
+
[router, t],
|
|
257
265
|
)
|
|
258
266
|
|
|
259
267
|
const columns = React.useMemo<ColumnDef<QuoteConfig>[]>(
|
|
@@ -5,6 +5,7 @@ import { Button } from '@open-mercato/ui/primitives/button'
|
|
|
5
5
|
import { Input } from '@open-mercato/ui/primitives/input'
|
|
6
6
|
import { Checkbox } from '@open-mercato/ui/primitives/checkbox'
|
|
7
7
|
import { Tag } from '@open-mercato/ui/primitives/tag'
|
|
8
|
+
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
8
9
|
import type { DependsOnEffect, DependsOnRule } from './page'
|
|
9
10
|
|
|
10
11
|
// ─── Helpers ─────────────────────────────────────────────────────
|
|
@@ -68,6 +69,7 @@ export function DependsOnRulesEditor({
|
|
|
68
69
|
parentOptions,
|
|
69
70
|
childOptions,
|
|
70
71
|
}: DependsOnRulesEditorProps) {
|
|
72
|
+
const t = useT()
|
|
71
73
|
const updateRule = (index: number, patch: Partial<DependsOnRule>) => {
|
|
72
74
|
const next = rules.map((r, i) => (i === index ? { ...r, ...patch } : r))
|
|
73
75
|
onChange(next)
|
|
@@ -85,11 +87,11 @@ export function DependsOnRulesEditor({
|
|
|
85
87
|
return (
|
|
86
88
|
<div className="space-y-2">
|
|
87
89
|
<p className="text-xs text-muted-foreground">
|
|
88
|
-
No rules yet. Add at least one to make this dependency effective.
|
|
90
|
+
{t('cpq.specifications.dependsOn.empty', 'No rules yet. Add at least one to make this dependency effective.')}
|
|
89
91
|
</p>
|
|
90
92
|
<Button type="button" variant="outline" size="sm" onClick={addRule}>
|
|
91
93
|
<Plus className="h-3.5 w-3.5" />
|
|
92
|
-
Add rule
|
|
94
|
+
{t('cpq.specifications.dependsOn.addRule', 'Add rule')}
|
|
93
95
|
</Button>
|
|
94
96
|
</div>
|
|
95
97
|
)
|
|
@@ -113,7 +115,7 @@ export function DependsOnRulesEditor({
|
|
|
113
115
|
</div>
|
|
114
116
|
<Button type="button" variant="outline" size="sm" onClick={addRule}>
|
|
115
117
|
<Plus className="h-3.5 w-3.5" />
|
|
116
|
-
Add rule
|
|
118
|
+
{t('cpq.specifications.dependsOn.addRule', 'Add rule')}
|
|
117
119
|
</Button>
|
|
118
120
|
</div>
|
|
119
121
|
)
|
|
@@ -140,11 +142,12 @@ function RuleRow({
|
|
|
140
142
|
onThenChange,
|
|
141
143
|
onRemove,
|
|
142
144
|
}: RuleRowProps) {
|
|
145
|
+
const t = useT()
|
|
143
146
|
return (
|
|
144
147
|
<div className="grid grid-cols-[1fr_auto_1fr_auto] items-start gap-2 rounded-md border bg-muted/20 p-2">
|
|
145
148
|
<div>
|
|
146
149
|
<label className="block text-[10px] font-medium uppercase tracking-wide text-muted-foreground mb-0.5">
|
|
147
|
-
When parent =
|
|
150
|
+
{t('cpq.specifications.dependsOn.whenParent', 'When parent =')}
|
|
148
151
|
</label>
|
|
149
152
|
{parentOptions && parentOptions.length > 0 ? (
|
|
150
153
|
<select
|
|
@@ -152,7 +155,7 @@ function RuleRow({
|
|
|
152
155
|
onChange={(e) => onWhenChange(e.target.value)}
|
|
153
156
|
className="w-full rounded-md border bg-background px-2 py-1.5 text-sm"
|
|
154
157
|
>
|
|
155
|
-
<option value=""
|
|
158
|
+
<option value="">{t('cpq.specifications.dependsOn.selectValue', '— Select value —')}</option>
|
|
156
159
|
{parentOptions.map((opt) => (
|
|
157
160
|
<option key={opt.value} value={opt.value}>
|
|
158
161
|
{opt.label}
|
|
@@ -163,7 +166,7 @@ function RuleRow({
|
|
|
163
166
|
<Input
|
|
164
167
|
value={rule.when}
|
|
165
168
|
onChange={(e) => onWhenChange(e.target.value)}
|
|
166
|
-
placeholder=
|
|
169
|
+
placeholder={t('cpq.specifications.dependsOn.parentValuePlaceholder', 'Parent value')}
|
|
167
170
|
/>
|
|
168
171
|
)}
|
|
169
172
|
</div>
|
|
@@ -178,7 +181,7 @@ function RuleRow({
|
|
|
178
181
|
type="button"
|
|
179
182
|
onClick={onRemove}
|
|
180
183
|
className="mt-5 self-start rounded p-1.5 text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors"
|
|
181
|
-
title=
|
|
184
|
+
title={t('cpq.specifications.dependsOn.removeRule', 'Remove rule')}
|
|
182
185
|
>
|
|
183
186
|
<X className="h-4 w-4" />
|
|
184
187
|
</button>
|
|
@@ -196,19 +199,20 @@ type ThenInputProps = {
|
|
|
196
199
|
}
|
|
197
200
|
|
|
198
201
|
function ThenInput({ effect, value, childOptions, onChange }: ThenInputProps) {
|
|
202
|
+
const t = useT()
|
|
199
203
|
if (effect === 'toggle_required') {
|
|
200
204
|
const isRequired = value === true
|
|
201
205
|
return (
|
|
202
206
|
<div>
|
|
203
207
|
<label className="block text-[10px] font-medium uppercase tracking-wide text-muted-foreground mb-0.5">
|
|
204
|
-
Then required is
|
|
208
|
+
{t('cpq.specifications.dependsOn.thenRequiredIs', 'Then required is')}
|
|
205
209
|
</label>
|
|
206
210
|
<label className="flex items-center gap-2 rounded-md border bg-background px-2 py-1.5 text-sm cursor-pointer">
|
|
207
211
|
<Checkbox
|
|
208
212
|
checked={isRequired}
|
|
209
213
|
onCheckedChange={(checked) => onChange(checked === true)}
|
|
210
214
|
/>
|
|
211
|
-
<span>{isRequired ? 'Required' : 'Optional'}</span>
|
|
215
|
+
<span>{isRequired ? t('cpq.specifications.dependsOn.required', 'Required') : t('cpq.specifications.dependsOn.optional', 'Optional')}</span>
|
|
212
216
|
</label>
|
|
213
217
|
</div>
|
|
214
218
|
)
|
|
@@ -218,7 +222,7 @@ function ThenInput({ effect, value, childOptions, onChange }: ThenInputProps) {
|
|
|
218
222
|
return (
|
|
219
223
|
<div>
|
|
220
224
|
<label className="block text-[10px] font-medium uppercase tracking-wide text-muted-foreground mb-0.5">
|
|
221
|
-
Then set value to
|
|
225
|
+
{t('cpq.specifications.dependsOn.thenSetValueTo', 'Then set value to')}
|
|
222
226
|
</label>
|
|
223
227
|
{childOptions && childOptions.length > 0 ? (
|
|
224
228
|
<select
|
|
@@ -226,7 +230,7 @@ function ThenInput({ effect, value, childOptions, onChange }: ThenInputProps) {
|
|
|
226
230
|
onChange={(e) => onChange(e.target.value)}
|
|
227
231
|
className="w-full rounded-md border bg-background px-2 py-1.5 text-sm"
|
|
228
232
|
>
|
|
229
|
-
<option value=""
|
|
233
|
+
<option value="">{t('cpq.specifications.dependsOn.selectValue', '— Select value —')}</option>
|
|
230
234
|
{childOptions.map((opt) => (
|
|
231
235
|
<option key={opt.value} value={opt.value}>
|
|
232
236
|
{opt.label}
|
|
@@ -237,7 +241,7 @@ function ThenInput({ effect, value, childOptions, onChange }: ThenInputProps) {
|
|
|
237
241
|
<Input
|
|
238
242
|
value={typeof value === 'string' ? value : ''}
|
|
239
243
|
onChange={(e) => onChange(e.target.value)}
|
|
240
|
-
placeholder=
|
|
244
|
+
placeholder={t('cpq.specifications.dependsOn.valuePlaceholder', 'Value')}
|
|
241
245
|
/>
|
|
242
246
|
)}
|
|
243
247
|
</div>
|
|
@@ -257,7 +261,7 @@ function ThenInput({ effect, value, childOptions, onChange }: ThenInputProps) {
|
|
|
257
261
|
return (
|
|
258
262
|
<div>
|
|
259
263
|
<label className="block text-[10px] font-medium uppercase tracking-wide text-muted-foreground mb-0.5">
|
|
260
|
-
Then allow only
|
|
264
|
+
{t('cpq.specifications.dependsOn.thenAllowOnly', 'Then allow only')}
|
|
261
265
|
</label>
|
|
262
266
|
<div className="flex flex-wrap gap-1.5 rounded-md border bg-background px-2 py-1.5 text-sm min-h-[34px]">
|
|
263
267
|
{childOptions.map((opt) => {
|
|
@@ -288,12 +292,12 @@ function ThenInput({ effect, value, childOptions, onChange }: ThenInputProps) {
|
|
|
288
292
|
return (
|
|
289
293
|
<div>
|
|
290
294
|
<label className="block text-[10px] font-medium uppercase tracking-wide text-muted-foreground mb-0.5">
|
|
291
|
-
Then allow only (comma-separated)
|
|
295
|
+
{t('cpq.specifications.dependsOn.thenAllowOnlyCsv', 'Then allow only (comma-separated)')}
|
|
292
296
|
</label>
|
|
293
297
|
<Input
|
|
294
298
|
value={thenAsCsv(value)}
|
|
295
299
|
onChange={(e) => onChange(csvAsArray(e.target.value))}
|
|
296
|
-
placeholder=
|
|
300
|
+
placeholder={t('cpq.specifications.dependsOn.csvPlaceholder', 'value1, value2, value3')}
|
|
297
301
|
/>
|
|
298
302
|
</div>
|
|
299
303
|
)
|