@burdenoff/microfe-planmagnet 2026.926.2 → 2026.927.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 (53) hide show
  1. package/dist/planmagnet/pages/DashboardDashboardPagePage.d.ts.map +1 -1
  2. package/dist/planmagnet/pages/DashboardDashboardPagePage.js +14 -4
  3. package/dist/planmagnet/pages/DashboardDashboardPagePage.js.map +1 -1
  4. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
  5. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +102 -100
  6. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
  7. package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
  8. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +95 -94
  9. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
  10. package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
  11. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +1 -1
  12. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
  13. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
  14. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +97 -93
  15. package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
  16. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.d.ts.map +1 -1
  17. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +84 -73
  18. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js.map +1 -1
  19. package/dist/planmagnet/pages/ProjectsMilestonesPagePage.d.ts.map +1 -1
  20. package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js +13 -8
  21. package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js.map +1 -1
  22. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
  23. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +129 -125
  24. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
  25. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts.map +1 -1
  26. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +112 -109
  27. package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js.map +1 -1
  28. package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
  29. package/dist/planmagnet/pages/ReportsReportsPagePage.js +72 -83
  30. package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
  31. package/dist/planmagnet/pages/SprintsStartSprintPagePage.d.ts.map +1 -1
  32. package/dist/planmagnet/pages/SprintsStartSprintPagePage.js +103 -103
  33. package/dist/planmagnet/pages/SprintsStartSprintPagePage.js.map +1 -1
  34. package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +1 -1
  35. package/dist/planmagnet/pages/TasksEditTaskPagePage.js +101 -99
  36. package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
  37. package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
  38. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +127 -125
  39. package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
  40. package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
  41. package/dist/planmagnet/pages/TasksTasksPagePage.js +8 -11
  42. package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
  43. package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +1 -1
  44. package/dist/planmagnet/pages/TeamTeamPagePage.js +67 -68
  45. package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
  46. package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.d.ts.map +1 -1
  47. package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.js +1 -5
  48. package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.js.map +1 -1
  49. package/dist/planmagnet/people/People.d.ts +18 -0
  50. package/dist/planmagnet/people/People.d.ts.map +1 -1
  51. package/dist/planmagnet/people/People.js +26 -12
  52. package/dist/planmagnet/people/People.js.map +1 -1
  53. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardDashboardPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/DashboardDashboardPagePage.tsx"],"names":[],"mappings":"AAwFA,wBAAgB,0BAA0B,4CAiWzC"}
1
+ {"version":3,"file":"DashboardDashboardPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/DashboardDashboardPagePage.tsx"],"names":[],"mappings":"AAgGA,wBAAgB,0BAA0B,4CAqWzC"}
@@ -30,6 +30,10 @@ var S = d`
30
30
  id
31
31
  name
32
32
  projectId
33
+ project {
34
+ id
35
+ name
36
+ }
33
37
  status
34
38
  startDate
35
39
  endDate
@@ -50,6 +54,10 @@ var S = d`
50
54
  name
51
55
  description
52
56
  projectId
57
+ project {
58
+ id
59
+ name
60
+ }
53
61
  status
54
62
  dueDate
55
63
  ownerId
@@ -164,8 +172,9 @@ function C() {
164
172
  className: "text-xs text-muted-foreground",
165
173
  children: [
166
174
  C("planmagnet.dashboard.shared.project", "Project"),
167
- ": ",
168
- e.projectId
175
+ ":",
176
+ " ",
177
+ e.project?.name ?? C("planmagnet.dashboard.shared.projectUnavailable", "not available")
169
178
  ]
170
179
  })] }), /* @__PURE__ */ h(_, {
171
180
  variant: "secondary",
@@ -242,8 +251,9 @@ function C() {
242
251
  className: "text-xs text-muted-foreground",
243
252
  children: [
244
253
  C("planmagnet.dashboard.shared.project", "Project"),
245
- ": ",
246
- e.projectId
254
+ ":",
255
+ " ",
256
+ e.project?.name ?? C("planmagnet.dashboard.shared.projectUnavailable", "not available")
247
257
  ]
248
258
  }),
249
259
  /* @__PURE__ */ h("p", {
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardDashboardPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/DashboardDashboardPagePage.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, Badge } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n LayoutDashboard,\n FolderKanban,\n CheckSquare,\n Zap,\n Users,\n Calendar,\n TrendingUp,\n AlertTriangle,\n ArrowUpRight,\n} from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { PersonName } from '../people/People';\n\nconst GET_DASHBOARD_DATA = gql`\n query GetDashboardData($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 50 }) {\n items {\n id\n name\n description\n key\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n createdAt\n }\n totalCount\n }\n planmagnetSprints(workspaceId: $workspaceId, pagination: { first: 50 }) {\n items {\n id\n name\n projectId\n status\n startDate\n endDate\n goal\n capacity\n velocity\n workItems {\n id\n status\n storyPoints\n }\n }\n totalCount\n }\n planmagnetMilestones(workspaceId: $workspaceId, pagination: { first: 50 }) {\n items {\n id\n name\n description\n projectId\n status\n dueDate\n ownerId\n createdAt\n }\n totalCount\n }\n planmagnetWorkItems(workspaceId: $workspaceId, pagination: { first: 20 }) {\n items {\n id\n key\n description\n status\n priority\n storyPoints\n assigneeId\n projectId\n labels\n createdAt\n }\n totalCount\n }\n }\n`;\n\nexport function DashboardDashboardPagePage() {\n const { workspaceId } = usePlanMagnet();\n const { t } = useI18n();\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_DASHBOARD_DATA, {\n variables: { workspaceId: workspaceId ?? 'default' },\n });\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 <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n if (error)\n return (\n <div className=\"p-6 text-red-500\">\n {t('planmagnet.dashboard.errorLoading', 'Error loading dashboard')}: {error.message}\n </div>\n );\n\n const projects = data?.planmagnetProjects?.items ?? [];\n const sprints = data?.planmagnetSprints?.items ?? [];\n const milestones = data?.planmagnetMilestones?.items ?? [];\n const workItems = data?.planmagnetWorkItems?.items ?? [];\n\n const activeProjects = projects.filter((p: { status: string }) => p.status === 'ACTIVE');\n const completedProjects = projects.filter((p: { status: string }) => p.status === 'COMPLETED');\n const activeSprints = sprints.filter((s: { status: string }) => s.status === 'ACTIVE');\n const openMilestones = milestones.filter(\n (m: { status: string }) => m.status === 'PENDING' || m.status === 'IN_PROGRESS'\n );\n // The list shows four; the \"upcoming\" count is all of them (it was the\n // sliced list's length, so it could never exceed 4).\n const upcomingMilestones = openMilestones.slice(0, 4);\n const recentWorkItems = workItems.slice(0, 5);\n // Work items carry only a projectId; the page already holds the projects, so\n // show the name instead of the raw id (P1.1). A project outside the first 50\n // falls back to a short id rather than the full UUID. Deliberately NOT a\n // useMemo: this line runs after the loading/error early returns, and a hook\n // here would change the hook count between renders and crash the page.\n const projectNameById = new Map<string, string>(\n projects.map((p: { id: string; name: string }) => [p.id, p.name])\n );\n\n const metrics = [\n {\n label: t('planmagnet.dashboard.metrics.totalProjects.label', 'Total Projects'),\n // Totals are the server's totalCount: the lists here hold one page (50).\n value: String(data?.planmagnetProjects?.totalCount ?? projects.length),\n trend: `${activeProjects.length} ${t('planmagnet.dashboard.metrics.totalProjects.trend', 'active')}`,\n },\n {\n label: t('planmagnet.dashboard.metrics.activeSprints.label', 'Active Sprints'),\n value: String(activeSprints.length),\n trend: `${data?.planmagnetSprints?.totalCount ?? sprints.length} ${t('planmagnet.dashboard.metrics.activeSprints.trend', 'total')}`,\n },\n {\n label: t('planmagnet.dashboard.metrics.workItems.label', 'Work Items'),\n value: String(data?.planmagnetWorkItems?.totalCount ?? 0),\n trend: t('planmagnet.dashboard.metrics.workItems.trend', 'across all projects'),\n },\n {\n label: t('planmagnet.dashboard.metrics.milestones.label', 'Milestones'),\n value: String(data?.planmagnetMilestones?.totalCount ?? milestones.length),\n trend: `${openMilestones.length} ${t('planmagnet.dashboard.metrics.milestones.trend', 'upcoming')}`,\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold flex items-center gap-2\">\n <LayoutDashboard className=\"h-6 w-6\" />\n {t('planmagnet.dashboard.title', 'Dashboard')}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {t('planmagnet.dashboard.subtitle', 'Welcome back! Here is your project overview.')}\n </p>\n </div>\n </div>\n\n {/* KPI Metrics */}\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n {metrics.map((m) => (\n <Card key={m.label}>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">{m.label}</CardTitle>\n <TrendingUp className=\"h-4 w-4 text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold\">{m.value}</div>\n <p className=\"text-xs text-muted-foreground\">{m.trend}</p>\n </CardContent>\n </Card>\n ))}\n </div>\n\n <div className=\"grid gap-6 lg:grid-cols-12\">\n {/* Active Sprints */}\n <Card className=\"lg:col-span-8\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Zap className=\"h-5 w-5 text-blue-500\" />\n {t('planmagnet.dashboard.activeSprints.title', 'Active Sprints')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {activeSprints.map(\n (sprint: {\n id: string;\n name: string;\n projectId: string;\n capacity: number | null;\n velocity: number | null;\n startDate: string | null;\n endDate: string | null;\n workItems: { id: string; status: string; storyPoints: number | null }[];\n }) => {\n const totalPoints = sprint.workItems.reduce(\n (sum: number, wi: { storyPoints: number | null }) => sum + (wi.storyPoints ?? 0),\n 0\n );\n const completedPoints = sprint.workItems\n .filter((wi: { status: string }) => wi.status === 'DONE')\n .reduce(\n (sum: number, wi: { storyPoints: number | null }) =>\n sum + (wi.storyPoints ?? 0),\n 0\n );\n const totalTasks = sprint.workItems.length;\n const completedTasks = sprint.workItems.filter(\n (wi: { status: string }) => wi.status === 'DONE'\n ).length;\n const pct = totalPoints > 0 ? Math.round((completedPoints / totalPoints) * 100) : 0;\n return (\n <div key={sprint.id} className=\"rounded-lg border p-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <div>\n <p className=\"font-medium\">{sprint.name}</p>\n <p className=\"text-xs text-muted-foreground\">\n {t('planmagnet.dashboard.shared.project', 'Project')}: {sprint.projectId}\n </p>\n </div>\n <Badge variant=\"secondary\">\n {completedPoints}/{totalPoints}{' '}\n {t('planmagnet.dashboard.shared.pointsShort', 'pts')}\n </Badge>\n </div>\n <div className=\"w-full h-2 bg-muted rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-primary rounded-full transition-all\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <div className=\"flex items-center justify-between mt-2 text-xs text-muted-foreground\">\n <span>\n {completedTasks}/{totalTasks}{' '}\n {t('planmagnet.dashboard.shared.tasks', 'tasks')}\n </span>\n <span>\n {sprint.startDate ? new Date(sprint.startDate).toLocaleDateString() : '—'} -{' '}\n {sprint.endDate ? new Date(sprint.endDate).toLocaleDateString() : '—'}\n </span>\n </div>\n </div>\n );\n }\n )}\n {activeSprints.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">\n {t('planmagnet.dashboard.activeSprints.empty', 'No active sprints.')}\n </p>\n )}\n </CardContent>\n </Card>\n\n {/* Sidebar */}\n <div className=\"lg:col-span-4 space-y-6\">\n {/* On-Hold Projects */}\n {projects.filter((p: { status: string }) => p.status === 'ON_HOLD').length > 0 && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <AlertTriangle className=\"h-5 w-5 text-orange-500\" />\n {t('planmagnet.dashboard.onHoldProjects.title', 'On-Hold Projects')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {projects\n .filter((p: { status: string }) => p.status === 'ON_HOLD')\n .map((p: { id: string; name: string; status: string }) => (\n <div\n key={p.id}\n className=\"flex items-center justify-between rounded border p-2\"\n >\n <div>\n <p className=\"text-sm font-medium\">{p.name}</p>\n </div>\n <Badge variant=\"destructive\">\n {p.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n ))}\n </CardContent>\n </Card>\n )}\n\n {/* Upcoming Milestones */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Calendar className=\"h-5 w-5 text-green-500\" />\n {t('planmagnet.dashboard.upcomingMilestones.title', 'Upcoming Milestones')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {upcomingMilestones.map(\n (ms: {\n id: string;\n name: string;\n projectId: string;\n dueDate: string | null;\n status: string;\n }) => (\n <div key={ms.id} className=\"flex items-start gap-3 rounded border p-2\">\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium truncate\">{ms.name}</p>\n <p className=\"text-xs text-muted-foreground\">\n {t('planmagnet.dashboard.shared.project', 'Project')}: {ms.projectId}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {t('planmagnet.dashboard.shared.due', 'Due')}{' '}\n {ms.dueDate ? new Date(ms.dueDate).toLocaleDateString() : '—'}\n </p>\n </div>\n <Badge variant=\"secondary\" className=\"text-xs flex-shrink-0 capitalize\">\n {ms.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n )\n )}\n {upcomingMilestones.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-2\">\n {t('planmagnet.dashboard.upcomingMilestones.empty', 'No upcoming milestones.')}\n </p>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n\n {/* Recent Work Items & Project Status */}\n <div className=\"grid gap-6 lg:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <CheckSquare className=\"h-5 w-5 text-purple-500\" />\n {t('planmagnet.dashboard.recentWorkItems.title', 'Recent Work Items')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {recentWorkItems.map(\n (item: {\n id: string;\n key: string;\n description: string | null;\n status: string;\n storyPoints: number | null;\n assigneeId: string | null;\n projectId: string;\n }) => (\n <div key={item.id} className=\"flex items-center justify-between rounded border p-2\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{item.key}</p>\n <p className=\"text-xs text-muted-foreground\">\n {projectNameById.get(item.projectId) ??\n `Project ${item.projectId.slice(0, 6)}`}\n {item.assigneeId ? (\n <>\n {' \\u00b7 '}\n <PersonName id={item.assigneeId} />\n </>\n ) : null}\n </p>\n </div>\n <div className=\"flex items-center gap-2 flex-shrink-0\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {item.storyPoints ?? 0} {t('planmagnet.dashboard.shared.pointsShort', 'pts')}\n </Badge>\n <Badge variant=\"secondary\" className=\"text-xs capitalize\">\n {item.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n </div>\n )\n )}\n {recentWorkItems.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">\n {t('planmagnet.dashboard.recentWorkItems.empty', 'No work items yet.')}\n </p>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <FolderKanban className=\"h-5 w-5 text-cyan-500\" />\n {t('planmagnet.dashboard.projectStatus.title', 'Project Status')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {activeProjects.map(\n (p: { id: string; name: string; status: string; ownerId: string }) => (\n <div key={p.id} className=\"flex items-center justify-between rounded border p-2\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{p.name}</p>\n <p className=\"text-xs text-muted-foreground capitalize\">\n {p.status.toLowerCase().replace('_', ' ')}\n </p>\n </div>\n <div className=\"flex items-center gap-2 ml-3 flex-shrink-0\">\n <Users className=\"h-3 w-3 text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground\">\n <PersonName id={p.ownerId} />\n </span>\n <ArrowUpRight className=\"h-3 w-3 text-muted-foreground\" />\n </div>\n </div>\n )\n )}\n {activeProjects.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">\n {t('planmagnet.dashboard.projectStatus.empty', 'No active projects.')}\n </p>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardDashboardPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/DashboardDashboardPagePage.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, Badge } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n LayoutDashboard,\n FolderKanban,\n CheckSquare,\n Zap,\n Users,\n Calendar,\n TrendingUp,\n AlertTriangle,\n ArrowUpRight,\n} from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { PersonName } from '../people/People';\n\nconst GET_DASHBOARD_DATA = gql`\n query GetDashboardData($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 50 }) {\n items {\n id\n name\n description\n key\n status\n methodology\n ownerId\n startDate\n endDate\n tags\n createdAt\n }\n totalCount\n }\n planmagnetSprints(workspaceId: $workspaceId, pagination: { first: 50 }) {\n items {\n id\n name\n projectId\n project {\n id\n name\n }\n status\n startDate\n endDate\n goal\n capacity\n velocity\n workItems {\n id\n status\n storyPoints\n }\n }\n totalCount\n }\n planmagnetMilestones(workspaceId: $workspaceId, pagination: { first: 50 }) {\n items {\n id\n name\n description\n projectId\n project {\n id\n name\n }\n status\n dueDate\n ownerId\n createdAt\n }\n totalCount\n }\n planmagnetWorkItems(workspaceId: $workspaceId, pagination: { first: 20 }) {\n items {\n id\n key\n description\n status\n priority\n storyPoints\n assigneeId\n projectId\n labels\n createdAt\n }\n totalCount\n }\n }\n`;\n\nexport function DashboardDashboardPagePage() {\n const { workspaceId } = usePlanMagnet();\n const { t } = useI18n();\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_DASHBOARD_DATA, {\n variables: { workspaceId: workspaceId ?? 'default' },\n });\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 <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n if (error)\n return (\n <div className=\"p-6 text-red-500\">\n {t('planmagnet.dashboard.errorLoading', 'Error loading dashboard')}: {error.message}\n </div>\n );\n\n const projects = data?.planmagnetProjects?.items ?? [];\n const sprints = data?.planmagnetSprints?.items ?? [];\n const milestones = data?.planmagnetMilestones?.items ?? [];\n const workItems = data?.planmagnetWorkItems?.items ?? [];\n\n const activeProjects = projects.filter((p: { status: string }) => p.status === 'ACTIVE');\n const completedProjects = projects.filter((p: { status: string }) => p.status === 'COMPLETED');\n const activeSprints = sprints.filter((s: { status: string }) => s.status === 'ACTIVE');\n const openMilestones = milestones.filter(\n (m: { status: string }) => m.status === 'PENDING' || m.status === 'IN_PROGRESS'\n );\n // The list shows four; the \"upcoming\" count is all of them (it was the\n // sliced list's length, so it could never exceed 4).\n const upcomingMilestones = openMilestones.slice(0, 4);\n const recentWorkItems = workItems.slice(0, 5);\n // Work items carry only a projectId; the page already holds the projects, so\n // show the name instead of the raw id (P1.1). A project outside the first 50\n // falls back to a short id rather than the full UUID. Deliberately NOT a\n // useMemo: this line runs after the loading/error early returns, and a hook\n // here would change the hook count between renders and crash the page.\n const projectNameById = new Map<string, string>(\n projects.map((p: { id: string; name: string }) => [p.id, p.name])\n );\n\n const metrics = [\n {\n label: t('planmagnet.dashboard.metrics.totalProjects.label', 'Total Projects'),\n // Totals are the server's totalCount: the lists here hold one page (50).\n value: String(data?.planmagnetProjects?.totalCount ?? projects.length),\n trend: `${activeProjects.length} ${t('planmagnet.dashboard.metrics.totalProjects.trend', 'active')}`,\n },\n {\n label: t('planmagnet.dashboard.metrics.activeSprints.label', 'Active Sprints'),\n value: String(activeSprints.length),\n trend: `${data?.planmagnetSprints?.totalCount ?? sprints.length} ${t('planmagnet.dashboard.metrics.activeSprints.trend', 'total')}`,\n },\n {\n label: t('planmagnet.dashboard.metrics.workItems.label', 'Work Items'),\n value: String(data?.planmagnetWorkItems?.totalCount ?? 0),\n trend: t('planmagnet.dashboard.metrics.workItems.trend', 'across all projects'),\n },\n {\n label: t('planmagnet.dashboard.metrics.milestones.label', 'Milestones'),\n value: String(data?.planmagnetMilestones?.totalCount ?? milestones.length),\n trend: `${openMilestones.length} ${t('planmagnet.dashboard.metrics.milestones.trend', 'upcoming')}`,\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold flex items-center gap-2\">\n <LayoutDashboard className=\"h-6 w-6\" />\n {t('planmagnet.dashboard.title', 'Dashboard')}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {t('planmagnet.dashboard.subtitle', 'Welcome back! Here is your project overview.')}\n </p>\n </div>\n </div>\n\n {/* KPI Metrics */}\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n {metrics.map((m) => (\n <Card key={m.label}>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">{m.label}</CardTitle>\n <TrendingUp className=\"h-4 w-4 text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold\">{m.value}</div>\n <p className=\"text-xs text-muted-foreground\">{m.trend}</p>\n </CardContent>\n </Card>\n ))}\n </div>\n\n <div className=\"grid gap-6 lg:grid-cols-12\">\n {/* Active Sprints */}\n <Card className=\"lg:col-span-8\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Zap className=\"h-5 w-5 text-blue-500\" />\n {t('planmagnet.dashboard.activeSprints.title', 'Active Sprints')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {activeSprints.map(\n (sprint: {\n id: string;\n name: string;\n projectId: string;\n capacity: number | null;\n velocity: number | null;\n startDate: string | null;\n endDate: string | null;\n workItems: { id: string; status: string; storyPoints: number | null }[];\n }) => {\n const totalPoints = sprint.workItems.reduce(\n (sum: number, wi: { storyPoints: number | null }) => sum + (wi.storyPoints ?? 0),\n 0\n );\n const completedPoints = sprint.workItems\n .filter((wi: { status: string }) => wi.status === 'DONE')\n .reduce(\n (sum: number, wi: { storyPoints: number | null }) =>\n sum + (wi.storyPoints ?? 0),\n 0\n );\n const totalTasks = sprint.workItems.length;\n const completedTasks = sprint.workItems.filter(\n (wi: { status: string }) => wi.status === 'DONE'\n ).length;\n const pct = totalPoints > 0 ? Math.round((completedPoints / totalPoints) * 100) : 0;\n return (\n <div key={sprint.id} className=\"rounded-lg border p-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <div>\n <p className=\"font-medium\">{sprint.name}</p>\n <p className=\"text-xs text-muted-foreground\">\n {t('planmagnet.dashboard.shared.project', 'Project')}:{' '}\n {sprint.project?.name ??\n t('planmagnet.dashboard.shared.projectUnavailable', 'not available')}\n </p>\n </div>\n <Badge variant=\"secondary\">\n {completedPoints}/{totalPoints}{' '}\n {t('planmagnet.dashboard.shared.pointsShort', 'pts')}\n </Badge>\n </div>\n <div className=\"w-full h-2 bg-muted rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-primary rounded-full transition-all\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <div className=\"flex items-center justify-between mt-2 text-xs text-muted-foreground\">\n <span>\n {completedTasks}/{totalTasks}{' '}\n {t('planmagnet.dashboard.shared.tasks', 'tasks')}\n </span>\n <span>\n {sprint.startDate ? new Date(sprint.startDate).toLocaleDateString() : '—'} -{' '}\n {sprint.endDate ? new Date(sprint.endDate).toLocaleDateString() : '—'}\n </span>\n </div>\n </div>\n );\n }\n )}\n {activeSprints.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">\n {t('planmagnet.dashboard.activeSprints.empty', 'No active sprints.')}\n </p>\n )}\n </CardContent>\n </Card>\n\n {/* Sidebar */}\n <div className=\"lg:col-span-4 space-y-6\">\n {/* On-Hold Projects */}\n {projects.filter((p: { status: string }) => p.status === 'ON_HOLD').length > 0 && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <AlertTriangle className=\"h-5 w-5 text-orange-500\" />\n {t('planmagnet.dashboard.onHoldProjects.title', 'On-Hold Projects')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {projects\n .filter((p: { status: string }) => p.status === 'ON_HOLD')\n .map((p: { id: string; name: string; status: string }) => (\n <div\n key={p.id}\n className=\"flex items-center justify-between rounded border p-2\"\n >\n <div>\n <p className=\"text-sm font-medium\">{p.name}</p>\n </div>\n <Badge variant=\"destructive\">\n {p.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n ))}\n </CardContent>\n </Card>\n )}\n\n {/* Upcoming Milestones */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Calendar className=\"h-5 w-5 text-green-500\" />\n {t('planmagnet.dashboard.upcomingMilestones.title', 'Upcoming Milestones')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {upcomingMilestones.map(\n (ms: {\n id: string;\n name: string;\n projectId: string;\n dueDate: string | null;\n status: string;\n }) => (\n <div key={ms.id} className=\"flex items-start gap-3 rounded border p-2\">\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium truncate\">{ms.name}</p>\n <p className=\"text-xs text-muted-foreground\">\n {t('planmagnet.dashboard.shared.project', 'Project')}:{' '}\n {ms.project?.name ??\n t('planmagnet.dashboard.shared.projectUnavailable', 'not available')}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {t('planmagnet.dashboard.shared.due', 'Due')}{' '}\n {ms.dueDate ? new Date(ms.dueDate).toLocaleDateString() : '—'}\n </p>\n </div>\n <Badge variant=\"secondary\" className=\"text-xs flex-shrink-0 capitalize\">\n {ms.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n )\n )}\n {upcomingMilestones.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-2\">\n {t('planmagnet.dashboard.upcomingMilestones.empty', 'No upcoming milestones.')}\n </p>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n\n {/* Recent Work Items & Project Status */}\n <div className=\"grid gap-6 lg:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <CheckSquare className=\"h-5 w-5 text-purple-500\" />\n {t('planmagnet.dashboard.recentWorkItems.title', 'Recent Work Items')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {recentWorkItems.map(\n (item: {\n id: string;\n key: string;\n description: string | null;\n status: string;\n storyPoints: number | null;\n assigneeId: string | null;\n projectId: string;\n }) => (\n <div key={item.id} className=\"flex items-center justify-between rounded border p-2\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{item.key}</p>\n <p className=\"text-xs text-muted-foreground\">\n {projectNameById.get(item.projectId) ??\n `Project ${item.projectId.slice(0, 6)}`}\n {item.assigneeId ? (\n <>\n {' \\u00b7 '}\n <PersonName id={item.assigneeId} />\n </>\n ) : null}\n </p>\n </div>\n <div className=\"flex items-center gap-2 flex-shrink-0\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {item.storyPoints ?? 0} {t('planmagnet.dashboard.shared.pointsShort', 'pts')}\n </Badge>\n <Badge variant=\"secondary\" className=\"text-xs capitalize\">\n {item.status.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n </div>\n )\n )}\n {recentWorkItems.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">\n {t('planmagnet.dashboard.recentWorkItems.empty', 'No work items yet.')}\n </p>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <FolderKanban className=\"h-5 w-5 text-cyan-500\" />\n {t('planmagnet.dashboard.projectStatus.title', 'Project Status')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {activeProjects.map(\n (p: { id: string; name: string; status: string; ownerId: string }) => (\n <div key={p.id} className=\"flex items-center justify-between rounded border p-2\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{p.name}</p>\n <p className=\"text-xs text-muted-foreground capitalize\">\n {p.status.toLowerCase().replace('_', ' ')}\n </p>\n </div>\n <div className=\"flex items-center gap-2 ml-3 flex-shrink-0\">\n <Users className=\"h-3 w-3 text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground\">\n <PersonName id={p.ownerId} />\n </span>\n <ArrowUpRight className=\"h-3 w-3 text-muted-foreground\" />\n </div>\n </div>\n )\n )}\n {activeProjects.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">\n {t('planmagnet.dashboard.projectStatus.empty', 'No active projects.')}\n </p>\n )}\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":"AA2DA,wBAAgB,6BAA6B,4CAkN5C"}
1
+ {"version":3,"file":"ProductsFeatureDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/ProductsFeatureDetailPagePage.tsx"],"names":[],"mappings":"AA4DA,wBAAgB,6BAA6B,4CAqN5C"}
@@ -1,12 +1,13 @@
1
1
  import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
2
- import { Loader2 as t, MessageSquare as n, Star as r, Target as i, ThumbsUp as a } from "lucide-react";
3
- import { useParams as o } from "react-router";
4
- import { gql as s } from "@apollo/client";
5
- import { useQuery as c } from "@apollo/client/react";
6
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
7
- import { Badge as d, Card as f, CardContent as p, CardHeader as m, CardTitle as h } from "@burdenoff/fe-libs/ui";
2
+ import { PersonName as t } from "../people/People.js";
3
+ import { Loader2 as n, MessageSquare as r, Star as i, Target as a, ThumbsUp as o } from "lucide-react";
4
+ import { useParams as s } from "react-router";
5
+ import { gql as c } from "@apollo/client";
6
+ import { useQuery as l } from "@apollo/client/react";
7
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
8
+ import { Badge as f, Card as p, CardContent as m, CardHeader as h, CardTitle as g } from "@burdenoff/fe-libs/ui";
8
9
  //#region src/planmagnet/pages/ProductsFeatureDetailPagePage.tsx
9
- var g = s`
10
+ var _ = c`
10
11
  query GetFeatureRequest($id: ID!) {
11
12
  planmagnetFeatureRequest(id: $id) {
12
13
  id
@@ -40,44 +41,45 @@ var g = s`
40
41
  }
41
42
  }
42
43
  `;
43
- function _() {
44
- let { workspaceId: s } = e(), _ = o().id ?? "", { data: v, loading: y, error: b } = c(g, {
45
- variables: { id: _ },
46
- skip: !_
44
+ function v() {
45
+ let { workspaceId: c } = e(), v = s().id ?? "", { data: y, loading: b, error: x } = l(_, {
46
+ variables: { id: v },
47
+ skip: !v
47
48
  });
48
- if (y && !v) return /* @__PURE__ */ l("div", {
49
+ if (b && !y) return /* @__PURE__ */ u("div", {
49
50
  className: "flex items-center justify-center p-12",
50
- children: /* @__PURE__ */ l(t, { className: "h-8 w-8 animate-spin text-muted-foreground" })
51
+ children: /* @__PURE__ */ u(n, { className: "h-8 w-8 animate-spin text-muted-foreground" })
51
52
  });
52
- if (b) return /* @__PURE__ */ u("div", {
53
+ if (x) return /* @__PURE__ */ d("div", {
53
54
  className: "p-6 text-destructive",
54
- children: ["Failed to load feature: ", b.message]
55
+ children: ["Failed to load feature: ", x.message]
55
56
  });
56
- let x = v?.planmagnetFeatureRequest;
57
- if (!x) return /* @__PURE__ */ l("div", {
57
+ let S = y?.planmagnetFeatureRequest;
58
+ if (!S) return /* @__PURE__ */ u("div", {
58
59
  className: "p-6 text-muted-foreground",
59
60
  children: "Feature not found."
60
61
  });
61
- let S = x.votes ?? [], C = x.competitors ?? [];
62
- return /* @__PURE__ */ u("div", {
62
+ let C = S.votes ?? [], w = S.competitors ?? [];
63
+ return /* @__PURE__ */ d("div", {
63
64
  className: "space-y-6 p-6",
64
65
  children: [
65
- /* @__PURE__ */ u("div", {
66
+ /* @__PURE__ */ d("div", {
66
67
  className: "flex items-center justify-between",
67
- children: [/* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("h1", {
68
+ children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("h1", {
68
69
  className: "text-2xl font-semibold",
69
- children: x.title
70
- }), /* @__PURE__ */ u("p", {
70
+ children: S.title
71
+ }), /* @__PURE__ */ d("p", {
71
72
  className: "text-sm text-muted-foreground",
72
73
  children: [
73
74
  "Submitted by: ",
74
- x.submittedBy,
75
- " · Effort: ",
76
- x.effortEstimate ?? "N/A"
75
+ /* @__PURE__ */ u(t, { id: S.submittedBy }),
76
+ " · Effort:",
77
+ " ",
78
+ S.effortEstimate ?? "N/A"
77
79
  ]
78
- })] }), /* @__PURE__ */ l("div", {
80
+ })] }), /* @__PURE__ */ u("div", {
79
81
  className: "flex gap-2",
80
- children: /* @__PURE__ */ l("span", {
82
+ children: /* @__PURE__ */ u("span", {
81
83
  className: `text-xs px-2 py-1 rounded-full capitalize ${{
82
84
  SUBMITTED: "bg-gray-100 text-gray-800",
83
85
  UNDER_REVIEW: "bg-yellow-100 text-yellow-800",
@@ -85,65 +87,65 @@ function _() {
85
87
  IN_PROGRESS: "bg-purple-100 text-purple-800",
86
88
  COMPLETED: "bg-green-100 text-green-800",
87
89
  DECLINED: "bg-red-100 text-red-800"
88
- }[x.status] ?? "bg-gray-100"}`,
89
- children: x.status.toLowerCase().replace("_", " ")
90
+ }[S.status] ?? "bg-gray-100"}`,
91
+ children: S.status.toLowerCase().replace("_", " ")
90
92
  })
91
93
  })]
92
94
  }),
93
- /* @__PURE__ */ u("div", {
95
+ /* @__PURE__ */ d("div", {
94
96
  className: "grid grid-cols-2 md:grid-cols-4 gap-4",
95
97
  children: [
96
- /* @__PURE__ */ l(f, { children: /* @__PURE__ */ u(p, {
98
+ /* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
97
99
  className: "pt-4 text-center",
98
100
  children: [
99
- /* @__PURE__ */ l(i, { className: "h-5 w-5 mx-auto text-primary" }),
100
- /* @__PURE__ */ l("p", {
101
+ /* @__PURE__ */ u(a, { className: "h-5 w-5 mx-auto text-primary" }),
102
+ /* @__PURE__ */ u("p", {
101
103
  className: "text-2xl font-bold mt-1",
102
- children: x.priorityScore ?? 0
104
+ children: S.priorityScore ?? 0
103
105
  }),
104
- /* @__PURE__ */ l("p", {
106
+ /* @__PURE__ */ u("p", {
105
107
  className: "text-xs text-muted-foreground",
106
108
  children: "Priority Score"
107
109
  })
108
110
  ]
109
111
  }) }),
110
- /* @__PURE__ */ l(f, { children: /* @__PURE__ */ u(p, {
112
+ /* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
111
113
  className: "pt-4 text-center",
112
114
  children: [
113
- /* @__PURE__ */ l(a, { className: "h-5 w-5 mx-auto text-green-500" }),
114
- /* @__PURE__ */ l("p", {
115
+ /* @__PURE__ */ u(o, { className: "h-5 w-5 mx-auto text-green-500" }),
116
+ /* @__PURE__ */ u("p", {
115
117
  className: "text-2xl font-bold mt-1",
116
- children: x.voteCount
118
+ children: S.voteCount
117
119
  }),
118
- /* @__PURE__ */ l("p", {
120
+ /* @__PURE__ */ u("p", {
119
121
  className: "text-xs text-muted-foreground",
120
122
  children: "Votes"
121
123
  })
122
124
  ]
123
125
  }) }),
124
- /* @__PURE__ */ l(f, { children: /* @__PURE__ */ u(p, {
126
+ /* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
125
127
  className: "pt-4 text-center",
126
128
  children: [
127
- /* @__PURE__ */ l(r, { className: "h-5 w-5 mx-auto text-yellow-500" }),
128
- /* @__PURE__ */ l("p", {
129
+ /* @__PURE__ */ u(i, { className: "h-5 w-5 mx-auto text-yellow-500" }),
130
+ /* @__PURE__ */ u("p", {
129
131
  className: "text-2xl font-bold mt-1",
130
- children: x.businessValue ?? 0
132
+ children: S.businessValue ?? 0
131
133
  }),
132
- /* @__PURE__ */ l("p", {
134
+ /* @__PURE__ */ u("p", {
133
135
  className: "text-xs text-muted-foreground",
134
136
  children: "Business Value"
135
137
  })
136
138
  ]
137
139
  }) }),
138
- /* @__PURE__ */ l(f, { children: /* @__PURE__ */ u(p, {
140
+ /* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
139
141
  className: "pt-4 text-center",
140
142
  children: [
141
- /* @__PURE__ */ l(n, { className: "h-5 w-5 mx-auto text-blue-500" }),
142
- /* @__PURE__ */ l("p", {
143
+ /* @__PURE__ */ u(r, { className: "h-5 w-5 mx-auto text-blue-500" }),
144
+ /* @__PURE__ */ u("p", {
143
145
  className: "text-2xl font-bold mt-1",
144
- children: C.length
146
+ children: w.length
145
147
  }),
146
- /* @__PURE__ */ l("p", {
148
+ /* @__PURE__ */ u("p", {
147
149
  className: "text-xs text-muted-foreground",
148
150
  children: "Competitors"
149
151
  })
@@ -151,130 +153,130 @@ function _() {
151
153
  }) })
152
154
  ]
153
155
  }),
154
- /* @__PURE__ */ u("div", {
156
+ /* @__PURE__ */ d("div", {
155
157
  className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
156
- children: [/* @__PURE__ */ u("div", {
158
+ children: [/* @__PURE__ */ d("div", {
157
159
  className: "lg:col-span-2 space-y-6",
158
160
  children: [
159
- /* @__PURE__ */ u(f, { children: [/* @__PURE__ */ l(m, { children: /* @__PURE__ */ l(h, { children: "Description" }) }), /* @__PURE__ */ l(p, { children: /* @__PURE__ */ l("p", {
161
+ /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ u(g, { children: "Description" }) }), /* @__PURE__ */ u(m, { children: /* @__PURE__ */ u("p", {
160
162
  className: "text-sm",
161
- children: x.description ?? "No description provided."
163
+ children: S.description ?? "No description provided."
162
164
  }) })] }),
163
- /* @__PURE__ */ u(f, { children: [/* @__PURE__ */ l(m, { children: /* @__PURE__ */ u(h, { children: [
165
+ /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ d(g, { children: [
164
166
  "Votes (",
165
- S.length,
167
+ C.length,
166
168
  ")"
167
- ] }) }), /* @__PURE__ */ u(p, {
169
+ ] }) }), /* @__PURE__ */ d(m, {
168
170
  className: "space-y-3",
169
- children: [S.length === 0 && /* @__PURE__ */ l("p", {
171
+ children: [C.length === 0 && /* @__PURE__ */ u("p", {
170
172
  className: "text-sm text-muted-foreground",
171
173
  children: "No votes yet."
172
- }), S.map((e) => /* @__PURE__ */ u("div", {
174
+ }), C.map((e) => /* @__PURE__ */ d("div", {
173
175
  className: "flex items-start justify-between border rounded-md p-3",
174
- children: [/* @__PURE__ */ u("div", { children: [/* @__PURE__ */ u("p", {
176
+ children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d("p", {
175
177
  className: "text-sm font-medium",
176
- children: ["Voter: ", e.voterId]
177
- }), e.comment && /* @__PURE__ */ l("p", {
178
+ children: ["Voter: ", /* @__PURE__ */ u(t, { id: e.voterId })]
179
+ }), e.comment && /* @__PURE__ */ u("p", {
178
180
  className: "text-xs text-muted-foreground mt-1",
179
181
  children: e.comment
180
- })] }), /* @__PURE__ */ u("div", {
182
+ })] }), /* @__PURE__ */ d("div", {
181
183
  className: "flex items-center gap-1",
182
- children: [/* @__PURE__ */ l(a, { className: "h-3 w-3 text-green-500" }), /* @__PURE__ */ l("span", {
184
+ children: [/* @__PURE__ */ u(o, { className: "h-3 w-3 text-green-500" }), /* @__PURE__ */ u("span", {
183
185
  className: "text-sm font-bold",
184
186
  children: e.weight
185
187
  })]
186
188
  })]
187
189
  }, e.id))]
188
190
  })] }),
189
- C.length > 0 && /* @__PURE__ */ u(f, { children: [/* @__PURE__ */ l(m, { children: /* @__PURE__ */ u(h, { children: [
191
+ w.length > 0 && /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ d(g, { children: [
190
192
  "Competitor Analysis (",
191
- C.length,
193
+ w.length,
192
194
  ")"
193
- ] }) }), /* @__PURE__ */ l(p, {
195
+ ] }) }), /* @__PURE__ */ u(m, {
194
196
  className: "space-y-3",
195
- children: C.map((e) => /* @__PURE__ */ u("div", {
197
+ children: w.map((e) => /* @__PURE__ */ d("div", {
196
198
  className: "border rounded-md p-3",
197
- children: [/* @__PURE__ */ u("div", {
199
+ children: [/* @__PURE__ */ d("div", {
198
200
  className: "flex items-center justify-between",
199
- children: [/* @__PURE__ */ l("p", {
201
+ children: [/* @__PURE__ */ u("p", {
200
202
  className: "text-sm font-medium",
201
203
  children: e.name
202
- }), e.website && /* @__PURE__ */ l("span", {
204
+ }), e.website && /* @__PURE__ */ u("span", {
203
205
  className: "text-xs text-primary",
204
206
  children: e.website
205
207
  })]
206
- }), e.description && /* @__PURE__ */ l("p", {
208
+ }), e.description && /* @__PURE__ */ u("p", {
207
209
  className: "text-xs text-muted-foreground mt-1",
208
210
  children: e.description
209
211
  })]
210
212
  }, e.id))
211
213
  })] })
212
214
  ]
213
- }), /* @__PURE__ */ u("div", {
215
+ }), /* @__PURE__ */ d("div", {
214
216
  className: "space-y-6",
215
- children: [/* @__PURE__ */ u(f, { children: [/* @__PURE__ */ l(m, { children: /* @__PURE__ */ l(h, { children: "Details" }) }), /* @__PURE__ */ u(p, {
217
+ children: [/* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ u(g, { children: "Details" }) }), /* @__PURE__ */ d(m, {
216
218
  className: "space-y-3 text-sm",
217
219
  children: [
218
- /* @__PURE__ */ u("div", {
220
+ /* @__PURE__ */ d("div", {
219
221
  className: "flex justify-between",
220
- children: [/* @__PURE__ */ l("span", {
222
+ children: [/* @__PURE__ */ u("span", {
221
223
  className: "text-muted-foreground",
222
224
  children: "Status"
223
- }), /* @__PURE__ */ l(d, {
225
+ }), /* @__PURE__ */ u(f, {
224
226
  variant: "secondary",
225
227
  className: "capitalize",
226
- children: x.status.toLowerCase().replace("_", " ")
228
+ children: S.status.toLowerCase().replace("_", " ")
227
229
  })]
228
230
  }),
229
- /* @__PURE__ */ u("div", {
231
+ /* @__PURE__ */ d("div", {
230
232
  className: "flex justify-between",
231
- children: [/* @__PURE__ */ l("span", {
233
+ children: [/* @__PURE__ */ u("span", {
232
234
  className: "text-muted-foreground",
233
235
  children: "Priority Score"
234
- }), /* @__PURE__ */ l(d, {
236
+ }), /* @__PURE__ */ u(f, {
235
237
  variant: "outline",
236
- children: x.priorityScore ?? "N/A"
238
+ children: S.priorityScore ?? "N/A"
237
239
  })]
238
240
  }),
239
- /* @__PURE__ */ u("div", {
241
+ /* @__PURE__ */ d("div", {
240
242
  className: "flex justify-between",
241
- children: [/* @__PURE__ */ l("span", {
243
+ children: [/* @__PURE__ */ u("span", {
242
244
  className: "text-muted-foreground",
243
245
  children: "Effort"
244
- }), /* @__PURE__ */ l(d, {
246
+ }), /* @__PURE__ */ u(f, {
245
247
  variant: "outline",
246
248
  className: "capitalize",
247
- children: x.effortEstimate ?? "N/A"
249
+ children: S.effortEstimate ?? "N/A"
248
250
  })]
249
251
  }),
250
- /* @__PURE__ */ u("div", {
252
+ /* @__PURE__ */ d("div", {
251
253
  className: "flex justify-between",
252
- children: [/* @__PURE__ */ l("span", {
254
+ children: [/* @__PURE__ */ u("span", {
253
255
  className: "text-muted-foreground",
254
256
  children: "Business Value"
255
- }), /* @__PURE__ */ l("span", {
257
+ }), /* @__PURE__ */ u("span", {
256
258
  className: "font-medium",
257
- children: x.businessValue ?? "N/A"
259
+ children: S.businessValue ?? "N/A"
258
260
  })]
259
261
  }),
260
- /* @__PURE__ */ u("div", {
262
+ /* @__PURE__ */ d("div", {
261
263
  className: "flex justify-between",
262
- children: [/* @__PURE__ */ l("span", {
264
+ children: [/* @__PURE__ */ u("span", {
263
265
  className: "text-muted-foreground",
264
266
  children: "Submitted By"
265
- }), /* @__PURE__ */ l("span", { children: x.submittedBy })]
267
+ }), /* @__PURE__ */ u(t, { id: S.submittedBy })]
266
268
  }),
267
- /* @__PURE__ */ u("div", {
269
+ /* @__PURE__ */ d("div", {
268
270
  className: "flex justify-between",
269
- children: [/* @__PURE__ */ l("span", {
271
+ children: [/* @__PURE__ */ u("span", {
270
272
  className: "text-muted-foreground",
271
273
  children: "Updated"
272
- }), /* @__PURE__ */ l("span", { children: new Date(x.updatedAt).toLocaleDateString() })]
274
+ }), /* @__PURE__ */ u("span", { children: new Date(S.updatedAt).toLocaleDateString() })]
273
275
  })
274
276
  ]
275
- })] }), x.tags?.length > 0 && /* @__PURE__ */ u(f, { children: [/* @__PURE__ */ l(m, { children: /* @__PURE__ */ l(h, { children: "Tags" }) }), /* @__PURE__ */ l(p, {
277
+ })] }), S.tags?.length > 0 && /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ u(g, { children: "Tags" }) }), /* @__PURE__ */ u(m, {
276
278
  className: "flex flex-wrap gap-1",
277
- children: x.tags.map((e) => /* @__PURE__ */ l(d, {
279
+ children: S.tags.map((e) => /* @__PURE__ */ u(f, {
278
280
  variant: "outline",
279
281
  className: "text-xs",
280
282
  children: e
@@ -286,6 +288,6 @@ function _() {
286
288
  });
287
289
  }
288
290
  //#endregion
289
- export { _ as ProductsFeatureDetailPagePage };
291
+ export { v as ProductsFeatureDetailPagePage };
290
292
 
291
293
  //# sourceMappingURL=ProductsFeatureDetailPagePage.js.map