@open-mercato/core 0.6.4-develop.3929.1.fcf7afece2 → 0.6.4-develop.3944.1.4100aa7fbe

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.
Files changed (72) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/customers/backend/customers/deals/create/page.js +3 -61
  3. package/dist/modules/customers/backend/customers/deals/create/page.js.map +2 -2
  4. package/dist/modules/customers/components/detail/DealForm.js +2 -0
  5. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  6. package/dist/modules/customers/components/detail/create/CreateDealForm.js +233 -0
  7. package/dist/modules/customers/components/detail/create/CreateDealForm.js.map +7 -0
  8. package/dist/modules/customers/components/detail/create/DealAssociationsField.js +209 -0
  9. package/dist/modules/customers/components/detail/create/DealAssociationsField.js.map +7 -0
  10. package/dist/modules/customers/components/detail/create/DealAssociationsSection.js +67 -0
  11. package/dist/modules/customers/components/detail/create/DealAssociationsSection.js.map +7 -0
  12. package/dist/modules/customers/components/detail/create/DealCreateSidebar.js +73 -0
  13. package/dist/modules/customers/components/detail/create/DealCreateSidebar.js.map +7 -0
  14. package/dist/modules/customers/components/detail/create/DealCurrencyField.js +92 -0
  15. package/dist/modules/customers/components/detail/create/DealCurrencyField.js.map +7 -0
  16. package/dist/modules/customers/components/detail/create/DealCustomAttributes.js +81 -0
  17. package/dist/modules/customers/components/detail/create/DealCustomAttributes.js.map +7 -0
  18. package/dist/modules/customers/components/detail/create/DealDetailsFields.js +171 -0
  19. package/dist/modules/customers/components/detail/create/DealDetailsFields.js.map +7 -0
  20. package/dist/modules/customers/components/detail/create/DealFormField.js +24 -0
  21. package/dist/modules/customers/components/detail/create/DealFormField.js.map +7 -0
  22. package/dist/modules/customers/components/detail/create/DealSectionCard.js +29 -0
  23. package/dist/modules/customers/components/detail/create/DealSectionCard.js.map +7 -0
  24. package/dist/modules/customers/components/detail/create/DealTipsCard.js +19 -0
  25. package/dist/modules/customers/components/detail/create/DealTipsCard.js.map +7 -0
  26. package/dist/modules/customers/components/detail/create/PipelineSelect.js +41 -0
  27. package/dist/modules/customers/components/detail/create/PipelineSelect.js.map +7 -0
  28. package/dist/modules/customers/components/detail/create/PipelineStageSelect.js +49 -0
  29. package/dist/modules/customers/components/detail/create/PipelineStageSelect.js.map +7 -0
  30. package/dist/modules/customers/components/detail/create/SuffixInput.js +21 -0
  31. package/dist/modules/customers/components/detail/create/SuffixInput.js.map +7 -0
  32. package/dist/modules/customers/components/detail/create/dealCustomFieldControl.js +270 -0
  33. package/dist/modules/customers/components/detail/create/dealCustomFieldControl.js.map +7 -0
  34. package/dist/modules/customers/components/detail/create/dealFormTypes.js +17 -0
  35. package/dist/modules/customers/components/detail/create/dealFormTypes.js.map +7 -0
  36. package/dist/modules/customers/components/detail/create/dealNumericInput.js +16 -0
  37. package/dist/modules/customers/components/detail/create/dealNumericInput.js.map +7 -0
  38. package/dist/modules/customers/components/detail/create/useDealCustomFields.js +93 -0
  39. package/dist/modules/customers/components/detail/create/useDealCustomFields.js.map +7 -0
  40. package/dist/modules/customers/components/detail/create/useDealPipelines.js +59 -0
  41. package/dist/modules/customers/components/detail/create/useDealPipelines.js.map +7 -0
  42. package/dist/modules/customers/components/formConfig.js +4 -2
  43. package/dist/modules/customers/components/formConfig.js.map +2 -2
  44. package/dist/modules/dictionaries/components/DictionaryEntrySelect.js +5 -2
  45. package/dist/modules/dictionaries/components/DictionaryEntrySelect.js.map +2 -2
  46. package/package.json +7 -7
  47. package/src/modules/customers/backend/customers/deals/create/page.tsx +3 -64
  48. package/src/modules/customers/components/detail/DealForm.tsx +2 -0
  49. package/src/modules/customers/components/detail/create/CreateDealForm.tsx +254 -0
  50. package/src/modules/customers/components/detail/create/DealAssociationsField.tsx +253 -0
  51. package/src/modules/customers/components/detail/create/DealAssociationsSection.tsx +72 -0
  52. package/src/modules/customers/components/detail/create/DealCreateSidebar.tsx +79 -0
  53. package/src/modules/customers/components/detail/create/DealCurrencyField.tsx +108 -0
  54. package/src/modules/customers/components/detail/create/DealCustomAttributes.tsx +118 -0
  55. package/src/modules/customers/components/detail/create/DealDetailsFields.tsx +171 -0
  56. package/src/modules/customers/components/detail/create/DealFormField.tsx +39 -0
  57. package/src/modules/customers/components/detail/create/DealSectionCard.tsx +40 -0
  58. package/src/modules/customers/components/detail/create/DealTipsCard.tsx +26 -0
  59. package/src/modules/customers/components/detail/create/PipelineSelect.tsx +55 -0
  60. package/src/modules/customers/components/detail/create/PipelineStageSelect.tsx +70 -0
  61. package/src/modules/customers/components/detail/create/SuffixInput.tsx +20 -0
  62. package/src/modules/customers/components/detail/create/dealCustomFieldControl.tsx +310 -0
  63. package/src/modules/customers/components/detail/create/dealFormTypes.ts +29 -0
  64. package/src/modules/customers/components/detail/create/dealNumericInput.ts +20 -0
  65. package/src/modules/customers/components/detail/create/useDealCustomFields.ts +118 -0
  66. package/src/modules/customers/components/detail/create/useDealPipelines.ts +80 -0
  67. package/src/modules/customers/components/formConfig.tsx +3 -0
  68. package/src/modules/customers/i18n/de.json +26 -0
  69. package/src/modules/customers/i18n/en.json +26 -0
  70. package/src/modules/customers/i18n/es.json +26 -0
  71. package/src/modules/customers/i18n/pl.json +26 -0
  72. package/src/modules/dictionaries/components/DictionaryEntrySelect.tsx +12 -1
@@ -0,0 +1,73 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Sparkles } from "lucide-react";
4
+ import { DealSectionCard } from "./DealSectionCard.js";
5
+ import { DealTipsCard } from "./DealTipsCard.js";
6
+ import {
7
+ DealCustomAttributes
8
+ } from "./DealCustomAttributes.js";
9
+ function DealCreateSidebar({
10
+ tr,
11
+ customValues,
12
+ onCustomChange,
13
+ errors,
14
+ disabled,
15
+ customCount,
16
+ manageHref,
17
+ onCustomLoaded
18
+ }) {
19
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
20
+ /* @__PURE__ */ jsx(
21
+ DealSectionCard,
22
+ {
23
+ icon: Sparkles,
24
+ title: tr("customers.deals.create.sections.custom.title", "Custom attributes"),
25
+ subtitle: tr("customers.deals.create.sections.custom.subtitle", "{count} fields defined for this tenant", {
26
+ count: customCount
27
+ }),
28
+ children: /* @__PURE__ */ jsx(
29
+ DealCustomAttributes,
30
+ {
31
+ values: customValues,
32
+ onChange: onCustomChange,
33
+ errors,
34
+ disabled,
35
+ manageHref,
36
+ labels: {
37
+ manage: tr("customers.deals.create.sections.custom.manage", "Manage fields"),
38
+ empty: tr("customers.deals.create.sections.custom.empty", "No custom fields defined for deals yet."),
39
+ loading: tr("customers.deals.create.sections.custom.loading", "Loading custom fields\u2026")
40
+ },
41
+ onLoaded: onCustomLoaded
42
+ }
43
+ )
44
+ }
45
+ ),
46
+ /* @__PURE__ */ jsx(
47
+ DealTipsCard,
48
+ {
49
+ title: tr("customers.deals.create.tips.title", "Tips for better deals"),
50
+ tips: [
51
+ tr(
52
+ "customers.deals.create.tips.item1",
53
+ 'Use the company name + short deliverable format in the title (e.g. "Copperleaf \u2014 Q3 Renewal")'
54
+ ),
55
+ tr(
56
+ "customers.deals.create.tips.item2",
57
+ "Set probability based on pipeline stage: Qual 10-25%, Proposal 30-50%, Negotiation 50-75%, Contract 75-90%"
58
+ ),
59
+ tr(
60
+ "customers.deals.create.tips.item3",
61
+ "Link primary decision maker as first person \u2014 they get default email CC on activities"
62
+ )
63
+ ]
64
+ }
65
+ )
66
+ ] });
67
+ }
68
+ var DealCreateSidebar_default = DealCreateSidebar;
69
+ export {
70
+ DealCreateSidebar,
71
+ DealCreateSidebar_default as default
72
+ };
73
+ //# sourceMappingURL=DealCreateSidebar.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/customers/components/detail/create/DealCreateSidebar.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Sparkles } from 'lucide-react'\nimport { DealSectionCard } from './DealSectionCard'\nimport { DealTipsCard } from './DealTipsCard'\nimport {\n DealCustomAttributes,\n type DealCustomAttributesLoadState,\n} from './DealCustomAttributes'\nimport type { Translate } from './dealFormTypes'\n\nexport type DealCreateSidebarProps = {\n tr: Translate\n customValues: Record<string, unknown>\n onCustomChange: (key: string, value: unknown) => void\n errors: Record<string, string>\n disabled: boolean\n customCount: number\n manageHref: string\n onCustomLoaded: (state: DealCustomAttributesLoadState) => void\n}\n\nexport function DealCreateSidebar({\n tr,\n customValues,\n onCustomChange,\n errors,\n disabled,\n customCount,\n manageHref,\n onCustomLoaded,\n}: DealCreateSidebarProps) {\n return (\n <div className=\"space-y-4\">\n <DealSectionCard\n icon={Sparkles}\n title={tr('customers.deals.create.sections.custom.title', 'Custom attributes')}\n subtitle={tr('customers.deals.create.sections.custom.subtitle', '{count} fields defined for this tenant', {\n count: customCount,\n })}\n >\n <DealCustomAttributes\n values={customValues}\n onChange={onCustomChange}\n errors={errors}\n disabled={disabled}\n manageHref={manageHref}\n labels={{\n manage: tr('customers.deals.create.sections.custom.manage', 'Manage fields'),\n empty: tr('customers.deals.create.sections.custom.empty', 'No custom fields defined for deals yet.'),\n loading: tr('customers.deals.create.sections.custom.loading', 'Loading custom fields\u2026'),\n }}\n onLoaded={onCustomLoaded}\n />\n </DealSectionCard>\n\n <DealTipsCard\n title={tr('customers.deals.create.tips.title', 'Tips for better deals')}\n tips={[\n tr(\n 'customers.deals.create.tips.item1',\n 'Use the company name + short deliverable format in the title (e.g. \"Copperleaf \u2014 Q3 Renewal\")',\n ),\n tr(\n 'customers.deals.create.tips.item2',\n 'Set probability based on pipeline stage: Qual 10-25%, Proposal 30-50%, Negotiation 50-75%, Contract 75-90%',\n ),\n tr(\n 'customers.deals.create.tips.item3',\n 'Link primary decision maker as first person \u2014 they get default email CC on activities',\n ),\n ]}\n />\n </div>\n )\n}\n\nexport default DealCreateSidebar\n"],
5
+ "mappings": ";AAkCI,SAQI,KARJ;AA/BJ,SAAS,gBAAgB;AACzB,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,OAEK;AAcA,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,SACE,qBAAC,SAAI,WAAU,aACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,OAAO,GAAG,gDAAgD,mBAAmB;AAAA,QAC7E,UAAU,GAAG,mDAAmD,0CAA0C;AAAA,UACxG,OAAO;AAAA,QACT,CAAC;AAAA,QAED;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ;AAAA,YACR,UAAU;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA,YACA,QAAQ;AAAA,cACN,QAAQ,GAAG,iDAAiD,eAAe;AAAA,cAC3E,OAAO,GAAG,gDAAgD,yCAAyC;AAAA,cACnG,SAAS,GAAG,kDAAkD,6BAAwB;AAAA,YACxF;AAAA,YACA,UAAU;AAAA;AAAA,QACZ;AAAA;AAAA,IACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,GAAG,qCAAqC,uBAAuB;AAAA,QACtE,MAAM;AAAA,UACJ;AAAA,YACE;AAAA,YACA;AAAA,UACF;AAAA,UACA;AAAA,YACE;AAAA,YACA;AAAA,UACF;AAAA,UACA;AAAA,YACE;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAEA,IAAO,4BAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,92 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "@open-mercato/shared/lib/utils";
5
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
6
+ import { DictionaryEntrySelect } from "@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect";
7
+ import { useCurrencyDictionary } from "../hooks/useCurrencyDictionary.js";
8
+ const CURRENCY_PRIORITY = ["EUR", "USD", "GBP", "PLN"];
9
+ function DealCurrencyField({ id, value, onChange, disabled = false }) {
10
+ const t = useT();
11
+ const { data, error: rawError, isLoading, refetch } = useCurrencyDictionary();
12
+ const dictError = rawError ? rawError instanceof Error ? rawError.message : String(rawError) : null;
13
+ const resolvedError = React.useMemo(() => {
14
+ if (dictError) return dictError;
15
+ if (!isLoading && !data) {
16
+ return t("customers.deals.form.currency.missing", "Currency dictionary is not configured yet.");
17
+ }
18
+ return null;
19
+ }, [data, dictError, isLoading, t]);
20
+ const fetchOptions = React.useCallback(async () => {
21
+ let payload = data ?? null;
22
+ if (!payload) {
23
+ try {
24
+ payload = await refetch();
25
+ } catch (err) {
26
+ const message = err instanceof Error ? err.message : String(err ?? "");
27
+ throw new Error(message || t("customers.deals.form.currency.error", "Failed to load currency dictionary."));
28
+ }
29
+ }
30
+ if (!payload) {
31
+ throw new Error(t("customers.deals.form.currency.missing", "Currency dictionary is not configured yet."));
32
+ }
33
+ const priorityOrder = /* @__PURE__ */ new Map();
34
+ CURRENCY_PRIORITY.forEach((code, index) => priorityOrder.set(code, index));
35
+ const prioritized = [];
36
+ const remainder = [];
37
+ payload.entries.forEach((entry) => {
38
+ const code = entry.value.toUpperCase();
39
+ const label = entry.label && entry.label.length ? `${code} \u2013 ${entry.label}` : code;
40
+ const option = { value: code, label, color: null, icon: null };
41
+ if (priorityOrder.has(code)) prioritized.push(option);
42
+ else remainder.push(option);
43
+ });
44
+ prioritized.sort((a, b) => priorityOrder.get(a.value) - priorityOrder.get(b.value));
45
+ remainder.sort((a, b) => a.label.localeCompare(b.label, void 0, { sensitivity: "base" }));
46
+ return [...prioritized, ...remainder];
47
+ }, [data, refetch, t]);
48
+ const labels = React.useMemo(
49
+ () => ({
50
+ placeholder: t("customers.deals.form.currency.placeholder", "Select currency\u2026"),
51
+ addLabel: t("customers.deals.form.currency.add", "Add currency"),
52
+ dialogTitle: t("customers.deals.form.currency.dialogTitle", "Add currency"),
53
+ valueLabel: t("customers.deals.form.currency.valueLabel", "Currency code"),
54
+ valuePlaceholder: t("customers.deals.form.currency.valuePlaceholder", "e.g. USD"),
55
+ labelLabel: t("customers.deals.form.currency.labelLabel", "Label"),
56
+ labelPlaceholder: t("customers.deals.form.currency.labelPlaceholder", "Display name shown in UI"),
57
+ emptyError: t("customers.deals.form.currency.error.required", "Currency code is required."),
58
+ cancelLabel: t("customers.deals.form.currency.cancel", "Cancel"),
59
+ saveLabel: t("customers.deals.form.currency.save", "Save"),
60
+ errorLoad: t("customers.deals.form.currency.error", "Failed to load currency dictionary."),
61
+ errorSave: t("customers.deals.form.currency.error", "Failed to load currency dictionary."),
62
+ loadingLabel: t("customers.deals.form.currency.loading", "Loading currencies\u2026"),
63
+ manageTitle: t("customers.deals.form.currency.manage", "Manage currency dictionary")
64
+ }),
65
+ [t]
66
+ );
67
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
68
+ /* @__PURE__ */ jsx(
69
+ DictionaryEntrySelect,
70
+ {
71
+ id,
72
+ value: value || void 0,
73
+ onChange: (next) => onChange(next ?? ""),
74
+ fetchOptions,
75
+ labels,
76
+ manageHref: "/backend/config/dictionaries?key=currency",
77
+ allowInlineCreate: false,
78
+ allowAppearance: false,
79
+ selectClassName: "w-full",
80
+ disabled,
81
+ showLabelInput: false
82
+ }
83
+ ),
84
+ resolvedError ? /* @__PURE__ */ jsx("p", { className: cn("text-xs", dictError ? "text-status-error-text" : "text-muted-foreground"), children: resolvedError }) : null
85
+ ] });
86
+ }
87
+ var DealCurrencyField_default = DealCurrencyField;
88
+ export {
89
+ DealCurrencyField,
90
+ DealCurrencyField_default as default
91
+ };
92
+ //# sourceMappingURL=DealCurrencyField.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/customers/components/detail/create/DealCurrencyField.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DictionaryEntrySelect } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\nimport { useCurrencyDictionary } from '../hooks/useCurrencyDictionary'\n\nconst CURRENCY_PRIORITY = ['EUR', 'USD', 'GBP', 'PLN'] as const\n\nexport type DealCurrencyFieldProps = {\n id?: string\n value: string\n onChange: (code: string) => void\n disabled?: boolean\n}\n\nexport function DealCurrencyField({ id, value, onChange, disabled = false }: DealCurrencyFieldProps) {\n const t = useT()\n const { data, error: rawError, isLoading, refetch } = useCurrencyDictionary()\n const dictError = rawError\n ? rawError instanceof Error\n ? rawError.message\n : String(rawError)\n : null\n\n const resolvedError = React.useMemo(() => {\n if (dictError) return dictError\n if (!isLoading && !data) {\n return t('customers.deals.form.currency.missing', 'Currency dictionary is not configured yet.')\n }\n return null\n }, [data, dictError, isLoading, t])\n\n const fetchOptions = React.useCallback(async () => {\n let payload = data ?? null\n if (!payload) {\n try {\n payload = await refetch()\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err ?? '')\n throw new Error(message || t('customers.deals.form.currency.error', 'Failed to load currency dictionary.'))\n }\n }\n if (!payload) {\n throw new Error(t('customers.deals.form.currency.missing', 'Currency dictionary is not configured yet.'))\n }\n const priorityOrder = new Map<string, number>()\n CURRENCY_PRIORITY.forEach((code, index) => priorityOrder.set(code, index))\n const prioritized: { value: string; label: string; color: string | null; icon: string | null }[] = []\n const remainder: { value: string; label: string; color: string | null; icon: string | null }[] = []\n payload.entries.forEach((entry) => {\n const code = entry.value.toUpperCase()\n const label = entry.label && entry.label.length ? `${code} \u2013 ${entry.label}` : code\n const option = { value: code, label, color: null, icon: null }\n if (priorityOrder.has(code)) prioritized.push(option)\n else remainder.push(option)\n })\n prioritized.sort((a, b) => priorityOrder.get(a.value)! - priorityOrder.get(b.value)!)\n remainder.sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: 'base' }))\n return [...prioritized, ...remainder]\n }, [data, refetch, t])\n\n const labels = React.useMemo(\n () => ({\n placeholder: t('customers.deals.form.currency.placeholder', 'Select currency\u2026'),\n addLabel: t('customers.deals.form.currency.add', 'Add currency'),\n dialogTitle: t('customers.deals.form.currency.dialogTitle', 'Add currency'),\n valueLabel: t('customers.deals.form.currency.valueLabel', 'Currency code'),\n valuePlaceholder: t('customers.deals.form.currency.valuePlaceholder', 'e.g. USD'),\n labelLabel: t('customers.deals.form.currency.labelLabel', 'Label'),\n labelPlaceholder: t('customers.deals.form.currency.labelPlaceholder', 'Display name shown in UI'),\n emptyError: t('customers.deals.form.currency.error.required', 'Currency code is required.'),\n cancelLabel: t('customers.deals.form.currency.cancel', 'Cancel'),\n saveLabel: t('customers.deals.form.currency.save', 'Save'),\n errorLoad: t('customers.deals.form.currency.error', 'Failed to load currency dictionary.'),\n errorSave: t('customers.deals.form.currency.error', 'Failed to load currency dictionary.'),\n loadingLabel: t('customers.deals.form.currency.loading', 'Loading currencies\u2026'),\n manageTitle: t('customers.deals.form.currency.manage', 'Manage currency dictionary'),\n }),\n [t],\n )\n\n return (\n <div className=\"space-y-1\">\n <DictionaryEntrySelect\n id={id}\n value={value || undefined}\n onChange={(next) => onChange(next ?? '')}\n fetchOptions={fetchOptions}\n labels={labels}\n manageHref=\"/backend/config/dictionaries?key=currency\"\n allowInlineCreate={false}\n allowAppearance={false}\n selectClassName=\"w-full\"\n disabled={disabled}\n showLabelInput={false}\n />\n {resolvedError ? (\n <p className={cn('text-xs', dictError ? 'text-status-error-text' : 'text-muted-foreground')}>\n {resolvedError}\n </p>\n ) : null}\n </div>\n )\n}\n\nexport default DealCurrencyField\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,81 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Plus } from "lucide-react";
5
+ import { fetchCustomFieldFormStructure } from "@open-mercato/ui/backend/utils/customFieldForms";
6
+ import { LinkButton } from "@open-mercato/ui/primitives/link-button";
7
+ import { Spinner } from "@open-mercato/ui/primitives/spinner";
8
+ import { E } from "../../../../../generated/entities.ids.generated.js";
9
+ import { DealCustomFieldControl } from "./dealCustomFieldControl.js";
10
+ function ManageFieldsLink({ href, label }) {
11
+ return /* @__PURE__ */ jsx(LinkButton, { asChild: true, variant: "gray", size: "sm", children: /* @__PURE__ */ jsxs("a", { href, className: "inline-flex items-center gap-1", children: [
12
+ /* @__PURE__ */ jsx(Plus, { className: "size-3.5" }),
13
+ label
14
+ ] }) });
15
+ }
16
+ function DealCustomAttributes({
17
+ values,
18
+ onChange,
19
+ errors,
20
+ disabled = false,
21
+ manageHref,
22
+ labels,
23
+ onLoaded
24
+ }) {
25
+ const [fields, setFields] = React.useState([]);
26
+ const [isLoading, setIsLoading] = React.useState(true);
27
+ const onLoadedRef = React.useRef(onLoaded);
28
+ React.useEffect(() => {
29
+ onLoadedRef.current = onLoaded;
30
+ }, [onLoaded]);
31
+ React.useEffect(() => {
32
+ let cancelled = false;
33
+ setIsLoading(true);
34
+ fetchCustomFieldFormStructure([E.customers.customer_deal]).then((result) => {
35
+ if (cancelled) return;
36
+ setFields(result.fields);
37
+ setIsLoading(false);
38
+ onLoadedRef.current?.({ fields: result.fields, definitions: result.definitions });
39
+ }).catch(() => {
40
+ if (cancelled) return;
41
+ setFields([]);
42
+ setIsLoading(false);
43
+ onLoadedRef.current?.({ fields: [], definitions: [] });
44
+ });
45
+ return () => {
46
+ cancelled = true;
47
+ };
48
+ }, []);
49
+ if (isLoading) {
50
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
51
+ /* @__PURE__ */ jsx(Spinner, { className: "size-4" }),
52
+ labels.loading
53
+ ] });
54
+ }
55
+ if (fields.length === 0) {
56
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
57
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: labels.empty }),
58
+ /* @__PURE__ */ jsx(ManageFieldsLink, { href: manageHref, label: labels.manage })
59
+ ] });
60
+ }
61
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
62
+ fields.map((field) => /* @__PURE__ */ jsx(
63
+ DealCustomFieldControl,
64
+ {
65
+ field,
66
+ value: values[field.id],
67
+ onChange: (next) => onChange(field.id, next),
68
+ error: errors?.[field.id],
69
+ disabled
70
+ },
71
+ field.id
72
+ )),
73
+ /* @__PURE__ */ jsx("div", { className: "pt-1", children: /* @__PURE__ */ jsx(ManageFieldsLink, { href: manageHref, label: labels.manage }) })
74
+ ] });
75
+ }
76
+ var DealCustomAttributes_default = DealCustomAttributes;
77
+ export {
78
+ DealCustomAttributes,
79
+ DealCustomAttributes_default as default
80
+ };
81
+ //# sourceMappingURL=DealCustomAttributes.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/customers/components/detail/create/DealCustomAttributes.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Plus } from 'lucide-react'\nimport type { CrudField } from '@open-mercato/ui/backend/CrudForm'\nimport type { CustomFieldDefDto } from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport { fetchCustomFieldFormStructure } from '@open-mercato/ui/backend/utils/customFieldForms'\nimport { LinkButton } from '@open-mercato/ui/primitives/link-button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { E } from '#generated/entities.ids.generated'\nimport { DealCustomFieldControl } from './dealCustomFieldControl'\n\nexport type DealCustomAttributesLoadState = {\n fields: CrudField[]\n definitions: CustomFieldDefDto[]\n}\n\nexport type DealCustomAttributesProps = {\n values: Record<string, unknown>\n onChange: (key: string, value: unknown) => void\n errors?: Record<string, string>\n disabled?: boolean\n manageHref: string\n labels: {\n manage: string\n empty: string\n loading: string\n }\n onLoaded?: (state: DealCustomAttributesLoadState) => void\n}\n\nfunction ManageFieldsLink({ href, label }: { href: string; label: string }) {\n return (\n <LinkButton asChild variant=\"gray\" size=\"sm\">\n <a href={href} className=\"inline-flex items-center gap-1\">\n <Plus className=\"size-3.5\" />\n {label}\n </a>\n </LinkButton>\n )\n}\n\nexport function DealCustomAttributes({\n values,\n onChange,\n errors,\n disabled = false,\n manageHref,\n labels,\n onLoaded,\n}: DealCustomAttributesProps) {\n const [fields, setFields] = React.useState<CrudField[]>([])\n const [isLoading, setIsLoading] = React.useState(true)\n const onLoadedRef = React.useRef(onLoaded)\n\n React.useEffect(() => {\n onLoadedRef.current = onLoaded\n }, [onLoaded])\n\n React.useEffect(() => {\n let cancelled = false\n setIsLoading(true)\n fetchCustomFieldFormStructure([E.customers.customer_deal])\n .then((result) => {\n if (cancelled) return\n setFields(result.fields)\n setIsLoading(false)\n onLoadedRef.current?.({ fields: result.fields, definitions: result.definitions })\n })\n .catch(() => {\n if (cancelled) return\n setFields([])\n setIsLoading(false)\n onLoadedRef.current?.({ fields: [], definitions: [] })\n })\n return () => {\n cancelled = true\n }\n }, [])\n\n if (isLoading) {\n return (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"size-4\" />\n {labels.loading}\n </div>\n )\n }\n\n if (fields.length === 0) {\n return (\n <div className=\"space-y-3\">\n <p className=\"text-sm text-muted-foreground\">{labels.empty}</p>\n <ManageFieldsLink href={manageHref} label={labels.manage} />\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {fields.map((field) => (\n <DealCustomFieldControl\n key={field.id}\n field={field}\n value={values[field.id]}\n onChange={(next) => onChange(field.id, next)}\n error={errors?.[field.id]}\n disabled={disabled}\n />\n ))}\n <div className=\"pt-1\">\n <ManageFieldsLink href={manageHref} label={labels.manage} />\n </div>\n </div>\n )\n}\n\nexport default DealCustomAttributes\n"],
5
+ "mappings": ";AAkCM,SACE,KADF;AAhCN,YAAY,WAAW;AACvB,SAAS,YAAY;AAGrB,SAAS,qCAAqC;AAC9C,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,SAAS;AAClB,SAAS,8BAA8B;AAqBvC,SAAS,iBAAiB,EAAE,MAAM,MAAM,GAAoC;AAC1E,SACE,oBAAC,cAAW,SAAO,MAAC,SAAQ,QAAO,MAAK,MACtC,+BAAC,OAAE,MAAY,WAAU,kCACvB;AAAA,wBAAC,QAAK,WAAU,YAAW;AAAA,IAC1B;AAAA,KACH,GACF;AAEJ;AAEO,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AACF,GAA8B;AAC5B,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAsB,CAAC,CAAC;AAC1D,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,IAAI;AACrD,QAAM,cAAc,MAAM,OAAO,QAAQ;AAEzC,QAAM,UAAU,MAAM;AACpB,gBAAY,UAAU;AAAA,EACxB,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,UAAU,MAAM;AACpB,QAAI,YAAY;AAChB,iBAAa,IAAI;AACjB,kCAA8B,CAAC,EAAE,UAAU,aAAa,CAAC,EACtD,KAAK,CAAC,WAAW;AAChB,UAAI,UAAW;AACf,gBAAU,OAAO,MAAM;AACvB,mBAAa,KAAK;AAClB,kBAAY,UAAU,EAAE,QAAQ,OAAO,QAAQ,aAAa,OAAO,YAAY,CAAC;AAAA,IAClF,CAAC,EACA,MAAM,MAAM;AACX,UAAI,UAAW;AACf,gBAAU,CAAC,CAAC;AACZ,mBAAa,KAAK;AAClB,kBAAY,UAAU,EAAE,QAAQ,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC;AAAA,IACvD,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,MAAI,WAAW;AACb,WACE,qBAAC,SAAI,WAAU,yDACb;AAAA,0BAAC,WAAQ,WAAU,UAAS;AAAA,MAC3B,OAAO;AAAA,OACV;AAAA,EAEJ;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,WACE,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,OAAE,WAAU,iCAAiC,iBAAO,OAAM;AAAA,MAC3D,oBAAC,oBAAiB,MAAM,YAAY,OAAO,OAAO,QAAQ;AAAA,OAC5D;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAU,aACZ;AAAA,WAAO,IAAI,CAAC,UACX;AAAA,MAAC;AAAA;AAAA,QAEC;AAAA,QACA,OAAO,OAAO,MAAM,EAAE;AAAA,QACtB,UAAU,CAAC,SAAS,SAAS,MAAM,IAAI,IAAI;AAAA,QAC3C,OAAO,SAAS,MAAM,EAAE;AAAA,QACxB;AAAA;AAAA,MALK,MAAM;AAAA,IAMb,CACD;AAAA,IACD,oBAAC,SAAI,WAAU,QACb,8BAAC,oBAAiB,MAAM,YAAY,OAAO,OAAO,QAAQ,GAC5D;AAAA,KACF;AAEJ;AAEA,IAAO,+BAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,171 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { format } from "date-fns/format";
4
+ import { parseISO } from "date-fns/parseISO";
5
+ import { Input } from "@open-mercato/ui/primitives/input";
6
+ import { Textarea } from "@open-mercato/ui/primitives/textarea";
7
+ import { DatePicker } from "@open-mercato/ui/primitives/date-picker";
8
+ import { DictionarySelectField } from "../../formConfig.js";
9
+ import { DealFormField } from "./DealFormField.js";
10
+ import { PipelineSelect } from "./PipelineSelect.js";
11
+ import { PipelineStageSelect } from "./PipelineStageSelect.js";
12
+ import { SuffixInput } from "./SuffixInput.js";
13
+ import { DealCurrencyField } from "./DealCurrencyField.js";
14
+ import { sanitizeAmount, sanitizeProbability } from "./dealNumericInput.js";
15
+ function toDate(value) {
16
+ if (!value) return null;
17
+ const parsed = parseISO(value);
18
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
19
+ }
20
+ function DealDetailsFields({
21
+ values,
22
+ errors,
23
+ isSubmitting,
24
+ patch,
25
+ onPipelineChange,
26
+ pipelines,
27
+ stages,
28
+ statusLabels,
29
+ tr
30
+ }) {
31
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
32
+ /* @__PURE__ */ jsx(
33
+ DealFormField,
34
+ {
35
+ fieldId: "title",
36
+ label: tr("customers.deals.create.fields.title", "Deal title"),
37
+ required: true,
38
+ hint: tr("customers.deals.create.hints.title", "Short, descriptive name shown on pipeline cards"),
39
+ error: errors.title,
40
+ children: /* @__PURE__ */ jsx(
41
+ Input,
42
+ {
43
+ value: values.title,
44
+ onChange: (event) => patch({ title: event.target.value }),
45
+ "aria-invalid": errors.title ? true : void 0,
46
+ disabled: isSubmitting
47
+ }
48
+ )
49
+ }
50
+ ),
51
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [
52
+ /* @__PURE__ */ jsx(DealFormField, { fieldId: "status", label: tr("customers.people.detail.deals.fields.status", "Status"), children: /* @__PURE__ */ jsx(
53
+ DictionarySelectField,
54
+ {
55
+ kind: "deal-statuses",
56
+ value: values.status || void 0,
57
+ onChange: (next) => patch({ status: next ?? "" }),
58
+ labels: statusLabels,
59
+ selectClassName: "w-full",
60
+ showActiveAppearance: false
61
+ }
62
+ ) }),
63
+ /* @__PURE__ */ jsx(DealFormField, { fieldId: "pipelineId", label: tr("customers.people.detail.deals.fields.pipeline", "Pipeline"), children: /* @__PURE__ */ jsx(
64
+ PipelineSelect,
65
+ {
66
+ pipelines,
67
+ value: values.pipelineId,
68
+ onChange: onPipelineChange,
69
+ disabled: isSubmitting,
70
+ placeholder: tr("customers.deals.form.pipeline.placeholder", "Select pipeline\u2026")
71
+ }
72
+ ) })
73
+ ] }),
74
+ /* @__PURE__ */ jsx(
75
+ DealFormField,
76
+ {
77
+ fieldId: "pipelineStageId",
78
+ label: tr("customers.people.detail.deals.fields.pipelineStage", "Pipeline stage"),
79
+ hint: tr("customers.deals.create.hints.pipelineStage", "Stages depend on the selected pipeline"),
80
+ children: /* @__PURE__ */ jsx(
81
+ PipelineStageSelect,
82
+ {
83
+ stages,
84
+ value: values.pipelineStageId,
85
+ onChange: (id) => patch({ pipelineStageId: id }),
86
+ disabled: isSubmitting || !values.pipelineId,
87
+ placeholder: tr("customers.deals.form.pipelineStage.placeholder", "Select stage\u2026"),
88
+ formatCount: (position, total) => tr("customers.deals.create.fields.stageOf", "\xB7 stage {position} of {total}", { position, total })
89
+ }
90
+ )
91
+ }
92
+ ),
93
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [
94
+ /* @__PURE__ */ jsx(
95
+ DealFormField,
96
+ {
97
+ fieldId: "valueAmount",
98
+ label: tr("customers.deals.create.fields.valueAmount", "Deal value"),
99
+ hint: tr("customers.deals.create.hints.valueAmount", "Potential revenue from this opportunity"),
100
+ error: errors.valueAmount,
101
+ children: /* @__PURE__ */ jsx(
102
+ SuffixInput,
103
+ {
104
+ suffix: values.valueCurrency,
105
+ inputMode: "decimal",
106
+ value: values.valueAmount,
107
+ onChange: (event) => patch({ valueAmount: sanitizeAmount(event.target.value) }),
108
+ placeholder: "0",
109
+ "aria-invalid": errors.valueAmount ? true : void 0,
110
+ disabled: isSubmitting
111
+ }
112
+ )
113
+ }
114
+ ),
115
+ /* @__PURE__ */ jsx(DealFormField, { fieldId: "valueCurrency", label: tr("customers.people.detail.deals.fields.valueCurrency", "Currency"), children: /* @__PURE__ */ jsx(
116
+ DealCurrencyField,
117
+ {
118
+ value: values.valueCurrency,
119
+ onChange: (code) => patch({ valueCurrency: code }),
120
+ disabled: isSubmitting
121
+ }
122
+ ) })
123
+ ] }),
124
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [
125
+ /* @__PURE__ */ jsx(
126
+ DealFormField,
127
+ {
128
+ fieldId: "probability",
129
+ label: tr("customers.deals.create.fields.probability", "Probability"),
130
+ hint: tr("customers.deals.create.hints.probability", "0 \u2013 100%, used for weighted pipeline value"),
131
+ error: errors.probability,
132
+ children: /* @__PURE__ */ jsx(
133
+ SuffixInput,
134
+ {
135
+ suffix: "%",
136
+ inputMode: "numeric",
137
+ value: values.probability,
138
+ onChange: (event) => patch({ probability: sanitizeProbability(event.target.value) }),
139
+ placeholder: "0",
140
+ "aria-invalid": errors.probability ? true : void 0,
141
+ disabled: isSubmitting
142
+ }
143
+ )
144
+ }
145
+ ),
146
+ /* @__PURE__ */ jsx(DealFormField, { fieldId: "expectedCloseAt", label: tr("customers.deals.create.fields.expectedCloseAt", "Expected close date"), children: /* @__PURE__ */ jsx(
147
+ DatePicker,
148
+ {
149
+ value: toDate(values.expectedCloseAt),
150
+ onChange: (date) => patch({ expectedCloseAt: date ? format(date, "yyyy-MM-dd") : "" }),
151
+ disabled: isSubmitting,
152
+ placeholder: tr("customers.deals.create.fields.datePlaceholder", "Pick a date")
153
+ }
154
+ ) })
155
+ ] }),
156
+ /* @__PURE__ */ jsx(DealFormField, { fieldId: "description", label: tr("customers.people.detail.deals.fields.description", "Description"), children: /* @__PURE__ */ jsx(
157
+ Textarea,
158
+ {
159
+ value: values.description,
160
+ onChange: (event) => patch({ description: event.target.value }),
161
+ disabled: isSubmitting
162
+ }
163
+ ) })
164
+ ] });
165
+ }
166
+ var DealDetailsFields_default = DealDetailsFields;
167
+ export {
168
+ DealDetailsFields,
169
+ DealDetailsFields_default as default
170
+ };
171
+ //# sourceMappingURL=DealDetailsFields.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/customers/components/detail/create/DealDetailsFields.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { format } from 'date-fns/format'\nimport { parseISO } from 'date-fns/parseISO'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { DatePicker } from '@open-mercato/ui/primitives/date-picker'\nimport { DictionarySelectField } from '../../formConfig'\nimport { createDictionarySelectLabels } from '../utils'\nimport { DealFormField } from './DealFormField'\nimport { PipelineSelect } from './PipelineSelect'\nimport { PipelineStageSelect } from './PipelineStageSelect'\nimport { SuffixInput } from './SuffixInput'\nimport { DealCurrencyField } from './DealCurrencyField'\nimport { sanitizeAmount, sanitizeProbability } from './dealNumericInput'\nimport type { BaseValues } from './dealFormTypes'\nimport type { PipelineOption, PipelineStageOption } from './useDealPipelines'\n\ntype Translate = (key: string, fallback: string, params?: Record<string, string | number>) => string\n\nexport type DealDetailsFieldsProps = {\n values: BaseValues\n errors: Record<string, string>\n isSubmitting: boolean\n patch: (partial: Partial<BaseValues>) => void\n onPipelineChange: (id: string) => void\n pipelines: PipelineOption[]\n stages: PipelineStageOption[]\n statusLabels: ReturnType<typeof createDictionarySelectLabels>\n tr: Translate\n}\n\nfunction toDate(value: string): Date | null {\n if (!value) return null\n const parsed = parseISO(value)\n return Number.isNaN(parsed.getTime()) ? null : parsed\n}\n\nexport function DealDetailsFields({\n values,\n errors,\n isSubmitting,\n patch,\n onPipelineChange,\n pipelines,\n stages,\n statusLabels,\n tr,\n}: DealDetailsFieldsProps) {\n return (\n <>\n <DealFormField\n fieldId=\"title\"\n label={tr('customers.deals.create.fields.title', 'Deal title')}\n required\n hint={tr('customers.deals.create.hints.title', 'Short, descriptive name shown on pipeline cards')}\n error={errors.title}\n >\n <Input\n value={values.title}\n onChange={(event) => patch({ title: event.target.value })}\n aria-invalid={errors.title ? true : undefined}\n disabled={isSubmitting}\n />\n </DealFormField>\n\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <DealFormField fieldId=\"status\" label={tr('customers.people.detail.deals.fields.status', 'Status')}>\n <DictionarySelectField\n kind=\"deal-statuses\"\n value={values.status || undefined}\n onChange={(next) => patch({ status: next ?? '' })}\n labels={statusLabels}\n selectClassName=\"w-full\"\n showActiveAppearance={false}\n />\n </DealFormField>\n <DealFormField fieldId=\"pipelineId\" label={tr('customers.people.detail.deals.fields.pipeline', 'Pipeline')}>\n <PipelineSelect\n pipelines={pipelines}\n value={values.pipelineId}\n onChange={onPipelineChange}\n disabled={isSubmitting}\n placeholder={tr('customers.deals.form.pipeline.placeholder', 'Select pipeline\u2026')}\n />\n </DealFormField>\n </div>\n\n <DealFormField\n fieldId=\"pipelineStageId\"\n label={tr('customers.people.detail.deals.fields.pipelineStage', 'Pipeline stage')}\n hint={tr('customers.deals.create.hints.pipelineStage', 'Stages depend on the selected pipeline')}\n >\n <PipelineStageSelect\n stages={stages}\n value={values.pipelineStageId}\n onChange={(id) => patch({ pipelineStageId: id })}\n disabled={isSubmitting || !values.pipelineId}\n placeholder={tr('customers.deals.form.pipelineStage.placeholder', 'Select stage\u2026')}\n formatCount={(position, total) =>\n tr('customers.deals.create.fields.stageOf', '\u00B7 stage {position} of {total}', { position, total })\n }\n />\n </DealFormField>\n\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <DealFormField\n fieldId=\"valueAmount\"\n label={tr('customers.deals.create.fields.valueAmount', 'Deal value')}\n hint={tr('customers.deals.create.hints.valueAmount', 'Potential revenue from this opportunity')}\n error={errors.valueAmount}\n >\n <SuffixInput\n suffix={values.valueCurrency}\n inputMode=\"decimal\"\n value={values.valueAmount}\n onChange={(event) => patch({ valueAmount: sanitizeAmount(event.target.value) })}\n placeholder=\"0\"\n aria-invalid={errors.valueAmount ? true : undefined}\n disabled={isSubmitting}\n />\n </DealFormField>\n <DealFormField fieldId=\"valueCurrency\" label={tr('customers.people.detail.deals.fields.valueCurrency', 'Currency')}>\n <DealCurrencyField\n value={values.valueCurrency}\n onChange={(code) => patch({ valueCurrency: code })}\n disabled={isSubmitting}\n />\n </DealFormField>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <DealFormField\n fieldId=\"probability\"\n label={tr('customers.deals.create.fields.probability', 'Probability')}\n hint={tr('customers.deals.create.hints.probability', '0 \u2013 100%, used for weighted pipeline value')}\n error={errors.probability}\n >\n <SuffixInput\n suffix=\"%\"\n inputMode=\"numeric\"\n value={values.probability}\n onChange={(event) => patch({ probability: sanitizeProbability(event.target.value) })}\n placeholder=\"0\"\n aria-invalid={errors.probability ? true : undefined}\n disabled={isSubmitting}\n />\n </DealFormField>\n <DealFormField fieldId=\"expectedCloseAt\" label={tr('customers.deals.create.fields.expectedCloseAt', 'Expected close date')}>\n <DatePicker\n value={toDate(values.expectedCloseAt)}\n onChange={(date) => patch({ expectedCloseAt: date ? format(date, 'yyyy-MM-dd') : '' })}\n disabled={isSubmitting}\n placeholder={tr('customers.deals.create.fields.datePlaceholder', 'Pick a date')}\n />\n </DealFormField>\n </div>\n\n <DealFormField fieldId=\"description\" label={tr('customers.people.detail.deals.fields.description', 'Description')}>\n <Textarea\n value={values.description}\n onChange={(event) => patch({ description: event.target.value })}\n disabled={isSubmitting}\n />\n </DealFormField>\n </>\n )\n}\n\nexport default DealDetailsFields\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Label } from "@open-mercato/ui/primitives/label";
5
+ function DealFormField({ label, fieldId, required, hint, error, children }) {
6
+ const generatedId = React.useId();
7
+ const controlId = fieldId ?? generatedId;
8
+ const control = React.isValidElement(children) ? React.cloneElement(children, { id: controlId }) : children;
9
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", "data-crud-field-id": fieldId, children: [
10
+ /* @__PURE__ */ jsxs(Label, { htmlFor: controlId, children: [
11
+ label,
12
+ required ? /* @__PURE__ */ jsx("span", { className: "text-destructive", children: " *" }) : null
13
+ ] }),
14
+ control,
15
+ hint ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: hint }) : null,
16
+ error ? /* @__PURE__ */ jsx("p", { className: "text-xs text-status-error-text", children: error }) : null
17
+ ] });
18
+ }
19
+ var DealFormField_default = DealFormField;
20
+ export {
21
+ DealFormField,
22
+ DealFormField_default as default
23
+ };
24
+ //# sourceMappingURL=DealFormField.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/customers/components/detail/create/DealFormField.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Label } from '@open-mercato/ui/primitives/label'\n\nexport type DealFormFieldProps = {\n label: string\n /**\n * Stable field key exposed as `data-crud-field-id` and used as the control's `id`.\n * Lets Playwright target the control via the project's `data-crud-field-id` convention\n * (see .ai/lessons.md). Falls back to a generated id for label/control association only.\n */\n fieldId?: string\n required?: boolean\n hint?: string\n error?: string\n children: React.ReactNode\n}\n\nexport function DealFormField({ label, fieldId, required, hint, error, children }: DealFormFieldProps) {\n const generatedId = React.useId()\n const controlId = fieldId ?? generatedId\n const control = React.isValidElement(children)\n ? React.cloneElement(children as React.ReactElement<{ id?: string }>, { id: controlId })\n : children\n return (\n <div className=\"space-y-2\" data-crud-field-id={fieldId}>\n <Label htmlFor={controlId}>\n {label}\n {required ? <span className=\"text-destructive\"> *</span> : null}\n </Label>\n {control}\n {hint ? <p className=\"text-xs text-muted-foreground\">{hint}</p> : null}\n {error ? <p className=\"text-xs text-status-error-text\">{error}</p> : null}\n </div>\n )\n}\n\nexport default DealFormField\n"],
5
+ "mappings": ";AA2BM,SAEc,KAFd;AAzBN,YAAY,WAAW;AACvB,SAAS,aAAa;AAgBf,SAAS,cAAc,EAAE,OAAO,SAAS,UAAU,MAAM,OAAO,SAAS,GAAuB;AACrG,QAAM,cAAc,MAAM,MAAM;AAChC,QAAM,YAAY,WAAW;AAC7B,QAAM,UAAU,MAAM,eAAe,QAAQ,IACzC,MAAM,aAAa,UAAiD,EAAE,IAAI,UAAU,CAAC,IACrF;AACJ,SACE,qBAAC,SAAI,WAAU,aAAY,sBAAoB,SAC7C;AAAA,yBAAC,SAAM,SAAS,WACb;AAAA;AAAA,MACA,WAAW,oBAAC,UAAK,WAAU,oBAAmB,gBAAE,IAAU;AAAA,OAC7D;AAAA,IACC;AAAA,IACA,OAAO,oBAAC,OAAE,WAAU,iCAAiC,gBAAK,IAAO;AAAA,IACjE,QAAQ,oBAAC,OAAE,WAAU,kCAAkC,iBAAM,IAAO;AAAA,KACvE;AAEJ;AAEA,IAAO,wBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,29 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { cn } from "@open-mercato/shared/lib/utils";
4
+ function DealSectionCard({
5
+ icon: Icon,
6
+ title,
7
+ subtitle,
8
+ actions,
9
+ children,
10
+ className
11
+ }) {
12
+ return /* @__PURE__ */ jsxs("section", { className: cn("rounded-lg border border-border bg-card shadow-sm p-6 space-y-6", className), children: [
13
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
14
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [
15
+ /* @__PURE__ */ jsx("div", { className: "flex size-8 shrink-0 items-center justify-center rounded-md bg-brand-violet/10", children: /* @__PURE__ */ jsx(Icon, { className: "size-4 text-brand-violet" }) }),
16
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
17
+ /* @__PURE__ */ jsx("p", { className: "text-base font-semibold text-foreground", children: title }),
18
+ subtitle ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: subtitle }) : null
19
+ ] })
20
+ ] }),
21
+ actions ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2", children: actions }) : null
22
+ ] }),
23
+ /* @__PURE__ */ jsx("div", { className: "space-y-4", children })
24
+ ] });
25
+ }
26
+ export {
27
+ DealSectionCard
28
+ };
29
+ //# sourceMappingURL=DealSectionCard.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/customers/components/detail/create/DealSectionCard.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\nexport type DealSectionCardProps = {\n icon: React.ComponentType<{ className?: string }>\n title: string\n subtitle?: React.ReactNode\n actions?: React.ReactNode\n children: React.ReactNode\n className?: string\n}\n\nexport function DealSectionCard({\n icon: Icon,\n title,\n subtitle,\n actions,\n children,\n className,\n}: DealSectionCardProps) {\n return (\n <section className={cn('rounded-lg border border-border bg-card shadow-sm p-6 space-y-6', className)}>\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex min-w-0 items-center gap-3\">\n <div className=\"flex size-8 shrink-0 items-center justify-center rounded-md bg-brand-violet/10\">\n <Icon className=\"size-4 text-brand-violet\" />\n </div>\n <div className=\"flex min-w-0 flex-col gap-0.5\">\n <p className=\"text-base font-semibold text-foreground\">{title}</p>\n {subtitle ? <p className=\"text-xs text-muted-foreground\">{subtitle}</p> : null}\n </div>\n </div>\n {actions ? <div className=\"flex shrink-0 items-center gap-2\">{actions}</div> : null}\n </div>\n <div className=\"space-y-4\">{children}</div>\n </section>\n )\n}\n"],
5
+ "mappings": ";AA2BY,cAEF,YAFE;AAxBZ,SAAS,UAAU;AAWZ,SAAS,gBAAgB;AAAA,EAC9B,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,SACE,qBAAC,aAAQ,WAAW,GAAG,mEAAmE,SAAS,GACjG;AAAA,yBAAC,SAAI,WAAU,2CACb;AAAA,2BAAC,SAAI,WAAU,mCACb;AAAA,4BAAC,SAAI,WAAU,kFACb,8BAAC,QAAK,WAAU,4BAA2B,GAC7C;AAAA,QACA,qBAAC,SAAI,WAAU,iCACb;AAAA,8BAAC,OAAE,WAAU,2CAA2C,iBAAM;AAAA,UAC7D,WAAW,oBAAC,OAAE,WAAU,iCAAiC,oBAAS,IAAO;AAAA,WAC5E;AAAA,SACF;AAAA,MACC,UAAU,oBAAC,SAAI,WAAU,oCAAoC,mBAAQ,IAAS;AAAA,OACjF;AAAA,IACA,oBAAC,SAAI,WAAU,aAAa,UAAS;AAAA,KACvC;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Wand2 } from "lucide-react";
4
+ function DealTipsCard({ title, tips }) {
5
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border-l-4 border-status-info-border bg-status-info-bg px-5 py-4 space-y-3", children: [
6
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7
+ /* @__PURE__ */ jsx(Wand2, { className: "size-4 text-status-info-icon" }),
8
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-status-info-text", children: title })
9
+ ] }),
10
+ tips.map((tip, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
11
+ /* @__PURE__ */ jsx("span", { className: "mt-1.5 size-1.5 shrink-0 rounded-full bg-status-info-icon" }),
12
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: tip })
13
+ ] }, `${tip}-${index}`))
14
+ ] });
15
+ }
16
+ export {
17
+ DealTipsCard
18
+ };
19
+ //# sourceMappingURL=DealTipsCard.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/customers/components/detail/create/DealTipsCard.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Wand2 } from 'lucide-react'\n\nexport type DealTipsCardProps = {\n title: string\n tips: string[]\n}\n\nexport function DealTipsCard({ title, tips }: DealTipsCardProps) {\n return (\n <div className=\"rounded-lg border-l-4 border-status-info-border bg-status-info-bg px-5 py-4 space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Wand2 className=\"size-4 text-status-info-icon\" />\n <p className=\"text-sm font-semibold text-status-info-text\">{title}</p>\n </div>\n {tips.map((tip, index) => (\n <div key={`${tip}-${index}`} className=\"flex items-start gap-2\">\n <span className=\"mt-1.5 size-1.5 shrink-0 rounded-full bg-status-info-icon\" />\n <p className=\"text-xs text-muted-foreground\">{tip}</p>\n </div>\n ))}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAaM,SACE,KADF;AAVN,SAAS,aAAa;AAOf,SAAS,aAAa,EAAE,OAAO,KAAK,GAAsB;AAC/D,SACE,qBAAC,SAAI,WAAU,yFACb;AAAA,yBAAC,SAAI,WAAU,2BACb;AAAA,0BAAC,SAAM,WAAU,gCAA+B;AAAA,MAChD,oBAAC,OAAE,WAAU,+CAA+C,iBAAM;AAAA,OACpE;AAAA,IACC,KAAK,IAAI,CAAC,KAAK,UACd,qBAAC,SAA4B,WAAU,0BACrC;AAAA,0BAAC,UAAK,WAAU,6DAA4D;AAAA,MAC5E,oBAAC,OAAE,WAAU,iCAAiC,eAAI;AAAA,SAF1C,GAAG,GAAG,IAAI,KAAK,EAGzB,CACD;AAAA,KACH;AAEJ;",
6
+ "names": []
7
+ }