@cellarnode/ui 0.19.1 → 0.20.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 (49) hide show
  1. package/dist/chat/chat-ws.d.ts +56 -0
  2. package/dist/chat/chat-ws.d.ts.map +1 -1
  3. package/dist/chat/chat-ws.js +103 -0
  4. package/dist/chat/chat-ws.js.map +1 -1
  5. package/dist/chat/index.d.ts +1 -1
  6. package/dist/chat/index.d.ts.map +1 -1
  7. package/dist/components/journey-card.d.ts +9 -1
  8. package/dist/components/journey-card.d.ts.map +1 -1
  9. package/dist/components/journey-card.js +13 -6
  10. package/dist/components/journey-card.js.map +1 -1
  11. package/dist/components/journey-card.stories.d.ts +2 -0
  12. package/dist/components/journey-card.stories.d.ts.map +1 -1
  13. package/dist/components/journey-card.stories.js +43 -0
  14. package/dist/components/journey-card.stories.js.map +1 -1
  15. package/dist/components/sortable-card-context.d.ts +18 -0
  16. package/dist/components/sortable-card-context.d.ts.map +1 -0
  17. package/dist/components/sortable-card-context.js +18 -0
  18. package/dist/components/sortable-card-context.js.map +1 -0
  19. package/dist/components/sortable-card-shell.d.ts +40 -21
  20. package/dist/components/sortable-card-shell.d.ts.map +1 -1
  21. package/dist/components/sortable-card-shell.js +46 -39
  22. package/dist/components/sortable-card-shell.js.map +1 -1
  23. package/dist/components/sortable-card-shell.stories.d.ts +1 -1
  24. package/dist/components/sortable-card-shell.stories.d.ts.map +1 -1
  25. package/dist/components/sortable-card-shell.stories.js +28 -15
  26. package/dist/components/sortable-card-shell.stories.js.map +1 -1
  27. package/dist/components/sortable-card-shell.test.js +57 -16
  28. package/dist/components/sortable-card-shell.test.js.map +1 -1
  29. package/dist/offer/attachments-card.d.ts +7 -1
  30. package/dist/offer/attachments-card.d.ts.map +1 -1
  31. package/dist/offer/attachments-card.js +3 -3
  32. package/dist/offer/attachments-card.js.map +1 -1
  33. package/dist/offer/index.d.ts +1 -1
  34. package/dist/offer/index.d.ts.map +1 -1
  35. package/dist/offer/negotiation-section.d.ts +9 -1
  36. package/dist/offer/negotiation-section.d.ts.map +1 -1
  37. package/dist/offer/negotiation-section.js +2 -2
  38. package/dist/offer/negotiation-section.js.map +1 -1
  39. package/dist/offer/offer-document.d.ts +24 -24
  40. package/dist/offer/offer-document.d.ts.map +1 -1
  41. package/dist/offer/offer-document.js +269 -49
  42. package/dist/offer/offer-document.js.map +1 -1
  43. package/dist/offer/offer-document.stories.d.ts +11 -0
  44. package/dist/offer/offer-document.stories.d.ts.map +1 -1
  45. package/dist/offer/offer-document.stories.js +136 -84
  46. package/dist/offer/offer-document.stories.js.map +1 -1
  47. package/dist/offer/types.d.ts +81 -0
  48. package/dist/offer/types.d.ts.map +1 -1
  49. package/package.json +1 -1
@@ -62,7 +62,7 @@ export type { NegotiationSectionProps } from "./negotiation-section";
62
62
  export { OfferExportButton } from "./offer-export-button";
63
63
  export type { OfferExportButtonProps } from "./offer-export-button";
64
64
  export { OfferDocument } from "./offer-document";
65
- export type { OfferDocumentProps, OfferDocumentAction } from "./offer-document";
65
+ export type { OfferDocumentProps } from "./offer-document";
66
66
  export { ImporterPickerModal, type ImporterPickerModalProps, type ImporterPickerImporter, type ImporterPickerMode, } from "../components/importer-picker-modal";
67
67
  export { OffersSentPanel, type OffersSentPanelProps, type OfferBranch, } from "../components/branch-overview-panel";
68
68
  export { FinalizeDealModal, type FinalizeDealModalProps, type FinalizeDealTerm, type FinalizeDealClosedBranch, } from "../components/branch-resolution-modal";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/offer/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/offer/index.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,15 @@ export interface NegotiationSectionProps {
5
5
  viewerRole?: Perspective;
6
6
  viewerAdvantageFor?: (event: TimelineEventData) => ViewerAdvantage;
7
7
  onOpenComposer?: () => void;
8
+ /**
9
+ * Optional pagination hook — when provided, renders a "Load older events"
10
+ * button at the top of the timeline that invokes the handler. Undefined
11
+ * means "all events loaded; no pagination affordance".
12
+ */
13
+ onLoadOlder?: () => void;
14
+ /** Disables the load-older button while a prior request is in flight. */
15
+ loadOlderDisabled?: boolean;
8
16
  className?: string;
9
17
  }
10
- export declare function NegotiationSection({ events, viewerOrgId: _viewerOrgId, viewerRole: _viewerRole, viewerAdvantageFor, onOpenComposer, className, }: NegotiationSectionProps): import("react/jsx-runtime").JSX.Element;
18
+ export declare function NegotiationSection({ events, viewerOrgId: _viewerOrgId, viewerRole: _viewerRole, viewerAdvantageFor, onOpenComposer, onLoadOlder, loadOlderDisabled, className, }: NegotiationSectionProps): import("react/jsx-runtime").JSX.Element;
11
19
  //# sourceMappingURL=negotiation-section.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"negotiation-section.d.ts","sourceRoot":"","sources":["../../src/offer/negotiation-section.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,WAAW,EACZ,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,eAAe,CAAC;IACnE,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,WAAW,EAAE,YAAY,EACzB,UAAU,EAAE,WAAW,EACvB,kBAAkB,EAClB,cAAc,EACd,SAAS,GACV,EAAE,uBAAuB,2CAgLzB"}
1
+ {"version":3,"file":"negotiation-section.d.ts","sourceRoot":"","sources":["../../src/offer/negotiation-section.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,WAAW,EACZ,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,eAAe,CAAC;IACnE,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,WAAW,EAAE,YAAY,EACzB,UAAU,EAAE,WAAW,EACvB,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,SAAS,GACV,EAAE,uBAAuB,2CA+LzB"}
@@ -6,7 +6,7 @@ import { ShadcnButton as Button } from "../components/shadcn-button";
6
6
  import { useSafeVirtualizer } from "../chat/use-safe-virtualizer";
7
7
  import { TimelineEvent } from "./timeline-event";
8
8
  import { NewActivityPill } from "./new-activity-pill";
9
- export function NegotiationSection({ events, viewerOrgId: _viewerOrgId, viewerRole: _viewerRole, viewerAdvantageFor, onOpenComposer, className, }) {
9
+ export function NegotiationSection({ events, viewerOrgId: _viewerOrgId, viewerRole: _viewerRole, viewerAdvantageFor, onOpenComposer, onLoadOlder, loadOlderDisabled, className, }) {
10
10
  const scrollRef = useRef(null);
11
11
  const [newEventCount, setNewEventCount] = useState(0);
12
12
  const [focusedIndex, setFocusedIndex] = useState(0);
@@ -80,7 +80,7 @@ export function NegotiationSection({ events, viewerOrgId: _viewerOrgId, viewerRo
80
80
  else
81
81
  eventListRef.current.delete(index);
82
82
  }, []);
83
- return (_jsxs("section", { "aria-labelledby": "negotiation-heading", className: cn("rounded-2xl border border-border/60 bg-card p-4", className), children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { id: "negotiation-heading", className: "text-xs/5 font-semibold uppercase tracking-wide text-muted-foreground", children: "Negotiation" }), onOpenComposer && (_jsxs(Button, { size: "sm", onClick: onOpenComposer, children: [_jsx(ArrowLeftRight, { "aria-hidden": true, className: "size-4" }), "Counter"] }))] }), _jsxs("div", { ref: scrollRef, className: "relative mt-3 max-h-[480px] overflow-y-auto", children: [events.length === 0 ? (_jsx("p", { className: "py-6 text-center text-sm text-muted-foreground", children: "No activity yet." })) : shouldVirtualize ? (_jsx("ol", { role: "list", "aria-label": "Negotiation timeline", className: "relative", style: { height: virtualizer.getTotalSize() }, onKeyDown: handleKeyDown, children: virtualizer.getVirtualItems().map((row) => {
83
+ return (_jsxs("section", { "aria-labelledby": "negotiation-heading", className: cn("rounded-2xl border border-border/60 bg-card p-4", className), children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { id: "negotiation-heading", className: "text-xs/5 font-semibold uppercase tracking-wide text-muted-foreground", children: "Negotiation" }), onOpenComposer && (_jsxs(Button, { size: "sm", onClick: onOpenComposer, children: [_jsx(ArrowLeftRight, { "aria-hidden": true, className: "size-4" }), "Counter"] }))] }), _jsxs("div", { ref: scrollRef, className: "relative mt-3 max-h-[480px] overflow-y-auto", children: [onLoadOlder && events.length > 0 && (_jsx("div", { className: "mb-2 flex justify-center", children: _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: onLoadOlder, disabled: loadOlderDisabled, "aria-label": "Load older events", className: "h-7 text-xs", children: "Load older events" }) })), events.length === 0 ? (_jsx("p", { className: "py-6 text-center text-sm text-muted-foreground", children: "No activity yet." })) : shouldVirtualize ? (_jsx("ol", { role: "list", "aria-label": "Negotiation timeline", className: "relative", style: { height: virtualizer.getTotalSize() }, onKeyDown: handleKeyDown, children: virtualizer.getVirtualItems().map((row) => {
84
84
  const ev = events[row.index];
85
85
  return (_jsx("div", { ref: virtualizer.measureElement, "data-index": row.index, style: {
86
86
  position: "absolute",
@@ -1 +1 @@
1
- {"version":3,"file":"negotiation-section.js","sourceRoot":"","sources":["../../src/offer/negotiation-section.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,YAAY,IAAI,MAAM,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAgBtD,MAAM,UAAU,kBAAkB,CAAC,EACjC,MAAM,EACN,WAAW,EAAE,YAAY,EACzB,UAAU,EAAE,WAAW,EACvB,kBAAkB,EAClB,cAAc,EACd,SAAS,GACe;IACxB,MAAM,SAAS,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC/C,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3C,wEAAwE;IACxE,0EAA0E;IAC1E,2EAA2E;IAC3E,sBAAsB;IACtB,MAAM,YAAY,GAAG,MAAM,CAAoC,IAAI,GAAG,EAAE,CAAC,CAAC;IAC1E,yEAAyE;IACzE,4EAA4E;IAC5E,yEAAyE;IACzE,MAAM,iBAAiB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAExC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,CAAC,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC;YACzC,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC;YAC7B,IAAI,EAAE,EAAE,CAAC;gBACP,MAAM,UAAU,GAAG,EAAE,CAAC,YAAY,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,YAAY,GAAG,EAAE,CAAC;gBACzE,IAAI,CAAC,UAAU,EAAE,CAAC;oBAChB,gBAAgB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;gBACtE,CAAC;YACH,CAAC;QACH,CAAC;QACD,YAAY,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;IACvC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAEpB,4EAA4E;IAC5E,4EAA4E;IAC5E,qEAAqE;IACrE,0EAA0E;IAC1E,uCAAuC;IACvC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,iBAAiB,CAAC,OAAO;YAAE,OAAO;QACvC,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAClD,EAAE,EAAE,KAAK,EAAE,CAAC;QACZ,iBAAiB,CAAC,OAAO,GAAG,KAAK,CAAC;IACpC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAEnB,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC;IAC5C,MAAM,WAAW,GAAG,kBAAkB,CAAC;QACrC,KAAK,EAAE,MAAM,CAAC,MAAM;QACpB,gBAAgB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO;QACzC,YAAY,EAAE,GAAG,EAAE,CAAC,EAAE;QACtB,QAAQ,EAAE,CAAC;QACX,OAAO,EAAE,gBAAgB;KAC1B,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,CAAwC,EAAE,EAAE;QAC3C,IAAI,CAAC,CAAC,GAAG,KAAK,WAAW,EAAE,CAAC;YAC1B,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,iBAAiB,CAAC,OAAO,GAAG,IAAI,CAAC;YACjC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7D,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YAC/B,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,iBAAiB,CAAC,OAAO,GAAG,IAAI,CAAC;YACjC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,KAAK,MAAM,EAAE,CAAC;YAC5B,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,iBAAiB,CAAC,OAAO,GAAG,IAAI,CAAC;YACjC,eAAe,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,EAAE,CAAC;YAC3B,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,iBAAiB,CAAC,OAAO,GAAG,IAAI,CAAC;YACjC,eAAe,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACrC,CAAC;IACH,CAAC,EACD,CAAC,MAAM,CAAC,MAAM,CAAC,CAChB,CAAC;IAEF,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,KAAa,EAAE,IAA0B,EAAE,EAAE;QAC5E,IAAI,IAAI;YAAE,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;;YAC3C,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,sCACkB,qBAAqB,EACrC,SAAS,EAAE,EAAE,CAAC,iDAAiD,EAAE,SAAS,CAAC,aAE3E,eAAK,SAAS,EAAC,mCAAmC,aAChD,aACE,EAAE,EAAC,qBAAqB,EACxB,SAAS,EAAC,uEAAuE,4BAG9E,EACJ,cAAc,IAAI,CACjB,MAAC,MAAM,IAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,cAAc,aACvC,KAAC,cAAc,yBAAa,SAAS,EAAC,QAAQ,GAAG,eAE1C,CACV,IACG,EACN,eACE,GAAG,EAAE,SAAS,EACd,SAAS,EAAC,6CAA6C,aAEtD,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACrB,YAAG,SAAS,EAAC,gDAAgD,iCAEzD,CACL,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CACrB,aACE,IAAI,EAAC,MAAM,gBACA,sBAAsB,EACjC,SAAS,EAAC,UAAU,EACpB,KAAK,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,YAAY,EAAE,EAAE,EAC7C,SAAS,EAAE,aAAa,YAEvB,WAAW,CAAC,eAAe,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;4BACzC,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;4BAC7B,OAAO,CACL,cAEE,GAAG,EAAE,WAAW,CAAC,cAAc,gBACnB,GAAG,CAAC,KAAK,EACrB,KAAK,EAAE;oCACL,QAAQ,EAAE,UAAU;oCACpB,GAAG,EAAE,CAAC;oCACN,IAAI,EAAE,CAAC;oCACP,KAAK,EAAE,CAAC;oCACR,SAAS,EAAE,cAAc,GAAG,CAAC,KAAK,KAAK;iCACxC,YAED,KAAC,aAAa,IACZ,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,EAC3C,KAAK,EAAE,EAAE,EACT,eAAe,EACb,kBAAkB,EAAE,CAAC,EAAE,CAAC,IAAI,SAAS,EAEvC,QAAQ,EAAE,YAAY,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAC7C,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,GACzC,IAnBG,EAAE,CAAC,EAAE,CAoBN,CACP,CAAC;wBACJ,CAAC,CAAC,GACC,CACN,CAAC,CAAC,CAAC,CACF,aACE,IAAI,EAAC,MAAM,gBACA,sBAAsB,EACjC,SAAS,EAAC,WAAW,EACrB,SAAS,EAAE,aAAa,YAEvB,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CACrB,KAAC,aAAa,IAEZ,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,EACnC,KAAK,EAAE,EAAE,EACT,eAAe,EAAE,kBAAkB,EAAE,CAAC,EAAE,CAAC,IAAI,SAAS,EACtD,QAAQ,EAAE,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACrC,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,IAL5B,EAAE,CAAC,EAAE,CAMV,CACH,CAAC,GACC,CACN,EACA,aAAa,GAAG,CAAC,IAAI,CACpB,cAAK,SAAS,EAAC,yDAAyD,YACtE,cAAK,SAAS,EAAC,qBAAqB,YAClC,KAAC,eAAe,IACd,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,GAAG,EAAE;oCACZ,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC;oCAC7B,IAAI,EAAE;wCAAE,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC;oCACvC,gBAAgB,CAAC,CAAC,CAAC,CAAC;gCACtB,CAAC,GACD,GACE,GACF,CACP,IACG,IACE,CACX,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"negotiation-section.js","sourceRoot":"","sources":["../../src/offer/negotiation-section.tsx"],"names":[],"mappings":"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"}
@@ -1,33 +1,33 @@
1
- import { type FactsCardStatus } from "./facts-card";
2
- import { type OfferProductBeverage, type OfferProductVariant } from "./offer-product-card";
3
- import { type OpportunityCardData } from "./opportunity-card";
4
- import type { MatchEvaluation, OfferAttachmentItem, OfferFxInfo, OfferPartyInfo, OfferPresenceEntry, OfferSectionId, OfferTerms, Perspective, SectionOverride, TimelineEventData } from "./types";
5
- export type OfferDocumentAction = "counter" | "accept" | "decline" | "withdraw" | "reopen" | "renew";
1
+ import type { MatchEvaluation, OfferAttachmentItem, OfferCounterBody, OfferCounts, OfferFxInfo, OfferParties, OfferPresenceEntry, OfferRaw, OfferSectionId, Perspective, SectionOverride, TimelineEventData } from "./types";
6
2
  export interface OfferDocumentProps {
7
- offerId: string;
8
- status: FactsCardStatus;
9
- round: number;
3
+ offer: OfferRaw;
4
+ matchEvaluation: MatchEvaluation | null;
5
+ counts?: OfferCounts;
6
+ fx?: OfferFxInfo | null;
7
+ presence?: OfferPresenceEntry[];
8
+ parties: OfferParties;
9
+ timelineEvents: TimelineEventData[];
10
+ /** Whether there are older timeline events beyond what's loaded. */
11
+ hasMoreTimeline?: boolean;
12
+ /** Load the next older page; OfferDocument exposes this via the negotiation shell. */
13
+ onLoadOlderTimeline?: () => void;
10
14
  perspective: Perspective;
11
15
  viewerOrgId: string;
12
- producer: OfferPartyInfo;
13
- importer: OfferPartyInfo;
14
- opportunity: OpportunityCardData;
15
- beverage: OfferProductBeverage;
16
- variant: OfferProductVariant;
17
- terms: OfferTerms;
18
- previousTerms?: OfferTerms;
19
- evaluation: MatchEvaluation;
20
- attachments: OfferAttachmentItem[];
21
- events: TimelineEventData[];
22
- presence: OfferPresenceEntry[];
23
- fx?: OfferFxInfo;
16
+ /** Currency the tender was denominated in — enables FX display in FactsCard. */
24
17
  tenderCurrency?: string;
25
- /** Per-section overrides (hide / reorder / override default-open). */
18
+ onCounter: (body: OfferCounterBody) => Promise<void>;
19
+ onAccept: () => Promise<void>;
20
+ onDecline: () => Promise<void>;
21
+ onWithdraw: () => Promise<void>;
22
+ onUploadAttachment?: (file: File) => Promise<void>;
23
+ /** Optional "reopen" / "renew" terminal-state escape hatches. */
24
+ onReopen?: () => Promise<void>;
25
+ onRenew?: () => Promise<void>;
26
+ /** True when the socket is reconnecting; renders a non-blocking banner. */
27
+ isReconnecting?: boolean;
26
28
  sections?: Partial<Record<OfferSectionId, SectionOverride>>;
27
- onAction: (action: OfferDocumentAction) => void;
28
- onOpenComposer?: () => void;
29
29
  onOpenAttachment?: (a: OfferAttachmentItem) => void;
30
30
  className?: string;
31
31
  }
32
- export declare function OfferDocument({ offerId, status, round, perspective, viewerOrgId, producer, importer, opportunity, beverage, variant, terms, previousTerms, evaluation, attachments, events, presence, fx, tenderCurrency, sections, onAction, onOpenComposer, onOpenAttachment, className, }: OfferDocumentProps): import("react/jsx-runtime").JSX.Element;
32
+ export declare function OfferDocument({ offer, matchEvaluation, counts, fx, presence, parties, timelineEvents, hasMoreTimeline: _hasMoreTimeline, onLoadOlderTimeline, perspective, viewerOrgId, tenderCurrency, onCounter, onAccept, onDecline, onWithdraw, onUploadAttachment, onReopen, onRenew, isReconnecting, sections, onOpenAttachment, className, }: OfferDocumentProps): import("react/jsx-runtime").JSX.Element;
33
33
  //# sourceMappingURL=offer-document.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"offer-document.d.ts","sourceRoot":"","sources":["../../src/offer/offer-document.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAI/D,OAAO,EAAoB,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC7G,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG/E,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,WAAW,EACX,eAAe,EACf,iBAAiB,EAElB,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,mBAAmB,GAC3B,SAAS,GACT,QAAQ,GACR,SAAS,GACT,UAAU,GACV,QAAQ,GACR,OAAO,CAAC;AAEZ,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IAEpB,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,cAAc,CAAC;IACzB,WAAW,EAAE,mBAAmB,CAAC;IACjC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,OAAO,EAAE,mBAAmB,CAAC;IAC7B,KAAK,EAAE,UAAU,CAAC;IAClB,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,UAAU,EAAE,eAAe,CAAC;IAC5B,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,EAAE,CAAC,EAAE,WAAW,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;IAE5D,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,gBAAgB,CAAC,EAAE,CAAC,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAEpD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA6ED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,MAAM,EACN,KAAK,EACL,WAAW,EACX,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,OAAO,EACP,KAAK,EACL,aAAa,EACb,UAAU,EACV,WAAW,EACX,MAAM,EACN,QAAQ,EACR,EAAE,EACF,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,SAAS,GACV,EAAE,kBAAkB,2CAgMpB"}
1
+ {"version":3,"file":"offer-document.d.ts","sourceRoot":"","sources":["../../src/offer/offer-document.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,YAAY,EAEZ,kBAAkB,EAClB,QAAQ,EACR,cAAc,EAEd,WAAW,EACX,eAAe,EACf,iBAAiB,EAElB,MAAM,SAAS,CAAC;AASjB,MAAM,WAAW,kBAAkB;IAEjC,KAAK,EAAE,QAAQ,CAAC;IAChB,eAAe,EAAE,eAAe,GAAG,IAAI,CAAC;IACxC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,EAAE,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAChC,OAAO,EAAE,YAAY,CAAC;IACtB,cAAc,EAAE,iBAAiB,EAAE,CAAC;IACpC,oEAAoE;IACpE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,sFAAsF;IACtF,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IAGjC,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,SAAS,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAG9B,2EAA2E;IAC3E,cAAc,CAAC,EAAE,OAAO,CAAC;IAGzB,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;IAC5D,gBAAgB,CAAC,EAAE,CAAC,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgOD,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,eAAe,EACf,MAAM,EACN,EAAE,EACF,QAAQ,EACR,OAAO,EACP,cAAc,EACd,eAAe,EAAE,gBAAgB,EACjC,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,cAAc,EACd,SAAS,EACT,QAAQ,EACR,SAAS,EACT,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,SAAS,GACV,EAAE,kBAAkB,2CAmSpB"}
@@ -1,9 +1,10 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useMemo } from "react";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
3
  import { cn } from "../lib/utils";
4
4
  import { ShadcnButton as Button } from "../components/shadcn-button";
5
5
  import { AttachmentsCard } from "./attachments-card";
6
6
  import { BuyerNotesCard } from "./buyer-notes-card";
7
+ import { CounterSlideOver } from "./counter-slide-over";
7
8
  import { FactsCard } from "./facts-card";
8
9
  import { MatchCompatibilityCard } from "./match-compatibility-card";
9
10
  import { NegotiationSection } from "./negotiation-section";
@@ -22,7 +23,31 @@ const DEFAULT_ORDER = [
22
23
  "attachments",
23
24
  "negotiation",
24
25
  ];
25
- function producerCtas(status, viewerInitiator) {
26
+ /**
27
+ * Map the backend offer status enum onto the narrower FactsCardStatus
28
+ * surface the rail + facts strip render against. Unknown strings fall
29
+ * through to "proposed" so a partial payload still renders.
30
+ */
31
+ function mapOfferStatus(raw) {
32
+ switch (raw) {
33
+ case "counter_pending":
34
+ return "counter_pending";
35
+ case "accepted":
36
+ return "accepted";
37
+ case "declined":
38
+ case "rejected":
39
+ return "declined";
40
+ case "expired":
41
+ return "expired";
42
+ case "withdrawn":
43
+ return "withdrawn";
44
+ // Negotiation "working" states — draft / submitted / sent /
45
+ // in_negotiation / proposed — all render as "proposed" to the rail.
46
+ default:
47
+ return "proposed";
48
+ }
49
+ }
50
+ function deriveRailActions(status, viewerInitiator) {
26
51
  switch (status) {
27
52
  case "proposed":
28
53
  return viewerInitiator ? ["withdraw"] : ["counter", "accept", "decline"];
@@ -39,11 +64,6 @@ function producerCtas(status, viewerInitiator) {
39
64
  return [];
40
65
  }
41
66
  }
42
- // Blocker B9 — CTA aria-label composition. Screen-reader users should
43
- // hear the full context ("Accept offer for Barolo DOCG 2020 from Fattoria
44
- // San Marco") rather than a raw UUID ("Accept offer offer-1"). When the
45
- // beverage or producer name is missing (defensive — this should not
46
- // happen in practice), we fall back to the offer id segment.
47
67
  const ACTION_VERB = {
48
68
  counter: "Counter",
49
69
  accept: "Accept",
@@ -54,23 +74,12 @@ const ACTION_VERB = {
54
74
  };
55
75
  function ctaAriaLabel(action, beverageName, producerName, offerId) {
56
76
  const verb = ACTION_VERB[action];
57
- if (beverageName && producerName) {
77
+ if (beverageName && producerName)
58
78
  return `${verb} offer for ${beverageName} from ${producerName}`;
59
- }
60
79
  if (beverageName)
61
80
  return `${verb} offer for ${beverageName}`;
62
- // Defensive fallback — should never fire because OfferDocumentProps
63
- // requires `beverage.name` and `producer.name`, but keeps the aria-label
64
- // non-empty even if a consumer passes an empty string.
65
81
  return `${verb} offer ${offerId}`;
66
82
  }
67
- // Blocker B9 / spec §19 — Screen-reader announcement on offer state
68
- // transitions. The OfferDocument rail exposes a dedicated
69
- // `role="status"` live region separate from FactsCard's price-focused
70
- // live region. It emits a composed sentence like
71
- // "Offer accepted — no further counters possible"
72
- // whenever the `status` prop changes. This is the region that the
73
- // `StateTransitionAnnouncement` story asserts against.
74
83
  const STATE_TRANSITION_SENTENCE = {
75
84
  proposed: "Offer proposed — awaiting counterparty response",
76
85
  counter_pending: "Counter pending — awaiting review",
@@ -79,7 +88,149 @@ const STATE_TRANSITION_SENTENCE = {
79
88
  expired: "Offer expired — validity window closed",
80
89
  withdrawn: "Offer withdrawn by initiator",
81
90
  };
82
- export function OfferDocument({ offerId, status, round, perspective, viewerOrgId, producer, importer, opportunity, beverage, variant, terms, previousTerms, evaluation, attachments, events, presence, fx, tenderCurrency, sections, onAction, onOpenComposer, onOpenAttachment, className, }) {
91
+ function numberOrNull(v) {
92
+ if (v == null)
93
+ return null;
94
+ const n = typeof v === "string" ? Number(v) : v;
95
+ return Number.isFinite(n) ? n : null;
96
+ }
97
+ function deriveTerms(offer) {
98
+ const price = numberOrNull(offer.price) ?? 0;
99
+ const volume = numberOrNull(offer.availableVolume ?? offer.volume) ?? 0;
100
+ const validUntil = typeof offer.validThrough === "string"
101
+ ? offer.validThrough
102
+ : offer.validThrough instanceof Date
103
+ ? offer.validThrough.toISOString()
104
+ : undefined;
105
+ return {
106
+ price,
107
+ currency: offer.currency ?? "EUR",
108
+ volume,
109
+ paymentTerms: offer.paymentTerms ?? undefined,
110
+ incoterms: offer.deliveryTerms ?? undefined,
111
+ validUntil,
112
+ };
113
+ }
114
+ function derivePreviousTerms(offer) {
115
+ const prev = offer.previousRoundTerms;
116
+ if (!prev || typeof prev !== "object")
117
+ return undefined;
118
+ const price = numberOrNull(prev.price);
119
+ const volume = numberOrNull(prev.volume);
120
+ if (price == null && volume == null)
121
+ return undefined;
122
+ return {
123
+ price: price ?? 0,
124
+ currency: prev.currency ?? offer.currency ?? "EUR",
125
+ volume: volume ?? 0,
126
+ paymentTerms: prev.paymentTerms,
127
+ incoterms: prev.incoterms,
128
+ };
129
+ }
130
+ function deriveProducer(offer, parties) {
131
+ const snap = (offer.orgSnapshot ?? {});
132
+ const region = typeof snap.region === "string" ? snap.region : undefined;
133
+ const city = typeof snap.city === "string" ? snap.city : undefined;
134
+ const country = parties.producer.country ?? (typeof snap.country === "string" ? snap.country : undefined);
135
+ const location = [city, region, country].filter(Boolean).join(", ") || undefined;
136
+ return {
137
+ orgId: parties.producer.orgId,
138
+ name: parties.producer.name ?? (typeof snap.name === "string" ? snap.name : "Producer"),
139
+ location,
140
+ logoUrl: parties.producer.logoUrl ?? (typeof snap.logoUrl === "string" ? snap.logoUrl : undefined),
141
+ primaryContactName: typeof snap.primaryContactName === "string" ? snap.primaryContactName : undefined,
142
+ primaryContactEmail: typeof snap.primaryContactEmail === "string" ? snap.primaryContactEmail : undefined,
143
+ };
144
+ }
145
+ function deriveImporter(parties) {
146
+ if (!parties.importer) {
147
+ // A declarable placeholder — PartiesCard tolerates "TBD" / empty name and
148
+ // rendering stays stable for draft / unsent offers that have no recipient yet.
149
+ return { orgId: "", name: "Pending recipient", location: undefined };
150
+ }
151
+ return {
152
+ orgId: parties.importer.orgId,
153
+ name: parties.importer.name ?? "Importer",
154
+ location: parties.importer.country ?? undefined,
155
+ logoUrl: parties.importer.logoUrl ?? undefined,
156
+ };
157
+ }
158
+ function deriveOpportunity(offer) {
159
+ const snap = (offer.opportunitySnapshot ?? {});
160
+ const title = typeof snap.name === "string" ? snap.name : "Opportunity";
161
+ const deadlineIso = typeof snap.deadline === "string" ? snap.deadline : snap.deadline instanceof Date ? snap.deadline.toISOString() : null;
162
+ const closingDays = deadlineIso
163
+ ? Math.max(0, Math.ceil((new Date(deadlineIso).getTime() - Date.now()) / (1000 * 60 * 60 * 24)))
164
+ : 0;
165
+ const priceMax = numberOrNull(snap.priceMax);
166
+ const volumeLiters = numberOrNull(snap.volumeLiters);
167
+ const requirements = [];
168
+ if (typeof snap.description === "string" && snap.description.trim())
169
+ requirements.push(snap.description);
170
+ if (Array.isArray(snap.certificateRequirements)) {
171
+ for (const c of snap.certificateRequirements) {
172
+ if (typeof c === "string")
173
+ requirements.push(`Certification: ${c}`);
174
+ }
175
+ }
176
+ return {
177
+ id: offer.opportunityId ?? "",
178
+ title,
179
+ closingDays,
180
+ priceCeilingEuro: priceMax ?? undefined,
181
+ volumeOptions: volumeLiters != null ? [volumeLiters] : undefined,
182
+ requirements: requirements.length ? requirements : undefined,
183
+ };
184
+ }
185
+ function deriveProduct(offer) {
186
+ const snap = (offer.variantSnapshot ?? {});
187
+ const bevType = (snap.beverageType ?? {});
188
+ const beverage = {
189
+ id: typeof snap.beverageId === "string" ? snap.beverageId : "",
190
+ name: typeof snap.beverageName === "string" ? snap.beverageName : "Product",
191
+ producer: typeof snap.producer === "string" ? snap.producer : undefined,
192
+ countryOfOrigin: typeof snap.countryOfOrigin === "string" ? snap.countryOfOrigin : undefined,
193
+ beverageType: {
194
+ category: typeof bevType.category === "string" ? bevType.category : undefined,
195
+ subtype: typeof bevType.subtype === "string" ? bevType.subtype : undefined,
196
+ },
197
+ };
198
+ const variant = {
199
+ id: typeof snap.variantId === "string"
200
+ ? snap.variantId
201
+ : (offer.variantId ?? ""),
202
+ vintage: typeof snap.vintage === "number" ? snap.vintage : null,
203
+ packaging: typeof snap.packaging === "string" ? snap.packaging : undefined,
204
+ closure: typeof snap.closure === "string" ? snap.closure : undefined,
205
+ abv: numberOrNull(snap.abv),
206
+ residualSugar: numberOrNull(snap.residualSugar),
207
+ organic: Boolean(snap.organic),
208
+ fairtrade: Boolean(snap.fairtrade),
209
+ sustainable: Boolean(snap.sustainable),
210
+ imageUrl: typeof snap.imageUrl === "string" ? snap.imageUrl : null,
211
+ };
212
+ return { beverage, variant };
213
+ }
214
+ const NEUTRAL_EVALUATION = {
215
+ headline: "partial",
216
+ headlineSummary: "Match evaluation unavailable",
217
+ criteria: [],
218
+ freeTextFields: [],
219
+ hiddenReasons: [],
220
+ };
221
+ export function OfferDocument({ offer, matchEvaluation, counts, fx, presence, parties, timelineEvents, hasMoreTimeline: _hasMoreTimeline, onLoadOlderTimeline, perspective, viewerOrgId, tenderCurrency, onCounter, onAccept, onDecline, onWithdraw, onUploadAttachment, onReopen, onRenew, isReconnecting, sections, onOpenAttachment, className, }) {
222
+ const offerId = offer.offerId ?? offer.id ?? "";
223
+ const status = mapOfferStatus(offer.status);
224
+ const round = offer.currentRound ?? 1;
225
+ const terms = useMemo(() => deriveTerms(offer), [offer]);
226
+ const previousTerms = useMemo(() => derivePreviousTerms(offer), [offer]);
227
+ const producer = useMemo(() => deriveProducer(offer, parties), [offer, parties]);
228
+ const importer = useMemo(() => deriveImporter(parties), [parties]);
229
+ const opportunity = useMemo(() => deriveOpportunity(offer), [offer]);
230
+ const { beverage, variant } = useMemo(() => deriveProduct(offer), [offer]);
231
+ const evaluation = matchEvaluation ?? NEUTRAL_EVALUATION;
232
+ const attachments = offer.attachments ?? [];
233
+ const presenceList = presence ?? [];
83
234
  const orderedIds = useMemo(() => {
84
235
  const overrides = sections ?? {};
85
236
  const active = DEFAULT_ORDER.filter((id) => !overrides[id]?.hidden);
@@ -90,36 +241,105 @@ export function OfferDocument({ offerId, status, round, perspective, viewerOrgId
90
241
  });
91
242
  }, [sections]);
92
243
  const viewerInitiator = (status === "proposed" && viewerOrgId === producer.orgId) ||
93
- (status === "counter_pending" && events[events.length - 1]?.actorOrgId === viewerOrgId);
94
- const ctas = producerCtas(status, viewerInitiator);
95
- // Blocker B3 — viewerAdvantage is per-criterion and per-round. It must
96
- // come from the backend evaluator (Plan 2) where each `MatchCriterion`
97
- // carries its own `viewerAdvantage` scoped to the viewer. A flat
98
- // page-level constant is wrong per spec §11: "Delta polarity: Producer:
99
- // emerald · Importer: rose" describes a per-field rule, not a page-wide
100
- // tone. We do NOT compute one here. Downstream cards that need the top-
101
- // line viewer advantage (e.g. FactsCard price delta) derive it from the
102
- // `price` criterion's own `viewerAdvantage`, with "neutral" as a safe
103
- // fallback when the criterion is missing / FX-unavailable (§6.6).
244
+ (status === "counter_pending" && timelineEvents[timelineEvents.length - 1]?.actorOrgId === viewerOrgId);
245
+ const railActions = deriveRailActions(status, viewerInitiator);
104
246
  const priceCriterion = evaluation.criteria.find((c) => c.id === "price");
105
247
  const topLineAdvantage = priceCriterion?.viewerAdvantage ?? "neutral";
106
- // Stable document-generation timestamp: captured once per mount, not on every re-render.
107
248
  const printedAt = useMemo(() => new Date().toISOString(), []);
108
- return (_jsxs("div", { "data-offer-document": true, "data-offer-id": offerId, "data-printed-at": printedAt, className: cn("mx-auto w-full max-w-6xl space-y-4 p-4", className), children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("nav", { "data-offer-nav-chrome": true, "aria-label": "breadcrumb", className: "text-xs text-muted-foreground", children: [perspective === "producer" ? "Sprint board" : "Offers", " / Offer ", offerId.slice(0, 8)] }), _jsx(OfferExportButton, { offerId: offerId })] }), _jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", children: STATE_TRANSITION_SENTENCE[status] }), _jsx("div", { "data-offer-facts-card": true, children: _jsx(FactsCard, { status: status, round: round, terms: terms, previousPrice: previousTerms?.price,
109
- // Blocker B3 — derived from the `price` criterion's own
110
- // `viewerAdvantage`, not a flat page-level constant. This keeps
111
- // the price-delta chip polarity aligned with the backend's
112
- // viewer-scoped evaluation (spec §11: "Delta polarity" per-field).
113
- viewerAdvantage: topLineAdvantage, perspective: perspective, presence: presence, fx: fx, tenderCurrency: tenderCurrency, onExport: () => window.print() }) }), _jsxs("div", { className: "grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_220px]", children: [_jsx("main", { className: "space-y-4", children: orderedIds.map((id) => (_jsxs("div", { "data-offer-section": true, "data-section-id": id, children: [id === "parties" && (_jsx(PartiesCard, { producer: producer, importer: importer, viewerOrgId: viewerOrgId, variant: sections?.parties?.defaultOpen ? "expanded" : "collapsed" })), id === "opportunity" && (_jsx(OpportunityCard, { opportunity: opportunity, variant: sections?.opportunity?.defaultOpen ? "expanded" : "collapsed" })), id === "product" && (_jsx(OfferProductCard, { variant: variant, beverage: beverage, variantDisplay: sections?.product?.defaultOpen === false ? "collapsed" : "expanded" })), id === "terms" && (_jsx(TermsCard, { terms: terms, previousTerms: previousTerms, variant: sections?.terms?.defaultOpen ? "expanded" : "collapsed",
114
- // Blocker B3 — TermsCard now derives per-row polarity
115
- // from `perspective` + each cell's delta direction rather
116
- // than a single flat `viewerAdvantage` constant. Price up
117
- // is emerald for a producer, rose for an importer, etc.
118
- perspective: perspective })), id === "match" && (_jsx(MatchCompatibilityCard, { evaluation: evaluation,
119
- // Blocker B3 — each criterion row derives its own colour
120
- // from its own `viewerAdvantage` field. Passing
121
- // `perspective` is informational (e.g. for accessible
122
- // labels like "Producer: price improved").
123
- perspective: perspective })), id === "notes" && _jsx(BuyerNotesCard, { notes: evaluation.freeTextFields }), id === "attachments" && (_jsx(AttachmentsCard, { attachments: attachments, onOpen: (a) => onOpenAttachment?.(a) })), id === "negotiation" && (_jsx(NegotiationSection, { events: events, viewerOrgId: viewerOrgId, viewerRole: perspective, onOpenComposer: onOpenComposer }))] }, id))) }), _jsx("aside", { "data-offer-rail": true, "aria-label": "Actions and meta", className: "hidden lg:block", children: _jsxs("div", { className: "sticky top-24 space-y-3", children: [_jsxs("div", { className: "rounded-xl border border-border/60 bg-card p-3", children: [_jsx("div", { className: "text-xs uppercase tracking-wide text-muted-foreground", children: "Actions" }), _jsxs("div", { className: "mt-2 flex flex-wrap gap-2", children: [ctas.length === 0 && (_jsx("span", { className: "text-xs text-muted-foreground", children: "No actions available." })), ctas.map((a) => (_jsx(Button, { size: "sm", "aria-label": ctaAriaLabel(a, beverage.name, producer.name, offerId), onClick: () => onAction(a), children: a }, a)))] })] }), _jsxs("div", { className: "rounded-xl border border-border/60 bg-card p-3 text-xs", children: [_jsx("div", { className: "uppercase tracking-wide text-muted-foreground", children: "Status" }), _jsx("div", { className: "mt-1 font-medium capitalize", children: status.replace("_", " ") }), _jsxs("div", { className: "mt-1 text-muted-foreground", children: ["R", round, " of 4 max"] })] }), _jsxs("div", { className: "rounded-xl border border-border/60 bg-card p-3 text-xs", children: [_jsx("div", { className: "uppercase tracking-wide text-muted-foreground", children: "Offer" }), _jsx("div", { className: "mt-1 font-mono", children: offerId }), _jsxs("div", { className: "mt-1 text-muted-foreground", children: [events.length, " events \u00B7 ", attachments.length, " files"] })] }), _jsxs("div", { className: "rounded-xl border border-border/60 bg-card p-3", children: [_jsx("div", { className: "text-xs uppercase tracking-wide text-muted-foreground", children: "Export" }), _jsx("div", { className: "mt-2", children: _jsx(OfferExportButton, { offerId: offerId }) })] })] }) })] })] }));
249
+ /* ── Composer (CounterSlideOver) — owned internally ── */
250
+ const [composerOpen, setComposerOpen] = useState(false);
251
+ /**
252
+ * Mid-compose race banner: when the counterparty lands a new round while
253
+ * the composer is open, we surface a diff banner inside the composer and
254
+ * let the user re-pre-fill from the new round. The banner is driven by a
255
+ * latched `bannerRound` — if the prop `round` changes while the composer
256
+ * is open AND differs from the round we opened at, the banner fires.
257
+ */
258
+ const openedAtRound = useRef(null);
259
+ const [composerBanner, setComposerBanner] = useState(undefined);
260
+ useEffect(() => {
261
+ if (!composerOpen)
262
+ return;
263
+ if (openedAtRound.current == null) {
264
+ openedAtRound.current = round;
265
+ return;
266
+ }
267
+ if (round !== openedAtRound.current) {
268
+ setComposerBanner({
269
+ kind: "incoming_counter",
270
+ roundN: round,
271
+ headline: "The counterparty sent a new counter while you were composing.",
272
+ onDismiss: () => setComposerBanner(undefined),
273
+ onReset: () => setComposerBanner(undefined),
274
+ });
275
+ }
276
+ }, [composerOpen, round]);
277
+ useEffect(() => {
278
+ if (!composerOpen) {
279
+ openedAtRound.current = null;
280
+ setComposerBanner(undefined);
281
+ }
282
+ }, [composerOpen]);
283
+ const handleRailClick = async (a) => {
284
+ try {
285
+ switch (a) {
286
+ case "counter":
287
+ setComposerOpen(true);
288
+ return;
289
+ case "accept":
290
+ await onAccept();
291
+ return;
292
+ case "decline":
293
+ await onDecline();
294
+ return;
295
+ case "withdraw":
296
+ await onWithdraw();
297
+ return;
298
+ case "reopen":
299
+ await onReopen?.();
300
+ return;
301
+ case "renew":
302
+ await onRenew?.();
303
+ return;
304
+ }
305
+ }
306
+ catch {
307
+ /* Dashboard owns toast / retry — we stay silent here. */
308
+ }
309
+ };
310
+ const attachmentInputRef = useRef(null);
311
+ const handleAttachmentUpload = () => {
312
+ attachmentInputRef.current?.click();
313
+ };
314
+ const handleAttachmentFileChange = async (event) => {
315
+ const file = event.target.files?.[0];
316
+ event.target.value = ""; // reset so the same file can be re-selected
317
+ if (!file || !onUploadAttachment)
318
+ return;
319
+ try {
320
+ await onUploadAttachment(file);
321
+ }
322
+ catch {
323
+ /* Dashboard owns toast. */
324
+ }
325
+ };
326
+ return (_jsxs("div", { "data-offer-document": true, "data-offer-id": offerId, "data-printed-at": printedAt, className: cn("mx-auto w-full max-w-6xl space-y-4 p-4", className), children: [isReconnecting && (_jsx("div", { role: "status", "aria-live": "polite", className: "rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-900 dark:border-amber-900 dark:bg-amber-950 dark:text-amber-50", children: "Reconnecting\u2026" })), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("nav", { "data-offer-nav-chrome": true, "aria-label": "breadcrumb", className: "text-xs text-muted-foreground", children: [perspective === "producer" ? "Sprint board" : "Offers", " / Offer ", offerId.slice(0, 8)] }), _jsx(OfferExportButton, { offerId: offerId })] }), _jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", children: STATE_TRANSITION_SENTENCE[status] }), _jsx("div", { "data-offer-facts-card": true, children: _jsx(FactsCard, { status: status, round: round, terms: terms, previousPrice: previousTerms?.price, viewerAdvantage: topLineAdvantage, perspective: perspective, presence: presenceList, fx: fx ?? undefined, tenderCurrency: tenderCurrency, onExport: () => window.print() }) }), _jsxs("div", { className: "grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_220px]", children: [_jsx("main", { className: "space-y-4", children: orderedIds.map((id) => (_jsxs("div", { "data-offer-section": true, "data-section-id": id, children: [id === "parties" && (_jsx(PartiesCard, { producer: producer, importer: importer, viewerOrgId: viewerOrgId, variant: sections?.parties?.defaultOpen ? "expanded" : "collapsed" })), id === "opportunity" && (_jsx(OpportunityCard, { opportunity: opportunity, variant: sections?.opportunity?.defaultOpen ? "expanded" : "collapsed" })), id === "product" && (_jsx(OfferProductCard, { variant: variant, beverage: beverage, variantDisplay: sections?.product?.defaultOpen === false ? "collapsed" : "expanded" })), id === "terms" && (_jsx(TermsCard, { terms: terms, previousTerms: previousTerms, variant: sections?.terms?.defaultOpen ? "expanded" : "collapsed", perspective: perspective })), id === "match" && _jsx(MatchCompatibilityCard, { evaluation: evaluation, perspective: perspective }), id === "notes" && _jsx(BuyerNotesCard, { notes: evaluation.freeTextFields }), id === "attachments" && (_jsx(AttachmentsCard, { attachments: attachments, onOpen: (a) => onOpenAttachment?.(a), onUpload: onUploadAttachment ? handleAttachmentUpload : undefined })), id === "negotiation" && (_jsx(NegotiationSection, { events: timelineEvents, viewerOrgId: viewerOrgId, viewerRole: perspective, onOpenComposer: () => setComposerOpen(true), onLoadOlder: onLoadOlderTimeline }))] }, id))) }), _jsx("aside", { "data-offer-rail": true, "aria-label": "Actions and meta", className: "hidden lg:block", children: _jsxs("div", { className: "sticky top-24 space-y-3", children: [_jsxs("div", { className: "rounded-xl border border-border/60 bg-card p-3", children: [_jsx("div", { className: "text-xs uppercase tracking-wide text-muted-foreground", children: "Actions" }), _jsxs("div", { className: "mt-2 flex flex-wrap gap-2", children: [railActions.length === 0 && _jsx("span", { className: "text-xs text-muted-foreground", children: "No actions available." }), railActions.map((a) => (_jsx(Button, { size: "sm", "aria-label": ctaAriaLabel(a, beverage.name, producer.name, offerId), onClick: () => void handleRailClick(a), children: ACTION_VERB[a] }, a)))] })] }), _jsxs("div", { className: "rounded-xl border border-border/60 bg-card p-3 text-xs", children: [_jsx("div", { className: "uppercase tracking-wide text-muted-foreground", children: "Status" }), _jsx("div", { className: "mt-1 font-medium capitalize", children: status.replace("_", " ") }), _jsxs("div", { className: "mt-1 text-muted-foreground", children: ["R", round, " of 4 max"] })] }), _jsxs("div", { className: "rounded-xl border border-border/60 bg-card p-3 text-xs", children: [_jsx("div", { className: "uppercase tracking-wide text-muted-foreground", children: "Offer" }), _jsx("div", { className: "mt-1 font-mono", children: offerId }), _jsxs("div", { className: "mt-1 text-muted-foreground", children: [(counts?.messages ?? timelineEvents.length), " events \u00B7 ", counts?.attachments ?? attachments.length, " files"] })] }), _jsxs("div", { className: "rounded-xl border border-border/60 bg-card p-3", children: [_jsx("div", { className: "text-xs uppercase tracking-wide text-muted-foreground", children: "Export" }), _jsx("div", { className: "mt-2", children: _jsx(OfferExportButton, { offerId: offerId }) })] })] }) })] }), _jsx("input", { ref: attachmentInputRef, type: "file", className: "sr-only", "aria-hidden": true, onChange: handleAttachmentFileChange }), _jsx(CounterSlideOver, { open: composerOpen, onClose: () => setComposerOpen(false), offerId: offerId, round: round, allowedIncoterms: ["EXW", "FCA", "CIF", "CIP", "DAP", "DDP"], baselineTerms: previousTerms ?? terms, initialMatchEvaluation: evaluation, onSubmit: async (draft) => {
327
+ const body = {
328
+ clientEventId: typeof crypto !== "undefined" && typeof crypto.randomUUID === "function"
329
+ ? crypto.randomUUID()
330
+ : `${Date.now()}-${Math.random().toString(16).slice(2)}`,
331
+ expectedRound: round,
332
+ price: draft.price ?? null,
333
+ volume: draft.volume ?? null,
334
+ incoterms: draft.incoterms ?? null,
335
+ payment: draft.paymentTerms ?? null,
336
+ delivery: draft.deliveryDate ?? null,
337
+ validUntil: draft.validUntil ?? null,
338
+ message: draft.message ?? null,
339
+ attachmentIds: draft.attachmentIds,
340
+ };
341
+ await onCounter(body);
342
+ setComposerOpen(false);
343
+ }, onEvaluateDraft: () => evaluation, banner: composerBanner })] }));
124
344
  }
125
345
  //# sourceMappingURL=offer-document.js.map