@burdenoff/microfe-planmagnet 2026.1002.1 → 2026.1002.2

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 (95) hide show
  1. package/dist/generated/wspace-operations.d.ts +1814 -401
  2. package/dist/generated/wspace-operations.d.ts.map +1 -1
  3. package/dist/generated/wspace-types.d.ts +5167 -54
  4. package/dist/generated/wspace-types.d.ts.map +1 -1
  5. package/dist/index.js +8 -8
  6. package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
  7. package/dist/planmagnet/PlanMagnetRoot.js +172 -160
  8. package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
  9. package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
  10. package/dist/planmagnet/PlanMagnetRoutes.js +95 -83
  11. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  12. package/dist/planmagnet/controls/Pickers.d.ts +7 -2
  13. package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
  14. package/dist/planmagnet/controls/Pickers.js +10 -9
  15. package/dist/planmagnet/controls/Pickers.js.map +1 -1
  16. package/dist/planmagnet/index.d.ts +1 -1
  17. package/dist/planmagnet/index.d.ts.map +1 -1
  18. package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js +4 -4
  19. package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js.map +1 -1
  20. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
  21. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +133 -131
  22. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
  23. package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
  24. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +5 -5
  25. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
  26. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +6 -6
  27. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
  28. package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
  29. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +105 -82
  30. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
  31. package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.d.ts +2 -0
  32. package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.d.ts.map +1 -0
  33. package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.js +174 -0
  34. package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.js.map +1 -0
  35. package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.d.ts +2 -0
  36. package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.d.ts.map +1 -0
  37. package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.js +350 -0
  38. package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.js.map +1 -0
  39. package/dist/planmagnet/pages/ProductsProductLinesPagePage.d.ts +2 -0
  40. package/dist/planmagnet/pages/ProductsProductLinesPagePage.d.ts.map +1 -0
  41. package/dist/planmagnet/pages/ProductsProductLinesPagePage.js +168 -0
  42. package/dist/planmagnet/pages/ProductsProductLinesPagePage.js.map +1 -0
  43. package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +1 -1
  44. package/dist/planmagnet/pages/ProductsProductsPagePage.js +1 -1
  45. package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
  46. package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
  47. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +156 -154
  48. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
  49. package/dist/planmagnet/product/FeatureLinkPanels.d.ts +29 -0
  50. package/dist/planmagnet/product/FeatureLinkPanels.d.ts.map +1 -0
  51. package/dist/planmagnet/product/FeatureLinkPanels.js +373 -0
  52. package/dist/planmagnet/product/FeatureLinkPanels.js.map +1 -0
  53. package/dist/planmagnet/product/ProductControls.js +1 -1
  54. package/dist/planmagnet/product/ProductControls.js.map +1 -1
  55. package/dist/planmagnet/product/ProductFeatureControls.d.ts +39 -0
  56. package/dist/planmagnet/product/ProductFeatureControls.d.ts.map +1 -0
  57. package/dist/planmagnet/product/ProductFeatureControls.js +315 -0
  58. package/dist/planmagnet/product/ProductFeatureControls.js.map +1 -0
  59. package/dist/planmagnet/product/ProductFeatureLinkCard.d.ts +4 -0
  60. package/dist/planmagnet/product/ProductFeatureLinkCard.d.ts.map +1 -0
  61. package/dist/planmagnet/product/ProductFeatureLinkCard.js +192 -0
  62. package/dist/planmagnet/product/ProductFeatureLinkCard.js.map +1 -0
  63. package/dist/planmagnet/product/ProductLineControls.d.ts +52 -0
  64. package/dist/planmagnet/product/ProductLineControls.d.ts.map +1 -0
  65. package/dist/planmagnet/product/ProductLineControls.js +417 -0
  66. package/dist/planmagnet/product/ProductLineControls.js.map +1 -0
  67. package/dist/planmagnet/product/ProductTeamsPanel.d.ts +4 -0
  68. package/dist/planmagnet/product/ProductTeamsPanel.d.ts.map +1 -0
  69. package/dist/planmagnet/product/ProductTeamsPanel.js +129 -0
  70. package/dist/planmagnet/product/ProductTeamsPanel.js.map +1 -0
  71. package/dist/planmagnet/product/WorkItemProductFeatureChip.d.ts +4 -0
  72. package/dist/planmagnet/product/WorkItemProductFeatureChip.d.ts.map +1 -0
  73. package/dist/planmagnet/product/WorkItemProductFeatureChip.js +41 -0
  74. package/dist/planmagnet/product/WorkItemProductFeatureChip.js.map +1 -0
  75. package/dist/planmagnet/product/hierarchy.d.ts +127 -0
  76. package/dist/planmagnet/product/hierarchy.d.ts.map +1 -0
  77. package/dist/planmagnet/product/hierarchy.js +173 -0
  78. package/dist/planmagnet/product/hierarchy.js.map +1 -0
  79. package/dist/planmagnet/product/hierarchyOperations.d.ts +35 -0
  80. package/dist/planmagnet/product/hierarchyOperations.d.ts.map +1 -0
  81. package/dist/planmagnet/product/hierarchyOperations.js +440 -0
  82. package/dist/planmagnet/product/hierarchyOperations.js.map +1 -0
  83. package/dist/planmagnet/product/refusal.d.ts +14 -0
  84. package/dist/planmagnet/product/refusal.d.ts.map +1 -0
  85. package/dist/planmagnet/product/refusal.js +10 -0
  86. package/dist/planmagnet/product/refusal.js.map +1 -0
  87. package/dist/planmagnet/product/routes.d.ts +4 -0
  88. package/dist/planmagnet/product/routes.d.ts.map +1 -1
  89. package/dist/planmagnet/product/routes.js +2 -2
  90. package/dist/planmagnet/product/routes.js.map +1 -1
  91. package/dist/shared/utils/i18n.d.ts +3 -0
  92. package/dist/shared/utils/i18n.d.ts.map +1 -1
  93. package/dist/shared/utils/i18n.js +1 -1
  94. package/dist/shared/utils/i18n.js.map +1 -1
  95. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsFeatureAnalyticsPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsFeatureAnalyticsPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { TrendingUp, ThumbsUp, Users, BarChart3, Target, Loader2 } from 'lucide-react';\nimport { useParams } from 'react-router';\nimport { countLabel, useFeatureCounts } from '../hooks/useCounts';\n\nconst GET_FEATURE_REQUEST_ANALYTICS = gql`\n query GetFeatureRequestAnalytics($id: ID!) {\n planmagnetFeatureRequest(id: $id) {\n id\n title\n description\n status\n businessValue\n effortEstimate\n priorityScore\n voteCount\n voteRank\n submittedBy\n tags\n createdAt\n updatedAt\n votes {\n id\n voterId\n weight\n comment\n createdAt\n }\n competitors {\n id\n name\n }\n }\n }\n`;\n\ninterface VoteNode {\n id: string;\n voterId: string;\n weight: number;\n comment: string | null;\n createdAt: string;\n}\n\nexport function ProductsFeatureAnalyticsPagePage() {\n const params = useParams<{ id: string }>();\n const featureId = params.id ?? '';\n\n const {\n data,\n loading,\n error,\n } = // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n useQuery<Record<string, any>>(GET_FEATURE_REQUEST_ANALYTICS, {\n variables: { id: featureId },\n skip: !featureId,\n });\n\n // Rank and distribution cover EVERY request, from the server (BOFF-7995: both were computed over the 100\n // newest in the browser, so a workspace with more read \"of 100\", and an older request had no rank).\n const featureCounts = useFeatureCounts();\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load analytics: {error.message}</div>;\n }\n\n const feature = data?.planmagnetFeatureRequest;\n if (!feature) return <div className=\"p-6 text-muted-foreground\">Feature not found.</div>;\n\n const votes: VoteNode[] = feature.votes ?? [];\n const competitorCount = feature.competitors?.length ?? 0;\n\n // Vote distribution by weight\n const votesByWeight: Record<number, number> = {};\n for (const v of votes) {\n votesByWeight[v.weight] = (votesByWeight[v.weight] || 0) + 1;\n }\n const maxVoteWeight = Math.max(...Object.values(votesByWeight), 1);\n\n // Vote timeline - group by creation date\n const voteTimeline: { date: string; count: number }[] = [];\n const voteDateMap: Record<string, number> = {};\n for (const v of votes) {\n const date = new Date(v.createdAt).toLocaleDateString();\n voteDateMap[date] = (voteDateMap[date] || 0) + 1;\n }\n for (const [date, count] of Object.entries(voteDateMap)) {\n voteTimeline.push({ date, count });\n }\n voteTimeline.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());\n const maxTimelineCount = Math.max(...voteTimeline.map((d) => d.count), 1);\n\n const statusDistribution: Record<string, number> = featureCounts\n ? Object.fromEntries(Object.entries(featureCounts.byStatus).filter(([, n]) => n > 0))\n : {};\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Feature Analytics</h1>\n <p className=\"text-sm text-muted-foreground\">\n {feature.title} - {feature.status.toLowerCase().replace('_', ' ')}\n </p>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Target className=\"h-4 w-4\" />\n Priority Score\n </div>\n <p className=\"text-2xl font-bold mt-1\">{feature.priorityScore ?? 0}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <ThumbsUp className=\"h-4 w-4\" />\n Total Votes\n </div>\n <p className=\"text-2xl font-bold mt-1\">{feature.voteCount}</p>\n <p className=\"text-xs text-green-600 mt-1\">\n Rank #{feature.voteRank} of {countLabel(featureCounts?.all)}\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Users className=\"h-4 w-4\" />\n Competitors\n </div>\n <p className=\"text-2xl font-bold mt-1\">{competitorCount}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <TrendingUp className=\"h-4 w-4\" />\n Business Value\n </div>\n <p className=\"text-2xl font-bold mt-1\">{feature.businessValue ?? 0}</p>\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4\" />\n Vote Timeline\n </CardTitle>\n </CardHeader>\n <CardContent>\n {voteTimeline.length === 0 ? (\n <p className=\"text-sm text-muted-foreground text-center py-8\">\n No vote data available\n </p>\n ) : (\n <div className=\"flex items-end gap-1 h-48\">\n {voteTimeline.map((d) => (\n <div key={d.date} className=\"flex-1 flex flex-col items-center gap-1\">\n <div className=\"w-full flex justify-center\">\n <div\n className=\"w-5 bg-primary rounded-t transition-all\"\n style={{ height: `${(d.count / maxTimelineCount) * 160}px` }}\n />\n </div>\n <span className=\"text-[10px] text-muted-foreground truncate max-w-[40px]\">\n {d.date}\n </span>\n </div>\n ))}\n </div>\n )}\n <p className=\"text-xs text-muted-foreground text-center mt-2\">Votes over time</p>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Vote Weight Distribution</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {Object.entries(votesByWeight).length === 0 ? (\n <p className=\"text-sm text-muted-foreground text-center py-8\">No votes recorded</p>\n ) : (\n Object.entries(votesByWeight)\n .sort(([a], [b]) => Number(a) - Number(b))\n .map(([weight, count]) => (\n <div key={weight}>\n <div className=\"flex justify-between text-sm mb-1\">\n <span>Weight {weight}</span>\n <span className=\"font-semibold\">{count} votes</span>\n </div>\n <div className=\"w-full h-3 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full rounded-full bg-primary\"\n style={{ width: `${(count / maxVoteWeight) * 100}%` }}\n />\n </div>\n </div>\n ))\n )}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <Card>\n <CardHeader>\n <CardTitle>All Features - Status Distribution</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {Object.entries(statusDistribution).map(([status, count]) => {\n const total = featureCounts?.all ?? 0;\n const pct = total > 0 ? Math.round((count / total) * 100) : 0;\n const colors: Record<string, string> = {\n SUBMITTED: 'bg-gray-400',\n UNDER_REVIEW: 'bg-yellow-400',\n PLANNED: 'bg-blue-400',\n IN_PROGRESS: 'bg-purple-400',\n COMPLETED: 'bg-green-400',\n DECLINED: 'bg-red-400',\n DUPLICATE: 'bg-orange-400',\n };\n return (\n <div key={status}>\n <div className=\"flex justify-between text-sm mb-1\">\n <span className=\"capitalize\">{status.toLowerCase().replace('_', ' ')}</span>\n <span className=\"font-medium\">\n {count} ({pct}%)\n </span>\n </div>\n <div className=\"w-full h-2 rounded-full bg-muted overflow-hidden\">\n <div\n className={`h-full rounded-full ${colors[status] ?? 'bg-gray-300'}`}\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n );\n })}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Feature Impact</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"text-center p-4 bg-muted rounded-md\">\n <p className=\"text-3xl font-bold text-primary\">{feature.voteCount}</p>\n <p className=\"text-sm text-muted-foreground\">total votes received</p>\n </div>\n <div className=\"grid grid-cols-2 gap-2 text-center\">\n <div className=\"p-3 border rounded-md\">\n <p className=\"text-lg font-semibold\">{feature.businessValue ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">business value</p>\n </div>\n <div className=\"p-3 border rounded-md\">\n <p className=\"text-lg font-semibold\">{feature.priorityScore ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">priority score</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;AASA,IAAM,IAAgC,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCzC,SAAgB,IAAmC;CAEjD,IAAM,IADS,GAA2B,CACjB,MAAM,IAEzB,EACJ,SACA,YACA,aAGA,EAA8B,GAA+B;EAC3D,WAAW,EAAE,IAAI,GAAW;EAC5B,MAAM,CAAC;EACR,CAAC,EAIE,IAAgB,GAAkB;AAMxC,KAAI,KAAW,CAAC,EACd,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAS,WAAU,8CAA+C,CAAA;EAC9D,CAAA;AAIV,KAAI,EACF,QAAO,kBAAC,OAAD;EAAK,WAAU;YAAf,CAAsC,8BAA2B,EAAM,QAAc;;CAG9F,IAAM,IAAU,GAAM;AACtB,KAAI,CAAC,EAAS,QAAO,kBAAC,OAAD;EAAK,WAAU;YAA4B;EAAwB,CAAA;CAExF,IAAM,IAAoB,EAAQ,SAAS,EAAE,EACvC,IAAkB,EAAQ,aAAa,UAAU,GAGjD,IAAwC,EAAE;AAChD,MAAK,IAAM,KAAK,EACd,GAAc,EAAE,WAAW,EAAc,EAAE,WAAW,KAAK;CAE7D,IAAM,IAAgB,KAAK,IAAI,GAAG,OAAO,OAAO,EAAc,EAAE,EAAE,EAG5D,IAAkD,EAAE,EACpD,IAAsC,EAAE;AAC9C,MAAK,IAAM,KAAK,GAAO;EACrB,IAAM,IAAO,IAAI,KAAK,EAAE,UAAU,CAAC,oBAAoB;AACvD,IAAY,MAAS,EAAY,MAAS,KAAK;;AAEjD,MAAK,IAAM,CAAC,GAAM,MAAU,OAAO,QAAQ,EAAY,CACrD,GAAa,KAAK;EAAE;EAAM;EAAO,CAAC;AAEpC,GAAa,MAAM,GAAG,MAAM,IAAI,KAAK,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;CACpF,IAAM,IAAmB,KAAK,IAAI,GAAG,EAAa,KAAK,MAAM,EAAE,MAAM,EAAE,EAAE,EAEnE,IAA6C,IAC/C,OAAO,YAAY,OAAO,QAAQ,EAAc,SAAS,CAAC,QAAQ,GAAG,OAAO,IAAI,EAAE,CAAC,GACnF,EAAE;AAEN,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cAAyB;IAAsB,CAAA,EAC7D,kBAAC,KAAD;IAAG,WAAU;cAAb;KACG,EAAQ;KAAM;KAAI,EAAQ,OAAO,aAAa,CAAC,QAAQ,KAAK,IAAI;KAC/D;MACA,EAAA,CAAA;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAa,WAAU;gBAAvB,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA,EAAA,iBAE1B;UACN,kBAAC,KAAD;OAAG,WAAU;iBAA2B,EAAQ,iBAAiB;OAAM,CAAA,CAC3D;SACT,CAAA;KACP,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAa,WAAU;gBAAvB;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA,EAAA,cAE5B;;OACN,kBAAC,KAAD;QAAG,WAAU;kBAA2B,EAAQ;QAAc,CAAA;OAC9D,kBAAC,KAAD;QAAG,WAAU;kBAAb;SAA2C;SAClC,EAAQ;SAAS;SAAK,EAAW,GAAe,IAAI;SACzD;;OACQ;SACT,CAAA;KACP,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAa,WAAU;gBAAvB,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA,EAAA,cAEzB;UACN,kBAAC,KAAD;OAAG,WAAU;iBAA2B;OAAoB,CAAA,CAChD;SACT,CAAA;KACP,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAa,WAAU;gBAAvB,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA,EAAA,iBAE9B;UACN,kBAAC,KAAD;OAAG,WAAU;iBAA2B,EAAQ,iBAAiB;OAAM,CAAA,CAC3D;SACT,CAAA;KACH;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KAAW,WAAU;eAArB,CACE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAAA,gBAEvB;QACD,CAAA,EACb,kBAAC,GAAD,EAAA,UAAA,CACG,EAAa,WAAW,IACvB,kBAAC,KAAD;KAAG,WAAU;eAAiD;KAE1D,CAAA,GAEJ,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAa,KAAK,MACjB,kBAAC,OAAD;MAAkB,WAAU;gBAA5B,CACE,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,OAAD;QACE,WAAU;QACV,OAAO,EAAE,QAAQ,GAAI,EAAE,QAAQ,IAAoB,IAAI,KAAK;QAC5D,CAAA;OACE,CAAA,EACN,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAE;OACE,CAAA,CACH;QAVI,EAAE,KAUN,CACN;KACE,CAAA,EAER,kBAAC,KAAD;KAAG,WAAU;eAAiD;KAAmB,CAAA,CACrE,EAAA,CAAA,CACT,EAAA,CAAA,EAEP,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,4BAAoC,CAAA,EACpC,CAAA,EACb,kBAAC,GAAD;KAAa,WAAU;eACpB,OAAO,QAAQ,EAAc,CAAC,WAAW,IACxC,kBAAC,KAAD;MAAG,WAAU;gBAAiD;MAAqB,CAAA,GAEnF,OAAO,QAAQ,EAAc,CAC1B,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,CACzC,KAAK,CAAC,GAAQ,OACb,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD,EAAA,UAAA,CAAM,WAAQ,EAAc,EAAA,CAAA,EAC5B,kBAAC,QAAD;OAAM,WAAU;iBAAhB,CAAiC,GAAM,SAAa;SAChD;SACN,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,OAAO,GAAI,IAAQ,IAAiB,IAAI,IAAI;OACrD,CAAA;MACE,CAAA,CACF,EAAA,EAXI,EAWJ,CACN;KAEM,CAAA,CACT,EAAA,CAAA,CACH;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,sCAA8C,CAAA,EAC9C,CAAA,EACb,kBAAC,GAAD;KAAa,WAAU;eACpB,OAAO,QAAQ,EAAmB,CAAC,KAAK,CAAC,GAAQ,OAAW;MAC3D,IAAM,IAAQ,GAAe,OAAO,GAC9B,IAAM,IAAQ,IAAI,KAAK,MAAO,IAAQ,IAAS,IAAI,GAAG;AAU5D,aACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAc,EAAO,aAAa,CAAC,QAAQ,KAAK,IAAI;QAAQ,CAAA,EAC5E,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACG;SAAM;SAAG;SAAI;SACT;UACH;UACN,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,OAAD;QACE,WAAW,uBAnBoB;SACrC,WAAW;SACX,cAAc;SACd,SAAS;SACT,aAAa;SACb,WAAW;SACX,UAAU;SACV,WAAW;SACZ,CAWgD,MAAW;QACpD,OAAO,EAAE,OAAO,GAAG,EAAI,IAAI;QAC3B,CAAA;OACE,CAAA,CACF,EAAA,EAbI,EAaJ;OAER;KACU,CAAA,CACT,EAAA,CAAA,EAEP,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,kBAA0B,CAAA,EAC1B,CAAA,EACb,kBAAC,GAAD;KAAa,WAAU;eAAvB,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAmC,EAAQ;OAAc,CAAA,EACtE,kBAAC,KAAD;OAAG,WAAU;iBAAgC;OAAwB,CAAA,CACjE;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAyB,EAAQ,iBAAiB;QAAM,CAAA,EACrE,kBAAC,KAAD;QAAG,WAAU;kBAAgC;QAAkB,CAAA,CAC3D;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAyB,EAAQ,iBAAiB;QAAM,CAAA,EACrE,kBAAC,KAAD;QAAG,WAAU;kBAAgC;QAAkB,CAAA,CAC3D;SACF;QACM;OACT,EAAA,CAAA,CACH;;GACF"}
1
+ {"version":3,"file":"ProductsFeatureAnalyticsPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsFeatureAnalyticsPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { TrendingUp, ThumbsUp, Users, BarChart3, Target, Loader2 } from 'lucide-react';\nimport { useParams } from 'react-router';\nimport { countLabel, useFeatureCounts } from '../hooks/useCounts';\n\nconst GET_FEATURE_REQUEST_ANALYTICS = gql`\n query GetFeatureRequestAnalytics($id: ID!) {\n planmagnetFeatureRequest(id: $id) {\n id\n title\n description\n status\n businessValue\n effortEstimate\n priorityScore\n voteCount\n voteRank\n submittedBy\n tags\n createdAt\n updatedAt\n votes {\n id\n voterId\n weight\n comment\n createdAt\n }\n competitors {\n id\n name\n }\n }\n }\n`;\n\ninterface VoteNode {\n id: string;\n voterId: string;\n weight: number;\n comment: string | null;\n createdAt: string;\n}\n\nexport function ProductsFeatureAnalyticsPagePage() {\n const params = useParams<{ id: string }>();\n const featureId = params.id ?? '';\n\n const {\n data,\n loading,\n error,\n } = // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n useQuery<Record<string, any>>(GET_FEATURE_REQUEST_ANALYTICS, {\n variables: { id: featureId },\n skip: !featureId,\n });\n\n // Rank and distribution cover EVERY request, from the server (BOFF-7995: both were computed over the 100\n // newest in the browser, so a workspace with more read \"of 100\", and an older request had no rank).\n const featureCounts = useFeatureCounts();\n\n // Only before the first load: a refetch must not blank the page (it\n\n // unmounts every component on it and loses their state).\n\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load analytics: {error.message}</div>;\n }\n\n const feature = data?.planmagnetFeatureRequest;\n if (!feature) return <div className=\"p-6 text-muted-foreground\">Feature request not found.</div>;\n\n const votes: VoteNode[] = feature.votes ?? [];\n const competitorCount = feature.competitors?.length ?? 0;\n\n // Vote distribution by weight\n const votesByWeight: Record<number, number> = {};\n for (const v of votes) {\n votesByWeight[v.weight] = (votesByWeight[v.weight] || 0) + 1;\n }\n const maxVoteWeight = Math.max(...Object.values(votesByWeight), 1);\n\n // Vote timeline - group by creation date\n const voteTimeline: { date: string; count: number }[] = [];\n const voteDateMap: Record<string, number> = {};\n for (const v of votes) {\n const date = new Date(v.createdAt).toLocaleDateString();\n voteDateMap[date] = (voteDateMap[date] || 0) + 1;\n }\n for (const [date, count] of Object.entries(voteDateMap)) {\n voteTimeline.push({ date, count });\n }\n voteTimeline.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());\n const maxTimelineCount = Math.max(...voteTimeline.map((d) => d.count), 1);\n\n const statusDistribution: Record<string, number> = featureCounts\n ? Object.fromEntries(Object.entries(featureCounts.byStatus).filter(([, n]) => n > 0))\n : {};\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Feature request analytics</h1>\n <p className=\"text-sm text-muted-foreground\">\n {feature.title} - {feature.status.toLowerCase().replace('_', ' ')}\n </p>\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Target className=\"h-4 w-4\" />\n Priority Score\n </div>\n <p className=\"text-2xl font-bold mt-1\">{feature.priorityScore ?? 0}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <ThumbsUp className=\"h-4 w-4\" />\n Total Votes\n </div>\n <p className=\"text-2xl font-bold mt-1\">{feature.voteCount}</p>\n <p className=\"text-xs text-green-600 mt-1\">\n Rank #{feature.voteRank} of {countLabel(featureCounts?.all)}\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Users className=\"h-4 w-4\" />\n Competitors\n </div>\n <p className=\"text-2xl font-bold mt-1\">{competitorCount}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <TrendingUp className=\"h-4 w-4\" />\n Business Value\n </div>\n <p className=\"text-2xl font-bold mt-1\">{feature.businessValue ?? 0}</p>\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4\" />\n Vote Timeline\n </CardTitle>\n </CardHeader>\n <CardContent>\n {voteTimeline.length === 0 ? (\n <p className=\"text-sm text-muted-foreground text-center py-8\">\n No vote data available\n </p>\n ) : (\n <div className=\"flex items-end gap-1 h-48\">\n {voteTimeline.map((d) => (\n <div key={d.date} className=\"flex-1 flex flex-col items-center gap-1\">\n <div className=\"w-full flex justify-center\">\n <div\n className=\"w-5 bg-primary rounded-t transition-all\"\n style={{ height: `${(d.count / maxTimelineCount) * 160}px` }}\n />\n </div>\n <span className=\"text-[10px] text-muted-foreground truncate max-w-[40px]\">\n {d.date}\n </span>\n </div>\n ))}\n </div>\n )}\n <p className=\"text-xs text-muted-foreground text-center mt-2\">Votes over time</p>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Vote Weight Distribution</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {Object.entries(votesByWeight).length === 0 ? (\n <p className=\"text-sm text-muted-foreground text-center py-8\">No votes recorded</p>\n ) : (\n Object.entries(votesByWeight)\n .sort(([a], [b]) => Number(a) - Number(b))\n .map(([weight, count]) => (\n <div key={weight}>\n <div className=\"flex justify-between text-sm mb-1\">\n <span>Weight {weight}</span>\n <span className=\"font-semibold\">{count} votes</span>\n </div>\n <div className=\"w-full h-3 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full rounded-full bg-primary\"\n style={{ width: `${(count / maxVoteWeight) * 100}%` }}\n />\n </div>\n </div>\n ))\n )}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <Card>\n <CardHeader>\n <CardTitle>All feature requests - status distribution</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {Object.entries(statusDistribution).map(([status, count]) => {\n const total = featureCounts?.all ?? 0;\n const pct = total > 0 ? Math.round((count / total) * 100) : 0;\n const colors: Record<string, string> = {\n SUBMITTED: 'bg-gray-400',\n UNDER_REVIEW: 'bg-yellow-400',\n PLANNED: 'bg-blue-400',\n IN_PROGRESS: 'bg-purple-400',\n COMPLETED: 'bg-green-400',\n DECLINED: 'bg-red-400',\n DUPLICATE: 'bg-orange-400',\n };\n return (\n <div key={status}>\n <div className=\"flex justify-between text-sm mb-1\">\n <span className=\"capitalize\">{status.toLowerCase().replace('_', ' ')}</span>\n <span className=\"font-medium\">\n {count} ({pct}%)\n </span>\n </div>\n <div className=\"w-full h-2 rounded-full bg-muted overflow-hidden\">\n <div\n className={`h-full rounded-full ${colors[status] ?? 'bg-gray-300'}`}\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n );\n })}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Request impact</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"text-center p-4 bg-muted rounded-md\">\n <p className=\"text-3xl font-bold text-primary\">{feature.voteCount}</p>\n <p className=\"text-sm text-muted-foreground\">total votes received</p>\n </div>\n <div className=\"grid grid-cols-2 gap-2 text-center\">\n <div className=\"p-3 border rounded-md\">\n <p className=\"text-lg font-semibold\">{feature.businessValue ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">business value</p>\n </div>\n <div className=\"p-3 border rounded-md\">\n <p className=\"text-lg font-semibold\">{feature.priorityScore ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">priority score</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsFeatureDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsFeatureDetailPagePage.tsx"],"names":[],"mappings":"AAqGA,wBAAgB,6BAA6B,4CA0R5C"}
1
+ {"version":3,"file":"ProductsFeatureDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsFeatureDetailPagePage.tsx"],"names":[],"mappings":"AAsGA,wBAAgB,6BAA6B,4CA8R5C"}
@@ -6,15 +6,16 @@ import { FeatureTriageActions as a, isOpenRequest as o, isSnoozed as s } from ".
6
6
  import { CategoryBadge as c, RatingDisplay as l } from "../controls/FeedbackControls.js";
7
7
  import { FeatureHeaderActions as u, FeaturePrioritizationCard as d, FeatureVoteButton as f } from "../controls/FeatureControls.js";
8
8
  import { FeatureInitiativeCard as p } from "../roadmaps/FeatureInitiativeCard.js";
9
- import { useState as m } from "react";
10
- import { Loader2 as h, MessageSquare as g, Star as _, Target as v, ThumbsUp as y } from "lucide-react";
11
- import { useParams as b } from "react-router";
12
- import { gql as x } from "@apollo/client";
13
- import { useQuery as S } from "@apollo/client/react";
14
- import { Fragment as C, jsx as w, jsxs as T } from "react/jsx-runtime";
15
- import { Badge as E, Card as D, CardContent as O, CardHeader as k, CardTitle as A } from "@burdenoff/fe-libs/ui";
9
+ import { ProductFeatureLinkCard as m } from "../product/ProductFeatureLinkCard.js";
10
+ import { useState as h } from "react";
11
+ import { Loader2 as g, MessageSquare as _, Star as v, Target as y, ThumbsUp as b } from "lucide-react";
12
+ import { useParams as x } from "react-router";
13
+ import { gql as S } from "@apollo/client";
14
+ import { useQuery as C } from "@apollo/client/react";
15
+ import { Fragment as w, jsx as T, jsxs as E } from "react/jsx-runtime";
16
+ import { Badge as D, Card as O, CardContent as k, CardHeader as A, CardTitle as j } from "@burdenoff/fe-libs/ui";
16
17
  //#region src/planmagnet/pages/ProductsFeatureDetailPagePage.tsx
17
- var j = x`
18
+ var M = S`
18
19
  query GetFeatureRequest($id: ID!) {
19
20
  planmagnetFeatureRequest(id: $id) {
20
21
  id
@@ -78,88 +79,88 @@ var j = x`
78
79
  }
79
80
  }
80
81
  `;
81
- function M() {
82
- let { workspaceId: x, currentUser: M } = e(), N = t(), [P] = m(() => Date.now()), F = b().id ?? "", { data: I, loading: L, error: R } = S(j, {
83
- variables: { id: F },
84
- skip: !F
82
+ function N() {
83
+ let { workspaceId: S, currentUser: N } = e(), P = t(), [F] = h(() => Date.now()), I = x().id ?? "", { data: L, loading: R, error: z } = C(M, {
84
+ variables: { id: I },
85
+ skip: !I
85
86
  });
86
- if (L && !I) return /* @__PURE__ */ w("div", {
87
+ if (R && !L) return /* @__PURE__ */ T("div", {
87
88
  className: "flex items-center justify-center p-12",
88
- children: /* @__PURE__ */ w(h, { className: "h-8 w-8 animate-spin text-muted-foreground" })
89
+ children: /* @__PURE__ */ T(g, { className: "h-8 w-8 animate-spin text-muted-foreground" })
89
90
  });
90
- if (R) return /* @__PURE__ */ T("div", {
91
+ if (z) return /* @__PURE__ */ E("div", {
91
92
  className: "p-6 text-destructive",
92
- children: ["Failed to load feature: ", R.message]
93
+ children: ["Failed to load feature request: ", z.message]
93
94
  });
94
- let z = I?.planmagnetFeatureRequest;
95
- if (!z) return /* @__PURE__ */ w("div", {
95
+ let B = L?.planmagnetFeatureRequest;
96
+ if (!B) return /* @__PURE__ */ T("div", {
96
97
  className: "p-6 text-muted-foreground",
97
- children: "Feature not found."
98
+ children: "Feature request not found."
98
99
  });
99
- let B = z.votes ?? [], V = z.competitors ?? [];
100
- return /* @__PURE__ */ T("div", {
100
+ let V = B.votes ?? [], H = B.competitors ?? [];
101
+ return /* @__PURE__ */ E("div", {
101
102
  className: "space-y-6 p-6",
102
103
  children: [
103
- /* @__PURE__ */ T("div", {
104
+ /* @__PURE__ */ E("div", {
104
105
  className: "flex items-center justify-between",
105
- children: [/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("h1", {
106
+ children: [/* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("h1", {
106
107
  className: "text-2xl font-semibold",
107
- children: z.title
108
- }), /* @__PURE__ */ T("p", {
108
+ children: B.title
109
+ }), /* @__PURE__ */ E("p", {
109
110
  className: "text-sm text-muted-foreground",
110
111
  children: [
111
112
  "Submitted by: ",
112
- /* @__PURE__ */ w(n, { id: z.submittedBy }),
113
+ /* @__PURE__ */ T(n, { id: B.submittedBy }),
113
114
  " · Effort:",
114
115
  " ",
115
- z.effortEstimate ?? "N/A"
116
+ B.effortEstimate ?? "N/A"
116
117
  ]
117
- })] }), /* @__PURE__ */ T("div", {
118
+ })] }), /* @__PURE__ */ E("div", {
118
119
  className: "flex flex-col items-end gap-2",
119
- children: [/* @__PURE__ */ w(f, {
120
- featureId: z.id,
121
- voted: B.some((e) => e.voterId === M?.id)
122
- }, z.id), /* @__PURE__ */ w(u, { feature: z })]
120
+ children: [/* @__PURE__ */ T(f, {
121
+ featureId: B.id,
122
+ voted: V.some((e) => e.voterId === N?.id)
123
+ }, B.id), /* @__PURE__ */ T(u, { feature: B })]
123
124
  })]
124
125
  }),
125
- o(z.status) && /* @__PURE__ */ T(D, {
126
+ o(B.status) && /* @__PURE__ */ E(O, {
126
127
  "data-testid": "triage-card",
127
- children: [/* @__PURE__ */ w(k, { children: /* @__PURE__ */ w(A, { children: "Triage" }) }), /* @__PURE__ */ T(O, {
128
+ children: [/* @__PURE__ */ T(A, { children: /* @__PURE__ */ T(j, { children: "Triage" }) }), /* @__PURE__ */ E(k, {
128
129
  className: "space-y-2",
129
- children: [/* @__PURE__ */ w("p", {
130
+ children: [/* @__PURE__ */ T("p", {
130
131
  className: "text-sm text-muted-foreground",
131
- children: s(z.snoozedUntil, P) ? `Snoozed until ${new Date(z.snoozedUntil).toLocaleString()} — it returns to the triage queue then.` : z.status === "SUBMITTED" ? "Waiting for a decision." : "Under review: accept it as planned, decline it, or merge it into its original."
132
- }), /* @__PURE__ */ w(a, {
133
- feature: z,
134
- now: P
132
+ children: s(B.snoozedUntil, F) ? `Snoozed until ${new Date(B.snoozedUntil).toLocaleString()} — it returns to the triage queue then.` : B.status === "SUBMITTED" ? "Waiting for a decision." : "Under review: accept it as planned, decline it, or merge it into its original."
133
+ }), /* @__PURE__ */ T(a, {
134
+ feature: B,
135
+ now: F
135
136
  })]
136
137
  })]
137
138
  }),
138
- z.status === "DECLINED" && z.declineReason && /* @__PURE__ */ w(D, {
139
+ B.status === "DECLINED" && B.declineReason && /* @__PURE__ */ T(O, {
139
140
  "data-testid": "decline-reason",
140
- children: /* @__PURE__ */ T(O, {
141
+ children: /* @__PURE__ */ E(k, {
141
142
  className: "pt-4 text-sm",
142
- children: [/* @__PURE__ */ w("span", {
143
+ children: [/* @__PURE__ */ T("span", {
143
144
  className: "font-medium",
144
145
  children: "Declined: "
145
- }), z.declineReason]
146
+ }), B.declineReason]
146
147
  })
147
148
  }),
148
- z.status === "DUPLICATE" && z.duplicateOfId && /* @__PURE__ */ w(D, {
149
+ B.status === "DUPLICATE" && B.duplicateOfId && /* @__PURE__ */ T(O, {
149
150
  "data-testid": "duplicate-of",
150
- children: /* @__PURE__ */ T(O, {
151
+ children: /* @__PURE__ */ E(k, {
151
152
  className: "pt-4 text-sm",
152
153
  children: [
153
- /* @__PURE__ */ w("span", {
154
+ /* @__PURE__ */ T("span", {
154
155
  className: "font-medium",
155
156
  children: "Duplicate of "
156
157
  }),
157
- z.duplicateOf ? /* @__PURE__ */ w("button", {
158
+ B.duplicateOf ? /* @__PURE__ */ T("button", {
158
159
  type: "button",
159
160
  className: "text-primary underline-offset-2 hover:underline",
160
- onClick: () => N(r("/products/feature-detail-page", z.duplicateOf.id)),
161
- children: z.duplicateOf.title
162
- }) : /* @__PURE__ */ w("span", {
161
+ onClick: () => P(r("/products/feature-detail-page", B.duplicateOf.id)),
162
+ children: B.duplicateOf.title
163
+ }) : /* @__PURE__ */ T("span", {
163
164
  className: "text-muted-foreground",
164
165
  children: "a request that has since been deleted"
165
166
  }),
@@ -168,60 +169,60 @@ function M() {
168
169
  ]
169
170
  })
170
171
  }),
171
- /* @__PURE__ */ T("div", {
172
+ /* @__PURE__ */ E("div", {
172
173
  className: "grid grid-cols-2 md:grid-cols-4 gap-4",
173
174
  children: [
174
- /* @__PURE__ */ w(D, { children: /* @__PURE__ */ T(O, {
175
+ /* @__PURE__ */ T(O, { children: /* @__PURE__ */ E(k, {
175
176
  className: "pt-4 text-center",
176
177
  children: [
177
- /* @__PURE__ */ w(v, { className: "h-5 w-5 mx-auto text-primary" }),
178
- /* @__PURE__ */ w("p", {
178
+ /* @__PURE__ */ T(y, { className: "h-5 w-5 mx-auto text-primary" }),
179
+ /* @__PURE__ */ T("p", {
179
180
  className: "text-2xl font-bold mt-1",
180
- children: z.priorityScore ?? 0
181
+ children: B.priorityScore ?? 0
181
182
  }),
182
- /* @__PURE__ */ w("p", {
183
+ /* @__PURE__ */ T("p", {
183
184
  className: "text-xs text-muted-foreground",
184
185
  children: "Priority Score"
185
186
  })
186
187
  ]
187
188
  }) }),
188
- /* @__PURE__ */ w(D, { children: /* @__PURE__ */ T(O, {
189
+ /* @__PURE__ */ T(O, { children: /* @__PURE__ */ E(k, {
189
190
  className: "pt-4 text-center",
190
191
  children: [
191
- /* @__PURE__ */ w(y, { className: "h-5 w-5 mx-auto text-green-500" }),
192
- /* @__PURE__ */ w("p", {
192
+ /* @__PURE__ */ T(b, { className: "h-5 w-5 mx-auto text-green-500" }),
193
+ /* @__PURE__ */ T("p", {
193
194
  className: "text-2xl font-bold mt-1",
194
- children: z.voteCount
195
+ children: B.voteCount
195
196
  }),
196
- /* @__PURE__ */ w("p", {
197
+ /* @__PURE__ */ T("p", {
197
198
  className: "text-xs text-muted-foreground",
198
199
  children: "Votes"
199
200
  })
200
201
  ]
201
202
  }) }),
202
- /* @__PURE__ */ w(D, { children: /* @__PURE__ */ T(O, {
203
+ /* @__PURE__ */ T(O, { children: /* @__PURE__ */ E(k, {
203
204
  className: "pt-4 text-center",
204
205
  children: [
205
- /* @__PURE__ */ w(_, { className: "h-5 w-5 mx-auto text-yellow-500" }),
206
- /* @__PURE__ */ w("p", {
206
+ /* @__PURE__ */ T(v, { className: "h-5 w-5 mx-auto text-yellow-500" }),
207
+ /* @__PURE__ */ T("p", {
207
208
  className: "text-2xl font-bold mt-1",
208
- children: z.businessValue ?? 0
209
+ children: B.businessValue ?? 0
209
210
  }),
210
- /* @__PURE__ */ w("p", {
211
+ /* @__PURE__ */ T("p", {
211
212
  className: "text-xs text-muted-foreground",
212
213
  children: "Business Value"
213
214
  })
214
215
  ]
215
216
  }) }),
216
- /* @__PURE__ */ w(D, { children: /* @__PURE__ */ T(O, {
217
+ /* @__PURE__ */ T(O, { children: /* @__PURE__ */ E(k, {
217
218
  className: "pt-4 text-center",
218
219
  children: [
219
- /* @__PURE__ */ w(g, { className: "h-5 w-5 mx-auto text-blue-500" }),
220
- /* @__PURE__ */ w("p", {
220
+ /* @__PURE__ */ T(_, { className: "h-5 w-5 mx-auto text-blue-500" }),
221
+ /* @__PURE__ */ T("p", {
221
222
  className: "text-2xl font-bold mt-1",
222
- children: V.length
223
+ children: H.length
223
224
  }),
224
- /* @__PURE__ */ w("p", {
225
+ /* @__PURE__ */ T("p", {
225
226
  className: "text-xs text-muted-foreground",
226
227
  children: "Competitors"
227
228
  })
@@ -229,147 +230,148 @@ function M() {
229
230
  }) })
230
231
  ]
231
232
  }),
232
- /* @__PURE__ */ T("div", {
233
+ /* @__PURE__ */ E("div", {
233
234
  className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
234
- children: [/* @__PURE__ */ T("div", {
235
+ children: [/* @__PURE__ */ E("div", {
235
236
  className: "lg:col-span-2 space-y-6",
236
237
  children: [
237
- /* @__PURE__ */ T(D, { children: [/* @__PURE__ */ w(k, { children: /* @__PURE__ */ w(A, { children: "Description" }) }), /* @__PURE__ */ w(O, { children: /* @__PURE__ */ w("p", {
238
+ /* @__PURE__ */ E(O, { children: [/* @__PURE__ */ T(A, { children: /* @__PURE__ */ T(j, { children: "Description" }) }), /* @__PURE__ */ T(k, { children: /* @__PURE__ */ T("p", {
238
239
  className: "text-sm",
239
- children: z.description ?? "No description provided."
240
+ children: B.description ?? "No description provided."
240
241
  }) })] }),
241
- /* @__PURE__ */ T(D, { children: [/* @__PURE__ */ w(k, { children: /* @__PURE__ */ T(A, { children: [
242
+ /* @__PURE__ */ E(O, { children: [/* @__PURE__ */ T(A, { children: /* @__PURE__ */ E(j, { children: [
242
243
  "Votes (",
243
- B.length,
244
+ V.length,
244
245
  ")"
245
- ] }) }), /* @__PURE__ */ T(O, {
246
+ ] }) }), /* @__PURE__ */ E(k, {
246
247
  className: "space-y-3",
247
- children: [B.length === 0 && /* @__PURE__ */ w("p", {
248
+ children: [V.length === 0 && /* @__PURE__ */ T("p", {
248
249
  className: "text-sm text-muted-foreground",
249
250
  children: "No votes yet."
250
- }), B.map((e) => /* @__PURE__ */ T("div", {
251
+ }), V.map((e) => /* @__PURE__ */ E("div", {
251
252
  className: "flex items-start justify-between border rounded-md p-3",
252
- children: [/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ T("p", {
253
+ children: [/* @__PURE__ */ E("div", { children: [/* @__PURE__ */ E("p", {
253
254
  className: "text-sm font-medium",
254
- children: ["Voter: ", /* @__PURE__ */ w(n, { id: e.voterId })]
255
- }), e.comment && /* @__PURE__ */ w("p", {
255
+ children: ["Voter: ", /* @__PURE__ */ T(n, { id: e.voterId })]
256
+ }), e.comment && /* @__PURE__ */ T("p", {
256
257
  className: "text-xs text-muted-foreground mt-1",
257
258
  children: e.comment
258
- })] }), /* @__PURE__ */ T("div", {
259
+ })] }), /* @__PURE__ */ E("div", {
259
260
  className: "flex items-center gap-1",
260
- children: [/* @__PURE__ */ w(y, { className: "h-3 w-3 text-green-500" }), /* @__PURE__ */ w("span", {
261
+ children: [/* @__PURE__ */ T(b, { className: "h-3 w-3 text-green-500" }), /* @__PURE__ */ T("span", {
261
262
  className: "text-sm font-bold",
262
263
  children: e.weight
263
264
  })]
264
265
  })]
265
266
  }, e.id))]
266
267
  })] }),
267
- /* @__PURE__ */ T(D, { children: [/* @__PURE__ */ w(k, { children: /* @__PURE__ */ T(A, { children: [
268
+ /* @__PURE__ */ E(O, { children: [/* @__PURE__ */ T(A, { children: /* @__PURE__ */ E(j, { children: [
268
269
  "Competitors (",
269
- V.length,
270
+ H.length,
270
271
  ")"
271
- ] }) }), /* @__PURE__ */ w(O, { children: /* @__PURE__ */ w(i, {
272
- featureRequestId: z.id,
273
- competitors: V
272
+ ] }) }), /* @__PURE__ */ T(k, { children: /* @__PURE__ */ T(i, {
273
+ featureRequestId: B.id,
274
+ competitors: H
274
275
  }) })] })
275
276
  ]
276
- }), /* @__PURE__ */ T("div", {
277
+ }), /* @__PURE__ */ E("div", {
277
278
  className: "space-y-6",
278
279
  children: [
279
- /* @__PURE__ */ w(p, {
280
- featureId: z.id,
281
- productId: z.productId ?? null,
282
- initiative: z.roadmapItem ?? null
280
+ /* @__PURE__ */ T(m, { featureRequestId: B.id }),
281
+ /* @__PURE__ */ T(p, {
282
+ featureId: B.id,
283
+ productId: B.productId ?? null,
284
+ initiative: B.roadmapItem ?? null
283
285
  }),
284
- /* @__PURE__ */ w(d, { feature: z }),
285
- /* @__PURE__ */ T(D, { children: [/* @__PURE__ */ w(k, { children: /* @__PURE__ */ w(A, { children: "Details" }) }), /* @__PURE__ */ T(O, {
286
+ /* @__PURE__ */ T(d, { feature: B }),
287
+ /* @__PURE__ */ E(O, { children: [/* @__PURE__ */ T(A, { children: /* @__PURE__ */ T(j, { children: "Details" }) }), /* @__PURE__ */ E(k, {
286
288
  className: "space-y-3 text-sm",
287
289
  children: [
288
- /* @__PURE__ */ T("div", {
290
+ /* @__PURE__ */ E("div", {
289
291
  className: "flex justify-between",
290
- children: [/* @__PURE__ */ w("span", {
292
+ children: [/* @__PURE__ */ T("span", {
291
293
  className: "text-muted-foreground",
292
294
  children: "Status"
293
- }), /* @__PURE__ */ w(E, {
295
+ }), /* @__PURE__ */ T(D, {
294
296
  variant: "secondary",
295
297
  className: "capitalize",
296
- children: z.status.toLowerCase().replace("_", " ")
298
+ children: B.status.toLowerCase().replace("_", " ")
297
299
  })]
298
300
  }),
299
- /* @__PURE__ */ T("div", {
301
+ /* @__PURE__ */ E("div", {
300
302
  className: "flex justify-between",
301
- children: [/* @__PURE__ */ w("span", {
303
+ children: [/* @__PURE__ */ T("span", {
302
304
  className: "text-muted-foreground",
303
305
  children: "Priority Score"
304
- }), /* @__PURE__ */ w(E, {
306
+ }), /* @__PURE__ */ T(D, {
305
307
  variant: "outline",
306
- children: z.priorityScore ?? "N/A"
308
+ children: B.priorityScore ?? "N/A"
307
309
  })]
308
310
  }),
309
- /* @__PURE__ */ T("div", {
311
+ /* @__PURE__ */ E("div", {
310
312
  className: "flex justify-between",
311
- children: [/* @__PURE__ */ w("span", {
313
+ children: [/* @__PURE__ */ T("span", {
312
314
  className: "text-muted-foreground",
313
315
  children: "Effort"
314
- }), /* @__PURE__ */ w(E, {
316
+ }), /* @__PURE__ */ T(D, {
315
317
  variant: "outline",
316
318
  className: "capitalize",
317
- children: z.effortEstimate ?? "N/A"
319
+ children: B.effortEstimate ?? "N/A"
318
320
  })]
319
321
  }),
320
- /* @__PURE__ */ T("div", {
322
+ /* @__PURE__ */ E("div", {
321
323
  className: "flex justify-between",
322
- children: [/* @__PURE__ */ w("span", {
324
+ children: [/* @__PURE__ */ T("span", {
323
325
  className: "text-muted-foreground",
324
326
  children: "Business Value"
325
- }), /* @__PURE__ */ w("span", {
327
+ }), /* @__PURE__ */ T("span", {
326
328
  className: "font-medium",
327
- children: z.businessValue ?? "N/A"
329
+ children: B.businessValue ?? "N/A"
328
330
  })]
329
331
  }),
330
- /* @__PURE__ */ T("div", {
332
+ /* @__PURE__ */ E("div", {
331
333
  className: "flex justify-between items-center",
332
- children: [/* @__PURE__ */ w("span", {
334
+ children: [/* @__PURE__ */ T("span", {
333
335
  className: "text-muted-foreground",
334
336
  children: "Rating"
335
- }), /* @__PURE__ */ w(l, { rating: z.rating ?? null })]
337
+ }), /* @__PURE__ */ T(l, { rating: B.rating ?? null })]
336
338
  }),
337
- /* @__PURE__ */ T("div", {
339
+ /* @__PURE__ */ E("div", {
338
340
  className: "flex justify-between items-center",
339
- children: [/* @__PURE__ */ w("span", {
341
+ children: [/* @__PURE__ */ T("span", {
340
342
  className: "text-muted-foreground",
341
343
  children: "Category"
342
- }), z.category ? /* @__PURE__ */ w(c, { category: z.category }) : /* @__PURE__ */ w("span", {
344
+ }), B.category ? /* @__PURE__ */ T(c, { category: B.category }) : /* @__PURE__ */ T("span", {
343
345
  className: "text-sm text-muted-foreground",
344
346
  children: "Not set"
345
347
  })]
346
348
  }),
347
- /* @__PURE__ */ T("div", {
349
+ /* @__PURE__ */ E("div", {
348
350
  className: "flex justify-between",
349
- children: [/* @__PURE__ */ w("span", {
351
+ children: [/* @__PURE__ */ T("span", {
350
352
  className: "text-muted-foreground",
351
353
  children: "Submitted By"
352
- }), /* @__PURE__ */ w(n, { id: z.submittedBy })]
354
+ }), /* @__PURE__ */ T(n, { id: B.submittedBy })]
353
355
  }),
354
- z.triagedAt && /* @__PURE__ */ T("div", {
356
+ B.triagedAt && /* @__PURE__ */ E("div", {
355
357
  className: "flex justify-between",
356
- children: [/* @__PURE__ */ w("span", {
358
+ children: [/* @__PURE__ */ T("span", {
357
359
  className: "text-muted-foreground",
358
360
  children: "Decided"
359
- }), /* @__PURE__ */ T("span", { children: [new Date(z.triagedAt).toLocaleDateString(), z.triagedBy && /* @__PURE__ */ T(C, { children: [" by ", /* @__PURE__ */ w(n, { id: z.triagedBy })] })] })]
361
+ }), /* @__PURE__ */ E("span", { children: [new Date(B.triagedAt).toLocaleDateString(), B.triagedBy && /* @__PURE__ */ E(w, { children: [" by ", /* @__PURE__ */ T(n, { id: B.triagedBy })] })] })]
360
362
  }),
361
- /* @__PURE__ */ T("div", {
363
+ /* @__PURE__ */ E("div", {
362
364
  className: "flex justify-between",
363
- children: [/* @__PURE__ */ w("span", {
365
+ children: [/* @__PURE__ */ T("span", {
364
366
  className: "text-muted-foreground",
365
367
  children: "Updated"
366
- }), /* @__PURE__ */ w("span", { children: new Date(z.updatedAt).toLocaleDateString() })]
368
+ }), /* @__PURE__ */ T("span", { children: new Date(B.updatedAt).toLocaleDateString() })]
367
369
  })
368
370
  ]
369
371
  })] }),
370
- z.tags?.length > 0 && /* @__PURE__ */ T(D, { children: [/* @__PURE__ */ w(k, { children: /* @__PURE__ */ w(A, { children: "Tags" }) }), /* @__PURE__ */ w(O, {
372
+ B.tags?.length > 0 && /* @__PURE__ */ E(O, { children: [/* @__PURE__ */ T(A, { children: /* @__PURE__ */ T(j, { children: "Tags" }) }), /* @__PURE__ */ T(k, {
371
373
  className: "flex flex-wrap gap-1",
372
- children: z.tags.map((e) => /* @__PURE__ */ w(E, {
374
+ children: B.tags.map((e) => /* @__PURE__ */ T(D, {
373
375
  variant: "outline",
374
376
  className: "text-xs",
375
377
  children: e
@@ -382,6 +384,6 @@ function M() {
382
384
  });
383
385
  }
384
386
  //#endregion
385
- export { M as ProductsFeatureDetailPagePage };
387
+ export { N as ProductsFeatureDetailPagePage };
386
388
 
387
389
  //# sourceMappingURL=ProductsFeatureDetailPagePage.js.map