@contractspec/example.crm-pipeline 1.57.0 โ 1.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +148 -164
- package/.turbo/turbo-prebuild.log +1 -0
- package/CHANGELOG.md +20 -0
- package/dist/browser/crm-pipeline.feature.js +75 -0
- package/dist/browser/deal/deal.enum.js +18 -0
- package/dist/browser/deal/deal.operation.js +396 -0
- package/dist/browser/deal/deal.schema.js +141 -0
- package/dist/browser/deal/deal.test-spec.js +58 -0
- package/dist/browser/deal/index.js +408 -0
- package/dist/browser/docs/crm-pipeline.docblock.js +113 -0
- package/dist/browser/docs/index.js +113 -0
- package/dist/browser/entities/company.entity.js +52 -0
- package/dist/browser/entities/contact.entity.js +66 -0
- package/dist/browser/entities/deal.entity.js +107 -0
- package/dist/browser/entities/index.js +343 -0
- package/dist/browser/entities/task.entity.js +99 -0
- package/dist/browser/events/contact.event.js +31 -0
- package/dist/browser/events/deal.event.js +101 -0
- package/dist/browser/events/index.js +158 -0
- package/dist/browser/events/task.event.js +28 -0
- package/dist/browser/example.js +39 -0
- package/dist/browser/handlers/crm.handlers.js +160 -0
- package/dist/browser/handlers/deal.handlers.js +293 -0
- package/dist/browser/handlers/index.js +456 -0
- package/dist/browser/handlers/mock-data.js +165 -0
- package/dist/browser/index.js +3279 -0
- package/dist/browser/operations/index.js +407 -0
- package/dist/browser/presentations/dashboard.presentation.js +52 -0
- package/dist/browser/presentations/index.js +284 -0
- package/dist/browser/presentations/pipeline.presentation.js +233 -0
- package/dist/browser/seeders/index.js +22 -0
- package/dist/browser/shared/overlay-types.js +0 -0
- package/dist/browser/ui/CrmDashboard.js +1325 -0
- package/dist/browser/ui/CrmDealCard.js +50 -0
- package/dist/browser/ui/CrmPipelineBoard.js +160 -0
- package/dist/browser/ui/hooks/index.js +186 -0
- package/dist/browser/ui/hooks/useDealList.js +84 -0
- package/dist/browser/ui/hooks/useDealMutations.js +100 -0
- package/dist/browser/ui/index.js +1972 -0
- package/dist/browser/ui/modals/CreateDealModal.js +211 -0
- package/dist/browser/ui/modals/DealActionsModal.js +428 -0
- package/dist/browser/ui/modals/index.js +638 -0
- package/dist/browser/ui/overlays/demo-overlays.js +55 -0
- package/dist/browser/ui/overlays/index.js +55 -0
- package/dist/browser/ui/renderers/index.js +827 -0
- package/dist/browser/ui/renderers/pipeline.markdown.js +564 -0
- package/dist/browser/ui/renderers/pipeline.renderer.js +264 -0
- package/dist/crm-pipeline.feature.d.ts +1 -6
- package/dist/crm-pipeline.feature.d.ts.map +1 -1
- package/dist/crm-pipeline.feature.js +74 -164
- package/dist/deal/deal.enum.d.ts +2 -7
- package/dist/deal/deal.enum.d.ts.map +1 -1
- package/dist/deal/deal.enum.js +16 -22
- package/dist/deal/deal.operation.d.ts +444 -450
- package/dist/deal/deal.operation.d.ts.map +1 -1
- package/dist/deal/deal.operation.js +390 -263
- package/dist/deal/deal.schema.d.ts +251 -256
- package/dist/deal/deal.schema.d.ts.map +1 -1
- package/dist/deal/deal.schema.js +131 -275
- package/dist/deal/deal.test-spec.d.ts +2 -7
- package/dist/deal/deal.test-spec.d.ts.map +1 -1
- package/dist/deal/deal.test-spec.js +56 -62
- package/dist/deal/index.d.ts +7 -4
- package/dist/deal/index.d.ts.map +1 -0
- package/dist/deal/index.js +408 -4
- package/dist/docs/crm-pipeline.docblock.d.ts +2 -1
- package/dist/docs/crm-pipeline.docblock.d.ts.map +1 -0
- package/dist/docs/crm-pipeline.docblock.js +45 -51
- package/dist/docs/index.d.ts +2 -1
- package/dist/docs/index.d.ts.map +1 -0
- package/dist/docs/index.js +114 -1
- package/dist/entities/company.entity.d.ts +27 -32
- package/dist/entities/company.entity.d.ts.map +1 -1
- package/dist/entities/company.entity.js +51 -61
- package/dist/entities/contact.entity.d.ts +31 -36
- package/dist/entities/contact.entity.d.ts.map +1 -1
- package/dist/entities/contact.entity.js +65 -76
- package/dist/entities/deal.entity.d.ts +52 -57
- package/dist/entities/deal.entity.d.ts.map +1 -1
- package/dist/entities/deal.entity.js +104 -116
- package/dist/entities/index.d.ts +6 -10
- package/dist/entities/index.d.ts.map +1 -1
- package/dist/entities/index.js +342 -31
- package/dist/entities/task.entity.d.ts +42 -47
- package/dist/entities/task.entity.d.ts.map +1 -1
- package/dist/entities/task.entity.js +95 -124
- package/dist/events/contact.event.d.ts +21 -27
- package/dist/events/contact.event.d.ts.map +1 -1
- package/dist/events/contact.event.js +29 -42
- package/dist/events/deal.event.d.ts +100 -106
- package/dist/events/deal.event.d.ts.map +1 -1
- package/dist/events/deal.event.js +93 -163
- package/dist/events/index.d.ts +4 -4
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +158 -4
- package/dist/events/task.event.d.ts +21 -27
- package/dist/events/task.event.d.ts.map +1 -1
- package/dist/events/task.event.js +26 -42
- package/dist/example.d.ts +2 -6
- package/dist/example.d.ts.map +1 -1
- package/dist/example.js +38 -50
- package/dist/handlers/crm.handlers.d.ts +80 -78
- package/dist/handlers/crm.handlers.d.ts.map +1 -1
- package/dist/handlers/crm.handlers.js +155 -166
- package/dist/handlers/deal.handlers.d.ts +58 -63
- package/dist/handlers/deal.handlers.d.ts.map +1 -1
- package/dist/handlers/deal.handlers.js +279 -105
- package/dist/handlers/index.d.ts +10 -4
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +456 -4
- package/dist/handlers/mock-data.d.ts +38 -41
- package/dist/handlers/mock-data.d.ts.map +1 -1
- package/dist/handlers/mock-data.js +162 -184
- package/dist/index.d.ts +13 -42
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3277 -53
- package/dist/node/crm-pipeline.feature.js +75 -0
- package/dist/node/deal/deal.enum.js +18 -0
- package/dist/node/deal/deal.operation.js +396 -0
- package/dist/node/deal/deal.schema.js +141 -0
- package/dist/node/deal/deal.test-spec.js +58 -0
- package/dist/node/deal/index.js +408 -0
- package/dist/node/docs/crm-pipeline.docblock.js +113 -0
- package/dist/node/docs/index.js +113 -0
- package/dist/node/entities/company.entity.js +52 -0
- package/dist/node/entities/contact.entity.js +66 -0
- package/dist/node/entities/deal.entity.js +107 -0
- package/dist/node/entities/index.js +343 -0
- package/dist/node/entities/task.entity.js +99 -0
- package/dist/node/events/contact.event.js +31 -0
- package/dist/node/events/deal.event.js +101 -0
- package/dist/node/events/index.js +158 -0
- package/dist/node/events/task.event.js +28 -0
- package/dist/node/example.js +39 -0
- package/dist/node/handlers/crm.handlers.js +160 -0
- package/dist/node/handlers/deal.handlers.js +293 -0
- package/dist/node/handlers/index.js +456 -0
- package/dist/node/handlers/mock-data.js +165 -0
- package/dist/node/index.js +3279 -0
- package/dist/node/operations/index.js +407 -0
- package/dist/node/presentations/dashboard.presentation.js +52 -0
- package/dist/node/presentations/index.js +284 -0
- package/dist/node/presentations/pipeline.presentation.js +233 -0
- package/dist/node/seeders/index.js +22 -0
- package/dist/node/shared/overlay-types.js +0 -0
- package/dist/node/ui/CrmDashboard.js +1325 -0
- package/dist/node/ui/CrmDealCard.js +50 -0
- package/dist/node/ui/CrmPipelineBoard.js +160 -0
- package/dist/node/ui/hooks/index.js +186 -0
- package/dist/node/ui/hooks/useDealList.js +84 -0
- package/dist/node/ui/hooks/useDealMutations.js +100 -0
- package/dist/node/ui/index.js +1972 -0
- package/dist/node/ui/modals/CreateDealModal.js +211 -0
- package/dist/node/ui/modals/DealActionsModal.js +428 -0
- package/dist/node/ui/modals/index.js +638 -0
- package/dist/node/ui/overlays/demo-overlays.js +55 -0
- package/dist/node/ui/overlays/index.js +55 -0
- package/dist/node/ui/renderers/index.js +827 -0
- package/dist/node/ui/renderers/pipeline.markdown.js +564 -0
- package/dist/node/ui/renderers/pipeline.renderer.js +264 -0
- package/dist/operations/index.d.ts +2 -5
- package/dist/operations/index.d.ts.map +1 -0
- package/dist/operations/index.js +407 -5
- package/dist/presentations/dashboard.presentation.d.ts +2 -7
- package/dist/presentations/dashboard.presentation.d.ts.map +1 -1
- package/dist/presentations/dashboard.presentation.js +51 -60
- package/dist/presentations/index.d.ts +3 -3
- package/dist/presentations/index.d.ts.map +1 -0
- package/dist/presentations/index.js +284 -3
- package/dist/presentations/pipeline.presentation.d.ts +4 -9
- package/dist/presentations/pipeline.presentation.d.ts.map +1 -1
- package/dist/presentations/pipeline.presentation.js +228 -116
- package/dist/seeders/index.d.ts +4 -8
- package/dist/seeders/index.d.ts.map +1 -1
- package/dist/seeders/index.js +21 -45
- package/dist/shared/overlay-types.d.ts +25 -28
- package/dist/shared/overlay-types.d.ts.map +1 -1
- package/dist/shared/overlay-types.js +1 -0
- package/dist/ui/CrmDashboard.d.ts +1 -6
- package/dist/ui/CrmDashboard.d.ts.map +1 -1
- package/dist/ui/CrmDashboard.js +1318 -296
- package/dist/ui/CrmDealCard.d.ts +8 -12
- package/dist/ui/CrmDealCard.d.ts.map +1 -1
- package/dist/ui/CrmDealCard.js +47 -45
- package/dist/ui/CrmPipelineBoard.d.ts +11 -20
- package/dist/ui/CrmPipelineBoard.d.ts.map +1 -1
- package/dist/ui/CrmPipelineBoard.js +157 -94
- package/dist/ui/hooks/index.d.ts +3 -3
- package/dist/ui/hooks/index.d.ts.map +1 -0
- package/dist/ui/hooks/index.js +185 -4
- package/dist/ui/hooks/useDealList.d.ts +28 -32
- package/dist/ui/hooks/useDealList.d.ts.map +1 -1
- package/dist/ui/hooks/useDealList.js +81 -90
- package/dist/ui/hooks/useDealMutations.d.ts +18 -22
- package/dist/ui/hooks/useDealMutations.d.ts.map +1 -1
- package/dist/ui/hooks/useDealMutations.js +97 -155
- package/dist/ui/index.d.ts +8 -14
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +1973 -15
- package/dist/ui/modals/CreateDealModal.d.ts +19 -29
- package/dist/ui/modals/CreateDealModal.d.ts.map +1 -1
- package/dist/ui/modals/CreateDealModal.js +209 -180
- package/dist/ui/modals/DealActionsModal.d.ts +31 -44
- package/dist/ui/modals/DealActionsModal.d.ts.map +1 -1
- package/dist/ui/modals/DealActionsModal.js +424 -367
- package/dist/ui/modals/index.d.ts +3 -3
- package/dist/ui/modals/index.d.ts.map +1 -0
- package/dist/ui/modals/index.js +638 -3
- package/dist/ui/overlays/demo-overlays.d.ts +10 -8
- package/dist/ui/overlays/demo-overlays.d.ts.map +1 -1
- package/dist/ui/overlays/demo-overlays.js +54 -66
- package/dist/ui/overlays/index.d.ts +2 -2
- package/dist/ui/overlays/index.d.ts.map +1 -0
- package/dist/ui/overlays/index.js +56 -3
- package/dist/ui/renderers/index.d.ts +3 -3
- package/dist/ui/renderers/index.d.ts.map +1 -0
- package/dist/ui/renderers/index.js +827 -3
- package/dist/ui/renderers/pipeline.markdown.d.ts +12 -11
- package/dist/ui/renderers/pipeline.markdown.d.ts.map +1 -1
- package/dist/ui/renderers/pipeline.markdown.js +560 -114
- package/dist/ui/renderers/pipeline.renderer.d.ts +9 -7
- package/dist/ui/renderers/pipeline.renderer.d.ts.map +1 -1
- package/dist/ui/renderers/pipeline.renderer.js +261 -24
- package/package.json +476 -90
- package/tsdown.config.js +1 -2
- package/.turbo/turbo-build$colon$bundle.log +0 -164
- package/dist/crm-pipeline.feature.js.map +0 -1
- package/dist/deal/deal.enum.js.map +0 -1
- package/dist/deal/deal.operation.js.map +0 -1
- package/dist/deal/deal.schema.js.map +0 -1
- package/dist/deal/deal.test-spec.js.map +0 -1
- package/dist/docs/crm-pipeline.docblock.js.map +0 -1
- package/dist/entities/company.entity.js.map +0 -1
- package/dist/entities/contact.entity.js.map +0 -1
- package/dist/entities/deal.entity.js.map +0 -1
- package/dist/entities/index.js.map +0 -1
- package/dist/entities/task.entity.js.map +0 -1
- package/dist/events/contact.event.js.map +0 -1
- package/dist/events/deal.event.js.map +0 -1
- package/dist/events/task.event.js.map +0 -1
- package/dist/example.js.map +0 -1
- package/dist/handlers/crm.handlers.js.map +0 -1
- package/dist/handlers/deal.handlers.js.map +0 -1
- package/dist/handlers/mock-data.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/presentations/dashboard.presentation.js.map +0 -1
- package/dist/presentations/pipeline.presentation.js.map +0 -1
- package/dist/seeders/index.js.map +0 -1
- package/dist/ui/CrmDashboard.js.map +0 -1
- package/dist/ui/CrmDealCard.js.map +0 -1
- package/dist/ui/CrmPipelineBoard.js.map +0 -1
- package/dist/ui/hooks/useDealList.js.map +0 -1
- package/dist/ui/hooks/useDealMutations.js.map +0 -1
- package/dist/ui/modals/CreateDealModal.js.map +0 -1
- package/dist/ui/modals/DealActionsModal.js.map +0 -1
- package/dist/ui/overlays/demo-overlays.js.map +0 -1
- package/dist/ui/renderers/pipeline.markdown.js.map +0 -1
- package/dist/ui/renderers/pipeline.renderer.js.map +0 -1
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useDealList.js","names":[],"sources":["../../../src/ui/hooks/useDealList.ts"],"sourcesContent":["'use client';\n\n/**\n * Hook for fetching and managing deal list data\n *\n * Uses runtime-local database-backed handlers.\n */\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useTemplateRuntime } from '@contractspec/lib.example-shared-ui';\nimport {\n type CrmHandlers,\n type Deal as RuntimeDeal,\n type ListDealsOutput as RuntimeListDealsOutput,\n type Stage,\n} from '../../handlers/crm.handlers';\n\n// Re-export types for convenience\nexport type Deal = RuntimeDeal;\nexport type ListDealsOutput = RuntimeListDealsOutput;\n\nexport interface UseDealListOptions {\n pipelineId?: string;\n stageId?: string;\n status?: 'OPEN' | 'WON' | 'LOST' | 'all';\n search?: string;\n limit?: number;\n}\n\nexport function useDealList(options: UseDealListOptions = {}) {\n const { handlers, projectId } = useTemplateRuntime<{ crm: CrmHandlers }>();\n const { crm } = handlers;\n\n const [data, setData] = useState<ListDealsOutput | null>(null);\n const [dealsByStage, setDealsByStage] = useState<Record<string, Deal[]>>({});\n const [stages, setStages] = useState<Stage[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [page, setPage] = useState(1);\n\n const pipelineId = options.pipelineId ?? 'pipeline-1';\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n\n try {\n const [dealsResult, stageDealsResult, stagesResult] = await Promise.all([\n crm.listDeals({\n projectId,\n pipelineId,\n stageId: options.stageId,\n status: options.status === 'all' ? undefined : options.status,\n search: options.search,\n limit: options.limit ?? 50,\n offset: (page - 1) * (options.limit ?? 50),\n }),\n crm.getDealsByStage({ projectId, pipelineId }),\n crm.getPipelineStages({ pipelineId }),\n ]);\n setData(dealsResult);\n setDealsByStage(stageDealsResult);\n setStages(stagesResult);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Unknown error'));\n } finally {\n setLoading(false);\n }\n }, [\n crm,\n projectId,\n pipelineId,\n options.stageId,\n options.status,\n options.search,\n options.limit,\n page,\n ]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n // Calculate stats\n const stats = useMemo(() => {\n if (!data) return null;\n const open = data.deals.filter((d: Deal) => d.status === 'OPEN');\n const won = data.deals.filter((d: Deal) => d.status === 'WON');\n const lost = data.deals.filter((d: Deal) => d.status === 'LOST');\n\n return {\n total: data.total,\n totalValue: data.totalValue,\n openCount: open.length,\n openValue: open.reduce((sum: number, d: Deal) => sum + d.value, 0),\n wonCount: won.length,\n wonValue: won.reduce((sum: number, d: Deal) => sum + d.value, 0),\n lostCount: lost.length,\n };\n }, [data]);\n\n return {\n data,\n dealsByStage,\n stages,\n loading,\n error,\n stats,\n page,\n refetch: fetchData,\n nextPage: () => setPage((p) => p + 1),\n prevPage: () => page > 1 && setPage((p) => p - 1),\n };\n}\n"],"mappings":";;;;;;;;;;;;AA4BA,SAAgB,YAAY,UAA8B,EAAE,EAAE;CAC5D,MAAM,EAAE,UAAU,cAAc,oBAA0C;CAC1E,MAAM,EAAE,QAAQ;CAEhB,MAAM,CAAC,MAAM,WAAW,SAAiC,KAAK;CAC9D,MAAM,CAAC,cAAc,mBAAmB,SAAiC,EAAE,CAAC;CAC5E,MAAM,CAAC,QAAQ,aAAa,SAAkB,EAAE,CAAC;CACjD,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,OAAO,YAAY,SAAuB,KAAK;CACtD,MAAM,CAAC,MAAM,WAAW,SAAS,EAAE;CAEnC,MAAM,aAAa,QAAQ,cAAc;CAEzC,MAAM,YAAY,YAAY,YAAY;AACxC,aAAW,KAAK;AAChB,WAAS,KAAK;AAEd,MAAI;GACF,MAAM,CAAC,aAAa,kBAAkB,gBAAgB,MAAM,QAAQ,IAAI;IACtE,IAAI,UAAU;KACZ;KACA;KACA,SAAS,QAAQ;KACjB,QAAQ,QAAQ,WAAW,QAAQ,SAAY,QAAQ;KACvD,QAAQ,QAAQ;KAChB,OAAO,QAAQ,SAAS;KACxB,SAAS,OAAO,MAAM,QAAQ,SAAS;KACxC,CAAC;IACF,IAAI,gBAAgB;KAAE;KAAW;KAAY,CAAC;IAC9C,IAAI,kBAAkB,EAAE,YAAY,CAAC;IACtC,CAAC;AACF,WAAQ,YAAY;AACpB,mBAAgB,iBAAiB;AACjC,aAAU,aAAa;WAChB,KAAK;AACZ,YAAS,eAAe,QAAQ,sBAAM,IAAI,MAAM,gBAAgB,CAAC;YACzD;AACR,cAAW,MAAM;;IAElB;EACD;EACA;EACA;EACA,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR;EACD,CAAC;AAEF,iBAAgB;AACd,aAAW;IACV,CAAC,UAAU,CAAC;AAoBf,QAAO;EACL;EACA;EACA;EACA;EACA;EACA,OAvBY,cAAc;AAC1B,OAAI,CAAC,KAAM,QAAO;GAClB,MAAM,OAAO,KAAK,MAAM,QAAQ,MAAY,EAAE,WAAW,OAAO;GAChE,MAAM,MAAM,KAAK,MAAM,QAAQ,MAAY,EAAE,WAAW,MAAM;GAC9D,MAAM,OAAO,KAAK,MAAM,QAAQ,MAAY,EAAE,WAAW,OAAO;AAEhE,UAAO;IACL,OAAO,KAAK;IACZ,YAAY,KAAK;IACjB,WAAW,KAAK;IAChB,WAAW,KAAK,QAAQ,KAAa,MAAY,MAAM,EAAE,OAAO,EAAE;IAClE,UAAU,IAAI;IACd,UAAU,IAAI,QAAQ,KAAa,MAAY,MAAM,EAAE,OAAO,EAAE;IAChE,WAAW,KAAK;IACjB;KACA,CAAC,KAAK,CAAC;EASR;EACA,SAAS;EACT,gBAAgB,SAAS,MAAM,IAAI,EAAE;EACrC,gBAAgB,OAAO,KAAK,SAAS,MAAM,IAAI,EAAE;EAClD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useDealMutations.js","names":[],"sources":["../../../src/ui/hooks/useDealMutations.ts"],"sourcesContent":["/**\n * Hook for CRM deal mutations (commands)\n *\n * Uses runtime-local database-backed handlers for:\n * - CreateDealContract\n * - MoveDealContract\n * - WinDealContract\n * - LoseDealContract\n */\nimport { useCallback, useState } from 'react';\nimport { useTemplateRuntime } from '@contractspec/lib.example-shared-ui';\nimport type {\n CreateDealInput,\n CrmHandlers,\n Deal,\n LoseDealInput,\n MoveDealInput,\n WinDealInput,\n} from '../../handlers/crm.handlers';\n\nexport interface MutationState<T> {\n loading: boolean;\n error: Error | null;\n data: T | null;\n}\n\nexport interface UseDealMutationsOptions {\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n}\n\nexport function useDealMutations(options: UseDealMutationsOptions = {}) {\n const { handlers, projectId } = useTemplateRuntime<{ crm: CrmHandlers }>();\n const { crm } = handlers;\n\n const [createState, setCreateState] = useState<MutationState<Deal>>({\n loading: false,\n error: null,\n data: null,\n });\n\n const [moveState, setMoveState] = useState<MutationState<Deal>>({\n loading: false,\n error: null,\n data: null,\n });\n\n const [winState, setWinState] = useState<MutationState<Deal>>({\n loading: false,\n error: null,\n data: null,\n });\n\n const [loseState, setLoseState] = useState<MutationState<Deal>>({\n loading: false,\n error: null,\n data: null,\n });\n\n /**\n * Create a new deal\n */\n const createDeal = useCallback(\n async (input: CreateDealInput): Promise<Deal | null> => {\n setCreateState({ loading: true, error: null, data: null });\n try {\n const result = await crm.createDeal(input, {\n projectId,\n ownerId: 'user-1', // Demo user\n });\n setCreateState({ loading: false, error: null, data: result });\n options.onSuccess?.();\n return result;\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error('Failed to create deal');\n setCreateState({ loading: false, error, data: null });\n options.onError?.(error);\n return null;\n }\n },\n [crm, projectId, options]\n );\n\n /**\n * Move a deal to a different stage\n */\n const moveDeal = useCallback(\n async (input: MoveDealInput): Promise<Deal | null> => {\n setMoveState({ loading: true, error: null, data: null });\n try {\n const result = await crm.moveDeal(input);\n setMoveState({ loading: false, error: null, data: result });\n options.onSuccess?.();\n return result;\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error('Failed to move deal');\n setMoveState({ loading: false, error, data: null });\n options.onError?.(error);\n return null;\n }\n },\n [crm, options]\n );\n\n /**\n * Mark a deal as won\n */\n const winDeal = useCallback(\n async (input: WinDealInput): Promise<Deal | null> => {\n setWinState({ loading: true, error: null, data: null });\n try {\n const result = await crm.winDeal(input);\n setWinState({ loading: false, error: null, data: result });\n options.onSuccess?.();\n return result;\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error('Failed to mark deal as won');\n setWinState({ loading: false, error, data: null });\n options.onError?.(error);\n return null;\n }\n },\n [crm, options]\n );\n\n /**\n * Mark a deal as lost\n */\n const loseDeal = useCallback(\n async (input: LoseDealInput): Promise<Deal | null> => {\n setLoseState({ loading: true, error: null, data: null });\n try {\n const result = await crm.loseDeal(input);\n setLoseState({ loading: false, error: null, data: result });\n options.onSuccess?.();\n return result;\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error('Failed to mark deal as lost');\n setLoseState({ loading: false, error, data: null });\n options.onError?.(error);\n return null;\n }\n },\n [crm, options]\n );\n\n return {\n // Mutations\n createDeal,\n moveDeal,\n winDeal,\n loseDeal,\n\n // State\n createState,\n moveState,\n winState,\n loseState,\n\n // Convenience\n isLoading:\n createState.loading ||\n moveState.loading ||\n winState.loading ||\n loseState.loading,\n };\n}\n\n// Note: Types are re-exported from the handlers package\n// Consumers should import types directly from '@contractspec/example.crm-pipeline/handlers'\n"],"mappings":";;;;;;;;;;;;;AA+BA,SAAgB,iBAAiB,UAAmC,EAAE,EAAE;CACtE,MAAM,EAAE,UAAU,cAAc,oBAA0C;CAC1E,MAAM,EAAE,QAAQ;CAEhB,MAAM,CAAC,aAAa,kBAAkB,SAA8B;EAClE,SAAS;EACT,OAAO;EACP,MAAM;EACP,CAAC;CAEF,MAAM,CAAC,WAAW,gBAAgB,SAA8B;EAC9D,SAAS;EACT,OAAO;EACP,MAAM;EACP,CAAC;CAEF,MAAM,CAAC,UAAU,eAAe,SAA8B;EAC5D,SAAS;EACT,OAAO;EACP,MAAM;EACP,CAAC;CAEF,MAAM,CAAC,WAAW,gBAAgB,SAA8B;EAC9D,SAAS;EACT,OAAO;EACP,MAAM;EACP,CAAC;AA6FF,QAAO;EAEL,YA1FiB,YACjB,OAAO,UAAiD;AACtD,kBAAe;IAAE,SAAS;IAAM,OAAO;IAAM,MAAM;IAAM,CAAC;AAC1D,OAAI;IACF,MAAM,SAAS,MAAM,IAAI,WAAW,OAAO;KACzC;KACA,SAAS;KACV,CAAC;AACF,mBAAe;KAAE,SAAS;KAAO,OAAO;KAAM,MAAM;KAAQ,CAAC;AAC7D,YAAQ,aAAa;AACrB,WAAO;YACA,KAAK;IACZ,MAAM,QACJ,eAAe,QAAQ,sBAAM,IAAI,MAAM,wBAAwB;AACjE,mBAAe;KAAE,SAAS;KAAO;KAAO,MAAM;KAAM,CAAC;AACrD,YAAQ,UAAU,MAAM;AACxB,WAAO;;KAGX;GAAC;GAAK;GAAW;GAAQ,CAC1B;EAuEC,UAlEe,YACf,OAAO,UAA+C;AACpD,gBAAa;IAAE,SAAS;IAAM,OAAO;IAAM,MAAM;IAAM,CAAC;AACxD,OAAI;IACF,MAAM,SAAS,MAAM,IAAI,SAAS,MAAM;AACxC,iBAAa;KAAE,SAAS;KAAO,OAAO;KAAM,MAAM;KAAQ,CAAC;AAC3D,YAAQ,aAAa;AACrB,WAAO;YACA,KAAK;IACZ,MAAM,QACJ,eAAe,QAAQ,sBAAM,IAAI,MAAM,sBAAsB;AAC/D,iBAAa;KAAE,SAAS;KAAO;KAAO,MAAM;KAAM,CAAC;AACnD,YAAQ,UAAU,MAAM;AACxB,WAAO;;KAGX,CAAC,KAAK,QAAQ,CACf;EAkDC,SA7Cc,YACd,OAAO,UAA8C;AACnD,eAAY;IAAE,SAAS;IAAM,OAAO;IAAM,MAAM;IAAM,CAAC;AACvD,OAAI;IACF,MAAM,SAAS,MAAM,IAAI,QAAQ,MAAM;AACvC,gBAAY;KAAE,SAAS;KAAO,OAAO;KAAM,MAAM;KAAQ,CAAC;AAC1D,YAAQ,aAAa;AACrB,WAAO;YACA,KAAK;IACZ,MAAM,QACJ,eAAe,QAAQ,sBAAM,IAAI,MAAM,6BAA6B;AACtE,gBAAY;KAAE,SAAS;KAAO;KAAO,MAAM;KAAM,CAAC;AAClD,YAAQ,UAAU,MAAM;AACxB,WAAO;;KAGX,CAAC,KAAK,QAAQ,CACf;EA6BC,UAxBe,YACf,OAAO,UAA+C;AACpD,gBAAa;IAAE,SAAS;IAAM,OAAO;IAAM,MAAM;IAAM,CAAC;AACxD,OAAI;IACF,MAAM,SAAS,MAAM,IAAI,SAAS,MAAM;AACxC,iBAAa;KAAE,SAAS;KAAO,OAAO;KAAM,MAAM;KAAQ,CAAC;AAC3D,YAAQ,aAAa;AACrB,WAAO;YACA,KAAK;IACZ,MAAM,QACJ,eAAe,QAAQ,sBAAM,IAAI,MAAM,8BAA8B;AACvE,iBAAa;KAAE,SAAS;KAAO;KAAO,MAAM;KAAM,CAAC;AACnD,YAAQ,UAAU,MAAM;AACxB,WAAO;;KAGX,CAAC,KAAK,QAAQ,CACf;EAUC;EACA;EACA;EACA;EAGA,WACE,YAAY,WACZ,UAAU,WACV,SAAS,WACT,UAAU;EACb"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CreateDealModal.js","names":[],"sources":["../../../src/ui/modals/CreateDealModal.tsx"],"sourcesContent":["'use client';\n\n/**\n * CreateDealModal - Form for creating a new deal\n *\n * Wires to CreateDealContract via useDealMutations hook.\n */\nimport { useState } from 'react';\nimport { Button, Input } from '@contractspec/lib.design-system';\n\n// Local type definition for modal props\nexport interface CreateDealInput {\n name: string;\n value: number;\n currency: string;\n pipelineId: string;\n stageId: string;\n expectedCloseDate?: Date;\n contactId?: string;\n companyId?: string;\n}\n\ninterface CreateDealModalProps {\n isOpen: boolean;\n onClose: () => void;\n onSubmit: (input: CreateDealInput) => Promise<void>;\n stages: { id: string; name: string }[];\n isLoading?: boolean;\n}\n\nconst CURRENCIES = ['USD', 'EUR', 'GBP', 'CAD'];\nconst DEFAULT_PIPELINE_ID = 'pipeline-1';\n\nexport function CreateDealModal({\n isOpen,\n onClose,\n onSubmit,\n stages,\n isLoading = false,\n}: CreateDealModalProps) {\n const [name, setName] = useState('');\n const [value, setValue] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [stageId, setStageId] = useState(stages[0]?.id ?? '');\n const [expectedCloseDate, setExpectedCloseDate] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n // Validation\n if (!name.trim()) {\n setError('Deal name is required');\n return;\n }\n\n const numericValue = parseFloat(value);\n if (isNaN(numericValue) || numericValue <= 0) {\n setError('Value must be a positive number');\n return;\n }\n\n if (!stageId) {\n setError('Please select a pipeline stage');\n return;\n }\n\n try {\n await onSubmit({\n name: name.trim(),\n value: numericValue,\n currency,\n pipelineId: DEFAULT_PIPELINE_ID,\n stageId,\n expectedCloseDate: expectedCloseDate\n ? new Date(expectedCloseDate)\n : undefined,\n });\n\n // Reset form\n setName('');\n setValue('');\n setCurrency('USD');\n setStageId(stages[0]?.id ?? '');\n setExpectedCloseDate('');\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create deal');\n }\n };\n\n if (!isOpen) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div\n className=\"bg-background/80 absolute inset-0 backdrop-blur-sm\"\n onClick={onClose}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') onClose();\n }}\n aria-label=\"Close modal\"\n />\n\n {/* Modal */}\n <div className=\"bg-card border-border relative z-10 w-full max-w-md rounded-xl border p-6 shadow-xl\">\n <h2 className=\"mb-4 text-xl font-semibold\">Create New Deal</h2>\n\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {/* Deal Name */}\n <div>\n <label\n htmlFor=\"deal-name\"\n className=\"text-muted-foreground mb-1 block text-sm font-medium\"\n >\n Deal Name *\n </label>\n <Input\n id=\"deal-name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g., Enterprise License - Acme Corp\"\n disabled={isLoading}\n />\n </div>\n\n {/* Value & Currency */}\n <div className=\"flex gap-3\">\n <div className=\"flex-1\">\n <label\n htmlFor=\"deal-value\"\n className=\"text-muted-foreground mb-1 block text-sm font-medium\"\n >\n Value *\n </label>\n <Input\n id=\"deal-value\"\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n value={value}\n onChange={(e) => setValue(e.target.value)}\n placeholder=\"50000\"\n disabled={isLoading}\n />\n </div>\n <div className=\"w-24\">\n <label\n htmlFor=\"deal-currency\"\n className=\"text-muted-foreground mb-1 block text-sm font-medium\"\n >\n Currency\n </label>\n <select\n id=\"deal-currency\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value)}\n disabled={isLoading}\n className=\"border-input bg-background focus:ring-ring h-10 w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none disabled:opacity-50\"\n >\n {CURRENCIES.map((c) => (\n <option key={c} value={c}>\n {c}\n </option>\n ))}\n </select>\n </div>\n </div>\n\n {/* Stage */}\n <div>\n <label\n htmlFor=\"deal-stage\"\n className=\"text-muted-foreground mb-1 block text-sm font-medium\"\n >\n Pipeline Stage *\n </label>\n <select\n id=\"deal-stage\"\n value={stageId}\n onChange={(e) => setStageId(e.target.value)}\n disabled={isLoading}\n className=\"border-input bg-background focus:ring-ring h-10 w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none disabled:opacity-50\"\n >\n {stages.map((stage) => (\n <option key={stage.id} value={stage.id}>\n {stage.name}\n </option>\n ))}\n </select>\n </div>\n\n {/* Expected Close Date */}\n <div>\n <label\n htmlFor=\"deal-close-date\"\n className=\"text-muted-foreground mb-1 block text-sm font-medium\"\n >\n Expected Close Date\n </label>\n <Input\n id=\"deal-close-date\"\n type=\"date\"\n value={expectedCloseDate}\n onChange={(e) => setExpectedCloseDate(e.target.value)}\n disabled={isLoading}\n />\n </div>\n\n {/* Error Message */}\n {error && (\n <div className=\"bg-destructive/10 text-destructive rounded-md p-3 text-sm\">\n {error}\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex justify-end gap-3 pt-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n onPress={onClose}\n disabled={isLoading}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={isLoading}>\n {isLoading ? 'Creating...' : 'Create Deal'}\n </Button>\n </div>\n </form>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DealActionsModal.js","names":[],"sources":["../../../src/ui/modals/DealActionsModal.tsx"],"sourcesContent":["'use client';\n\n/**\n * DealActionsModal - Actions for a specific deal (Win, Lose, Move)\n *\n * Wires to WinDealContract, LoseDealContract, MoveDealContract\n * via useDealMutations hook.\n */\nimport { useState } from 'react';\nimport { Button } from '@contractspec/lib.design-system';\n\n// Local type definitions for modal props\nexport interface Deal {\n id: string;\n name: string;\n value: number;\n currency: string;\n stageId: string;\n status: 'OPEN' | 'WON' | 'LOST' | 'STALE';\n}\n\nexport interface WinDealInput {\n dealId: string;\n wonSource?: string;\n notes?: string;\n}\n\nexport interface LoseDealInput {\n dealId: string;\n lostReason: string;\n notes?: string;\n}\n\nexport interface MoveDealInput {\n dealId: string;\n stageId: string;\n}\n\ntype ActionMode = 'menu' | 'win' | 'lose' | 'move';\n\ninterface DealActionsModalProps {\n isOpen: boolean;\n deal: Deal | null;\n stages: { id: string; name: string }[];\n onClose: () => void;\n onWin: (input: WinDealInput) => Promise<void>;\n onLose: (input: LoseDealInput) => Promise<void>;\n onMove: (input: MoveDealInput) => Promise<void>;\n isLoading?: boolean;\n}\n\nfunction formatCurrency(value: number, currency: string): string {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency,\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n }).format(value);\n}\n\nexport function DealActionsModal({\n isOpen,\n deal,\n stages,\n onClose,\n onWin,\n onLose,\n onMove,\n isLoading = false,\n}: DealActionsModalProps) {\n const [mode, setMode] = useState<ActionMode>('menu');\n const [wonSource, setWonSource] = useState('');\n const [lostReason, setLostReason] = useState('');\n const [notes, setNotes] = useState('');\n const [selectedStageId, setSelectedStageId] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n const resetForm = () => {\n setMode('menu');\n setWonSource('');\n setLostReason('');\n setNotes('');\n setSelectedStageId('');\n setError(null);\n };\n\n const handleClose = () => {\n resetForm();\n onClose();\n };\n\n const handleWin = async () => {\n if (!deal) return;\n setError(null);\n\n try {\n await onWin({\n dealId: deal.id,\n wonSource: wonSource.trim() || undefined,\n notes: notes.trim() || undefined,\n });\n handleClose();\n } catch (err) {\n setError(\n err instanceof Error ? err.message : 'Failed to mark deal as won'\n );\n }\n };\n\n const handleLose = async () => {\n if (!deal) return;\n setError(null);\n\n if (!lostReason.trim()) {\n setError('Please provide a reason for losing the deal');\n return;\n }\n\n try {\n await onLose({\n dealId: deal.id,\n lostReason: lostReason.trim(),\n notes: notes.trim() || undefined,\n });\n handleClose();\n } catch (err) {\n setError(\n err instanceof Error ? err.message : 'Failed to mark deal as lost'\n );\n }\n };\n\n const handleMove = async () => {\n if (!deal) return;\n setError(null);\n\n if (!selectedStageId) {\n setError('Please select a stage');\n return;\n }\n\n if (selectedStageId === deal.stageId) {\n setError('Deal is already in this stage');\n return;\n }\n\n try {\n await onMove({\n dealId: deal.id,\n stageId: selectedStageId,\n });\n handleClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to move deal');\n }\n };\n\n if (!isOpen || !deal) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div\n className=\"bg-background/80 absolute inset-0 backdrop-blur-sm\"\n onClick={handleClose}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') handleClose();\n }}\n aria-label=\"Close modal\"\n />\n\n {/* Modal */}\n <div className=\"bg-card border-border relative z-10 w-full max-w-md rounded-xl border p-6 shadow-xl\">\n {/* Deal Header */}\n <div className=\"border-border mb-4 border-b pb-4\">\n <h2 className=\"text-xl font-semibold\">{deal.name}</h2>\n <p className=\"text-primary text-lg font-medium\">\n {formatCurrency(deal.value, deal.currency)}\n </p>\n <span\n className={`mt-2 inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${\n deal.status === 'WON'\n ? 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400'\n : deal.status === 'LOST'\n ? 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400'\n : 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400'\n }`}\n >\n {deal.status}\n </span>\n </div>\n\n {/* Main Menu */}\n {mode === 'menu' && (\n <div className=\"space-y-3\">\n {deal.status === 'OPEN' && (\n <>\n <Button\n className=\"w-full justify-start\"\n variant=\"ghost\"\n onPress={() => setMode('win')}\n >\n <span className=\"mr-2\">๐</span> Mark as Won\n </Button>\n <Button\n className=\"w-full justify-start\"\n variant=\"ghost\"\n onPress={() => setMode('lose')}\n >\n <span className=\"mr-2\">โ</span> Mark as Lost\n </Button>\n <Button\n className=\"w-full justify-start\"\n variant=\"ghost\"\n onPress={() => {\n setSelectedStageId(deal.stageId);\n setMode('move');\n }}\n >\n <span className=\"mr-2\">โก๏ธ</span> Move to Stage\n </Button>\n </>\n )}\n {deal.status !== 'OPEN' && (\n <p className=\"text-muted-foreground py-4 text-center\">\n This deal is already {deal.status.toLowerCase()}. No actions\n available.\n </p>\n )}\n <div className=\"border-border border-t pt-3\">\n <Button\n className=\"w-full\"\n variant=\"outline\"\n onPress={handleClose}\n >\n Close\n </Button>\n </div>\n </div>\n )}\n\n {/* Win Form */}\n {mode === 'win' && (\n <div className=\"space-y-4\">\n <div>\n <label\n htmlFor=\"won-source\"\n className=\"text-muted-foreground mb-1 block text-sm font-medium\"\n >\n How did you win this deal?\n </label>\n <select\n id=\"won-source\"\n value={wonSource}\n onChange={(e) => setWonSource(e.target.value)}\n className=\"border-input bg-background focus:ring-ring h-10 w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none\"\n >\n <option value=\"\">Select a source...</option>\n <option value=\"referral\">Referral</option>\n <option value=\"cold_outreach\">Cold Outreach</option>\n <option value=\"inbound\">Inbound Lead</option>\n <option value=\"upsell\">Upsell</option>\n <option value=\"other\">Other</option>\n </select>\n </div>\n\n <div>\n <label\n htmlFor=\"win-notes\"\n className=\"text-muted-foreground mb-1 block text-sm font-medium\"\n >\n Notes (optional)\n </label>\n <textarea\n id=\"win-notes\"\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n placeholder=\"Any additional notes about the win...\"\n rows={3}\n className=\"border-input bg-background focus:ring-ring w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none\"\n />\n </div>\n\n {error && (\n <div className=\"bg-destructive/10 text-destructive rounded-md p-3 text-sm\">\n {error}\n </div>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <Button\n variant=\"ghost\"\n onPress={() => setMode('menu')}\n disabled={isLoading}\n >\n Back\n </Button>\n <Button onPress={handleWin} disabled={isLoading}>\n {isLoading ? 'Processing...' : '๐ Confirm Win'}\n </Button>\n </div>\n </div>\n )}\n\n {/* Lose Form */}\n {mode === 'lose' && (\n <div className=\"space-y-4\">\n <div>\n <label\n htmlFor=\"lost-reason\"\n className=\"text-muted-foreground mb-1 block text-sm font-medium\"\n >\n Why was this deal lost? *\n </label>\n <select\n id=\"lost-reason\"\n value={lostReason}\n onChange={(e) => setLostReason(e.target.value)}\n className=\"border-input bg-background focus:ring-ring h-10 w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none\"\n >\n <option value=\"\">Select a reason...</option>\n <option value=\"price\">Price too high</option>\n <option value=\"competitor\">Lost to competitor</option>\n <option value=\"no_budget\">No budget</option>\n <option value=\"no_decision\">No decision made</option>\n <option value=\"timing\">Bad timing</option>\n <option value=\"product_fit\">Product not a fit</option>\n <option value=\"other\">Other</option>\n </select>\n </div>\n\n <div>\n <label\n htmlFor=\"lose-notes\"\n className=\"text-muted-foreground mb-1 block text-sm font-medium\"\n >\n Notes (optional)\n </label>\n <textarea\n id=\"lose-notes\"\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n placeholder=\"Any additional details...\"\n rows={3}\n className=\"border-input bg-background focus:ring-ring w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none\"\n />\n </div>\n\n {error && (\n <div className=\"bg-destructive/10 text-destructive rounded-md p-3 text-sm\">\n {error}\n </div>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <Button\n variant=\"ghost\"\n onPress={() => setMode('menu')}\n disabled={isLoading}\n >\n Back\n </Button>\n <Button\n variant=\"destructive\"\n onPress={handleLose}\n disabled={isLoading}\n >\n {isLoading ? 'Processing...' : 'โ Confirm Loss'}\n </Button>\n </div>\n </div>\n )}\n\n {/* Move Form */}\n {mode === 'move' && (\n <div className=\"space-y-4\">\n <div>\n <label\n htmlFor=\"move-stage\"\n className=\"text-muted-foreground mb-1 block text-sm font-medium\"\n >\n Move to Stage\n </label>\n <select\n id=\"move-stage\"\n value={selectedStageId}\n onChange={(e) => setSelectedStageId(e.target.value)}\n className=\"border-input bg-background focus:ring-ring h-10 w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none\"\n >\n {stages.map((stage) => (\n <option key={stage.id} value={stage.id}>\n {stage.name}\n {stage.id === deal.stageId ? ' (current)' : ''}\n </option>\n ))}\n </select>\n </div>\n\n {error && (\n <div className=\"bg-destructive/10 text-destructive rounded-md p-3 text-sm\">\n {error}\n </div>\n )}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <Button\n variant=\"ghost\"\n onPress={() => setMode('menu')}\n disabled={isLoading}\n >\n Back\n </Button>\n <Button onPress={handleMove} disabled={isLoading}>\n {isLoading ? 'Moving...' : 'โก๏ธ Move Deal'}\n </Button>\n </div>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"demo-overlays.js","names":[],"sources":["../../../src/ui/overlays/demo-overlays.ts"],"sourcesContent":["/**\n * Demo Overlay Definitions for CRM Pipeline\n *\n * These overlays customize the presentation for different contexts\n * (e.g., demo users, different roles).\n */\nimport type { OverlayDefinition } from '../../shared/overlay-types';\n\n/**\n * Demo user overlay - sample data mode\n */\nexport const crmDemoOverlay: OverlayDefinition = {\n overlayId: 'crm-pipeline.demo-user',\n version: '1.0.0',\n description: 'Demo mode with sample data',\n appliesTo: {\n feature: 'crm-pipeline',\n role: 'demo',\n },\n modifications: [\n {\n type: 'hideField',\n field: 'importButton',\n reason: 'Not available in demo',\n },\n {\n type: 'hideField',\n field: 'exportButton',\n reason: 'Not available in demo',\n },\n {\n type: 'addBadge',\n position: 'header',\n label: 'Demo Mode',\n variant: 'warning',\n },\n ],\n};\n\n/**\n * Sales rep overlay - focused view for sales\n */\nexport const crmSalesRepOverlay: OverlayDefinition = {\n overlayId: 'crm-pipeline.sales-rep',\n version: '1.0.0',\n description: 'Sales rep focused view',\n appliesTo: {\n feature: 'crm-pipeline',\n role: 'sales-rep',\n },\n modifications: [\n {\n type: 'hideField',\n field: 'teamMetrics',\n reason: 'Team metrics for managers only',\n },\n { type: 'hideField', field: 'pipelineSettings', reason: 'Admin only' },\n { type: 'renameLabel', field: 'deals', newLabel: 'My Deals' },\n ],\n};\n\n/**\n * All overlays for crm-pipeline\n */\nexport const crmOverlays: OverlayDefinition[] = [\n crmDemoOverlay,\n crmSalesRepOverlay,\n];\n"],"mappings":";;;;AAWA,MAAa,iBAAoC;CAC/C,WAAW;CACX,SAAS;CACT,aAAa;CACb,WAAW;EACT,SAAS;EACT,MAAM;EACP;CACD,eAAe;EACb;GACE,MAAM;GACN,OAAO;GACP,QAAQ;GACT;EACD;GACE,MAAM;GACN,OAAO;GACP,QAAQ;GACT;EACD;GACE,MAAM;GACN,UAAU;GACV,OAAO;GACP,SAAS;GACV;EACF;CACF;;;;AAKD,MAAa,qBAAwC;CACnD,WAAW;CACX,SAAS;CACT,aAAa;CACb,WAAW;EACT,SAAS;EACT,MAAM;EACP;CACD,eAAe;EACb;GACE,MAAM;GACN,OAAO;GACP,QAAQ;GACT;EACD;GAAE,MAAM;GAAa,OAAO;GAAoB,QAAQ;GAAc;EACtE;GAAE,MAAM;GAAe,OAAO;GAAS,UAAU;GAAY;EAC9D;CACF;;;;AAKD,MAAa,cAAmC,CAC9C,gBACA,mBACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.markdown.js","names":[],"sources":["../../../src/ui/renderers/pipeline.markdown.ts"],"sourcesContent":["/**\n * Markdown renderer for CRM Pipeline presentation\n *\n * Imports handlers from the hooks module to ensure correct build order.\n */\nimport type { PresentationRenderer } from '@contractspec/lib.contracts';\nimport {\n mockListDealsHandler,\n mockGetPipelineStagesHandler,\n} from '../../handlers';\n\ninterface DealItem {\n id: string;\n name: string;\n value: number;\n currency: string;\n stageId: string;\n status: string;\n}\n\ninterface StageItem {\n id: string;\n name: string;\n position: number;\n}\n\nfunction formatCurrency(value: number, currency = 'USD'): string {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency,\n minimumFractionDigits: 0,\n }).format(value);\n}\n\n/**\n * Markdown renderer for CRM Pipeline Kanban view (crm-pipeline.deal.pipeline)\n * Only handles PipelineKanbanView component\n */\nexport const crmPipelineMarkdownRenderer: PresentationRenderer<{\n mimeType: string;\n body: string;\n}> = {\n target: 'markdown',\n render: async (desc, _ctx) => {\n // Only handle PipelineKanbanView\n if (\n desc.source.type !== 'component' ||\n desc.source.componentKey !== 'PipelineKanbanView'\n ) {\n throw new Error('crmPipelineMarkdownRenderer: not PipelineKanbanView');\n }\n\n const pipelineId = 'pipeline-1';\n const [dealsResult, stages] = await Promise.all([\n mockListDealsHandler({ pipelineId, limit: 50 }),\n mockGetPipelineStagesHandler({ pipelineId }),\n ]);\n\n const deals = dealsResult.deals as DealItem[];\n const stageList = stages as StageItem[];\n\n // Group deals by stage\n const dealsByStage: Record<string, DealItem[]> = {};\n for (const stage of stageList) {\n dealsByStage[stage.id] = deals.filter(\n (d) => d.stageId === stage.id && d.status === 'OPEN'\n );\n }\n\n // Build Markdown\n const lines: string[] = [\n '# CRM Pipeline',\n '',\n `**Total Value**: ${formatCurrency(dealsResult.totalValue)}`,\n `**Total Deals**: ${dealsResult.total}`,\n '',\n ];\n\n for (const stage of stageList.sort((a, b) => a.position - b.position)) {\n const stageDeals = dealsByStage[stage.id] ?? [];\n const stageValue = stageDeals.reduce((sum, d) => sum + d.value, 0);\n\n lines.push(`## ${stage.name}`);\n lines.push(\n `_${stageDeals.length} deals ยท ${formatCurrency(stageValue)}_`\n );\n lines.push('');\n\n if (stageDeals.length === 0) {\n lines.push('_No deals_');\n } else {\n for (const deal of stageDeals) {\n lines.push(\n `- **${deal.name}** - ${formatCurrency(deal.value, deal.currency)}`\n );\n }\n }\n\n lines.push('');\n }\n\n return {\n mimeType: 'text/markdown',\n body: lines.join('\\n'),\n };\n },\n};\n\n/**\n * Markdown renderer for CRM Dashboard (crm-pipeline.dashboard)\n * Only handles CrmDashboard component\n */\nexport const crmDashboardMarkdownRenderer: PresentationRenderer<{\n mimeType: string;\n body: string;\n}> = {\n target: 'markdown',\n render: async (desc, _ctx) => {\n // Only handle CrmDashboard\n if (\n desc.source.type !== 'component' ||\n desc.source.componentKey !== 'CrmDashboard'\n ) {\n throw new Error('crmDashboardMarkdownRenderer: not CrmDashboard');\n }\n\n const pipelineId = 'pipeline-1';\n const [dealsResult, stages] = await Promise.all([\n mockListDealsHandler({ pipelineId, limit: 100 }),\n mockGetPipelineStagesHandler({ pipelineId }),\n ]);\n\n const deals = dealsResult.deals as DealItem[];\n const stageList = stages as StageItem[];\n\n // Calculate stats\n const openDeals = deals.filter((d) => d.status === 'OPEN');\n const wonDeals = deals.filter((d) => d.status === 'WON');\n const lostDeals = deals.filter((d) => d.status === 'LOST');\n const openValue = openDeals.reduce((sum, d) => sum + d.value, 0);\n const wonValue = wonDeals.reduce((sum, d) => sum + d.value, 0);\n\n // Build dashboard markdown\n const lines: string[] = [\n '# CRM Dashboard',\n '',\n '> Sales pipeline overview and key metrics',\n '',\n '## Summary',\n '',\n '| Metric | Value |',\n '|--------|-------|',\n `| Total Deals | ${dealsResult.total} |`,\n `| Pipeline Value | ${formatCurrency(dealsResult.totalValue)} |`,\n `| Open Deals | ${openDeals.length} (${formatCurrency(openValue)}) |`,\n `| Won Deals | ${wonDeals.length} (${formatCurrency(wonValue)}) |`,\n `| Lost Deals | ${lostDeals.length} |`,\n '',\n '## Pipeline Stages',\n '',\n ];\n\n // Stage summary table\n lines.push('| Stage | Deals | Value |');\n lines.push('|-------|-------|-------|');\n for (const stage of stageList.sort((a, b) => a.position - b.position)) {\n const stageDeals = openDeals.filter((d) => d.stageId === stage.id);\n const stageValue = stageDeals.reduce((sum, d) => sum + d.value, 0);\n lines.push(\n `| ${stage.name} | ${stageDeals.length} | ${formatCurrency(stageValue)} |`\n );\n }\n\n lines.push('');\n lines.push('## Recent Deals');\n lines.push('');\n\n // Top 10 recent deals\n const recentDeals = deals.slice(0, 10);\n if (recentDeals.length === 0) {\n lines.push('_No deals yet._');\n } else {\n lines.push('| Deal | Value | Stage | Status |');\n lines.push('|------|-------|-------|--------|');\n for (const deal of recentDeals) {\n const stage = stageList.find((s) => s.id === deal.stageId);\n lines.push(\n `| ${deal.name} | ${formatCurrency(deal.value, deal.currency)} | ${stage?.name ?? '-'} | ${deal.status} |`\n );\n }\n }\n\n return {\n mimeType: 'text/markdown',\n body: lines.join('\\n'),\n };\n },\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.renderer.js","names":[],"sources":["../../../src/ui/renderers/pipeline.renderer.tsx"],"sourcesContent":["/**\n * React renderer for CRM Pipeline presentation\n *\n * Renders the CRM pipeline board component.\n * Data is fetched via the CrmPipelineBoard component's internal hooks.\n */\nimport * as React from 'react';\nimport type { PresentationRenderer } from '@contractspec/lib.contracts';\nimport { CrmPipelineBoard } from '../CrmPipelineBoard';\nimport { useDealList } from '../hooks/useDealList';\n\n/**\n * Wrapper component that provides data to CrmPipelineBoard\n */\nfunction CrmPipelineBoardWrapper() {\n const { dealsByStage, stages } = useDealList();\n return <CrmPipelineBoard dealsByStage={dealsByStage} stages={stages} />;\n}\n\nexport const crmPipelineReactRenderer: PresentationRenderer<React.ReactElement> =\n {\n target: 'react',\n render: async (desc, _ctx) => {\n if (desc.source.type !== 'component') {\n throw new Error('Invalid source type');\n }\n\n if (desc.source.componentKey !== 'CrmPipelineView') {\n throw new Error(`Unknown component: ${desc.source.componentKey}`);\n }\n\n // Note: The wrapper component will fetch data internally\n return <CrmPipelineBoardWrapper />;\n },\n };\n"],"mappings":";;;;;;;;;AAcA,SAAS,0BAA0B;CACjC,MAAM,EAAE,cAAc,WAAW,aAAa;AAC9C,QAAO,oBAAC;EAA+B;EAAsB;GAAU;;AAGzE,MAAa,2BACX;CACE,QAAQ;CACR,QAAQ,OAAO,MAAM,SAAS;AAC5B,MAAI,KAAK,OAAO,SAAS,YACvB,OAAM,IAAI,MAAM,sBAAsB;AAGxC,MAAI,KAAK,OAAO,iBAAiB,kBAC/B,OAAM,IAAI,MAAM,sBAAsB,KAAK,OAAO,eAAe;AAInE,SAAO,oBAAC,4BAA0B;;CAErC"}
|