@powerhousedao/service-offering 1.0.0-dev.22 → 1.0.0-dev.24

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 (66) hide show
  1. package/dist/document-models/resource-template/v1/actions.d.ts +1 -0
  2. package/dist/document-models/resource-template/v1/actions.d.ts.map +1 -1
  3. package/dist/document-models/resource-template/v1/gen/document-model.d.ts.map +1 -1
  4. package/dist/document-models/resource-template/v1/gen/document-model.js +174 -163
  5. package/dist/document-models/resource-template/v1/gen/document-schema.d.ts +6 -0
  6. package/dist/document-models/resource-template/v1/gen/document-schema.d.ts.map +1 -1
  7. package/dist/document-models/resource-template/v1/gen/ph-factories.d.ts.map +1 -1
  8. package/dist/document-models/resource-template/v1/gen/ph-factories.js +2 -0
  9. package/dist/document-models/resource-template/v1/gen/reducer.d.ts.map +1 -1
  10. package/dist/document-models/resource-template/v1/gen/reducer.js +6 -1
  11. package/dist/document-models/resource-template/v1/gen/schema/types.d.ts +7 -0
  12. package/dist/document-models/resource-template/v1/gen/schema/types.d.ts.map +1 -1
  13. package/dist/document-models/resource-template/v1/gen/schema/zod.d.ts +2 -1
  14. package/dist/document-models/resource-template/v1/gen/schema/zod.d.ts.map +1 -1
  15. package/dist/document-models/resource-template/v1/gen/schema/zod.js +9 -0
  16. package/dist/document-models/resource-template/v1/gen/template-management/actions.d.ts +6 -2
  17. package/dist/document-models/resource-template/v1/gen/template-management/actions.d.ts.map +1 -1
  18. package/dist/document-models/resource-template/v1/gen/template-management/creators.d.ts +3 -2
  19. package/dist/document-models/resource-template/v1/gen/template-management/creators.d.ts.map +1 -1
  20. package/dist/document-models/resource-template/v1/gen/template-management/creators.js +2 -1
  21. package/dist/document-models/resource-template/v1/gen/template-management/operations.d.ts +2 -1
  22. package/dist/document-models/resource-template/v1/gen/template-management/operations.d.ts.map +1 -1
  23. package/dist/document-models/resource-template/v1/gen/utils.d.ts.map +1 -1
  24. package/dist/document-models/resource-template/v1/gen/utils.js +2 -0
  25. package/dist/document-models/resource-template/v1/src/reducers/template-management.d.ts.map +1 -1
  26. package/dist/document-models/resource-template/v1/src/reducers/template-management.js +7 -0
  27. package/dist/document-models/resource-template/v1/tests/template-management.test.js +11 -1
  28. package/dist/document-models/service-offering/v1/actions.d.ts +1 -0
  29. package/dist/document-models/service-offering/v1/actions.d.ts.map +1 -1
  30. package/dist/document-models/service-offering/v1/gen/document-model.d.ts.map +1 -1
  31. package/dist/document-models/service-offering/v1/gen/document-model.js +31 -5
  32. package/dist/document-models/service-offering/v1/gen/reducer.d.ts.map +1 -1
  33. package/dist/document-models/service-offering/v1/gen/reducer.js +6 -1
  34. package/dist/document-models/service-offering/v1/gen/schema/types.d.ts +7 -0
  35. package/dist/document-models/service-offering/v1/gen/schema/types.d.ts.map +1 -1
  36. package/dist/document-models/service-offering/v1/gen/schema/zod.d.ts +2 -1
  37. package/dist/document-models/service-offering/v1/gen/schema/zod.d.ts.map +1 -1
  38. package/dist/document-models/service-offering/v1/gen/schema/zod.js +9 -0
  39. package/dist/document-models/service-offering/v1/gen/tiers/actions.d.ts +6 -2
  40. package/dist/document-models/service-offering/v1/gen/tiers/actions.d.ts.map +1 -1
  41. package/dist/document-models/service-offering/v1/gen/tiers/creators.d.ts +3 -2
  42. package/dist/document-models/service-offering/v1/gen/tiers/creators.d.ts.map +1 -1
  43. package/dist/document-models/service-offering/v1/gen/tiers/creators.js +2 -1
  44. package/dist/document-models/service-offering/v1/gen/tiers/error.d.ts +13 -1
  45. package/dist/document-models/service-offering/v1/gen/tiers/error.d.ts.map +1 -1
  46. package/dist/document-models/service-offering/v1/gen/tiers/error.js +13 -0
  47. package/dist/document-models/service-offering/v1/gen/tiers/operations.d.ts +2 -1
  48. package/dist/document-models/service-offering/v1/gen/tiers/operations.d.ts.map +1 -1
  49. package/dist/document-models/service-offering/v1/src/reducers/tiers.d.ts.map +1 -1
  50. package/dist/document-models/service-offering/v1/src/reducers/tiers.js +24 -1
  51. package/dist/document-models/service-offering/v1/tests/tiers.test.js +11 -1
  52. package/dist/editors/resource-template-editor/components/TemplateInfo.d.ts.map +1 -1
  53. package/dist/editors/resource-template-editor/components/TemplateInfo.js +45 -3
  54. package/dist/editors/service-offering-editor/components/ResourceTemplateSelector.d.ts.map +1 -1
  55. package/dist/editors/service-offering-editor/components/ResourceTemplateSelector.js +2 -0
  56. package/dist/editors/service-offering-editor/components/ServiceCatalog.d.ts.map +1 -1
  57. package/dist/editors/service-offering-editor/components/ServiceCatalog.js +4 -1
  58. package/dist/editors/service-offering-editor/components/TheMatrix.d.ts.map +1 -1
  59. package/dist/editors/service-offering-editor/components/TheMatrix.js +9 -5
  60. package/dist/editors/service-offering-editor/components/TierDefinition.d.ts.map +1 -1
  61. package/dist/editors/service-offering-editor/components/TierDefinition.js +25 -5
  62. package/dist/style.css +25 -0
  63. package/dist/subgraphs/resources-services/resolvers.js +4 -0
  64. package/dist/subgraphs/resources-services/schema.d.ts.map +1 -1
  65. package/dist/subgraphs/resources-services/schema.js +4 -0
  66. package/package.json +15 -15
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState, useEffect, useRef } from "react";
3
3
  import { generateId } from "document-model/core";
4
- import { updateTemplateInfo, updateTemplateStatus, setOperator, addTargetAudience, removeTargetAudience, setSetupServices, setRecurringServices, addFaq, updateFaq, deleteFaq, reorderFaqs, addContentSection, updateContentSection, deleteContentSection, reorderContentSections, } from "../../../document-models/resource-template/v1/gen/creators.js";
4
+ import { updateTemplateInfo, updateTemplateStatus, setOperator, setWeight, addTargetAudience, removeTargetAudience, setSetupServices, setRecurringServices, addFaq, updateFaq, deleteFaq, reorderFaqs, addContentSection, updateContentSection, deleteContentSection, reorderContentSections, } from "../../../document-models/resource-template/v1/gen/creators.js";
5
5
  import { MarkdownEditor } from "./markdown-editor.js";
6
6
  const STATUS_OPTIONS = [
7
7
  { value: "DRAFT", label: "Draft", color: "slate" },
@@ -85,6 +85,7 @@ export function TemplateInfo({ document, dispatch }) {
85
85
  const globalState = state.global;
86
86
  const [formData, setFormData] = useState({
87
87
  title: globalState.title || "",
88
+ subtitle: globalState.subtitle || "",
88
89
  summary: globalState.summary || "",
89
90
  description: globalState.description || "",
90
91
  operatorId: globalState.operatorId || "",
@@ -114,6 +115,7 @@ export function TemplateInfo({ document, dispatch }) {
114
115
  useEffect(() => {
115
116
  setFormData({
116
117
  title: globalState.title || "",
118
+ subtitle: globalState.subtitle || "",
117
119
  summary: globalState.summary || "",
118
120
  description: globalState.description || "",
119
121
  operatorId: globalState.operatorId || "",
@@ -123,6 +125,7 @@ export function TemplateInfo({ document, dispatch }) {
123
125
  });
124
126
  }, [
125
127
  globalState.title,
128
+ globalState.subtitle,
126
129
  globalState.summary,
127
130
  globalState.description,
128
131
  globalState.operatorId,
@@ -156,6 +159,10 @@ export function TemplateInfo({ document, dispatch }) {
156
159
  changes.infoLink = formData.infoLink || null;
157
160
  hasChanges = true;
158
161
  }
162
+ if (formData.subtitle !== (globalState.subtitle || "")) {
163
+ changes.subtitle = formData.subtitle || null;
164
+ hasChanges = true;
165
+ }
159
166
  if (hasChanges) {
160
167
  dispatch(updateTemplateInfo({
161
168
  ...changes,
@@ -420,7 +427,12 @@ export function TemplateInfo({ document, dispatch }) {
420
427
  backgroundImage: formData.thumbnailUrl
421
428
  ? `url(${formData.thumbnailUrl})`
422
429
  : undefined,
423
- }, children: [!formData.thumbnailUrl && (_jsxs("div", { className: "template-editor__thumbnail-placeholder", children: [_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [_jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }), _jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), _jsx("path", { d: "M21 15l-5-5L5 21" })] }), _jsx("span", { children: "Add Thumbnail" })] })), formData.thumbnailUrl && (_jsx("div", { className: `template-editor__status-badge template-editor__status-badge--${currentStatus?.color}`, children: currentStatus?.label }))] }), _jsx("div", { className: "template-editor__thumbnail-input", children: _jsx("input", { type: "text", value: formData.thumbnailUrl, onChange: (e) => handleFieldChange("thumbnailUrl", e.target.value), onBlur: handleInfoBlur, placeholder: "https://example.com/image.jpg", className: "template-editor__input template-editor__input--sm" }) })] }), _jsxs("div", { className: "template-editor__identity", children: [_jsxs("div", { className: "template-editor__title-row", children: [_jsx("input", { type: "text", value: formData.title, onChange: (e) => handleFieldChange("title", e.target.value), onBlur: handleInfoBlur, className: "template-editor__title-input", placeholder: "Product Title" }), _jsxs("div", { className: "template-editor__status-select", children: [_jsx("select", { value: formData.status, onChange: (e) => handleStatusChange(e.target.value), className: "template-editor__select", "data-status": currentStatus?.color, children: STATUS_OPTIONS.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value))) }), _jsx("span", { className: `template-editor__status-indicator template-editor__status-indicator--${currentStatus?.color}` })] })] }), _jsxs("div", { className: "template-editor__audiences", children: [globalState.targetAudiences.map((audience) => (_jsxs("span", { className: "template-editor__audience-tag", style: audience.color
430
+ }, children: [!formData.thumbnailUrl && (_jsxs("div", { className: "template-editor__thumbnail-placeholder", children: [_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [_jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }), _jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), _jsx("path", { d: "M21 15l-5-5L5 21" })] }), _jsx("span", { children: "Add Thumbnail" })] })), formData.thumbnailUrl && (_jsx("div", { className: `template-editor__status-badge template-editor__status-badge--${currentStatus?.color}`, children: currentStatus?.label }))] }), _jsx("div", { className: "template-editor__thumbnail-input", children: _jsx("input", { type: "text", value: formData.thumbnailUrl, onChange: (e) => handleFieldChange("thumbnailUrl", e.target.value), onBlur: handleInfoBlur, placeholder: "https://example.com/image.jpg", className: "template-editor__input template-editor__input--sm" }) })] }), _jsxs("div", { className: "template-editor__identity", children: [_jsxs("div", { className: "template-editor__title-row", children: [_jsx("input", { type: "text", value: formData.title, onChange: (e) => handleFieldChange("title", e.target.value), onBlur: handleInfoBlur, className: "template-editor__title-input", placeholder: "Product Title" }), _jsxs("div", { className: "template-editor__status-select", children: [_jsx("select", { value: formData.status, onChange: (e) => handleStatusChange(e.target.value), className: "template-editor__select", "data-status": currentStatus?.color, children: STATUS_OPTIONS.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value))) }), _jsx("span", { className: `template-editor__status-indicator template-editor__status-indicator--${currentStatus?.color}` })] })] }), _jsx("input", { type: "text", value: formData.subtitle, onChange: (e) => handleFieldChange("subtitle", e.target.value), onBlur: handleInfoBlur, className: "template-editor__title-input", placeholder: "Subtitle / Tagline", style: {
431
+ fontSize: "0.95rem",
432
+ fontWeight: 400,
433
+ color: "var(--rt-slate-600, #475569)",
434
+ marginTop: "-4px",
435
+ } }), _jsxs("div", { className: "template-editor__audiences", children: [globalState.targetAudiences.map((audience) => (_jsxs("span", { className: "template-editor__audience-tag", style: audience.color
424
436
  ? {
425
437
  backgroundColor: `${audience.color}15`,
426
438
  borderColor: `${audience.color}40`,
@@ -431,7 +443,37 @@ export function TemplateInfo({ document, dispatch }) {
431
443
  handleAddAudience(newAudienceLabel);
432
444
  if (e.key === "Escape")
433
445
  setShowAudienceInput(false);
434
- }, placeholder: "Audience name...", className: "template-editor__audience-input", autoFocus: true }), _jsx("button", { type: "button", onClick: () => handleAddAudience(newAudienceLabel), className: "template-editor__audience-add-btn", children: "Add" })] })) : (_jsxs("button", { type: "button", onClick: () => setShowAudienceInput(true), className: "template-editor__add-audience-btn", children: [_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("path", { d: "M12 5v14M5 12h14", strokeWidth: "2" }) }), "Add Audience"] }))] }), availablePresets.length > 0 && (_jsxs("div", { className: "template-editor__audience-presets", children: [_jsx("span", { className: "template-editor__presets-label", children: "Quick add:" }), availablePresets.slice(0, 4).map((preset) => (_jsx("button", { type: "button", onClick: () => handleAddAudience(preset.label, preset.color), className: "template-editor__preset-btn", style: { color: preset.color }, children: preset.label }, preset.label)))] })), _jsx("textarea", { value: formData.summary, onChange: (e) => handleFieldChange("summary", e.target.value), onBlur: handleInfoBlur, className: "template-editor__summary", placeholder: "Brief summary of your product...", rows: 2 })] })] }), _jsxs("section", { className: "template-editor__card template-editor__card--full", children: [_jsxs("div", { className: "template-editor__card-header", children: [_jsx("div", { className: "template-editor__card-icon template-editor__card-icon--violet", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", children: _jsx("path", { d: "M4 6h16M4 12h16M4 18h10" }) }) }), _jsxs("div", { children: [_jsx("h3", { className: "template-editor__card-title", children: "Description" }), _jsx("p", { className: "template-editor__card-subtitle", children: "Detailed description of your product" })] })] }), _jsx(MarkdownEditor, { label: "", height: 350, value: formData.description, onChange: (value) => handleFieldChange("description", value), onBlur: handleInfoBlur })] }), _jsxs("section", { className: "template-editor__card template-editor__card--full", children: [_jsxs("div", { className: "template-editor__card-header", children: [_jsx("div", { className: "template-editor__card-icon template-editor__card-icon--indigo", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", children: _jsx("path", { d: "M4 6h16M4 10h16M4 14h10M4 18h6" }) }) }), _jsxs("div", { children: [_jsx("h3", { className: "template-editor__card-title", children: "Expandable Content Sections" }), _jsx("p", { className: "template-editor__card-subtitle", children: "Add long-form article content with expandable titles" })] })] }), _jsx("div", { className: "template-editor__sections-list", children: sortedSections.map((section, index) => (_jsx("div", { className: `template-editor__section-item ${editingSectionId === section.id ? "template-editor__section-item--editing" : ""}`, children: editingSectionId === section.id ? (_jsxs("div", { className: "template-editor__section-edit-form", children: [_jsx("input", { type: "text", value: editingSectionTitle, onChange: (e) => setEditingSectionTitle(e.target.value), className: "template-editor__section-edit-title", placeholder: "Section title", autoFocus: true }), _jsx("textarea", { value: editingSectionContent, onChange: (e) => setEditingSectionContent(e.target.value), className: "template-editor__section-edit-content", placeholder: "Section content...", rows: 6 }), _jsxs("div", { className: "template-editor__section-edit-actions", children: [_jsx("button", { type: "button", onClick: handleSaveSectionEdit, className: "template-editor__section-save-btn", children: "Save" }), _jsx("button", { type: "button", onClick: handleCancelSectionEdit, className: "template-editor__section-cancel-btn", children: "Cancel" })] })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "template-editor__section-reorder", children: [_jsx("button", { type: "button", onClick: () => handleMoveSection(index, "up"), className: "template-editor__section-reorder-btn", disabled: index === 0, title: "Move up", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M18 15l-6-6-6 6" }) }) }), _jsx("button", { type: "button", onClick: () => handleMoveSection(index, "down"), className: "template-editor__section-reorder-btn", disabled: index === sortedSections.length - 1, title: "Move down", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M6 9l6 6 6-6" }) }) })] }), _jsx("button", { type: "button", onClick: () => toggleSectionExpanded(section.id), className: "template-editor__section-toggle", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", className: `template-editor__section-chevron ${expandedSections.has(section.id) ? "template-editor__section-chevron--expanded" : ""}`, children: _jsx("path", { d: "M6 9l6 6 6-6" }) }) }), _jsxs("div", { className: "template-editor__section-main", children: [_jsxs("div", { className: "template-editor__section-header", onClick: () => toggleSectionExpanded(section.id), children: [_jsx("span", { className: "template-editor__section-title", children: section.title }), _jsx("span", { className: "template-editor__section-preview", children: section.content.length > 80
446
+ }, placeholder: "Audience name...", className: "template-editor__audience-input", autoFocus: true }), _jsx("button", { type: "button", onClick: () => handleAddAudience(newAudienceLabel), className: "template-editor__audience-add-btn", children: "Add" })] })) : (_jsxs("button", { type: "button", onClick: () => setShowAudienceInput(true), className: "template-editor__add-audience-btn", children: [_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("path", { d: "M12 5v14M5 12h14", strokeWidth: "2" }) }), "Add Audience"] }))] }), availablePresets.length > 0 && (_jsxs("div", { className: "template-editor__audience-presets", children: [_jsx("span", { className: "template-editor__presets-label", children: "Quick add:" }), availablePresets.slice(0, 4).map((preset) => (_jsx("button", { type: "button", onClick: () => handleAddAudience(preset.label, preset.color), className: "template-editor__preset-btn", style: { color: preset.color }, children: preset.label }, preset.label)))] })), _jsx("textarea", { value: formData.summary, onChange: (e) => handleFieldChange("summary", e.target.value), onBlur: handleInfoBlur, className: "template-editor__summary", placeholder: "Brief summary of your product...", rows: 2 }), _jsxs("div", { style: {
447
+ display: "flex",
448
+ alignItems: "center",
449
+ gap: "8px",
450
+ marginTop: "8px",
451
+ }, children: [_jsx("label", { style: {
452
+ fontSize: "0.75rem",
453
+ fontWeight: 600,
454
+ textTransform: "uppercase",
455
+ letterSpacing: "0.05em",
456
+ color: "var(--rt-slate-500, #64748b)",
457
+ whiteSpace: "nowrap",
458
+ }, children: "Sort Weight" }), _jsx("input", { type: "number", value: globalState.weight ?? "", onChange: (e) => {
459
+ const val = e.target.value === "" ? null : parseInt(e.target.value, 10);
460
+ dispatch(setWeight({
461
+ weight: Number.isNaN(val) ? null : val,
462
+ lastModified: new Date().toISOString(),
463
+ }));
464
+ }, placeholder: "\u2014", style: {
465
+ width: "72px",
466
+ padding: "4px 8px",
467
+ fontSize: "0.8125rem",
468
+ border: "1px solid var(--rt-slate-200, #e2e8f0)",
469
+ borderRadius: "6px",
470
+ outline: "none",
471
+ textAlign: "center",
472
+ fontFamily: "var(--rt-font-mono, monospace)",
473
+ } }), _jsx("span", { style: {
474
+ fontSize: "0.6875rem",
475
+ color: "var(--rt-slate-400, #94a3b8)",
476
+ }, children: "Lower = higher priority" })] })] })] }), _jsxs("section", { className: "template-editor__card template-editor__card--full", children: [_jsxs("div", { className: "template-editor__card-header", children: [_jsx("div", { className: "template-editor__card-icon template-editor__card-icon--violet", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", children: _jsx("path", { d: "M4 6h16M4 12h16M4 18h10" }) }) }), _jsxs("div", { children: [_jsx("h3", { className: "template-editor__card-title", children: "Description" }), _jsx("p", { className: "template-editor__card-subtitle", children: "Detailed description of your product" })] })] }), _jsx(MarkdownEditor, { label: "", height: 350, value: formData.description, onChange: (value) => handleFieldChange("description", value), onBlur: handleInfoBlur })] }), _jsxs("section", { className: "template-editor__card template-editor__card--full", children: [_jsxs("div", { className: "template-editor__card-header", children: [_jsx("div", { className: "template-editor__card-icon template-editor__card-icon--indigo", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", children: _jsx("path", { d: "M4 6h16M4 10h16M4 14h10M4 18h6" }) }) }), _jsxs("div", { children: [_jsx("h3", { className: "template-editor__card-title", children: "Expandable Content Sections" }), _jsx("p", { className: "template-editor__card-subtitle", children: "Add long-form article content with expandable titles" })] })] }), _jsx("div", { className: "template-editor__sections-list", children: sortedSections.map((section, index) => (_jsx("div", { className: `template-editor__section-item ${editingSectionId === section.id ? "template-editor__section-item--editing" : ""}`, children: editingSectionId === section.id ? (_jsxs("div", { className: "template-editor__section-edit-form", children: [_jsx("input", { type: "text", value: editingSectionTitle, onChange: (e) => setEditingSectionTitle(e.target.value), className: "template-editor__section-edit-title", placeholder: "Section title", autoFocus: true }), _jsx("textarea", { value: editingSectionContent, onChange: (e) => setEditingSectionContent(e.target.value), className: "template-editor__section-edit-content", placeholder: "Section content...", rows: 6 }), _jsxs("div", { className: "template-editor__section-edit-actions", children: [_jsx("button", { type: "button", onClick: handleSaveSectionEdit, className: "template-editor__section-save-btn", children: "Save" }), _jsx("button", { type: "button", onClick: handleCancelSectionEdit, className: "template-editor__section-cancel-btn", children: "Cancel" })] })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "template-editor__section-reorder", children: [_jsx("button", { type: "button", onClick: () => handleMoveSection(index, "up"), className: "template-editor__section-reorder-btn", disabled: index === 0, title: "Move up", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M18 15l-6-6-6 6" }) }) }), _jsx("button", { type: "button", onClick: () => handleMoveSection(index, "down"), className: "template-editor__section-reorder-btn", disabled: index === sortedSections.length - 1, title: "Move down", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M6 9l6 6 6-6" }) }) })] }), _jsx("button", { type: "button", onClick: () => toggleSectionExpanded(section.id), className: "template-editor__section-toggle", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", className: `template-editor__section-chevron ${expandedSections.has(section.id) ? "template-editor__section-chevron--expanded" : ""}`, children: _jsx("path", { d: "M6 9l6 6 6-6" }) }) }), _jsxs("div", { className: "template-editor__section-main", children: [_jsxs("div", { className: "template-editor__section-header", onClick: () => toggleSectionExpanded(section.id), children: [_jsx("span", { className: "template-editor__section-title", children: section.title }), _jsx("span", { className: "template-editor__section-preview", children: section.content.length > 80
435
477
  ? `${section.content.substring(0, 80)}...`
436
478
  : section.content })] }), expandedSections.has(section.id) && (_jsx("div", { className: "template-editor__section-content", children: section.content }))] }), _jsxs("div", { className: "template-editor__section-actions", children: [_jsx("button", { type: "button", onClick: () => handleStartEditSection(section), className: "template-editor__section-action-btn", title: "Edit section", children: _jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" }), _jsx("path", { d: "M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" })] }) }), _jsx("button", { type: "button", onClick: () => handleDeleteContentSection(section.id), className: "template-editor__section-action-btn template-editor__section-action-btn--delete", title: "Delete section", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2" }) }) })] })] })) }, section.id))) }), _jsxs("div", { className: "template-editor__section-add-form", children: [_jsx("input", { type: "text", value: newSectionTitle, onChange: (e) => setNewSectionTitle(e.target.value), placeholder: "New section title...", className: "template-editor__section-new-title" }), _jsx("textarea", { value: newSectionContent, onChange: (e) => setNewSectionContent(e.target.value), placeholder: "Section content (long-form article content)...", className: "template-editor__section-new-content", rows: 4 }), (newSectionTitle || newSectionContent) && (_jsxs("button", { type: "button", onClick: handleAddContentSection, className: "template-editor__section-add-btn", disabled: !newSectionTitle.trim() || !newSectionContent.trim(), children: [_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("path", { d: "M12 5v14M5 12h14", strokeWidth: "2" }) }), "Add Section"] }))] })] }), _jsxs("section", { className: "template-editor__card template-editor__card--full", children: [_jsxs("div", { className: "template-editor__card-header", children: [_jsx("div", { className: "template-editor__card-icon template-editor__card-icon--sky", children: _jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("path", { d: "M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3" }), _jsx("path", { d: "M12 17h.01" })] }) }), _jsxs("div", { children: [_jsx("h3", { className: "template-editor__card-title", children: "Frequently Asked Questions" }), _jsx("p", { className: "template-editor__card-subtitle", children: "Common questions and answers about this product" })] })] }), _jsx("div", { className: "template-editor__faq-list", children: sortedFaqs.map((faq, index) => (_jsx("div", { className: `template-editor__faq-item ${editingFaqId === faq.id ? "template-editor__faq-item--editing" : ""}`, children: editingFaqId === faq.id ? (_jsxs("div", { className: "template-editor__faq-edit-form", children: [_jsx("input", { type: "text", value: editingFaqQuestion, onChange: (e) => setEditingFaqQuestion(e.target.value), className: "template-editor__faq-edit-question", placeholder: "Question", autoFocus: true }), _jsx("textarea", { value: editingFaqAnswer, onChange: (e) => setEditingFaqAnswer(e.target.value), className: "template-editor__faq-edit-answer", placeholder: "Answer", rows: 3 }), _jsxs("div", { className: "template-editor__faq-edit-actions", children: [_jsx("button", { type: "button", onClick: handleSaveFaqEdit, className: "template-editor__faq-save-btn", children: "Save" }), _jsx("button", { type: "button", onClick: handleCancelFaqEdit, className: "template-editor__faq-cancel-btn", children: "Cancel" })] })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "template-editor__faq-reorder", children: [_jsx("button", { type: "button", onClick: () => handleMoveFaq(index, "up"), className: "template-editor__faq-reorder-btn", disabled: index === 0, title: "Move up", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M18 15l-6-6-6 6" }) }) }), _jsx("button", { type: "button", onClick: () => handleMoveFaq(index, "down"), className: "template-editor__faq-reorder-btn", disabled: index === sortedFaqs.length - 1, title: "Move down", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M6 9l6 6 6-6" }) }) })] }), _jsx("div", { className: "template-editor__faq-number", children: index + 1 }), _jsxs("div", { className: "template-editor__faq-content", children: [_jsx("div", { className: "template-editor__faq-question", children: faq.question }), _jsx("div", { className: "template-editor__faq-answer", children: faq.answer })] }), _jsxs("div", { className: "template-editor__faq-actions", children: [_jsx("button", { type: "button", onClick: () => handleStartEditFaq(faq), className: "template-editor__faq-action-btn", title: "Edit FAQ", children: _jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" }), _jsx("path", { d: "M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" })] }) }), _jsx("button", { type: "button", onClick: () => handleDeleteFaq(faq.id), className: "template-editor__faq-action-btn template-editor__faq-action-btn--delete", title: "Delete FAQ", children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2" }) }) })] })] })) }, faq.id))) }), _jsxs("div", { className: "template-editor__faq-add-form", children: [_jsx("input", { type: "text", value: newFaqQuestion, onChange: (e) => setNewFaqQuestion(e.target.value), placeholder: "New question...", className: "template-editor__faq-new-question" }), _jsx("textarea", { value: newFaqAnswer, onChange: (e) => setNewFaqAnswer(e.target.value), placeholder: "Answer to the question...", className: "template-editor__faq-new-answer", rows: 2 }), (newFaqQuestion || newFaqAnswer) && (_jsxs("button", { type: "button", onClick: handleAddFaq, className: "template-editor__faq-add-btn", disabled: !newFaqQuestion.trim() || !newFaqAnswer.trim(), children: [_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: _jsx("path", { d: "M12 5v14M5 12h14", strokeWidth: "2" }) }), "Add FAQ"] }))] })] }), _jsxs("div", { className: "template-editor__section-divider", children: [_jsxs("div", { className: "template-editor__section-badge", children: [_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }), _jsx("path", { d: "M2 17l10 5 10-5" }), _jsx("path", { d: "M2 12l10 5 10-5" })] }), "Services Information"] }), _jsx("div", { className: "template-editor__section-divider-line" })] }), _jsxs("div", { className: "template-editor__grid", children: [_jsxs("section", { className: "template-editor__card", children: [_jsxs("div", { className: "template-editor__card-header", children: [_jsx("div", { className: "template-editor__card-icon template-editor__card-icon--emerald", children: _jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", children: [_jsx("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }), _jsx("path", { d: "M2 17l10 5 10-5" }), _jsx("path", { d: "M2 12l10 5 10-5" })] }) }), _jsxs("div", { children: [_jsx("h3", { className: "template-editor__card-title", children: "Formation & Setup" }), _jsx("p", { className: "template-editor__card-subtitle", children: "One-time setup services" })] }), _jsxs("button", { type: "button", onClick: () => setShowSetupTemplates(!showSetupTemplates), className: `template-editor__templates-toggle ${showSetupTemplates ? "template-editor__templates-toggle--active" : ""}`, children: [_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z" }) }), "Templates"] })] }), showSetupTemplates && (_jsx("div", { className: "template-editor__templates-panel", children: Object.entries(SETUP_SERVICE_TEMPLATES).map(([category, templates]) => (_jsxs("div", { className: "template-editor__template-category", children: [_jsx("span", { className: "template-editor__template-category-label", children: category }), _jsx("div", { className: "template-editor__template-items", children: templates.map((template) => {
437
479
  const isAdded = globalState.setupServices.includes(template.title);
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceTemplateSelector.d.ts","sourceRoot":"","sources":["../../../../editors/service-offering-editor/components/ResourceTemplateSelector.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,kEAAkE,CAAC;AAuF1E,UAAU,6BAA6B;IACrC,QAAQ,EAAE,uBAAuB,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;CACnD;AAED,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EACR,QAAQ,GACT,EAAE,6BAA6B,2CA0kB/B"}
1
+ {"version":3,"file":"ResourceTemplateSelector.d.ts","sourceRoot":"","sources":["../../../../editors/service-offering-editor/components/ResourceTemplateSelector.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,kEAAkE,CAAC;AAyF1E,UAAU,6BAA6B;IACrC,QAAQ,EAAE,uBAAuB,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;CACnD;AAED,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EACR,QAAQ,GACT,EAAE,6BAA6B,2CA0kB/B"}
@@ -48,6 +48,8 @@ function normalizeRemoteTemplate(remote) {
48
48
  optionGroups: [],
49
49
  faqFields: [],
50
50
  contentSections: [],
51
+ weight: null,
52
+ subtitle: null,
51
53
  },
52
54
  },
53
55
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceCatalog.d.ts","sourceRoot":"","sources":["../../../../editors/service-offering-editor/components/ServiceCatalog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EAMtB,MAAM,kEAAkE,CAAC;AAgH1E,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,uBAAuB,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;CACnD;AAED,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,mBAAmB,2CAokEzE"}
1
+ {"version":3,"file":"ServiceCatalog.d.ts","sourceRoot":"","sources":["../../../../editors/service-offering-editor/components/ServiceCatalog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EAMtB,MAAM,kEAAkE,CAAC;AAgH1E,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,uBAAuB,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;CACnD;AAED,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,mBAAmB,2CA8lEzE"}
@@ -724,11 +724,14 @@ export function ServiceCatalog({ document, dispatch }) {
724
724
  }), placeholder: "0", step: "0.1", min: "0", max: "100", className: "flex-1 py-1.5 px-2 pr-1 border-none text-sm text-slate-700 bg-transparent outline-none min-w-0 placeholder:text-slate-400", style: fontMono }), _jsx("span", { className: "px-3 py-2.5 pl-2 text-sm font-medium text-slate-400 bg-slate-50 whitespace-nowrap select-none", children: "%" })] })] })] })), effective !== null && discountPct > 0 && (_jsxs("div", { className: "flex items-center gap-2 mt-1.5 px-2.5 py-1.5 bg-emerald-50 rounded-md", children: [_jsx("span", { className: "text-[0.8125rem] text-emerald-600", children: "\u2192" }), _jsx("span", { className: "text-sm font-bold text-emerald-700", style: fontMono, children: formatPrice(effective, "USD") }), savingsPct > 0 && (_jsxs("span", { className: "ml-auto text-[0.6875rem] font-bold text-emerald-600 bg-emerald-100 px-2 py-0.5 rounded-full", style: fontMono, children: [savingsPct, "% off"] }))] }))] }, cycle));
725
725
  }) })] }))] })), editGroupType === "setup" && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx("span", { className: "text-[0.6875rem] font-semibold uppercase tracking-[0.05em] text-slate-500", children: "One-time Fee" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm text-slate-500", children: "$" }), _jsx("input", { type: "number", value: editGroupPrice, onChange: (e) => setEditGroupPrice(e.target.value), placeholder: "0", className: "flex-1 px-2.5 py-2 text-sm text-slate-800 bg-white border-[1.5px] border-slate-200 rounded-md focus:outline-none focus:border-violet-500 focus:shadow-[0_0_0_2px_rgb(237,233,254)]", style: fontSans, step: "0.01" })] })] }), tiers.length > 0 && parseFloat(editGroupPrice) > 0 && (_jsxs("div", { className: "flex flex-col gap-2.5", children: [_jsx("span", { className: "text-[0.6875rem] font-semibold uppercase tracking-[0.05em] text-slate-500", children: "Setup Fee Discounts by Tier & Billing Cycle" }), _jsx("div", { className: "flex gap-0 border-b border-slate-200 mb-3 overflow-x-auto", children: tiers.map((tier) => (_jsxs("button", { onClick: () => setEditTierTab(tier.id), className: `flex items-center gap-1.5 px-3 py-2 text-xs font-medium bg-none border-none border-b-2 cursor-pointer whitespace-nowrap transition-all duration-150 ${editTierTab === tier.id
726
726
  ? "text-violet-700 border-b-violet-600 font-semibold"
727
- : "text-slate-500 border-b-transparent hover:text-slate-700 hover:bg-slate-50"} ${tier.isCustomPricing ? "italic" : ""}`, style: fontSans, children: [tier.name, tier.isCustomPricing && (_jsx("span", { className: "text-[0.5625rem] font-semibold uppercase tracking-[0.04em] text-amber-600 bg-amber-50 px-[5px] py-px rounded-full", children: "Custom" }))] }, tier.id))) }), editTierTab &&
727
+ : "text-slate-500 border-b-transparent hover:text-slate-700 hover:bg-slate-50"} ${tier.isCustomPricing ? "italic" : ""}`, style: fontSans, children: [tier.name, tier.excludeFromSetupFee && (_jsx("span", { className: "text-[0.5625rem] font-semibold uppercase tracking-[0.04em] text-teal-600 bg-teal-50 px-[5px] py-px rounded-full", children: "No Fee" })), tier.isCustomPricing && (_jsx("span", { className: "text-[0.5625rem] font-semibold uppercase tracking-[0.04em] text-amber-600 bg-amber-50 px-[5px] py-px rounded-full", children: "Custom" }))] }, tier.id))) }), editTierTab &&
728
728
  (() => {
729
729
  const activeTier = tiers.find((t) => t.id === editTierTab);
730
730
  if (!activeTier)
731
731
  return null;
732
+ if (activeTier.excludeFromSetupFee) {
733
+ return (_jsxs("div", { className: "flex items-center gap-2 p-3 bg-teal-50 border border-dashed border-teal-300 rounded-md text-xs text-teal-700 italic", children: [_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", width: "16", height: "16", children: _jsx("path", { d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), _jsx("span", { children: "No setup fee \u2014 this tier is excluded from setup fees." })] }));
734
+ }
732
735
  if (activeTier.isCustomPricing) {
733
736
  return (_jsxs("div", { className: "flex items-center gap-2 p-3 bg-slate-50 border border-dashed border-slate-300 rounded-md text-xs text-slate-500 italic", children: [_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", width: "16", height: "16", children: _jsx("path", { d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), _jsx("span", { children: "Custom pricing tier \u2014 discounts negotiated per customer." })] }));
734
737
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TheMatrix.d.ts","sourceRoot":"","sources":["../../../../editors/service-offering-editor/components/TheMatrix.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAS3B,MAAM,kEAAkE,CAAC;AA2B1E,UAAU,cAAc;IACtB,QAAQ,EAAE,uBAAuB,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;CACnD;AAgDD,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,cAAc,2CAi8E/D"}
1
+ {"version":3,"file":"TheMatrix.d.ts","sourceRoot":"","sources":["../../../../editors/service-offering-editor/components/TheMatrix.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAS3B,MAAM,kEAAkE,CAAC;AA2B1E,UAAU,cAAc;IACtB,QAAQ,EAAE,uBAAuB,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;CACnD;AAgDD,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,cAAc,2CAq8E/D"}
@@ -867,7 +867,9 @@ export function TheMatrix({ document, dispatch }) {
867
867
  }
868
868
  : {}),
869
869
  }, children: idx === selectedTierIdx
870
- ? `${formatPrice(ab.setupCost, ab.setupCostCurrency || "USD")} one-time`
870
+ ? tier.excludeFromSetupFee
871
+ ? "No setup fee"
872
+ : `${formatPrice(ab.setupCost, ab.setupCostCurrency || "USD")} one-time`
871
873
  : null }, tier.id)))] }, `addon-setup-${ab.optionGroupId}`))), (() => {
872
874
  const setupBds = tierBreakdowns[selectedTierIdx]?.setupGroupBreakdowns ?? [];
873
875
  const totalSetupBase = setupBds.reduce((sum, s) => sum +
@@ -885,9 +887,11 @@ export function TheMatrix({ document, dispatch }) {
885
887
  }
886
888
  : {}),
887
889
  }, children: idx === selectedTierIdx
888
- ? hasDiscount
889
- ? `${formatPrice(totalSetupEffective, "USD")} one-time`
890
- : `${formatPrice(totalSetupBase, "USD")} one-time`
890
+ ? tier.excludeFromSetupFee
891
+ ? "No setup fee"
892
+ : hasDiscount
893
+ ? `${formatPrice(totalSetupEffective, "USD")} one-time`
894
+ : `${formatPrice(totalSetupBase, "USD")} one-time`
891
895
  : null }, tier.id)))] }));
892
896
  })()] }) }) })] }), selectedCell && (_jsx(ServiceLevelDetailPanel, { serviceId: selectedCell.serviceId, tierId: selectedCell.tierId, services: services, tiers: tiers, optionGroups: optionGroups, dispatch: dispatch, onClose: () => setSelectedCell(null) })), addServiceModal && (_jsx("div", { className: "fixed inset-0 bg-slate-900/75 backdrop-blur-sm flex items-center justify-center z-[100]", style: { animation: "modal-backdrop 0.2s ease-out" }, children: _jsxs("div", { className: "bg-white rounded-xl p-6 max-h-[85vh] overflow-y-auto", style: {
893
897
  width: "min(32rem, calc(100vw - 2rem))",
@@ -1129,7 +1133,7 @@ function ServiceGroupSection({ group, services, tiers, isSetupFormation, isOptio
1129
1133
  }
1130
1134
  const curr = group.currency || "USD";
1131
1135
  const hasDiscount = effectivePrice !== basePrice;
1132
- return (_jsxs("tr", { className: "bg-slate-50 [&>td]:py-2.5 [&>td]:px-4 [&>td]:font-semibold [&>td]:text-slate-700 [&>td]:border-b [&>td]:border-slate-200 [&>td:first-child]:sticky [&>td:first-child]:left-0 [&>td:first-child]:z-10 [&>td:first-child]:bg-slate-50", children: [_jsx("td", { children: "TOTAL SETUP FEE" }), _jsx("td", { colSpan: tiers.length, style: { textAlign: "center" }, children: hasDiscount ? (_jsxs(_Fragment, { children: [_jsx("span", { style: {
1136
+ return (_jsxs("tr", { className: "bg-slate-50 [&>td]:py-2.5 [&>td]:px-4 [&>td]:font-semibold [&>td]:text-slate-700 [&>td]:border-b [&>td]:border-slate-200 [&>td:first-child]:sticky [&>td:first-child]:left-0 [&>td:first-child]:z-10 [&>td:first-child]:bg-slate-50", children: [_jsx("td", { children: "TOTAL SETUP FEE" }), _jsx("td", { colSpan: tiers.length, style: { textAlign: "center" }, children: selectedTier?.excludeFromSetupFee ? (_jsx("span", { className: "text-slate-400 italic", children: "No setup fee for this tier" })) : hasDiscount ? (_jsxs(_Fragment, { children: [_jsx("span", { style: {
1133
1137
  textDecoration: "line-through",
1134
1138
  opacity: 0.5,
1135
1139
  marginRight: 6,
@@ -1 +1 @@
1
- {"version":3,"file":"TierDefinition.d.ts","sourceRoot":"","sources":["../../../../editors/service-offering-editor/components/TierDefinition.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EAItB,MAAM,kEAAkE,CAAC;AAW1E,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,uBAAuB,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;CACnD;AA6ED,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,mBAAmB,2CA0WzE"}
1
+ {"version":3,"file":"TierDefinition.d.ts","sourceRoot":"","sources":["../../../../editors/service-offering-editor/components/TierDefinition.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EAItB,MAAM,kEAAkE,CAAC;AAY1E,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,uBAAuB,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;CACnD;AA6ED,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,mBAAmB,2CAiYzE"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { memo, useMemo, useState, useCallback } from "react";
3
3
  import { generateId } from "document-model/core";
4
- import { addTier, updateTier, deleteTier, setAvailableBillingCycles, } from "../../../document-models/service-offering/v1/gen/creators.js";
4
+ import { addTier, updateTier, deleteTier, setAvailableBillingCycles, reorderTiers, } from "../../../document-models/service-offering/v1/gen/creators.js";
5
5
  import { calculateTierRecurringPrice, formatPrice } from "./pricing-utils.js";
6
6
  import { InfoIcon } from "./InfoIcon.js";
7
7
  import { ConfirmDialog } from "./ConfirmDialog.js";
@@ -119,6 +119,20 @@ export function TierDefinition({ document, dispatch }) {
119
119
  }));
120
120
  });
121
121
  };
122
+ const handleMoveTier = useCallback((tierIndex, direction) => {
123
+ const newIndex = direction === "left" ? tierIndex - 1 : tierIndex + 1;
124
+ if (newIndex < 0 || newIndex >= tiers.length)
125
+ return;
126
+ const reordered = tiers.map((t) => t.id);
127
+ [reordered[tierIndex], reordered[newIndex]] = [
128
+ reordered[newIndex],
129
+ reordered[tierIndex],
130
+ ];
131
+ dispatch(reorderTiers({
132
+ tierIds: reordered,
133
+ lastModified: new Date().toISOString(),
134
+ }));
135
+ }, [tiers, dispatch]);
122
136
  const getTierAccent = (index) => TIER_ACCENTS[index % TIER_ACCENTS.length];
123
137
  return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-col gap-6", children: [tiers.length === 0 && (_jsxs("div", { className: "rounded-xl p-6 mb-6 border border-violet-100", style: {
124
138
  background: "linear-gradient(135deg, rgb(245 243 255) 0%, rgb(240 249 255) 100%)",
@@ -149,7 +163,7 @@ export function TierDefinition({ document, dispatch }) {
149
163
  lastModified: new Date().toISOString(),
150
164
  }));
151
165
  }, children: opt.label }, opt.value));
152
- }) }), (state.global.availableBillingCycles ?? []).length === 0 && (_jsx("div", { className: "text-[0.6875rem] text-rose-600 py-1.5 px-2.5 bg-rose-50 rounded-md mt-2", children: "Select at least one billing cycle to enable pricing" }))] }), _jsxs("div", { className: "so-scrollbar-h flex flex-nowrap gap-6 overflow-x-auto overflow-y-visible pb-4", style: { scrollBehavior: "smooth", WebkitOverflowScrolling: "touch" }, children: [tiers.map((tier, index) => (_jsx(TierCard, { tier: tier, accent: getTierAccent(index), dispatch: dispatch, onDelete: () => handleDeleteTier(tier.id), isRecommended: tier.mostPopular, regularGroups: regularGroups }, tier.id))), isAddingTier ? (_jsxs("div", { className: "w-80 bg-white border-2 border-violet-200 rounded-xl p-6", style: { animation: "tier-slide-up 0.2s ease-out" }, children: [_jsx("h3", { className: "text-base font-bold text-slate-900 mb-5", style: { fontFamily: fontSans }, children: "New Subscription Tier" }), _jsxs("div", { className: "mb-4", children: [_jsx("label", { className: "block text-[0.625rem] font-medium uppercase tracking-widest text-slate-500 mb-1.5", style: { fontFamily: fontMono }, children: "Tier Name" }), _jsx("input", { type: "text", value: newTier.name, onChange: (e) => setNewTier({ ...newTier, name: e.target.value }), placeholder: "e.g., Basic, Professional", className: "w-full text-base font-semibold text-slate-900 bg-white border border-slate-200 rounded-[10px] py-2.5 px-3.5 outline-none transition-all duration-150 focus:border-violet-400 focus:shadow-[0_0_0_3px_rgb(237_233_254)] placeholder:font-normal placeholder:text-slate-400", style: { fontFamily: fontSans }, autoFocus: true })] }), _jsxs("label", { className: "flex items-center gap-2.5 mb-4 cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: newTier.isCustomPricing, onChange: (e) => setNewTier({
166
+ }) }), (state.global.availableBillingCycles ?? []).length === 0 && (_jsx("div", { className: "text-[0.6875rem] text-rose-600 py-1.5 px-2.5 bg-rose-50 rounded-md mt-2", children: "Select at least one billing cycle to enable pricing" }))] }), _jsxs("div", { className: "so-scrollbar-h flex flex-nowrap gap-6 overflow-x-auto overflow-y-visible pb-4", style: { scrollBehavior: "smooth", WebkitOverflowScrolling: "touch" }, children: [tiers.map((tier, index) => (_jsx(TierCard, { tier: tier, accent: getTierAccent(index), dispatch: dispatch, onDelete: () => handleDeleteTier(tier.id), isRecommended: tier.mostPopular, regularGroups: regularGroups, onMoveLeft: () => handleMoveTier(index, "left"), onMoveRight: () => handleMoveTier(index, "right"), isFirst: index === 0, isLast: index === tiers.length - 1 }, tier.id))), isAddingTier ? (_jsxs("div", { className: "w-80 bg-white border-2 border-violet-200 rounded-xl p-6", style: { animation: "tier-slide-up 0.2s ease-out" }, children: [_jsx("h3", { className: "text-base font-bold text-slate-900 mb-5", style: { fontFamily: fontSans }, children: "New Subscription Tier" }), _jsxs("div", { className: "mb-4", children: [_jsx("label", { className: "block text-[0.625rem] font-medium uppercase tracking-widest text-slate-500 mb-1.5", style: { fontFamily: fontMono }, children: "Tier Name" }), _jsx("input", { type: "text", value: newTier.name, onChange: (e) => setNewTier({ ...newTier, name: e.target.value }), placeholder: "e.g., Basic, Professional", className: "w-full text-base font-semibold text-slate-900 bg-white border border-slate-200 rounded-[10px] py-2.5 px-3.5 outline-none transition-all duration-150 focus:border-violet-400 focus:shadow-[0_0_0_3px_rgb(237_233_254)] placeholder:font-normal placeholder:text-slate-400", style: { fontFamily: fontSans }, autoFocus: true })] }), _jsxs("label", { className: "flex items-center gap-2.5 mb-4 cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: newTier.isCustomPricing, onChange: (e) => setNewTier({
153
167
  ...newTier,
154
168
  isCustomPricing: e.target.checked,
155
169
  }), className: "w-[1.125rem] h-[1.125rem] cursor-pointer", style: { accentColor: "#f59e0b" } }), _jsx("span", { className: "text-[0.8125rem] text-slate-600", children: "Custom Pricing (price varies per client)" })] }), _jsxs("div", { className: "flex gap-2.5 mt-5", children: [_jsx("button", { onClick: handleAddTier, disabled: !newTier.name.trim(), className: "flex-1 py-2.5 px-4 text-sm font-semibold rounded-[10px] cursor-pointer transition-all duration-150 bg-violet-600 text-white border-none hover:enabled:bg-violet-700 disabled:bg-slate-200 disabled:text-slate-400 disabled:cursor-not-allowed", style: { fontFamily: fontSans }, children: "Create Tier" }), _jsx("button", { onClick: () => {
@@ -161,7 +175,7 @@ export function TierDefinition({ document, dispatch }) {
161
175
  });
162
176
  }, className: "flex-1 py-2.5 px-4 text-sm font-semibold rounded-[10px] cursor-pointer transition-all duration-150 bg-slate-100 text-slate-700 border-none hover:bg-slate-200", style: { fontFamily: fontSans }, children: "Cancel" })] })] })) : (_jsxs("button", { onClick: () => setIsAddingTier(true), className: "group w-80 min-h-[280px] bg-white border-2 border-dashed border-slate-200 rounded-xl flex flex-col items-center justify-center gap-3 cursor-pointer transition-all duration-200 hover:border-violet-300 hover:bg-violet-50", children: [_jsx("div", { className: "w-14 h-14 rounded-full bg-slate-100 flex items-center justify-center transition-all duration-200 group-hover:bg-violet-100", children: _jsx("svg", { className: "w-6 h-6 text-slate-400 transition-all duration-150 group-hover:text-violet-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 4v16m8-8H4" }) }) }), _jsx("span", { className: "text-[0.9375rem] font-semibold text-slate-500 transition-all duration-150 group-hover:text-violet-600", style: { fontFamily: fontSans }, children: "Add Subscription Tier" })] }))] }), _jsxs("div", { className: "flex items-start gap-3.5 p-4 px-5 bg-amber-50 border border-amber-200 rounded-xl", children: [_jsx("svg", { className: "shrink-0 w-5 h-5 text-amber-600 mt-0.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), _jsxs("div", { className: "flex-1", children: [_jsx("p", { className: "text-sm font-semibold text-amber-800 mb-1", style: { fontFamily: fontSans }, children: "Pricing is managed at the option group level" }), _jsx("p", { className: "text-[0.8125rem] text-amber-700 leading-relaxed", children: "Billing cycles and pricing are configured per option group in the Service Catalog. Setup fees, recurring prices, and billing cycles apply to all tiers within each group." })] })] })] }), pendingDeleteTierId && (_jsx(ConfirmDialog, { title: "Delete this tier?", message: "This will remove the tier and all its pricing configuration. This action cannot be undone.", confirmLabel: "Delete Tier", variant: "danger", onConfirm: confirmDeleteTier, onCancel: () => setPendingDeleteTierId(null) }))] }));
163
177
  }
164
- const TierCard = memo(function TierCard({ tier, accent, dispatch, onDelete, isRecommended, regularGroups, }) {
178
+ const TierCard = memo(function TierCard({ tier, accent, dispatch, onDelete, isRecommended, regularGroups, onMoveLeft, onMoveRight, isFirst, isLast, }) {
165
179
  const [localName, setLocalName] = useState(tier.name);
166
180
  const [localDescription, setLocalDescription] = useState(tier.description || "");
167
181
  const isCustomPricing = tier.isCustomPricing ?? false;
@@ -204,7 +218,13 @@ const TierCard = memo(function TierCard({ tier, accent, dispatch, onDelete, isRe
204
218
  mostPopular: true,
205
219
  lastModified: new Date().toISOString(),
206
220
  }));
207
- }, children: [_jsx("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" }) }), "Set as Popular"] })), _jsx("div", { className: "h-1 w-full", style: { background: accent.color } }), _jsxs("div", { className: "so-scrollbar-v p-6 overflow-y-auto flex-1", children: [_jsxs("div", { className: "flex items-start justify-between mb-5", children: [_jsxs("div", { className: "flex-1", children: [_jsx("span", { className: "block text-[0.625rem] font-medium uppercase tracking-widest text-slate-400 mb-1.5", style: { fontFamily: fontMono }, children: "Tier Name" }), _jsx("input", { type: "text", value: localName, onChange: (e) => setLocalName(e.target.value), onBlur: handleNameBlur, className: "w-full text-[1.375rem] font-bold text-slate-900 bg-transparent border-none border-b-2 border-b-transparent pb-1 pl-0 transition-all duration-150 outline-none hover:border-b-slate-200 focus:border-b-violet-500", style: { fontFamily: fontSans } })] }), _jsx("button", { onClick: onDelete, className: "p-1.5 text-slate-400 bg-transparent border-none rounded-md cursor-pointer transition-all duration-150 hover:text-rose-500 hover:bg-rose-50", children: _jsx("svg", { width: "20", height: "20", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })] }), isCustomPricing && (_jsxs("div", { className: "flex items-center gap-2 py-3 px-4 bg-amber-50 border border-amber-200 rounded-[10px] mb-4", children: [_jsx("svg", { className: "w-5 h-5 text-amber-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), _jsxs("div", { className: "flex-1", children: [_jsx("span", { className: "block text-[0.8125rem] font-semibold text-amber-800", children: "Custom Pricing" }), _jsx("span", { className: "text-[0.6875rem] text-amber-600", children: "Price varies per client" })] })] })), !isCustomPricing && (_jsxs("div", { className: "mb-4", children: [_jsx("div", { className: "mb-1.5", children: _jsxs("span", { className: "block text-[0.625rem] font-medium uppercase tracking-widest text-slate-400 mb-1.5", style: { fontFamily: fontMono }, children: ["Recurring Price", _jsx(InfoIcon, { content: "This price is automatically calculated from the services and pricing configured in the Service Catalog. It is read-only \u2014 to change it, adjust pricing in your option groups." })] }) }), _jsxs("div", { className: "flex items-center gap-2 py-3.5 px-4 bg-slate-50 rounded-[10px] border border-slate-100", children: [_jsx("span", { children: "$" }), _jsx("span", { className: "text-[1.375rem] font-semibold text-emerald-700", style: { fontFamily: fontMono }, children: formatPrice(calculatedPrice.monthlyTotal).replace("$", "") }), _jsx("span", { className: "text-sm text-emerald-600 font-medium", children: "/mo" })] }), calculatedPrice.groupBreakdown.length > 0 && (_jsxs("div", { className: "mt-2 py-2 px-2.5 bg-slate-50 rounded-md border border-slate-100", children: [_jsxs("span", { className: "block text-[0.625rem] font-medium text-slate-500 uppercase tracking-wide mb-1.5", children: ["Sum of ", calculatedPrice.groupBreakdown.length, " service group", calculatedPrice.groupBreakdown.length !== 1 ? "s" : ""] }), calculatedPrice.groupBreakdown.map((g) => (_jsxs("div", { className: "flex items-center justify-between py-[0.1875rem]", children: [_jsxs("span", { className: `flex items-center gap-1 text-xs ${g.hasPrice ? "text-slate-600" : "text-amber-600"}`, children: [!g.hasPrice && (_jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", className: "w-3 h-3 text-amber-500", children: _jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" }) })), g.groupName] }), _jsx("span", { className: `text-xs font-medium ${g.hasPrice ? "text-slate-700" : "text-amber-500 italic"}`, style: { fontFamily: fontMono }, children: g.hasPrice ? formatPrice(g.monthlyAmount) : "$0" })] }, g.groupId)))] })), calculatedPrice.missingPriceGroups.length > 0 && (_jsxs("div", { className: "flex items-center gap-1.5 mt-2 py-1.5 px-2 text-[0.6875rem] text-amber-700 bg-amber-50 border border-amber-200 rounded-md", children: [_jsx("svg", { className: "shrink-0 w-3.5 h-3.5 text-amber-500", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }), _jsxs("span", { children: [calculatedPrice.missingPriceGroups.length, " group", calculatedPrice.missingPriceGroups.length !== 1
221
+ }, children: [_jsx("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" }) }), "Set as Popular"] })), _jsx("div", { className: "h-1 w-full", style: { background: accent.color } }), _jsxs("div", { className: "so-scrollbar-v p-6 overflow-y-auto flex-1", children: [_jsxs("div", { className: "flex items-start justify-between mb-5", children: [_jsxs("div", { className: "flex-1", children: [_jsx("span", { className: "block text-[0.625rem] font-medium uppercase tracking-widest text-slate-400 mb-1.5", style: { fontFamily: fontMono }, children: "Tier Name" }), _jsx("input", { type: "text", value: localName, onChange: (e) => setLocalName(e.target.value), onBlur: handleNameBlur, className: "w-full text-[1.375rem] font-bold text-slate-900 bg-transparent border-none border-b-2 border-b-transparent pb-1 pl-0 transition-all duration-150 outline-none hover:border-b-slate-200 focus:border-b-violet-500", style: { fontFamily: fontSans } })] }), _jsx("button", { onClick: onDelete, className: "p-1.5 text-slate-400 bg-transparent border-none rounded-md cursor-pointer transition-all duration-150 hover:text-rose-500 hover:bg-rose-50", children: _jsx("svg", { width: "20", height: "20", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })] }), isCustomPricing && (_jsxs("div", { className: "flex items-center gap-2 py-3 px-4 bg-amber-50 border border-amber-200 rounded-[10px] mb-4", children: [_jsx("svg", { className: "w-5 h-5 text-amber-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), _jsxs("div", { className: "flex-1", children: [_jsx("span", { className: "block text-[0.8125rem] font-semibold text-amber-800", children: "Custom Pricing" }), _jsx("span", { className: "text-[0.6875rem] text-amber-600", children: "Price varies per client" })] })] })), _jsxs("label", { className: "flex items-center gap-2.5 mb-4 cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: tier.excludeFromSetupFee ?? false, onChange: (e) => {
222
+ dispatch(updateTier({
223
+ id: tier.id,
224
+ excludeFromSetupFee: e.target.checked,
225
+ lastModified: new Date().toISOString(),
226
+ }));
227
+ }, className: "w-[1.125rem] h-[1.125rem] cursor-pointer", style: { accentColor: "#0d9488" } }), _jsx("span", { className: "text-[0.8125rem] text-slate-600", children: "Exclude from setup fee" })] }), !isCustomPricing && (_jsxs("div", { className: "mb-4", children: [_jsx("div", { className: "mb-1.5", children: _jsxs("span", { className: "block text-[0.625rem] font-medium uppercase tracking-widest text-slate-400 mb-1.5", style: { fontFamily: fontMono }, children: ["Recurring Price", _jsx(InfoIcon, { content: "This price is automatically calculated from the services and pricing configured in the Service Catalog. It is read-only \u2014 to change it, adjust pricing in your option groups." })] }) }), _jsxs("div", { className: "flex items-center gap-2 py-3.5 px-4 bg-slate-50 rounded-[10px] border border-slate-100", children: [_jsx("span", { children: "$" }), _jsx("span", { className: "text-[1.375rem] font-semibold text-emerald-700", style: { fontFamily: fontMono }, children: formatPrice(calculatedPrice.monthlyTotal).replace("$", "") }), _jsx("span", { className: "text-sm text-emerald-600 font-medium", children: "/mo" })] }), calculatedPrice.groupBreakdown.length > 0 && (_jsxs("div", { className: "mt-2 py-2 px-2.5 bg-slate-50 rounded-md border border-slate-100", children: [_jsxs("span", { className: "block text-[0.625rem] font-medium text-slate-500 uppercase tracking-wide mb-1.5", children: ["Sum of ", calculatedPrice.groupBreakdown.length, " service group", calculatedPrice.groupBreakdown.length !== 1 ? "s" : ""] }), calculatedPrice.groupBreakdown.map((g) => (_jsxs("div", { className: "flex items-center justify-between py-[0.1875rem]", children: [_jsxs("span", { className: `flex items-center gap-1 text-xs ${g.hasPrice ? "text-slate-600" : "text-amber-600"}`, children: [!g.hasPrice && (_jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", className: "w-3 h-3 text-amber-500", children: _jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" }) })), g.groupName] }), _jsx("span", { className: `text-xs font-medium ${g.hasPrice ? "text-slate-700" : "text-amber-500 italic"}`, style: { fontFamily: fontMono }, children: g.hasPrice ? formatPrice(g.monthlyAmount) : "$0" })] }, g.groupId)))] })), calculatedPrice.missingPriceGroups.length > 0 && (_jsxs("div", { className: "flex items-center gap-1.5 mt-2 py-1.5 px-2 text-[0.6875rem] text-amber-700 bg-amber-50 border border-amber-200 rounded-md", children: [_jsx("svg", { className: "shrink-0 w-3.5 h-3.5 text-amber-500", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }), _jsxs("span", { children: [calculatedPrice.missingPriceGroups.length, " group", calculatedPrice.missingPriceGroups.length !== 1
208
228
  ? "s"
209
- : "", " ", "without pricing (counted as $0)"] })] }))] })), _jsxs("div", { className: "mt-4", children: [_jsx("span", { className: "block text-[0.625rem] font-medium uppercase tracking-widest text-slate-400 mb-1.5", style: { fontFamily: fontMono }, children: "Description" }), _jsx("textarea", { value: localDescription, onChange: (e) => setLocalDescription(e.target.value), onBlur: handleDescriptionBlur, placeholder: "Add a description...", rows: 2, className: "w-full text-[0.8125rem] text-slate-600 bg-slate-50 border border-slate-200 rounded-[10px] p-3 resize-none outline-none transition-all duration-150 focus:border-violet-400 focus:shadow-[0_0_0_3px_rgb(237_233_254)] placeholder:text-slate-400", style: { fontFamily: fontSans } })] })] }), _jsxs("div", { className: "flex items-center gap-2 py-4 px-6 bg-slate-50 border-t border-slate-100", children: [_jsx("svg", { className: "w-4 h-4 text-slate-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), _jsx("span", { className: "text-xs text-slate-500", children: "Configure service levels in the Matrix view" })] })] }));
229
+ : "", " ", "without pricing (counted as $0)"] })] }))] })), _jsxs("div", { className: "mt-4", children: [_jsx("span", { className: "block text-[0.625rem] font-medium uppercase tracking-widest text-slate-400 mb-1.5", style: { fontFamily: fontMono }, children: "Description" }), _jsx("textarea", { value: localDescription, onChange: (e) => setLocalDescription(e.target.value), onBlur: handleDescriptionBlur, placeholder: "Add a description...", rows: 2, className: "w-full text-[0.8125rem] text-slate-600 bg-slate-50 border border-slate-200 rounded-[10px] p-3 resize-none outline-none transition-all duration-150 focus:border-violet-400 focus:shadow-[0_0_0_3px_rgb(237_233_254)] placeholder:text-slate-400", style: { fontFamily: fontSans } })] })] }), _jsxs("div", { className: "flex items-center justify-between py-3 px-6 bg-slate-50 border-t border-slate-100", children: [_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { onClick: onMoveLeft, disabled: isFirst, className: "p-1.5 rounded-md border-none cursor-pointer transition-all duration-150 bg-transparent text-slate-400 hover:enabled:text-violet-600 hover:enabled:bg-violet-50 disabled:opacity-30 disabled:cursor-not-allowed", title: "Move left", children: _jsx("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }) }), _jsx("button", { onClick: onMoveRight, disabled: isLast, className: "p-1.5 rounded-md border-none cursor-pointer transition-all duration-150 bg-transparent text-slate-400 hover:enabled:text-violet-600 hover:enabled:bg-violet-50 disabled:opacity-30 disabled:cursor-not-allowed", title: "Move right", children: _jsx("svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) }) })] }), _jsx("span", { className: "text-[0.6875rem] text-slate-400", children: "Matrix view for service levels" })] })] }));
210
230
  });
package/dist/style.css CHANGED
@@ -30,8 +30,12 @@
30
30
  --color-emerald-600: oklch(59.6% 0.145 163.225);
31
31
  --color-emerald-700: oklch(50.8% 0.118 165.612);
32
32
  --color-emerald-800: oklch(43.2% 0.095 166.913);
33
+ --color-teal-50: oklch(98.4% 0.014 180.72);
33
34
  --color-teal-100: oklch(95.3% 0.051 180.801);
35
+ --color-teal-300: oklch(85.5% 0.138 181.071);
34
36
  --color-teal-500: oklch(70.4% 0.14 182.503);
37
+ --color-teal-600: oklch(60% 0.118 184.704);
38
+ --color-teal-700: oklch(51.1% 0.096 186.391);
35
39
  --color-sky-50: oklch(97.7% 0.013 236.62);
36
40
  --color-sky-100: oklch(95.1% 0.026 236.824);
37
41
  --color-sky-200: oklch(90.1% 0.058 230.902);
@@ -1126,6 +1130,9 @@
1126
1130
  .border-slate-400 {
1127
1131
  border-color: var(--color-slate-400);
1128
1132
  }
1133
+ .border-teal-300 {
1134
+ border-color: var(--color-teal-300);
1135
+ }
1129
1136
  .border-teal-500 {
1130
1137
  border-color: var(--color-teal-500);
1131
1138
  }
@@ -1309,6 +1316,9 @@
1309
1316
  background-color: color-mix(in oklab, var(--color-slate-900) 75%, transparent);
1310
1317
  }
1311
1318
  }
1319
+ .bg-teal-50 {
1320
+ background-color: var(--color-teal-50);
1321
+ }
1312
1322
  .bg-teal-100 {
1313
1323
  background-color: var(--color-teal-100);
1314
1324
  }
@@ -1862,6 +1872,12 @@
1862
1872
  .text-teal-500 {
1863
1873
  color: var(--color-teal-500);
1864
1874
  }
1875
+ .text-teal-600 {
1876
+ color: var(--color-teal-600);
1877
+ }
1878
+ .text-teal-700 {
1879
+ color: var(--color-teal-700);
1880
+ }
1865
1881
  .text-violet-500 {
1866
1882
  color: var(--color-violet-500);
1867
1883
  }
@@ -2845,6 +2861,15 @@
2845
2861
  }
2846
2862
  }
2847
2863
  }
2864
+ .hover\:enabled\:bg-violet-50 {
2865
+ &:hover {
2866
+ @media (hover: hover) {
2867
+ &:enabled {
2868
+ background-color: var(--color-violet-50);
2869
+ }
2870
+ }
2871
+ }
2872
+ }
2848
2873
  .hover\:enabled\:bg-violet-100 {
2849
2874
  &:hover {
2850
2875
  @media (hover: hover) {
@@ -503,6 +503,8 @@ function mapResourceTemplateState(state, doc) {
503
503
  content: section.content,
504
504
  displayOrder: section.displayOrder,
505
505
  })),
506
+ weight: state.weight ?? null,
507
+ subtitle: state.subtitle || null,
506
508
  };
507
509
  }
508
510
  /**
@@ -588,6 +590,8 @@ function mapServiceOfferingState(state, doc) {
588
590
  name: tier.name,
589
591
  description: tier.description || null,
590
592
  isCustomPricing: tier.isCustomPricing,
593
+ mostPopular: tier.mostPopular,
594
+ excludeFromSetupFee: tier.excludeFromSetupFee ?? false,
591
595
  pricingMode: tier.pricingMode || null,
592
596
  pricing: {
593
597
  amount: tier.pricing?.amount ?? null,
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../subgraphs/resources-services/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,MAAM,EAAE,YAsVpB,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../subgraphs/resources-services/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,MAAM,EAAE,YA0VpB,CAAC"}
@@ -83,6 +83,8 @@ export const schema = gql `
83
83
  optionGroups: [RSOptionGroup!]!
84
84
  faqFields: [RSFaqField!]
85
85
  contentSections: [RSContentSection!]!
86
+ weight: Int
87
+ subtitle: String
86
88
  }
87
89
 
88
90
  enum RSTemplateStatus {
@@ -241,9 +243,11 @@ export const schema = gql `
241
243
  pricingMode: RSTierPricingMode
242
244
  pricing: RSServicePricing!
243
245
  defaultBillingCycle: RSBillingCycle
246
+ mostPopular: Boolean!
244
247
  billingCycleDiscounts: [RSBillingCycleDiscount!]!
245
248
  serviceLevels: [RSServiceLevelBinding!]!
246
249
  usageLimits: [RSServiceUsageLimit!]!
250
+ excludeFromSetupFee: Boolean!
247
251
  }
248
252
 
249
253
  type RSServicePricing {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/service-offering",
3
3
  "description": "service offering document models",
4
- "version": "1.0.0-dev.22",
4
+ "version": "1.0.0-dev.24",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
7
7
  "type": "git",
@@ -76,13 +76,13 @@
76
76
  },
77
77
  "dependencies": {
78
78
  "@electric-sql/pglite": "0.3.15",
79
- "@powerhousedao/builder-tools": "6.0.0-dev.104",
80
- "@powerhousedao/common": "6.0.0-dev.104",
81
- "@powerhousedao/design-system": "6.0.0-dev.104",
79
+ "@powerhousedao/builder-tools": "6.0.0-dev.105",
80
+ "@powerhousedao/common": "6.0.0-dev.105",
81
+ "@powerhousedao/design-system": "6.0.0-dev.105",
82
82
  "@powerhousedao/document-engineering": "1.40.1",
83
- "@powerhousedao/vetra": "6.0.0-dev.104",
83
+ "@powerhousedao/vetra": "6.0.0-dev.105",
84
84
  "@uiw/react-md-editor": "^4.0.11",
85
- "document-model": "6.0.0-dev.104",
85
+ "document-model": "6.0.0-dev.105",
86
86
  "graphql": "16.12.0",
87
87
  "graphql-tag": "^2.12.6",
88
88
  "lucide-react": "^0.577.0",
@@ -91,22 +91,22 @@
91
91
  },
92
92
  "devDependencies": {
93
93
  "@eslint/js": "^9.38.0",
94
+ "@powerhousedao/analytics-engine-core": "6.0.0-dev.105",
95
+ "@powerhousedao/config": "6.0.0-dev.105",
96
+ "@powerhousedao/connect": "6.0.0-dev.105",
97
+ "@powerhousedao/ph-cli": "6.0.0-dev.105",
98
+ "@powerhousedao/reactor-api": "6.0.0-dev.105",
99
+ "@powerhousedao/reactor-browser": "6.0.0-dev.105",
100
+ "@powerhousedao/reactor-local": "6.0.0-dev.105",
101
+ "@powerhousedao/switchboard": "6.0.0-dev.105",
94
102
  "@semantic-release/changelog": "^6.0.3",
95
103
  "@semantic-release/git": "^10.0.1",
96
- "@powerhousedao/analytics-engine-core": "6.0.0-dev.104",
97
- "@powerhousedao/config": "6.0.0-dev.104",
98
- "@powerhousedao/connect": "6.0.0-dev.104",
99
- "@powerhousedao/ph-cli": "6.0.0-dev.104",
100
- "@powerhousedao/reactor-api": "6.0.0-dev.104",
101
- "@powerhousedao/reactor-browser": "6.0.0-dev.104",
102
- "@powerhousedao/reactor-local": "6.0.0-dev.104",
103
- "@powerhousedao/switchboard": "6.0.0-dev.104",
104
104
  "@tailwindcss/cli": "^4.1.4",
105
105
  "@testing-library/react": "^16.3.0",
106
106
  "@types/node": "^24.9.2",
107
107
  "@types/react": "^19.2.3",
108
108
  "@vitejs/plugin-react": "^5.1.0",
109
- "document-drive": "6.0.0-dev.104",
109
+ "document-drive": "6.0.0-dev.105",
110
110
  "eslint": "^9.38.0",
111
111
  "eslint-config-prettier": "^10.1.8",
112
112
  "eslint-plugin-prettier": "^5.5.4",