strapi-plugin-hubspot 0.10.0 → 0.11.1

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 (36) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/_chunks/{Forms-BGdNbq-k.mjs → Forms-DadTbe9Q.mjs} +150 -12
  3. package/dist/_chunks/{Forms-BVkE1C46.js → Forms-Dn2W6OS4.js} +149 -11
  4. package/dist/_chunks/{HubspotFormInput-QJldybwT.mjs → HubspotFormInput-NO59AtM_.mjs} +1 -1
  5. package/dist/_chunks/{HubspotFormInput-ddrrD-GJ.js → HubspotFormInput-S_Z2t_DN.js} +1 -1
  6. package/dist/_chunks/{HubspotObjectInput-DZ4H-vju.js → HubspotObjectInput-BIgIa_Dm.js} +3 -3
  7. package/dist/_chunks/{HubspotObjectInput-B_W9dpvD.mjs → HubspotObjectInput-DAo3FAMz.mjs} +3 -3
  8. package/dist/_chunks/{HubspotPropertyInput-BJHUy5Zr.js → HubspotPropertyInput-B-piLcIy.js} +3 -3
  9. package/dist/_chunks/{HubspotPropertyInput-CiVxcnEt.mjs → HubspotPropertyInput-KX1Bhcsl.mjs} +3 -3
  10. package/dist/_chunks/{Settings-DaFRUzjG.js → Settings-DMu_QThB.js} +2 -2
  11. package/dist/_chunks/{Settings-B0NyQtsh.mjs → Settings-Dz0PEFOv.mjs} +2 -2
  12. package/dist/_chunks/{en-zJv-SuNb.js → en-BDGqW_yS.js} +17 -1
  13. package/dist/_chunks/{en-D1sHFQdN.mjs → en-CH5LSPkL.mjs} +17 -1
  14. package/dist/_chunks/{fr-E3zTW7pq.mjs → fr-65-RaB3w.mjs} +17 -1
  15. package/dist/_chunks/{fr-fh0uH6Rp.js → fr-C82LMqUM.js} +17 -1
  16. package/dist/_chunks/{index-rgjWxSn4.js → index-B7Ru1fu5.js} +6 -6
  17. package/dist/_chunks/{index-BpapRdHX.mjs → index-DA31TY2n.mjs} +6 -6
  18. package/dist/_chunks/{objectLabels-DQYwGDr3.mjs → objectLabels-Bl7sO5pb.mjs} +1 -1
  19. package/dist/_chunks/{objectLabels-mBjwR5EE.js → objectLabels-FTh984_h.js} +1 -1
  20. package/dist/_chunks/{useHubspotSchema-DX4JTPFt.mjs → useHubspotSchema-BlDilCHc.mjs} +1 -1
  21. package/dist/_chunks/{useHubspotSchema-CJEiHbjz.js → useHubspotSchema-C2_PuXEm.js} +1 -1
  22. package/dist/admin/index.js +1 -1
  23. package/dist/admin/index.mjs +1 -1
  24. package/dist/admin/src/builder/CompanyMapEditor.d.ts +14 -0
  25. package/dist/admin/src/builder/types.d.ts +11 -1
  26. package/dist/server/index.js +1012 -16
  27. package/dist/server/index.mjs +1012 -16
  28. package/dist/server/src/__tests__/company.test.d.ts +1 -0
  29. package/dist/server/src/company.d.ts +84 -0
  30. package/dist/server/src/conditions.d.ts +4 -0
  31. package/dist/server/src/content-types.d.ts +3 -0
  32. package/dist/server/src/data/naf.d.ts +1 -0
  33. package/dist/server/src/forms.d.ts +16 -0
  34. package/dist/server/src/index.d.ts +13 -0
  35. package/dist/shared/types.d.ts +36 -1
  36. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.11.1 — 2026-08-29
4
+
5
+ Ships the company-search sharpening that missed the 0.11.0 tarball (the
6
+ release was published before its PR merged):
7
+
8
+ - pasted SIRET/SIREN identifiers survive their formatting (spaces, dots,
9
+ dashes) and query directly;
10
+ - closed structures excluded at the source (`etat_administratif=A`);
11
+ - big groups surface up to 5 matching établissements.
12
+
13
+ ## 0.11.0 — 2026-08-29
14
+
15
+ ### Added — the `company` field (INSEE/SIRENE)
16
+ - New field type **`company`**: the visitor picks their company from the
17
+ French SIRENE registry (Recherche d'entreprises API — no key), siège and
18
+ matching établissements offered separately, closed ones filtered. Free text
19
+ stays allowed: an unfindable company submits its typed name alone.
20
+ - **The server is the authority**: the browser only nominates a SIRET; at
21
+ submission the plugin re-resolves it against SIRENE and maps fresh data. If
22
+ the API is down, the browser's snapshot is used and flagged unresolved.
23
+ - **Per-datum HubSpot mapping** (`companyMap`, server-side only — stripped
24
+ from the public API): legal name, SIRET, SIREN, address, postal code, city,
25
+ is-headquarters, NAF code + label (embedded NAF rev. 2 table), INSEE
26
+ headcount range — each with its own object + property picker in the builder.
27
+ - **Company dedup order**: mapped SIRET property → corporate email domain →
28
+ bare creation with the INSEE data. A personal email with a resolved SIRET
29
+ still gets its Company — the exact case the field exists for.
30
+ - Rotating **placeholder examples** (`placeholderExamples`, served publicly),
31
+ edited one per line in the builder.
32
+ - Public route `GET /api/hubspot/company-search?q=` (bounded, TTL-cached,
33
+ 4s timeout) for the frontend autocomplete; timeline note gains a company
34
+ line; submissions store the resolved records (`companies` attribute).
35
+ - Structural guard: a field name colliding with a company field's companion
36
+ keys (`<name>__siret`, `<name>__company`) is refused; `companyMap` entries
37
+ are validated against the portal schema like any mapping.
38
+
3
39
  ## 0.10.0 — 2026-08-29
4
40
 
5
41
  ### Added — HubSpot-parity condition operators
@@ -2,12 +2,12 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { useParams, useSearchParams, Link, useNavigate, Routes, Route } from "react-router-dom";
3
3
  import * as React from "react";
4
4
  import { u as useIntl } from "./index-CEh8vkxY.mjs";
5
- import { Typography, Flex, Box, SingleSelect, SingleSelectOption, MultiSelect, MultiSelectOption, TextInput, IconButton, Button, Field, Checkbox, Divider, Combobox, ComboboxOption, Loader, Badge, Textarea, Table, Thead, Tr, Th, Tbody, Td, Modal } from "@strapi/design-system";
5
+ import { Typography, Flex, Box, SingleSelect, SingleSelectOption, MultiSelect, MultiSelectOption, TextInput, IconButton, Button, Combobox, ComboboxOption, Field, Textarea, Checkbox, Divider, Loader, Badge, Table, Thead, Tr, Th, Tbody, Td, Modal } from "@strapi/design-system";
6
6
  import { Trash, Plus, ArrowClockwise, ArrowLeft, ArrowUp, ArrowDown, List, Duplicate, Download } from "@strapi/icons";
7
7
  import { useFetchClient } from "@strapi/strapi/admin";
8
- import { g as getTranslation, P as PLUGIN_ID } from "./index-BpapRdHX.mjs";
9
- import { o as objectLabel } from "./objectLabels-DQYwGDr3.mjs";
10
- import { u as useHubspotSchema } from "./useHubspotSchema-DX4JTPFt.mjs";
8
+ import { g as getTranslation, P as PLUGIN_ID } from "./index-DA31TY2n.mjs";
9
+ import { o as objectLabel } from "./objectLabels-Bl7sO5pb.mjs";
10
+ import { u as useHubspotSchema } from "./useHubspotSchema-BlDilCHc.mjs";
11
11
  const OPERATORS = [
12
12
  "eq",
13
13
  "neq",
@@ -159,7 +159,20 @@ const FIELD_TYPES = [
159
159
  "textarea",
160
160
  "select",
161
161
  "checkbox",
162
- "radio"
162
+ "radio",
163
+ "company"
164
+ ];
165
+ const COMPANY_DATA = [
166
+ "name",
167
+ "siret",
168
+ "siren",
169
+ "address",
170
+ "zip",
171
+ "city",
172
+ "headquarters",
173
+ "naf",
174
+ "nafLabel",
175
+ "headcount"
163
176
  ];
164
177
  let counter = 0;
165
178
  const makeId = (prefix) => `${prefix}_${Date.now().toString(36)}${(counter += 1).toString(36)}${Math.random().toString(36).slice(2, 6)}`;
@@ -174,6 +187,96 @@ function fieldsBefore(definition, beforeId) {
174
187
  }
175
188
  return out;
176
189
  }
190
+ const CompanyMapEditor = ({ map, onChange }) => {
191
+ const intl = useIntl();
192
+ const { formatMessage } = intl;
193
+ const { schema } = useHubspotSchema();
194
+ const t = (id, defaultMessage) => formatMessage({ id: getTranslation(id), defaultMessage });
195
+ const datumLabel = {
196
+ name: t("company.datum.name", "Legal name"),
197
+ siret: t("company.datum.siret", "SIRET"),
198
+ siren: t("company.datum.siren", "SIREN"),
199
+ address: t("company.datum.address", "Address"),
200
+ zip: t("company.datum.zip", "Postal code"),
201
+ city: t("company.datum.city", "City"),
202
+ headquarters: t("company.datum.headquarters", "Is headquarters"),
203
+ naf: t("company.datum.naf", "NAF code"),
204
+ nafLabel: t("company.datum.nafLabel", "NAF label"),
205
+ headcount: t("company.datum.headcount", "Headcount range")
206
+ };
207
+ const mapped = COMPANY_DATA.filter((d) => map[d]);
208
+ const unmapped = COMPANY_DATA.filter((d) => !map[d]);
209
+ const patch = (datum, entry) => {
210
+ const next = { ...map };
211
+ if (entry) next[datum] = entry;
212
+ else delete next[datum];
213
+ onChange(next);
214
+ };
215
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
216
+ mapped.map((datum) => {
217
+ const entry = map[datum] ?? {};
218
+ const object = entry.object?.trim() || "company";
219
+ const properties = (schema?.properties ?? []).filter((p) => p.object === object);
220
+ return /* @__PURE__ */ jsxs(Box, { background: "neutral100", hasRadius: true, padding: 2, children: [
221
+ /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", paddingBottom: 1, children: [
222
+ /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: datumLabel[datum] }),
223
+ /* @__PURE__ */ jsx(
224
+ IconButton,
225
+ {
226
+ label: t("company.remove-datum", "Stop sending this datum"),
227
+ onClick: () => patch(datum, void 0),
228
+ children: /* @__PURE__ */ jsx(Trash, {})
229
+ }
230
+ )
231
+ ] }),
232
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
233
+ /* @__PURE__ */ jsx(Box, { width: "130px", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx(
234
+ SingleSelect,
235
+ {
236
+ "aria-label": t("panel.object", "Object"),
237
+ value: object,
238
+ onChange: (v) => (
239
+ // A property never survives an object switch.
240
+ patch(datum, { object: String(v), property: void 0 })
241
+ ),
242
+ children: (schema?.objects ?? ["contact", "company"]).map((name) => /* @__PURE__ */ jsx(SingleSelectOption, { value: name, children: objectLabel(intl, name) }, name))
243
+ }
244
+ ) }),
245
+ /* @__PURE__ */ jsx(Box, { flex: "1", children: /* @__PURE__ */ jsx(
246
+ Combobox,
247
+ {
248
+ "aria-label": t("panel.property", "Property"),
249
+ value: entry.property ?? "",
250
+ onChange: (v) => patch(datum, { object, property: v || void 0 }),
251
+ onClear: () => patch(datum, { object, property: void 0 }),
252
+ placeholder: t("panel.property-placeholder", "Search a property…"),
253
+ children: properties.map((p) => /* @__PURE__ */ jsxs(ComboboxOption, { value: p.name, children: [
254
+ p.group ? `${p.group} · ` : "",
255
+ p.label,
256
+ " (",
257
+ p.name,
258
+ ")"
259
+ ] }, p.name))
260
+ }
261
+ ) })
262
+ ] })
263
+ ] }, datum);
264
+ }),
265
+ unmapped.length > 0 && /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
266
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": true, width: 12, height: 12 }),
267
+ /* @__PURE__ */ jsx(Box, { flex: "1", children: /* @__PURE__ */ jsx(
268
+ SingleSelect,
269
+ {
270
+ "aria-label": t("company.add-datum", "Send another datum"),
271
+ placeholder: t("company.add-datum", "Send another datum"),
272
+ value: "",
273
+ onChange: (v) => patch(v, { object: "company", property: void 0 }),
274
+ children: unmapped.map((datum) => /* @__PURE__ */ jsx(SingleSelectOption, { value: datum, children: datumLabel[datum] }, datum))
275
+ }
276
+ ) })
277
+ ] })
278
+ ] });
279
+ };
177
280
  const slugifyName = (label) => label.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
178
281
  const FieldPanel = ({ field, candidates, problem, onChange }) => {
179
282
  const intl = useIntl();
@@ -184,6 +287,13 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
184
287
  const properties = (schema?.properties ?? []).filter((p) => p.object === object);
185
288
  const selected = properties.find((p) => p.name === field.hubspot?.property);
186
289
  const isChoice = field.type === "select" || field.type === "radio";
290
+ const isCompany = field.type === "company";
291
+ const DEFAULT_COMPANY_MAP = {
292
+ name: { object: "company", property: "name" },
293
+ address: { object: "company", property: "address" },
294
+ zip: { object: "company", property: "zip" },
295
+ city: { object: "company", property: "city" }
296
+ };
187
297
  const setHubspot = (patch) => onChange({ hubspot: { ...field.hubspot, ...patch } });
188
298
  const importOptions = () => {
189
299
  if (!selected?.options?.length) return;
@@ -224,15 +334,30 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
224
334
  SingleSelect,
225
335
  {
226
336
  value: field.type,
227
- onChange: (v) => onChange({ type: v }),
337
+ onChange: (v) => onChange({
338
+ type: v,
339
+ ...v === "company" && !field.companyMap ? { companyMap: DEFAULT_COMPANY_MAP } : {}
340
+ }),
228
341
  children: FIELD_TYPES.map((type) => /* @__PURE__ */ jsx(SingleSelectOption, { value: type, children: type }, type))
229
342
  }
230
343
  )
231
344
  ] }),
232
345
  /* @__PURE__ */ jsxs(Flex, { gap: 4, children: [
233
346
  /* @__PURE__ */ jsx(Box, { flex: "1", children: /* @__PURE__ */ jsxs(Field.Root, { children: [
234
- /* @__PURE__ */ jsx(Field.Label, { children: t("panel.placeholder", "Placeholder") }),
235
- /* @__PURE__ */ jsx(
347
+ /* @__PURE__ */ jsx(Field.Label, { children: isCompany ? t("company.examples", "Placeholder examples (one per line)") : t("panel.placeholder", "Placeholder") }),
348
+ isCompany ? /* @__PURE__ */ jsx(
349
+ Textarea,
350
+ {
351
+ value: (field.placeholderExamples ?? []).join("\n"),
352
+ placeholder: t(
353
+ "company.examples-placeholder",
354
+ "Ex. : un établissement d'un grand groupe\nEx. : le siège de votre PME"
355
+ ),
356
+ onChange: (e) => onChange({
357
+ placeholderExamples: e.target.value.split("\n").map((line) => line.trim()).filter(Boolean)
358
+ })
359
+ }
360
+ ) : /* @__PURE__ */ jsx(
236
361
  TextInput,
237
362
  {
238
363
  value: field.placeholder ?? "",
@@ -367,7 +492,7 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
367
492
  /* @__PURE__ */ jsx(Divider, {}),
368
493
  /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
369
494
  /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
370
- /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: t("panel.hubspot", "HubSpot") }),
495
+ /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: isCompany ? t("company.section", "Company data (INSEE → HubSpot)") : t("panel.hubspot", "HubSpot") }),
371
496
  /* @__PURE__ */ jsx(
372
497
  IconButton,
373
498
  {
@@ -378,7 +503,20 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
378
503
  }
379
504
  )
380
505
  ] }),
381
- /* @__PURE__ */ jsxs(Field.Root, { children: [
506
+ isCompany && /* @__PURE__ */ jsxs(Fragment, { children: [
507
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
508
+ "company.section-hint",
509
+ "The visitor picks their company from the SIRENE registry; the server re-resolves the SIRET and sends each datum below to its property."
510
+ ) }),
511
+ /* @__PURE__ */ jsx(
512
+ CompanyMapEditor,
513
+ {
514
+ map: field.companyMap ?? {},
515
+ onChange: (companyMap) => onChange({ companyMap })
516
+ }
517
+ )
518
+ ] }),
519
+ !isCompany && /* @__PURE__ */ jsxs(Field.Root, { children: [
382
520
  /* @__PURE__ */ jsx(Field.Label, { children: t("panel.object", "Object") }),
383
521
  /* @__PURE__ */ jsx(
384
522
  SingleSelect,
@@ -391,7 +529,7 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
391
529
  }
392
530
  )
393
531
  ] }),
394
- /* @__PURE__ */ jsxs(Field.Root, { children: [
532
+ !isCompany && /* @__PURE__ */ jsxs(Field.Root, { children: [
395
533
  /* @__PURE__ */ jsx(Field.Label, { children: t("panel.property", "Property") }),
396
534
  /* @__PURE__ */ jsx(
397
535
  Combobox,
@@ -414,7 +552,7 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
414
552
  }) }),
415
553
  !field.hubspot?.property && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t("panel.property-hint", "Without a property, the answer is sent under the payload key.") })
416
554
  ] }),
417
- deepLink && /* @__PURE__ */ jsx("a", { href: deepLink, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "primary600", children: t("panel.view-in-hubspot", "View in HubSpot ↗") }) })
555
+ !isCompany && deepLink && /* @__PURE__ */ jsx("a", { href: deepLink, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "primary600", children: t("panel.view-in-hubspot", "View in HubSpot ↗") }) })
418
556
  ] }),
419
557
  /* @__PURE__ */ jsx(Divider, {}),
420
558
  /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
@@ -7,9 +7,9 @@ const index = require("./index-DkTxsEqL.js");
7
7
  const designSystem = require("@strapi/design-system");
8
8
  const icons = require("@strapi/icons");
9
9
  const admin = require("@strapi/strapi/admin");
10
- const index$1 = require("./index-rgjWxSn4.js");
11
- const objectLabels = require("./objectLabels-mBjwR5EE.js");
12
- const useHubspotSchema = require("./useHubspotSchema-CJEiHbjz.js");
10
+ const index$1 = require("./index-B7Ru1fu5.js");
11
+ const objectLabels = require("./objectLabels-FTh984_h.js");
12
+ const useHubspotSchema = require("./useHubspotSchema-C2_PuXEm.js");
13
13
  function _interopNamespace(e) {
14
14
  if (e && e.__esModule) return e;
15
15
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -179,7 +179,20 @@ const FIELD_TYPES = [
179
179
  "textarea",
180
180
  "select",
181
181
  "checkbox",
182
- "radio"
182
+ "radio",
183
+ "company"
184
+ ];
185
+ const COMPANY_DATA = [
186
+ "name",
187
+ "siret",
188
+ "siren",
189
+ "address",
190
+ "zip",
191
+ "city",
192
+ "headquarters",
193
+ "naf",
194
+ "nafLabel",
195
+ "headcount"
183
196
  ];
184
197
  let counter = 0;
185
198
  const makeId = (prefix) => `${prefix}_${Date.now().toString(36)}${(counter += 1).toString(36)}${Math.random().toString(36).slice(2, 6)}`;
@@ -194,6 +207,96 @@ function fieldsBefore(definition, beforeId) {
194
207
  }
195
208
  return out;
196
209
  }
210
+ const CompanyMapEditor = ({ map, onChange }) => {
211
+ const intl = index.useIntl();
212
+ const { formatMessage } = intl;
213
+ const { schema } = useHubspotSchema.useHubspotSchema();
214
+ const t = (id, defaultMessage) => formatMessage({ id: index$1.getTranslation(id), defaultMessage });
215
+ const datumLabel = {
216
+ name: t("company.datum.name", "Legal name"),
217
+ siret: t("company.datum.siret", "SIRET"),
218
+ siren: t("company.datum.siren", "SIREN"),
219
+ address: t("company.datum.address", "Address"),
220
+ zip: t("company.datum.zip", "Postal code"),
221
+ city: t("company.datum.city", "City"),
222
+ headquarters: t("company.datum.headquarters", "Is headquarters"),
223
+ naf: t("company.datum.naf", "NAF code"),
224
+ nafLabel: t("company.datum.nafLabel", "NAF label"),
225
+ headcount: t("company.datum.headcount", "Headcount range")
226
+ };
227
+ const mapped = COMPANY_DATA.filter((d) => map[d]);
228
+ const unmapped = COMPANY_DATA.filter((d) => !map[d]);
229
+ const patch = (datum, entry) => {
230
+ const next = { ...map };
231
+ if (entry) next[datum] = entry;
232
+ else delete next[datum];
233
+ onChange(next);
234
+ };
235
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
236
+ mapped.map((datum) => {
237
+ const entry = map[datum] ?? {};
238
+ const object = entry.object?.trim() || "company";
239
+ const properties = (schema?.properties ?? []).filter((p) => p.object === object);
240
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { background: "neutral100", hasRadius: true, padding: 2, children: [
241
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", paddingBottom: 1, children: [
242
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: datumLabel[datum] }),
243
+ /* @__PURE__ */ jsxRuntime.jsx(
244
+ designSystem.IconButton,
245
+ {
246
+ label: t("company.remove-datum", "Stop sending this datum"),
247
+ onClick: () => patch(datum, void 0),
248
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {})
249
+ }
250
+ )
251
+ ] }),
252
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
253
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { width: "130px", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(
254
+ designSystem.SingleSelect,
255
+ {
256
+ "aria-label": t("panel.object", "Object"),
257
+ value: object,
258
+ onChange: (v) => (
259
+ // A property never survives an object switch.
260
+ patch(datum, { object: String(v), property: void 0 })
261
+ ),
262
+ children: (schema?.objects ?? ["contact", "company"]).map((name) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: name, children: objectLabels.objectLabel(intl, name) }, name))
263
+ }
264
+ ) }),
265
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { flex: "1", children: /* @__PURE__ */ jsxRuntime.jsx(
266
+ designSystem.Combobox,
267
+ {
268
+ "aria-label": t("panel.property", "Property"),
269
+ value: entry.property ?? "",
270
+ onChange: (v) => patch(datum, { object, property: v || void 0 }),
271
+ onClear: () => patch(datum, { object, property: void 0 }),
272
+ placeholder: t("panel.property-placeholder", "Search a property…"),
273
+ children: properties.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ComboboxOption, { value: p.name, children: [
274
+ p.group ? `${p.group} · ` : "",
275
+ p.label,
276
+ " (",
277
+ p.name,
278
+ ")"
279
+ ] }, p.name))
280
+ }
281
+ ) })
282
+ ] })
283
+ ] }, datum);
284
+ }),
285
+ unmapped.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
286
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, { "aria-hidden": true, width: 12, height: 12 }),
287
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { flex: "1", children: /* @__PURE__ */ jsxRuntime.jsx(
288
+ designSystem.SingleSelect,
289
+ {
290
+ "aria-label": t("company.add-datum", "Send another datum"),
291
+ placeholder: t("company.add-datum", "Send another datum"),
292
+ value: "",
293
+ onChange: (v) => patch(v, { object: "company", property: void 0 }),
294
+ children: unmapped.map((datum) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: datum, children: datumLabel[datum] }, datum))
295
+ }
296
+ ) })
297
+ ] })
298
+ ] });
299
+ };
197
300
  const slugifyName = (label) => label.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
198
301
  const FieldPanel = ({ field, candidates, problem, onChange }) => {
199
302
  const intl = index.useIntl();
@@ -204,6 +307,13 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
204
307
  const properties = (schema?.properties ?? []).filter((p) => p.object === object);
205
308
  const selected = properties.find((p) => p.name === field.hubspot?.property);
206
309
  const isChoice = field.type === "select" || field.type === "radio";
310
+ const isCompany = field.type === "company";
311
+ const DEFAULT_COMPANY_MAP = {
312
+ name: { object: "company", property: "name" },
313
+ address: { object: "company", property: "address" },
314
+ zip: { object: "company", property: "zip" },
315
+ city: { object: "company", property: "city" }
316
+ };
207
317
  const setHubspot = (patch) => onChange({ hubspot: { ...field.hubspot, ...patch } });
208
318
  const importOptions = () => {
209
319
  if (!selected?.options?.length) return;
@@ -244,15 +354,30 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
244
354
  designSystem.SingleSelect,
245
355
  {
246
356
  value: field.type,
247
- onChange: (v) => onChange({ type: v }),
357
+ onChange: (v) => onChange({
358
+ type: v,
359
+ ...v === "company" && !field.companyMap ? { companyMap: DEFAULT_COMPANY_MAP } : {}
360
+ }),
248
361
  children: FIELD_TYPES.map((type) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: type, children: type }, type))
249
362
  }
250
363
  )
251
364
  ] }),
252
365
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, children: [
253
366
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { flex: "1", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
254
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: t("panel.placeholder", "Placeholder") }),
255
- /* @__PURE__ */ jsxRuntime.jsx(
367
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: isCompany ? t("company.examples", "Placeholder examples (one per line)") : t("panel.placeholder", "Placeholder") }),
368
+ isCompany ? /* @__PURE__ */ jsxRuntime.jsx(
369
+ designSystem.Textarea,
370
+ {
371
+ value: (field.placeholderExamples ?? []).join("\n"),
372
+ placeholder: t(
373
+ "company.examples-placeholder",
374
+ "Ex. : un établissement d'un grand groupe\nEx. : le siège de votre PME"
375
+ ),
376
+ onChange: (e) => onChange({
377
+ placeholderExamples: e.target.value.split("\n").map((line) => line.trim()).filter(Boolean)
378
+ })
379
+ }
380
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
256
381
  designSystem.TextInput,
257
382
  {
258
383
  value: field.placeholder ?? "",
@@ -387,7 +512,7 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
387
512
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {}),
388
513
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
389
514
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: [
390
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: t("panel.hubspot", "HubSpot") }),
515
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: isCompany ? t("company.section", "Company data (INSEE → HubSpot)") : t("panel.hubspot", "HubSpot") }),
391
516
  /* @__PURE__ */ jsxRuntime.jsx(
392
517
  designSystem.IconButton,
393
518
  {
@@ -398,7 +523,20 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
398
523
  }
399
524
  )
400
525
  ] }),
401
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
526
+ isCompany && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
527
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
528
+ "company.section-hint",
529
+ "The visitor picks their company from the SIRENE registry; the server re-resolves the SIRET and sends each datum below to its property."
530
+ ) }),
531
+ /* @__PURE__ */ jsxRuntime.jsx(
532
+ CompanyMapEditor,
533
+ {
534
+ map: field.companyMap ?? {},
535
+ onChange: (companyMap) => onChange({ companyMap })
536
+ }
537
+ )
538
+ ] }),
539
+ !isCompany && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
402
540
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: t("panel.object", "Object") }),
403
541
  /* @__PURE__ */ jsxRuntime.jsx(
404
542
  designSystem.SingleSelect,
@@ -411,7 +549,7 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
411
549
  }
412
550
  )
413
551
  ] }),
414
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
552
+ !isCompany && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
415
553
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: t("panel.property", "Property") }),
416
554
  /* @__PURE__ */ jsxRuntime.jsx(
417
555
  designSystem.Combobox,
@@ -434,7 +572,7 @@ const FieldPanel = ({ field, candidates, problem, onChange }) => {
434
572
  }) }),
435
573
  !field.hubspot?.property && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t("panel.property-hint", "Without a property, the answer is sent under the payload key.") })
436
574
  ] }),
437
- deepLink && /* @__PURE__ */ jsxRuntime.jsx("a", { href: deepLink, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "primary600", children: t("panel.view-in-hubspot", "View in HubSpot ↗") }) })
575
+ !isCompany && deepLink && /* @__PURE__ */ jsxRuntime.jsx("a", { href: deepLink, target: "_blank", rel: "noreferrer", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "primary600", children: t("panel.view-in-hubspot", "View in HubSpot ↗") }) })
438
576
  ] }),
439
577
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {}),
440
578
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
@@ -3,7 +3,7 @@ import * as React from "react";
3
3
  import { u as useIntl } from "./index-CEh8vkxY.mjs";
4
4
  import { Field, Flex, Loader, Combobox, ComboboxOption } from "@strapi/design-system";
5
5
  import { useFetchClient } from "@strapi/strapi/admin";
6
- import { P as PLUGIN_ID, g as getTranslation } from "./index-BpapRdHX.mjs";
6
+ import { P as PLUGIN_ID, g as getTranslation } from "./index-DA31TY2n.mjs";
7
7
  const HubspotFormInput = React.forwardRef(
8
8
  ({ name, value, onChange, disabled, error, required, label, hint, labelAction }, ref) => {
9
9
  const { formatMessage } = useIntl();
@@ -5,7 +5,7 @@ const React = require("react");
5
5
  const index = require("./index-DkTxsEqL.js");
6
6
  const designSystem = require("@strapi/design-system");
7
7
  const admin = require("@strapi/strapi/admin");
8
- const index$1 = require("./index-rgjWxSn4.js");
8
+ const index$1 = require("./index-B7Ru1fu5.js");
9
9
  function _interopNamespace(e) {
10
10
  if (e && e.__esModule) return e;
11
11
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -4,9 +4,9 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const React = require("react");
5
5
  const index = require("./index-DkTxsEqL.js");
6
6
  const designSystem = require("@strapi/design-system");
7
- const index$1 = require("./index-rgjWxSn4.js");
8
- const objectLabels = require("./objectLabels-mBjwR5EE.js");
9
- const useHubspotSchema = require("./useHubspotSchema-CJEiHbjz.js");
7
+ const index$1 = require("./index-B7Ru1fu5.js");
8
+ const objectLabels = require("./objectLabels-FTh984_h.js");
9
+ const useHubspotSchema = require("./useHubspotSchema-C2_PuXEm.js");
10
10
  function _interopNamespace(e) {
11
11
  if (e && e.__esModule) return e;
12
12
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -2,9 +2,9 @@ import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { u as useIntl } from "./index-CEh8vkxY.mjs";
4
4
  import { Field, Flex, Loader, SingleSelect, SingleSelectOption } from "@strapi/design-system";
5
- import { g as getTranslation } from "./index-BpapRdHX.mjs";
6
- import { o as objectLabel } from "./objectLabels-DQYwGDr3.mjs";
7
- import { u as useHubspotSchema } from "./useHubspotSchema-DX4JTPFt.mjs";
5
+ import { g as getTranslation } from "./index-DA31TY2n.mjs";
6
+ import { o as objectLabel } from "./objectLabels-Bl7sO5pb.mjs";
7
+ import { u as useHubspotSchema } from "./useHubspotSchema-BlDilCHc.mjs";
8
8
  const HubspotObjectInput = React.forwardRef(
9
9
  ({ name, value, onChange, disabled, error, required, label, hint, labelAction }, ref) => {
10
10
  const intl = useIntl();
@@ -6,9 +6,9 @@ const index = require("./index-DkTxsEqL.js");
6
6
  const designSystem = require("@strapi/design-system");
7
7
  const icons = require("@strapi/icons");
8
8
  const admin = require("@strapi/strapi/admin");
9
- const index$1 = require("./index-rgjWxSn4.js");
10
- const objectLabels = require("./objectLabels-mBjwR5EE.js");
11
- const useHubspotSchema = require("./useHubspotSchema-CJEiHbjz.js");
9
+ const index$1 = require("./index-B7Ru1fu5.js");
10
+ const objectLabels = require("./objectLabels-FTh984_h.js");
11
+ const useHubspotSchema = require("./useHubspotSchema-C2_PuXEm.js");
12
12
  function _interopNamespace(e) {
13
13
  if (e && e.__esModule) return e;
14
14
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -4,9 +4,9 @@ import { u as useIntl } from "./index-CEh8vkxY.mjs";
4
4
  import { Field, Flex, Loader, Combobox, ComboboxOption, IconButton, Button, Typography, Link } from "@strapi/design-system";
5
5
  import { ArrowClockwise } from "@strapi/icons";
6
6
  import { useField } from "@strapi/strapi/admin";
7
- import { g as getTranslation } from "./index-BpapRdHX.mjs";
8
- import { o as objectLabel } from "./objectLabels-DQYwGDr3.mjs";
9
- import { u as useHubspotSchema } from "./useHubspotSchema-DX4JTPFt.mjs";
7
+ import { g as getTranslation } from "./index-DA31TY2n.mjs";
8
+ import { o as objectLabel } from "./objectLabels-Bl7sO5pb.mjs";
9
+ import { u as useHubspotSchema } from "./useHubspotSchema-BlDilCHc.mjs";
10
10
  const oneLine = {
11
11
  display: "block",
12
12
  whiteSpace: "nowrap",
@@ -5,9 +5,9 @@ const React = require("react");
5
5
  const index = require("./index-DkTxsEqL.js");
6
6
  const designSystem = require("@strapi/design-system");
7
7
  const admin = require("@strapi/strapi/admin");
8
- const index$1 = require("./index-rgjWxSn4.js");
8
+ const index$1 = require("./index-B7Ru1fu5.js");
9
9
  const reactRouterDom = require("react-router-dom");
10
- const objectLabels = require("./objectLabels-mBjwR5EE.js");
10
+ const objectLabels = require("./objectLabels-FTh984_h.js");
11
11
  function _interopNamespace(e) {
12
12
  if (e && e.__esModule) return e;
13
13
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -3,9 +3,9 @@ import * as React from "react";
3
3
  import { u as useIntl } from "./index-CEh8vkxY.mjs";
4
4
  import { Flex, Divider, Typography, Button, Box, Link, Badge, Loader, Field } from "@strapi/design-system";
5
5
  import { useFetchClient } from "@strapi/strapi/admin";
6
- import { g as getTranslation, P as PLUGIN_ID } from "./index-BpapRdHX.mjs";
6
+ import { g as getTranslation, P as PLUGIN_ID } from "./index-DA31TY2n.mjs";
7
7
  import { Link as Link$1 } from "react-router-dom";
8
- import { o as objectLabel } from "./objectLabels-DQYwGDr3.mjs";
8
+ import { o as objectLabel } from "./objectLabels-Bl7sO5pb.mjs";
9
9
  const AuditSection = ({ configured }) => {
10
10
  const intl = useIntl();
11
11
  const { formatMessage } = intl;
@@ -253,6 +253,22 @@ const en = {
253
253
  "condition.op.startsWith": "starts with",
254
254
  "condition.op.endsWith": "ends with",
255
255
  "condition.values": "Values",
256
- "condition.values-placeholder": "value1, value2…"
256
+ "condition.values-placeholder": "value1, value2…",
257
+ "company.section": "Company data (INSEE → HubSpot)",
258
+ "company.section-hint": "The visitor picks their company from the SIRENE registry; the server re-resolves the SIRET and sends each datum below to its property.",
259
+ "company.examples": "Placeholder examples (one per line)",
260
+ "company.examples-placeholder": "Ex. : un établissement d'un grand groupe\nEx. : le siège de votre PME",
261
+ "company.add-datum": "Send another datum",
262
+ "company.remove-datum": "Stop sending this datum",
263
+ "company.datum.name": "Legal name",
264
+ "company.datum.siret": "SIRET",
265
+ "company.datum.siren": "SIREN",
266
+ "company.datum.address": "Address",
267
+ "company.datum.zip": "Postal code",
268
+ "company.datum.city": "City",
269
+ "company.datum.headquarters": "Is headquarters",
270
+ "company.datum.naf": "NAF code",
271
+ "company.datum.nafLabel": "NAF label",
272
+ "company.datum.headcount": "Headcount range"
257
273
  };
258
274
  exports.default = en;