@burdenoff/microfe-crewfoundry 2026.704.6 → 2026.707.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/crewfoundry/CrewFoundryRoutes.js +51 -43
- package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
- package/dist/crewfoundry/components/forms/formValues.js +5 -2
- package/dist/crewfoundry/components/forms/formValues.js.map +1 -1
- package/dist/crewfoundry/components/viz/AllocationBar.js +68 -0
- package/dist/crewfoundry/components/viz/AllocationBar.js.map +1 -0
- package/dist/crewfoundry/components/viz/AreaChart.js +102 -0
- package/dist/crewfoundry/components/viz/AreaChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/AvatarStack.js +36 -0
- package/dist/crewfoundry/components/viz/AvatarStack.js.map +1 -0
- package/dist/crewfoundry/components/viz/BarChart.js +83 -0
- package/dist/crewfoundry/components/viz/BarChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/CertificateCard.js +118 -0
- package/dist/crewfoundry/components/viz/CertificateCard.js.map +1 -0
- package/dist/crewfoundry/components/viz/DonutChart.js +109 -0
- package/dist/crewfoundry/components/viz/DonutChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/HBarFunnel.js +54 -0
- package/dist/crewfoundry/components/viz/HBarFunnel.js.map +1 -0
- package/dist/crewfoundry/components/viz/Heatmap.js +91 -0
- package/dist/crewfoundry/components/viz/Heatmap.js.map +1 -0
- package/dist/crewfoundry/components/viz/KanbanBoard.js +50 -0
- package/dist/crewfoundry/components/viz/KanbanBoard.js.map +1 -0
- package/dist/crewfoundry/components/viz/LineChart.js +123 -0
- package/dist/crewfoundry/components/viz/LineChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/OrgTree.js +83 -0
- package/dist/crewfoundry/components/viz/OrgTree.js.map +1 -0
- package/dist/crewfoundry/components/viz/PathSteps.js +68 -0
- package/dist/crewfoundry/components/viz/PathSteps.js.map +1 -0
- package/dist/crewfoundry/components/viz/ProgressRing.js +68 -0
- package/dist/crewfoundry/components/viz/ProgressRing.js.map +1 -0
- package/dist/crewfoundry/components/viz/RatingStars.js +51 -0
- package/dist/crewfoundry/components/viz/RatingStars.js.map +1 -0
- package/dist/crewfoundry/components/viz/SegmentedTabs.js +69 -0
- package/dist/crewfoundry/components/viz/SegmentedTabs.js.map +1 -0
- package/dist/crewfoundry/components/viz/SkillBar.js +3 -0
- package/dist/crewfoundry/components/viz/Sparkline.js +74 -0
- package/dist/crewfoundry/components/viz/Sparkline.js.map +1 -0
- package/dist/crewfoundry/components/viz/StatCard.js +60 -0
- package/dist/crewfoundry/components/viz/StatCard.js.map +1 -0
- package/dist/crewfoundry/components/viz/StepProgress.js +3 -0
- package/dist/crewfoundry/components/viz/Timeline.js +66 -0
- package/dist/crewfoundry/components/viz/Timeline.js.map +1 -0
- package/dist/crewfoundry/components/viz/index.js +23 -0
- package/dist/crewfoundry/components/viz/lib/Avatar.js +30 -0
- package/dist/crewfoundry/components/viz/lib/Avatar.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/CartesianFrame.js +119 -0
- package/dist/crewfoundry/components/viz/lib/CartesianFrame.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js +35 -0
- package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/format.js +21 -0
- package/dist/crewfoundry/components/viz/lib/format.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/geometry.js +69 -0
- package/dist/crewfoundry/components/viz/lib/geometry.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/hooks.js +39 -0
- package/dist/crewfoundry/components/viz/lib/hooks.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/palette.js +27 -0
- package/dist/crewfoundry/components/viz/lib/palette.js.map +1 -0
- package/dist/crewfoundry/lib/analytics.js +323 -0
- package/dist/crewfoundry/lib/analytics.js.map +1 -0
- package/dist/crewfoundry/lib/companyFinance.js +16 -0
- package/dist/crewfoundry/lib/companyFinance.js.map +1 -0
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +226 -283
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +107 -120
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +122 -162
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +121 -158
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +316 -211
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +75 -27
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +167 -165
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +168 -109
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +401 -290
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js +0 -41
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +84 -75
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +368 -174
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +236 -201
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +369 -196
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +269 -270
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +210 -110
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +216 -178
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +385 -0
- package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js.map +1 -0
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js +189 -130
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +397 -241
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js +262 -147
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +345 -167
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +98 -24
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +289 -108
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +221 -114
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +134 -135
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +148 -97
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +264 -157
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +85 -93
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +289 -140
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +140 -78
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +142 -184
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/dist/crewfoundry/utils/cn.js +10 -0
- package/dist/crewfoundry/utils/cn.js.map +1 -0
- package/dist/crewfoundry/utils/courseProgress.js +46 -0
- package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
- package/dist/node_modules/clsx/dist/clsx.js +18 -0
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardDashboardPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/DashboardDashboardPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n AuroraBackground,\n EmphasisPanel,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { Activity, Briefcase, Calendar, TrendingUp, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport { useCrewFoundry } from '../providers/CrewFoundryProvider';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\nexport function DashboardDashboardPagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { showToast } = useGlobalUi();\n const { currentUser } = useCrewFoundry();\n const {\n employees,\n jobPostings,\n interviews,\n leaveRequests,\n notifications,\n projects,\n updateLeaveRequest,\n } = useCrewFoundryStore();\n const [processingLeaveId, setProcessingLeaveId] = useState<string | null>(null);\n\n const approverName =\n currentUser?.name ||\n [currentUser?.firstName, currentUser?.lastName].filter(Boolean).join(' ') ||\n currentUser?.email ||\n 'Manager';\n\n const decideLeave = async (id: string, status: 'approved' | 'rejected') => {\n setProcessingLeaveId(id);\n try {\n await updateLeaveRequest(id, { status, approverName });\n showToast(status === 'approved' ? 'Leave approved' : 'Leave rejected', 'success');\n } catch (error) {\n showToast(error instanceof Error ? error.message : 'Unable to update leave request', 'error');\n } finally {\n setProcessingLeaveId(null);\n }\n };\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n\n const activeEmployees = employees.filter((e) => e.status === 'active').length;\n const onLeave = employees.filter((e) => e.status === 'on_leave').length;\n const openPositions = jobPostings.filter((j) => j.status === 'active').length;\n const totalApplicants = jobPostings.reduce((sum, j) => sum + j.applicants, 0);\n const pendingLeaves = leaveRequests.filter((l) => l.status === 'pending').length;\n const unreadNotifications = notifications.filter((n) => !n.read).length;\n const activeProjects = projects.filter((p) => p.status === 'active').length;\n const avgPerformance = (\n employees.reduce((sum, e) => sum + e.performanceScore, 0) / Math.max(employees.length, 1)\n ).toFixed(1);\n\n const departmentHeadcount = employees.reduce<Record<string, number>>((acc, e) => {\n acc[e.department] = (acc[e.department] || 0) + 1;\n return acc;\n }, {});\n\n const headcountValues = Object.values(departmentHeadcount);\n const maxHeadcount = headcountValues.length ? Math.max(...headcountValues) : 1;\n\n const scheduledInterviews = [...interviews]\n .filter((i) => i.status === 'scheduled')\n .sort((a, b) => `${a.date} ${a.time}`.localeCompare(`${b.date} ${b.time}`));\n const upcomingInterviews = scheduledInterviews.slice(0, 5);\n\n const recentLeaveRequests = [...leaveRequests].sort((a, b) => {\n if (a.status === 'pending' && b.status !== 'pending') return -1;\n if (b.status === 'pending' && a.status !== 'pending') return 1;\n return b.startDate.localeCompare(a.startDate);\n });\n const {\n page: leavePage,\n pageSize: leavePageSize,\n offset: leaveOffset,\n setPage: setLeavePage,\n } = usePagination({ initialPageSize: 6 });\n const leavePageItems = recentLeaveRequests.slice(leaveOffset, leaveOffset + leavePageSize);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"relative overflow-hidden rounded-xl border border-border-seam bg-gloss-card p-6\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{t('crewfoundry.dashboard.title', 'Workforce Dashboard')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'crewfoundry.dashboard.subtitle',\n \"Overview of your organization's workforce metrics\"\n )}\n </p>\n <PagePurpose className=\"mt-2\">\n {t(\n 'crewfoundry.dashboard.purpose',\n 'Your workforce command center — see headcount, hiring, performance, and projects at a glance, then jump straight to the area that needs your attention.'\n )}\n </PagePurpose>\n </div>\n </div>\n </div>\n\n <NextSteps\n storageKey=\"crewfoundry-dashboard\"\n steps={[\n {\n id: 'employees',\n label: t('crewfoundry.dashboard.next.employees', 'Review your team'),\n description: t(\n 'crewfoundry.dashboard.next.employeesDesc',\n 'Open the employee directory to see who is active and on leave.'\n ),\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('../hr/employees-page'),\n },\n {\n id: 'hiring',\n label: t('crewfoundry.dashboard.next.hiring', 'Post a new job'),\n description: t(\n 'crewfoundry.dashboard.next.hiringDesc',\n 'Create an opening to start collecting applicants.'\n ),\n icon: <Briefcase className=\"h-4 w-4\" />,\n onClick: () => navigate('../hiring/create-job-page'),\n },\n {\n id: 'projects',\n label: t('crewfoundry.dashboard.next.projects', 'Check active projects'),\n description: t(\n 'crewfoundry.dashboard.next.projectsDesc',\n 'Track progress and budgets across in-flight work.'\n ),\n icon: <Activity className=\"h-4 w-4\" />,\n onClick: () => navigate('../projects/projects-page'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">\n {t('crewfoundry.dashboard.stats.totalEmployees', 'Total Employees')}\n </CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{employees.length}</div>\n <p className=\"text-xs text-text-secondary\">\n {activeEmployees} {t('crewfoundry.dashboard.stats.active', 'active')}, {onLeave}{' '}\n {t('crewfoundry.dashboard.stats.onLeave', 'on leave')}\n </p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">\n {t('crewfoundry.dashboard.stats.openPositions', 'Open Positions')}\n </CardTitle>\n <Briefcase className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{openPositions}</div>\n <p className=\"text-xs text-text-secondary\">\n {totalApplicants}{' '}\n {t('crewfoundry.dashboard.stats.totalApplicants', 'total applicants')}\n </p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">\n {t('crewfoundry.dashboard.stats.avgPerformance', 'Avg Performance')}\n </CardTitle>\n <TrendingUp className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgPerformance}/5</div>\n <p className=\"text-xs text-text-secondary\">\n {t(\n 'crewfoundry.dashboard.stats.performanceTrend',\n `Team average across ${employees.length} employees`\n )}\n </p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">\n {t('crewfoundry.dashboard.stats.activeProjects', 'Active Projects')}\n </CardTitle>\n <Activity className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activeProjects}</div>\n <p className=\"text-xs text-text-secondary\">\n {pendingLeaves}{' '}\n {t('crewfoundry.dashboard.stats.pendingLeaveRequests', 'pending leave requests')}\n </p>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-7\">\n <EmphasisPanel className=\"col-span-4\">\n <div className=\"mb-1 text-lg font-semibold\">\n {t('crewfoundry.dashboard.departmentHeadcount.title', 'Department Headcount')}\n </div>\n <p className=\"mb-4 text-sm text-text-secondary\">\n {t(\n 'crewfoundry.dashboard.departmentHeadcount.description',\n 'Employee distribution across departments'\n )}\n </p>\n <div className=\"space-y-3\">\n {Object.entries(departmentHeadcount)\n .sort(([, a], [, b]) => b - a)\n .map(([dept, count]) => (\n <div key={dept} className=\"flex items-center gap-3\">\n <span className=\"w-24 text-sm text-text-secondary truncate\">{dept}</span>\n <div className=\"flex-1 h-4 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-4 bg-action-primary-bg rounded\"\n style={{ width: `${Math.round((count / maxHeadcount) * 100)}%` }}\n />\n </div>\n <span className=\"text-sm font-medium w-8 text-right tabular-nums\">{count}</span>\n </div>\n ))}\n </div>\n </EmphasisPanel>\n\n <Card className=\"col-span-3\">\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <CardTitle>\n {t('crewfoundry.dashboard.notifications.title', 'Recent Notifications')}\n </CardTitle>\n <Badge variant=\"secondary\">\n {unreadNotifications} {t('crewfoundry.dashboard.notifications.unread', 'unread')}\n </Badge>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {notifications.slice(0, 5).map((notif) => (\n <div key={notif.id} className=\"flex items-start gap-3\">\n <div\n className={`mt-1 h-2 w-2 rounded-full flex-shrink-0 motion-safe:animate-vc-glow-pulse ${\n notif.type === 'success'\n ? 'bg-status-success-text'\n : notif.type === 'warning'\n ? 'bg-status-warning-text'\n : notif.type === 'error'\n ? 'bg-status-error-text'\n : 'bg-status-info-text'\n }`}\n />\n <div className=\"flex-1 min-w-0\">\n <p className={`text-sm ${notif.read ? 'text-text-secondary' : 'font-medium'}`}>\n {notif.title}\n </p>\n <p className=\"text-xs text-text-secondary truncate\">{notif.message}</p>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>\n {t('crewfoundry.dashboard.upcomingInterviews.title', 'Upcoming Interviews')}\n </CardTitle>\n <CardDescription>\n {t('crewfoundry.dashboard.upcomingInterviews.description', 'Scheduled for this week')}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {upcomingInterviews.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t(\n 'crewfoundry.dashboard.upcomingInterviews.emptyTitle',\n 'No interviews scheduled'\n )}\n description={t(\n 'crewfoundry.dashboard.upcomingInterviews.emptyDescription',\n 'Scheduled interviews will appear here.'\n )}\n />\n )}\n {upcomingInterviews.map((interview) => (\n <div\n key={interview.id}\n className=\"flex items-center justify-between rounded border p-3\"\n >\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium truncate\">{interview.candidateName}</p>\n <p className=\"text-xs text-text-secondary truncate\">{interview.position}</p>\n </div>\n <div className=\"flex items-center gap-2 flex-shrink-0\">\n <div className=\"text-right\">\n <p className=\"text-xs font-medium\">{interview.date}</p>\n <p className=\"text-xs text-text-secondary\">{interview.time}</p>\n </div>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {formatEnumLabel(interview.type)}\n </Badge>\n </div>\n </div>\n ))}\n {scheduledInterviews.length > upcomingInterviews.length && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full\"\n onClick={() => navigate('../hiring/interviews-page')}\n >\n {t('crewfoundry.dashboard.upcomingInterviews.viewAll', 'View all interviews')}\n </Button>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>\n {t('crewfoundry.dashboard.leaveRequests.title', 'Recent Leave Requests')}\n </CardTitle>\n <CardDescription>\n {t('crewfoundry.dashboard.leaveRequests.description', 'Pending approval')}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {leaveRequests.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('crewfoundry.dashboard.leaveRequests.emptyTitle', 'No leave requests')}\n description={t(\n 'crewfoundry.dashboard.leaveRequests.emptyDescription',\n 'Pending leave requests will appear here.'\n )}\n />\n )}\n {leavePageItems.map((leave) => (\n <div key={leave.id} className=\"flex items-center justify-between rounded border p-3\">\n <div className=\"flex items-center gap-3\">\n <div>\n <p className=\"text-sm font-medium\">{leave.employeeName}</p>\n <div className=\"flex items-center gap-2 text-xs text-text-secondary\">\n <Calendar className=\"h-3 w-3\" />\n <span>\n {leave.startDate} - {leave.endDate}\n </span>\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n {leave.status === 'pending' && (\n <div className=\"flex gap-1\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs\"\n disabled={processingLeaveId === leave.id}\n onClick={() => void decideLeave(leave.id, 'rejected')}\n >\n {t('crewfoundry.dashboard.leaveRequests.reject', 'Reject')}\n </Button>\n <Button\n size=\"sm\"\n className=\"h-7 text-xs\"\n disabled={processingLeaveId === leave.id}\n onClick={() => void decideLeave(leave.id, 'approved')}\n >\n {t('crewfoundry.dashboard.leaveRequests.approve', 'Approve')}\n </Button>\n </div>\n )}\n <Badge\n variant={\n leave.status === 'approved'\n ? 'default'\n : leave.status === 'pending'\n ? 'secondary'\n : 'destructive'\n }\n >\n {formatEnumLabel(leave.status)}\n </Badge>\n <Badge variant=\"outline\">{formatEnumLabel(leave.type)}</Badge>\n </div>\n </div>\n ))}\n {recentLeaveRequests.length > leavePageSize && (\n <Pagination\n page={leavePage}\n pageSize={leavePageSize}\n totalItems={recentLeaveRequests.length}\n onPageChange={setLeavePage}\n />\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/crewfoundry/pages/DashboardDashboardPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n AuroraBackground,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport {\n Activity,\n Briefcase,\n Calendar,\n FolderPlus,\n Plus,\n TrendingUp,\n UserPlus,\n Users,\n} from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport { useCrewFoundry } from '../providers/CrewFoundryProvider';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\nimport { AreaChart, HBarFunnel, StatCard, getInitials } from '../components/viz';\nimport { headcountByMonth, momDelta } from '../lib/analytics';\n\n/** Cumulative count of entities per absolute month index, from their date field. */\nfunction cumulativeSeries(dates: (string | undefined | null)[]): number[] {\n const indices = dates\n .map((value) => (value ? new Date(value) : null))\n .filter((date): date is Date => date !== null && !Number.isNaN(date.getTime()))\n .map((date) => date.getUTCFullYear() * 12 + date.getUTCMonth());\n if (indices.length === 0) {\n return [];\n }\n const min = Math.min(...indices);\n const max = Math.max(...indices);\n const series: number[] = [];\n for (let index = min; index <= max; index += 1) {\n series.push(indices.filter((start) => start <= index).length);\n }\n return series;\n}\n\n/** Last-vs-prior percentage change of a raw series, for KPI trend arrows. */\nfunction seriesDeltaPercent(values: number[]): number | undefined {\n if (values.length < 2) {\n return undefined;\n }\n const current = values[values.length - 1];\n const previous = values[values.length - 2];\n if (previous <= 0) {\n return undefined;\n }\n return Math.round(((current - previous) / previous) * 100);\n}\n\n/** Circular initials avatar (backend has no interview-candidate photos). */\nfunction InitialsAvatar({ name, size = 38 }: { name: string; size?: number }) {\n return (\n <span\n aria-hidden=\"true\"\n className=\"inline-flex shrink-0 items-center justify-center rounded-full bg-bg-elevated font-medium text-text-secondary\"\n style={{ width: size, height: size, fontSize: Math.round(size * 0.36) }}\n >\n {getInitials(name)}\n </span>\n );\n}\n\nconst STAGE_ORDER = ['new', 'screening', 'interview', 'assessment', 'offer', 'hired'] as const;\n\nexport function DashboardDashboardPagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { showToast } = useGlobalUi();\n const { currentUser } = useCrewFoundry();\n const {\n employees,\n jobPostings,\n interviews,\n leaveRequests,\n projects,\n candidates,\n announcements,\n updateLeaveRequest,\n } = useCrewFoundryStore();\n const [processingLeaveId, setProcessingLeaveId] = useState<string | null>(null);\n const [expandedAnnouncements, setExpandedAnnouncements] = useState<Record<string, boolean>>({});\n\n const approverName =\n currentUser?.name ||\n [currentUser?.firstName, currentUser?.lastName].filter(Boolean).join(' ') ||\n currentUser?.email ||\n 'Manager';\n\n const decideLeave = async (id: string, status: 'approved' | 'rejected') => {\n setProcessingLeaveId(id);\n try {\n await updateLeaveRequest(id, { status, approverName });\n showToast(status === 'approved' ? 'Leave approved' : 'Leave rejected', 'success');\n } catch (error) {\n showToast(error instanceof Error ? error.message : 'Unable to update leave request', 'error');\n } finally {\n setProcessingLeaveId(null);\n }\n };\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n\n const activeEmployees = employees.filter((e) => e.status === 'active').length;\n const onLeave = employees.filter((e) => e.status === 'on_leave').length;\n const openPositions = jobPostings.filter((j) => j.status === 'active').length;\n const totalApplicants = jobPostings.reduce((sum, j) => sum + j.applicants, 0);\n const pendingLeaves = leaveRequests.filter((l) => l.status === 'pending').length;\n const activeProjects = projects.filter((p) => p.status === 'active').length;\n const avgPerformance = (\n employees.reduce((sum, e) => sum + e.performanceScore, 0) / Math.max(employees.length, 1)\n ).toFixed(1);\n\n // Real cumulative headcount time-series from employee start dates.\n const headcountSeries = useMemo(() => headcountByMonth(employees), [employees]);\n const headcountValues = headcountSeries.map((point) => point.value);\n const headcountDelta = momDelta(headcountSeries).deltaPercent;\n\n const openingsSeries = useMemo(\n () => cumulativeSeries(jobPostings.filter((job) => job.status === 'active').map((j) => j.postedDate)),\n [jobPostings]\n );\n const projectsSeries = useMemo(\n () => cumulativeSeries(projects.filter((p) => p.status === 'active').map((p) => p.startDate)),\n [projects]\n );\n\n // Descending hiring funnel: candidates who have reached at least each stage.\n const pipelineCounts = useMemo(() => {\n const rankOf = (status: string) => STAGE_ORDER.indexOf(status as (typeof STAGE_ORDER)[number]);\n const reached = (minRank: number) =>\n candidates.filter((candidate) => rankOf(candidate.status) >= minRank).length;\n return {\n applied: candidates.length,\n screening: reached(1),\n interview: reached(2),\n offer: reached(4),\n hired: reached(5),\n };\n }, [candidates]);\n const pipeline = [\n { label: t('crewfoundry.dashboard.pipeline.applied', 'Applied'), value: pipelineCounts.applied },\n {\n label: t('crewfoundry.dashboard.pipeline.screening', 'Screening'),\n value: pipelineCounts.screening,\n },\n {\n label: t('crewfoundry.dashboard.pipeline.interview', 'Interview'),\n value: pipelineCounts.interview,\n },\n { label: t('crewfoundry.dashboard.pipeline.offer', 'Offer'), value: pipelineCounts.offer },\n { label: t('crewfoundry.dashboard.pipeline.hired', 'Hired'), value: pipelineCounts.hired },\n ];\n\n const employeeByName = useMemo(() => {\n const map = new Map<string, string | undefined>();\n for (const employee of employees) {\n map.set(`${employee.firstName} ${employee.lastName}`.trim().toLowerCase(), employee.avatar);\n }\n return map;\n }, [employees]);\n\n const scheduledInterviews = [...interviews]\n .filter((i) => i.status === 'scheduled')\n .sort((a, b) => `${a.date} ${a.time}`.localeCompare(`${b.date} ${b.time}`));\n const upcomingInterviews = scheduledInterviews.slice(0, 5);\n\n const sortedAnnouncements = useMemo(\n () =>\n [...announcements].sort((a, b) => {\n if (a.isPinned !== b.isPinned) {\n return a.isPinned ? -1 : 1;\n }\n return b.createdAt.localeCompare(a.createdAt);\n }),\n [announcements]\n );\n const topAnnouncements = sortedAnnouncements.slice(0, 4);\n\n const recentLeaveRequests = [...leaveRequests].sort((a, b) => {\n if (a.status === 'pending' && b.status !== 'pending') return -1;\n if (b.status === 'pending' && a.status !== 'pending') return 1;\n return b.startDate.localeCompare(a.startDate);\n });\n const {\n page: leavePage,\n pageSize: leavePageSize,\n offset: leaveOffset,\n setPage: setLeavePage,\n } = usePagination({ initialPageSize: 6 });\n const leavePageItems = recentLeaveRequests.slice(leaveOffset, leaveOffset + leavePageSize);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"relative overflow-hidden rounded-xl border border-border-seam bg-gloss-card p-6\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{t('crewfoundry.dashboard.title', 'Command Center')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {t('crewfoundry.dashboard.subtitle', 'Your workforce at a glance')}\n </p>\n <PagePurpose className=\"mt-2\">\n {t(\n 'crewfoundry.dashboard.purpose',\n 'Your workforce command center — see headcount, hiring, performance, and projects at a glance, then jump straight to the area that needs your attention.'\n )}\n </PagePurpose>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button className=\"self-start\">\n <Plus className=\"mr-1 h-4 w-4\" />\n {t('crewfoundry.dashboard.new', 'New')}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-52\">\n <DropdownMenuLabel>{t('crewfoundry.dashboard.newMenu', 'Create')}</DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuItem onClick={() => navigate('../hr/employees-page')}>\n <UserPlus className=\"mr-2 h-4 w-4\" />\n {t('crewfoundry.dashboard.newEmployee', 'Add employee')}\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => navigate('../hiring/create-job-page')}>\n <Briefcase className=\"mr-2 h-4 w-4\" />\n {t('crewfoundry.dashboard.newJob', 'Post a job')}\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => navigate('../projects/projects-page')}>\n <FolderPlus className=\"mr-2 h-4 w-4\" />\n {t('crewfoundry.dashboard.newProject', 'New project')}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n\n <NextSteps\n storageKey=\"crewfoundry-dashboard\"\n steps={[\n {\n id: 'employees',\n label: t('crewfoundry.dashboard.next.employees', 'Review your team'),\n description: t(\n 'crewfoundry.dashboard.next.employeesDesc',\n 'Open the employee directory to see who is active and on leave.'\n ),\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('../hr/employees-page'),\n },\n {\n id: 'hiring',\n label: t('crewfoundry.dashboard.next.hiring', 'Post a new job'),\n description: t(\n 'crewfoundry.dashboard.next.hiringDesc',\n 'Create an opening to start collecting applicants.'\n ),\n icon: <Briefcase className=\"h-4 w-4\" />,\n onClick: () => navigate('../hiring/create-job-page'),\n },\n {\n id: 'projects',\n label: t('crewfoundry.dashboard.next.projects', 'Check active projects'),\n description: t(\n 'crewfoundry.dashboard.next.projectsDesc',\n 'Track progress and budgets across in-flight work.'\n ),\n icon: <Activity className=\"h-4 w-4\" />,\n onClick: () => navigate('../projects/projects-page'),\n },\n ]}\n />\n\n {/* Bento: KPI grid + headcount growth + upcoming interviews */}\n <div className=\"grid gap-4 lg:grid-cols-12\">\n <div className=\"grid gap-4 sm:grid-cols-2 lg:col-span-5\">\n <StatCard\n label={t('crewfoundry.dashboard.stats.totalEmployees', 'Total Employees')}\n value={employees.length}\n delta={headcountDelta || undefined}\n deltaLabel={t('crewfoundry.dashboard.stats.fromLastMonth', 'from last month')}\n icon={<Users className=\"h-4 w-4\" />}\n sparkline={headcountValues}\n sparklineVariant=\"area\"\n />\n <StatCard\n label={t('crewfoundry.dashboard.stats.openPositions', 'Open Positions')}\n value={openPositions}\n delta={seriesDeltaPercent(openingsSeries)}\n deltaLabel={t('crewfoundry.dashboard.stats.fromLastMonth', 'from last month')}\n icon={<Briefcase className=\"h-4 w-4\" />}\n sparkline={openingsSeries}\n sparklineVariant=\"area\"\n />\n <StatCard\n label={t('crewfoundry.dashboard.stats.activeProjects', 'Active Projects')}\n value={activeProjects}\n delta={seriesDeltaPercent(projectsSeries)}\n deltaLabel={t('crewfoundry.dashboard.stats.fromLastMonth', 'from last month')}\n icon={<Activity className=\"h-4 w-4\" />}\n sparkline={projectsSeries}\n sparklineVariant=\"area\"\n />\n <StatCard\n label={t('crewfoundry.dashboard.stats.avgPerformance', 'Avg Performance')}\n value={`${avgPerformance}`}\n icon={<TrendingUp className=\"h-4 w-4\" />}\n />\n </div>\n\n <Card className=\"lg:col-span-4\">\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('crewfoundry.dashboard.headcountGrowth.title', 'Headcount growth')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n {headcountSeries.length > 1 ? (\n <AreaChart\n series={headcountSeries}\n height={210}\n title=\"Cumulative headcount by month\"\n />\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('crewfoundry.dashboard.headcountGrowth.emptyTitle', 'Not enough history')}\n description={t(\n 'crewfoundry.dashboard.headcountGrowth.emptyDescription',\n 'Headcount growth appears once employees span more than one hiring month.'\n )}\n />\n )}\n </CardContent>\n </Card>\n\n <Card className=\"lg:col-span-3\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"text-base\">\n {t('crewfoundry.dashboard.upcomingInterviews.title', 'Upcoming interviews')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {upcomingInterviews.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t(\n 'crewfoundry.dashboard.upcomingInterviews.emptyTitle',\n 'No interviews scheduled'\n )}\n description={t(\n 'crewfoundry.dashboard.upcomingInterviews.emptyDescription',\n 'Scheduled interviews will appear here.'\n )}\n />\n )}\n {upcomingInterviews.map((interview) => {\n const avatar = employeeByName.get(interview.candidateName.trim().toLowerCase());\n return (\n <div key={interview.id} className=\"flex items-center gap-3\">\n {avatar ? (\n <img\n src={avatar}\n alt=\"\"\n className=\"h-9 w-9 shrink-0 rounded-full object-cover\"\n />\n ) : (\n <InitialsAvatar name={interview.candidateName} />\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium\">{interview.candidateName}</p>\n <p className=\"truncate text-xs text-text-secondary\">{interview.position}</p>\n </div>\n <div className=\"flex shrink-0 items-center gap-1.5 text-right\">\n <div>\n <p className=\"text-xs font-medium\">{interview.time}</p>\n <p className=\"text-[10px] text-text-secondary\">{interview.date}</p>\n </div>\n <Calendar className=\"h-3.5 w-3.5 text-text-secondary\" />\n </div>\n </div>\n );\n })}\n {scheduledInterviews.length > upcomingInterviews.length && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full\"\n onClick={() => navigate('../hiring/interviews-page')}\n >\n {t('crewfoundry.dashboard.upcomingInterviews.viewAll', 'View All')}\n </Button>\n )}\n </CardContent>\n </Card>\n </div>\n\n {/* Hiring pipeline funnel + announcements rail */}\n <div className=\"grid gap-4 lg:grid-cols-12\">\n <Card className=\"lg:col-span-8\">\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('crewfoundry.dashboard.pipeline.title', 'Hiring pipeline')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n {candidates.length > 0 ? (\n <HBarFunnel stages={pipeline} valueFormatter={(value) => `${value}`} />\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('crewfoundry.dashboard.pipeline.emptyTitle', 'No candidates yet')}\n description={t(\n 'crewfoundry.dashboard.pipeline.emptyDescription',\n 'Your hiring funnel appears here once candidates enter the pipeline.'\n )}\n />\n )}\n </CardContent>\n </Card>\n\n <Card className=\"lg:col-span-4\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle className=\"text-base\">\n {t('crewfoundry.dashboard.announcements.title', 'Announcements')}\n </CardTitle>\n {sortedAnnouncements.length > topAnnouncements.length && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => navigate('../communications/announcements-page')}\n >\n {t('crewfoundry.dashboard.announcements.viewAll', 'View All')}\n </Button>\n )}\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {topAnnouncements.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('crewfoundry.dashboard.announcements.emptyTitle', 'No announcements')}\n description={t(\n 'crewfoundry.dashboard.announcements.emptyDescription',\n 'Company announcements will appear here.'\n )}\n />\n )}\n {topAnnouncements.map((announcement) => {\n const expanded = expandedAnnouncements[announcement.id];\n const isLong = announcement.content.length > 120;\n return (\n <div key={announcement.id} className=\"space-y-1\">\n <div className=\"flex items-center gap-2\">\n <p className=\"text-sm font-medium\">{announcement.title}</p>\n {announcement.isPinned && (\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {t('crewfoundry.dashboard.announcements.pinned', 'Pinned')}\n </Badge>\n )}\n </div>\n <p className=\"text-xs text-text-secondary\">\n {announcement.createdAt} · {announcement.author}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {expanded || !isLong\n ? announcement.content\n : `${announcement.content.slice(0, 120)}…`}\n </p>\n {isLong && (\n <button\n type=\"button\"\n className=\"text-xs font-medium text-action-primary-bg hover:underline\"\n onClick={() =>\n setExpandedAnnouncements((prev) => ({\n ...prev,\n [announcement.id]: !prev[announcement.id],\n }))\n }\n >\n {expanded\n ? t('crewfoundry.dashboard.announcements.readLess', 'Read Less')\n : t('crewfoundry.dashboard.announcements.readMore', 'Read More')}\n </button>\n )}\n </div>\n );\n })}\n </CardContent>\n </Card>\n </div>\n\n {/* Leave approvals (real approve / reject) */}\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t('crewfoundry.dashboard.leaveRequests.title', 'Recent Leave Requests')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {leaveRequests.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('crewfoundry.dashboard.leaveRequests.emptyTitle', 'No leave requests')}\n description={t(\n 'crewfoundry.dashboard.leaveRequests.emptyDescription',\n 'Pending leave requests will appear here.'\n )}\n />\n )}\n {leavePageItems.map((leave) => (\n <div key={leave.id} className=\"flex items-center justify-between rounded border p-3\">\n <div className=\"flex items-center gap-3\">\n <InitialsAvatar name={leave.employeeName} size={34} />\n <div>\n <p className=\"text-sm font-medium\">{leave.employeeName}</p>\n <div className=\"flex items-center gap-2 text-xs text-text-secondary\">\n <Calendar className=\"h-3 w-3\" />\n <span>\n {leave.startDate} - {leave.endDate}\n </span>\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n {leave.status === 'pending' && (\n <div className=\"flex gap-1\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs\"\n disabled={processingLeaveId === leave.id}\n onClick={() => void decideLeave(leave.id, 'rejected')}\n >\n {t('crewfoundry.dashboard.leaveRequests.reject', 'Reject')}\n </Button>\n <Button\n size=\"sm\"\n className=\"h-7 text-xs\"\n disabled={processingLeaveId === leave.id}\n onClick={() => void decideLeave(leave.id, 'approved')}\n >\n {t('crewfoundry.dashboard.leaveRequests.approve', 'Approve')}\n </Button>\n </div>\n )}\n <Badge\n variant={\n leave.status === 'approved'\n ? 'default'\n : leave.status === 'pending'\n ? 'secondary'\n : 'destructive'\n }\n >\n {formatEnumLabel(leave.status)}\n </Badge>\n <Badge variant=\"outline\">{formatEnumLabel(leave.type)}</Badge>\n </div>\n </div>\n ))}\n {recentLeaveRequests.length > leavePageSize && (\n <Pagination\n page={leavePage}\n pageSize={leavePageSize}\n totalItems={recentLeaveRequests.length}\n onPageChange={setLeavePage}\n />\n )}\n </CardContent>\n </Card>\n\n <p className=\"text-center text-xs text-text-muted\">\n {activeEmployees} {t('crewfoundry.dashboard.stats.active', 'active')} · {onLeave}{' '}\n {t('crewfoundry.dashboard.stats.onLeave', 'on leave')} · {totalApplicants}{' '}\n {t('crewfoundry.dashboard.stats.totalApplicants', 'total applicants')} · {pendingLeaves}{' '}\n {t('crewfoundry.dashboard.stats.pendingLeaveRequests', 'pending leave requests')}\n </p>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -18,10 +18,6 @@ var D = "https://graphqlworkspaces.burdenoff.com/workspaces/graphql", O = [
|
|
|
18
18
|
name: "Client",
|
|
19
19
|
domain: "Finance"
|
|
20
20
|
},
|
|
21
|
-
{
|
|
22
|
-
name: "Course",
|
|
23
|
-
domain: "Learning"
|
|
24
|
-
},
|
|
25
21
|
{
|
|
26
22
|
name: "Department",
|
|
27
23
|
domain: "HR"
|
|
@@ -34,26 +30,14 @@ var D = "https://graphqlworkspaces.burdenoff.com/workspaces/graphql", O = [
|
|
|
34
30
|
name: "Interview",
|
|
35
31
|
domain: "Hiring"
|
|
36
32
|
},
|
|
37
|
-
{
|
|
38
|
-
name: "Invoice",
|
|
39
|
-
domain: "Finance"
|
|
40
|
-
},
|
|
41
33
|
{
|
|
42
34
|
name: "JobPosting",
|
|
43
35
|
domain: "Hiring"
|
|
44
36
|
},
|
|
45
|
-
{
|
|
46
|
-
name: "LearningPath",
|
|
47
|
-
domain: "Learning"
|
|
48
|
-
},
|
|
49
37
|
{
|
|
50
38
|
name: "LeaveRequest",
|
|
51
39
|
domain: "HR"
|
|
52
40
|
},
|
|
53
|
-
{
|
|
54
|
-
name: "MarketplaceService",
|
|
55
|
-
domain: "Marketplace"
|
|
56
|
-
},
|
|
57
41
|
{
|
|
58
42
|
name: "PayrollRecord",
|
|
59
43
|
domain: "Finance"
|
|
@@ -138,31 +122,6 @@ function M() {
|
|
|
138
122
|
name: "Delete mutations",
|
|
139
123
|
description: "Remove records",
|
|
140
124
|
operations: n
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
id: "workflow",
|
|
144
|
-
name: "Workflow mutations",
|
|
145
|
-
description: "Enrollment & notifications",
|
|
146
|
-
operations: [
|
|
147
|
-
{
|
|
148
|
-
kind: "Mutation",
|
|
149
|
-
name: "enrollCrewCourse",
|
|
150
|
-
signature: "enrollCrewCourse(id: ID!): CrewCourse!",
|
|
151
|
-
description: "Enroll the current member into a learning course."
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
kind: "Mutation",
|
|
155
|
-
name: "markCrewNotificationRead",
|
|
156
|
-
signature: "markCrewNotificationRead(id: ID!): Boolean!",
|
|
157
|
-
description: "Mark a single notification as read."
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
kind: "Mutation",
|
|
161
|
-
name: "markAllCrewNotificationsRead",
|
|
162
|
-
signature: "markAllCrewNotificationsRead: Boolean!",
|
|
163
|
-
description: "Mark every notification as read."
|
|
164
|
-
}
|
|
165
|
-
]
|
|
166
125
|
}
|
|
167
126
|
];
|
|
168
127
|
}, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HelpApiDocumentationPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HelpApiDocumentationPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n Check,\n ChevronRight,\n Code2,\n Copy,\n Database,\n ListTree,\n Lock,\n Network,\n Search,\n} from 'lucide-react';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\n// The CrewFoundry API is served by wspace-crewfoundry-svc as an Apollo\n// Federation v2 subgraph, reached through the workspaces public GraphQL\n// gateway. There is no separate REST surface — this reference is derived\n// directly from the published subgraph schema.\nconst ENDPOINT = 'https://graphqlworkspaces.burdenoff.com/workspaces/graphql';\n\n// The 17 domain entities exposed by the subgraph, each with create / update /\n// remove mutations. Names and input types mirror the published schema exactly.\nconst ENTITIES: { name: string; domain: string }[] = [\n { name: 'Announcement', domain: 'Communications' },\n { name: 'Candidate', domain: 'Hiring' },\n { name: 'Client', domain: 'Finance' },\n { name: 'Course', domain: 'Learning' },\n { name: 'Department', domain: 'HR' },\n { name: 'Employee', domain: 'HR' },\n { name: 'Interview', domain: 'Hiring' },\n { name: 'Invoice', domain: 'Finance' },\n { name: 'JobPosting', domain: 'Hiring' },\n { name: 'LearningPath', domain: 'Learning' },\n { name: 'LeaveRequest', domain: 'HR' },\n { name: 'MarketplaceService', domain: 'Marketplace' },\n { name: 'PayrollRecord', domain: 'Finance' },\n { name: 'Project', domain: 'Projects' },\n { name: 'Team', domain: 'Teams' },\n { name: 'TimeEntry', domain: 'HR' },\n { name: 'Vendor', domain: 'Finance' },\n];\n\ntype OperationKind = 'Query' | 'Mutation';\n\ntype ApiOperation = {\n kind: OperationKind;\n name: string;\n signature: string;\n description: string;\n};\n\ntype ApiGroup = {\n id: string;\n name: string;\n description: string;\n operations: ApiOperation[];\n};\n\nconst kindColors: Record<OperationKind, string> = {\n Query: 'bg-status-success-bg text-status-success-text',\n Mutation: 'bg-status-info-bg text-status-info-text',\n};\n\nconst humanize = (value: string): string => value.replace(/([a-z])([A-Z])/g, '$1 $2').toLowerCase();\n\nconst copyToClipboard = async (text: string): Promise<boolean> => {\n try {\n if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(text);\n return true;\n }\n } catch {\n // Fall through to the legacy path for insecure / restricted contexts.\n }\n try {\n if (typeof document === 'undefined') {\n return false;\n }\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.position = 'fixed';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n textarea.focus();\n textarea.select();\n const succeeded = document.execCommand('copy');\n document.body.removeChild(textarea);\n return succeeded;\n } catch {\n return false;\n }\n};\n\nexport function HelpApiDocumentationPagePage() {\n const { employees, jobPostings, candidates, payrollRecords, leaveRequests } =\n useCrewFoundryStore();\n const { showToast } = useGlobalUi();\n const [search, setSearch] = useState('');\n const [copied, setCopied] = useState<string | null>(null);\n\n const groups = useMemo<ApiGroup[]>(() => {\n const createOps: ApiOperation[] = ENTITIES.map((entity) => ({\n kind: 'Mutation',\n name: `createCrew${entity.name}`,\n signature: `createCrew${entity.name}(input: CreateCrew${entity.name}Input!): Crew${entity.name}!`,\n description: `Create a ${humanize(entity.name)} record (${entity.domain}).`,\n }));\n const updateOps: ApiOperation[] = ENTITIES.map((entity) => ({\n kind: 'Mutation',\n name: `updateCrew${entity.name}`,\n signature: `updateCrew${entity.name}(id: ID!, input: UpdateCrew${entity.name}Input!): Crew${entity.name}!`,\n description: `Update an existing ${humanize(entity.name)} record (${entity.domain}).`,\n }));\n const removeOps: ApiOperation[] = ENTITIES.map((entity) => ({\n kind: 'Mutation',\n name: `removeCrew${entity.name}`,\n signature: `removeCrew${entity.name}(id: ID!): Boolean!`,\n description: `Delete a ${humanize(entity.name)} record (${entity.domain}).`,\n }));\n\n return [\n {\n id: 'queries',\n name: 'Queries',\n description: 'Read the workspace dataset',\n operations: [\n {\n kind: 'Query',\n name: 'crewfoundryBootstrap',\n signature: 'crewfoundryBootstrap: CrewfoundryBootstrap!',\n description: `Load the full workspace dataset in one call — ${employees.length} employees, ${jobPostings.length} job postings, ${candidates.length} candidates, ${payrollRecords.length} payroll records, ${leaveRequests.length} leave requests, and every other CrewFoundry collection.`,\n },\n ],\n },\n {\n id: 'create',\n name: 'Create mutations',\n description: 'Add new records',\n operations: createOps,\n },\n {\n id: 'update',\n name: 'Update mutations',\n description: 'Modify existing records',\n operations: updateOps,\n },\n {\n id: 'delete',\n name: 'Delete mutations',\n description: 'Remove records',\n operations: removeOps,\n },\n {\n id: 'workflow',\n name: 'Workflow mutations',\n description: 'Enrollment & notifications',\n operations: [\n {\n kind: 'Mutation',\n name: 'enrollCrewCourse',\n signature: 'enrollCrewCourse(id: ID!): CrewCourse!',\n description: 'Enroll the current member into a learning course.',\n },\n {\n kind: 'Mutation',\n name: 'markCrewNotificationRead',\n signature: 'markCrewNotificationRead(id: ID!): Boolean!',\n description: 'Mark a single notification as read.',\n },\n {\n kind: 'Mutation',\n name: 'markAllCrewNotificationsRead',\n signature: 'markAllCrewNotificationsRead: Boolean!',\n description: 'Mark every notification as read.',\n },\n ],\n },\n ];\n }, [\n candidates.length,\n employees.length,\n jobPostings.length,\n leaveRequests.length,\n payrollRecords.length,\n ]);\n\n const totalOperations = useMemo(\n () => groups.reduce((sum, group) => sum + group.operations.length, 0),\n [groups]\n );\n\n const filteredGroups = useMemo(() => {\n const term = search.trim().toLowerCase();\n if (!term) {\n return groups;\n }\n return groups\n .map((group) => ({\n ...group,\n operations: group.operations.filter(\n (op) =>\n op.name.toLowerCase().includes(term) ||\n op.signature.toLowerCase().includes(term) ||\n op.description.toLowerCase().includes(term)\n ),\n }))\n .filter((group) => group.operations.length > 0);\n }, [groups, search]);\n\n const handleCopy = async (value: string) => {\n const ok = await copyToClipboard(value);\n if (ok) {\n setCopied(value);\n showToast('Copied to clipboard', 'success');\n window.setTimeout(() => setCopied((current) => (current === value ? null : current)), 1500);\n } else {\n showToast('Unable to copy to clipboard', 'error');\n }\n };\n\n const scrollToGroup = (id: string) => {\n const target = typeof document !== 'undefined' ? document.getElementById(`group-${id}`) : null;\n target?.scrollIntoView({ behavior: 'smooth', block: 'start' });\n };\n\n const statTiles = [\n { icon: Network, label: 'Protocol', value: 'GraphQL', color: 'text-status-info-text' },\n {\n icon: Code2,\n label: 'Composition',\n value: 'Apollo Federation v2',\n color: 'text-action-primary-bg',\n },\n { icon: Lock, label: 'Auth', value: 'Bearer token', color: 'text-status-success-text' },\n {\n icon: ListTree,\n label: 'Operations',\n value: String(totalOperations),\n color: 'text-status-warning-text',\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex flex-col gap-3 md:flex-row md:items-start md:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>API Documentation</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n CrewFoundry GraphQL API reference for integrations\n </p>\n <PagePurpose className=\"mt-1\">\n Browse the CrewFoundry API reference — use it to find operations, understand request\n formats, and integrate CrewFoundry with your own tools.\n </PagePurpose>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"secondary\" className=\"max-w-full truncate font-mono text-[10px]\">\n {ENDPOINT}\n </Badge>\n <Button\n size=\"sm\"\n variant=\"outline\"\n aria-label=\"Copy the GraphQL endpoint URL\"\n onClick={() => void handleCopy(ENDPOINT)}\n >\n {copied === ENDPOINT ? (\n <Check className=\"mr-1 h-3 w-3 text-status-success-text\" />\n ) : (\n <Copy className=\"mr-1 h-3 w-3\" />\n )}\n Copy endpoint\n </Button>\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n {statTiles.map((item) => (\n <Card key={item.label}>\n <CardContent className=\"flex items-center gap-3 pt-6\">\n <item.icon className={`h-5 w-5 ${item.color}`} />\n <div className=\"min-w-0\">\n <p className=\"text-xs text-text-secondary\">{item.label}</p>\n <p className=\"truncate text-sm font-medium\">{item.value}</p>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n\n <div className=\"grid gap-6 lg:grid-cols-4\">\n <div className=\"space-y-4\">\n <EmphasisPanel>\n <div className=\"mb-2 text-sm font-semibold\">Jump to</div>\n <div className=\"space-y-2\">\n {groups.map((group) => (\n <button\n key={group.id}\n type=\"button\"\n aria-label={`Jump to ${group.name}`}\n onClick={() => scrollToGroup(group.id)}\n className=\"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors hover:bg-bg-sunken\"\n >\n <ListTree className=\"h-3 w-3 text-text-secondary\" />\n <span>{group.name}</span>\n <Badge variant=\"outline\" className=\"ml-auto text-[10px]\">\n {group.operations.length}\n </Badge>\n <ChevronRight className=\"h-3 w-3 text-text-secondary\" />\n </button>\n ))}\n </div>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">Authentication</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <div className=\"rounded-md bg-bg-sunken p-3\">\n <code className=\"font-mono text-xs\">Authorization: Bearer {'<token>'}</code>\n </div>\n <p className=\"text-xs text-text-secondary\">\n Requests are authenticated at the gateway edge. Send your session bearer token on\n every request; the gateway resolves the actor and enforces workspace-scoped RBAC\n before the subgraph runs.\n </p>\n </CardContent>\n </Card>\n </div>\n\n <div className=\"space-y-4 lg:col-span-3\">\n <div className=\"relative max-w-md\">\n <Search className=\"absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search operations...\"\n className=\"pl-9\"\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n />\n </div>\n\n {filteredGroups.map((group) => (\n <Card key={group.id} id={`group-${group.id}`} className=\"scroll-mt-6\">\n <CardHeader>\n <div className=\"flex items-center gap-2\">\n <Database className=\"h-4 w-4 text-text-secondary\" />\n <CardTitle className=\"text-base\">{group.name}</CardTitle>\n </div>\n <CardDescription>\n {group.description} · {group.operations.length} operations\n </CardDescription>\n </CardHeader>\n <CardContent className=\"p-0\">\n {group.operations.map((op, index) => (\n <div\n key={op.name}\n className={`flex items-center gap-3 px-6 py-3 hover:bg-bg-sunken/50 ${index < group.operations.length - 1 ? 'border-b' : ''}`}\n >\n <Badge\n className={`${kindColors[op.kind]} min-w-[64px] justify-center border-0 font-mono text-[10px]`}\n >\n {op.kind}\n </Badge>\n <div className=\"min-w-0 flex-1\">\n <code className=\"block truncate font-mono text-sm\">{op.signature}</code>\n <span className=\"text-xs text-text-secondary\">{op.description}</span>\n </div>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-6 w-6 shrink-0 p-0\"\n aria-label={`Copy ${op.name} operation name`}\n onClick={() => void handleCopy(op.name)}\n >\n {copied === op.name ? (\n <Check className=\"h-3 w-3 text-status-success-text\" />\n ) : (\n <Copy className=\"h-3 w-3 text-text-secondary\" />\n )}\n </Button>\n </div>\n ))}\n </CardContent>\n </Card>\n ))}\n\n {filteredGroups.length === 0 && (\n <div className=\"py-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No operations match\"\n description=\"Try a different search term to find the operation you need.\"\n />\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HelpApiDocumentationPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HelpApiDocumentationPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n Check,\n ChevronRight,\n Code2,\n Copy,\n Database,\n ListTree,\n Lock,\n Network,\n Search,\n} from 'lucide-react';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\n// The CrewFoundry API is served by wspace-crewfoundry-svc as an Apollo\n// Federation v2 subgraph, reached through the workspaces public GraphQL\n// gateway. There is no separate REST surface — this reference is derived\n// directly from the published subgraph schema.\nconst ENDPOINT = 'https://graphqlworkspaces.burdenoff.com/workspaces/graphql';\n\n// The 13 CrewFoundry-owned domain entities exposed by the subgraph, each with\n// create / update / remove mutations. Marketplace, billing/invoices,\n// notifications, and learning are intentionally served by shared owners.\nconst ENTITIES: { name: string; domain: string }[] = [\n { name: 'Announcement', domain: 'Communications' },\n { name: 'Candidate', domain: 'Hiring' },\n { name: 'Client', domain: 'Finance' },\n { name: 'Department', domain: 'HR' },\n { name: 'Employee', domain: 'HR' },\n { name: 'Interview', domain: 'Hiring' },\n { name: 'JobPosting', domain: 'Hiring' },\n { name: 'LeaveRequest', domain: 'HR' },\n { name: 'PayrollRecord', domain: 'Finance' },\n { name: 'Project', domain: 'Projects' },\n { name: 'Team', domain: 'Teams' },\n { name: 'TimeEntry', domain: 'HR' },\n { name: 'Vendor', domain: 'Finance' },\n];\n\ntype OperationKind = 'Query' | 'Mutation';\n\ntype ApiOperation = {\n kind: OperationKind;\n name: string;\n signature: string;\n description: string;\n};\n\ntype ApiGroup = {\n id: string;\n name: string;\n description: string;\n operations: ApiOperation[];\n};\n\nconst kindColors: Record<OperationKind, string> = {\n Query: 'bg-status-success-bg text-status-success-text',\n Mutation: 'bg-status-info-bg text-status-info-text',\n};\n\nconst humanize = (value: string): string => value.replace(/([a-z])([A-Z])/g, '$1 $2').toLowerCase();\n\nconst copyToClipboard = async (text: string): Promise<boolean> => {\n try {\n if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(text);\n return true;\n }\n } catch {\n // Fall through to the legacy path for insecure / restricted contexts.\n }\n try {\n if (typeof document === 'undefined') {\n return false;\n }\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.position = 'fixed';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n textarea.focus();\n textarea.select();\n const succeeded = document.execCommand('copy');\n document.body.removeChild(textarea);\n return succeeded;\n } catch {\n return false;\n }\n};\n\nexport function HelpApiDocumentationPagePage() {\n const { employees, jobPostings, candidates, payrollRecords, leaveRequests } =\n useCrewFoundryStore();\n const { showToast } = useGlobalUi();\n const [search, setSearch] = useState('');\n const [copied, setCopied] = useState<string | null>(null);\n\n const groups = useMemo<ApiGroup[]>(() => {\n const createOps: ApiOperation[] = ENTITIES.map((entity) => ({\n kind: 'Mutation',\n name: `createCrew${entity.name}`,\n signature: `createCrew${entity.name}(input: CreateCrew${entity.name}Input!): Crew${entity.name}!`,\n description: `Create a ${humanize(entity.name)} record (${entity.domain}).`,\n }));\n const updateOps: ApiOperation[] = ENTITIES.map((entity) => ({\n kind: 'Mutation',\n name: `updateCrew${entity.name}`,\n signature: `updateCrew${entity.name}(id: ID!, input: UpdateCrew${entity.name}Input!): Crew${entity.name}!`,\n description: `Update an existing ${humanize(entity.name)} record (${entity.domain}).`,\n }));\n const removeOps: ApiOperation[] = ENTITIES.map((entity) => ({\n kind: 'Mutation',\n name: `removeCrew${entity.name}`,\n signature: `removeCrew${entity.name}(id: ID!): Boolean!`,\n description: `Delete a ${humanize(entity.name)} record (${entity.domain}).`,\n }));\n\n return [\n {\n id: 'queries',\n name: 'Queries',\n description: 'Read the workspace dataset',\n operations: [\n {\n kind: 'Query',\n name: 'crewfoundryBootstrap',\n signature: 'crewfoundryBootstrap: CrewfoundryBootstrap!',\n description: `Load the full workspace dataset in one call — ${employees.length} employees, ${jobPostings.length} job postings, ${candidates.length} candidates, ${payrollRecords.length} payroll records, ${leaveRequests.length} leave requests, and every other CrewFoundry collection.`,\n },\n ],\n },\n {\n id: 'create',\n name: 'Create mutations',\n description: 'Add new records',\n operations: createOps,\n },\n {\n id: 'update',\n name: 'Update mutations',\n description: 'Modify existing records',\n operations: updateOps,\n },\n {\n id: 'delete',\n name: 'Delete mutations',\n description: 'Remove records',\n operations: removeOps,\n },\n ];\n }, [\n candidates.length,\n employees.length,\n jobPostings.length,\n leaveRequests.length,\n payrollRecords.length,\n ]);\n\n const totalOperations = useMemo(\n () => groups.reduce((sum, group) => sum + group.operations.length, 0),\n [groups]\n );\n\n const filteredGroups = useMemo(() => {\n const term = search.trim().toLowerCase();\n if (!term) {\n return groups;\n }\n return groups\n .map((group) => ({\n ...group,\n operations: group.operations.filter(\n (op) =>\n op.name.toLowerCase().includes(term) ||\n op.signature.toLowerCase().includes(term) ||\n op.description.toLowerCase().includes(term)\n ),\n }))\n .filter((group) => group.operations.length > 0);\n }, [groups, search]);\n\n const handleCopy = async (value: string) => {\n const ok = await copyToClipboard(value);\n if (ok) {\n setCopied(value);\n showToast('Copied to clipboard', 'success');\n window.setTimeout(() => setCopied((current) => (current === value ? null : current)), 1500);\n } else {\n showToast('Unable to copy to clipboard', 'error');\n }\n };\n\n const scrollToGroup = (id: string) => {\n const target = typeof document !== 'undefined' ? document.getElementById(`group-${id}`) : null;\n target?.scrollIntoView({ behavior: 'smooth', block: 'start' });\n };\n\n const statTiles = [\n { icon: Network, label: 'Protocol', value: 'GraphQL', color: 'text-status-info-text' },\n {\n icon: Code2,\n label: 'Composition',\n value: 'Apollo Federation v2',\n color: 'text-action-primary-bg',\n },\n { icon: Lock, label: 'Auth', value: 'Bearer token', color: 'text-status-success-text' },\n {\n icon: ListTree,\n label: 'Operations',\n value: String(totalOperations),\n color: 'text-status-warning-text',\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex flex-col gap-3 md:flex-row md:items-start md:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>API Documentation</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n CrewFoundry GraphQL API reference for integrations\n </p>\n <PagePurpose className=\"mt-1\">\n Browse the CrewFoundry API reference — use it to find operations, understand request\n formats, and integrate CrewFoundry with your own tools.\n </PagePurpose>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"secondary\" className=\"max-w-full truncate font-mono text-[10px]\">\n {ENDPOINT}\n </Badge>\n <Button\n size=\"sm\"\n variant=\"outline\"\n aria-label=\"Copy the GraphQL endpoint URL\"\n onClick={() => void handleCopy(ENDPOINT)}\n >\n {copied === ENDPOINT ? (\n <Check className=\"mr-1 h-3 w-3 text-status-success-text\" />\n ) : (\n <Copy className=\"mr-1 h-3 w-3\" />\n )}\n Copy endpoint\n </Button>\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n {statTiles.map((item) => (\n <Card key={item.label}>\n <CardContent className=\"flex items-center gap-3 pt-6\">\n <item.icon className={`h-5 w-5 ${item.color}`} />\n <div className=\"min-w-0\">\n <p className=\"text-xs text-text-secondary\">{item.label}</p>\n <p className=\"truncate text-sm font-medium\">{item.value}</p>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n\n <div className=\"grid gap-6 lg:grid-cols-4\">\n <div className=\"space-y-4\">\n <EmphasisPanel>\n <div className=\"mb-2 text-sm font-semibold\">Jump to</div>\n <div className=\"space-y-2\">\n {groups.map((group) => (\n <button\n key={group.id}\n type=\"button\"\n aria-label={`Jump to ${group.name}`}\n onClick={() => scrollToGroup(group.id)}\n className=\"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors hover:bg-bg-sunken\"\n >\n <ListTree className=\"h-3 w-3 text-text-secondary\" />\n <span>{group.name}</span>\n <Badge variant=\"outline\" className=\"ml-auto text-[10px]\">\n {group.operations.length}\n </Badge>\n <ChevronRight className=\"h-3 w-3 text-text-secondary\" />\n </button>\n ))}\n </div>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">Authentication</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <div className=\"rounded-md bg-bg-sunken p-3\">\n <code className=\"font-mono text-xs\">Authorization: Bearer {'<token>'}</code>\n </div>\n <p className=\"text-xs text-text-secondary\">\n Requests are authenticated at the gateway edge. Send your session bearer token on\n every request; the gateway resolves the actor and enforces workspace-scoped RBAC\n before the subgraph runs.\n </p>\n </CardContent>\n </Card>\n </div>\n\n <div className=\"space-y-4 lg:col-span-3\">\n <div className=\"relative max-w-md\">\n <Search className=\"absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search operations...\"\n className=\"pl-9\"\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n />\n </div>\n\n {filteredGroups.map((group) => (\n <Card key={group.id} id={`group-${group.id}`} className=\"scroll-mt-6\">\n <CardHeader>\n <div className=\"flex items-center gap-2\">\n <Database className=\"h-4 w-4 text-text-secondary\" />\n <CardTitle className=\"text-base\">{group.name}</CardTitle>\n </div>\n <CardDescription>\n {group.description} · {group.operations.length} operations\n </CardDescription>\n </CardHeader>\n <CardContent className=\"p-0\">\n {group.operations.map((op, index) => (\n <div\n key={op.name}\n className={`flex items-center gap-3 px-6 py-3 hover:bg-bg-sunken/50 ${index < group.operations.length - 1 ? 'border-b' : ''}`}\n >\n <Badge\n className={`${kindColors[op.kind]} min-w-[64px] justify-center border-0 font-mono text-[10px]`}\n >\n {op.kind}\n </Badge>\n <div className=\"min-w-0 flex-1\">\n <code className=\"block truncate font-mono text-sm\">{op.signature}</code>\n <span className=\"text-xs text-text-secondary\">{op.description}</span>\n </div>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-6 w-6 shrink-0 p-0\"\n aria-label={`Copy ${op.name} operation name`}\n onClick={() => void handleCopy(op.name)}\n >\n {copied === op.name ? (\n <Check className=\"h-3 w-3 text-status-success-text\" />\n ) : (\n <Copy className=\"h-3 w-3 text-text-secondary\" />\n )}\n </Button>\n </div>\n ))}\n </CardContent>\n </Card>\n ))}\n\n {filteredGroups.length === 0 && (\n <div className=\"py-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No operations match\"\n description=\"Try a different search term to find the operation you need.\"\n />\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAiCA,IAAM,IAAW,8DAKX,IAA+C;CACnD;EAAE,MAAM;EAAgB,QAAQ;EAAkB;CAClD;EAAE,MAAM;EAAa,QAAQ;EAAU;CACvC;EAAE,MAAM;EAAU,QAAQ;EAAW;CACrC;EAAE,MAAM;EAAc,QAAQ;EAAM;CACpC;EAAE,MAAM;EAAY,QAAQ;EAAM;CAClC;EAAE,MAAM;EAAa,QAAQ;EAAU;CACvC;EAAE,MAAM;EAAc,QAAQ;EAAU;CACxC;EAAE,MAAM;EAAgB,QAAQ;EAAM;CACtC;EAAE,MAAM;EAAiB,QAAQ;EAAW;CAC5C;EAAE,MAAM;EAAW,QAAQ;EAAY;CACvC;EAAE,MAAM;EAAQ,QAAQ;EAAS;CACjC;EAAE,MAAM;EAAa,QAAQ;EAAM;CACnC;EAAE,MAAM;EAAU,QAAQ;EAAW;CACtC,EAkBK,IAA4C;CAChD,OAAO;CACP,UAAU;CACX,EAEK,KAAY,MAA0B,EAAM,QAAQ,mBAAmB,QAAQ,CAAC,aAAa,EAE7F,IAAkB,OAAO,MAAmC;AAChE,KAAI;AACF,MAAI,OAAO,YAAc,OAAe,UAAU,WAAW,UAE3D,QADA,MAAM,UAAU,UAAU,UAAU,EAAK,EAClC;SAEH;AAGR,KAAI;AACF,MAAI,OAAO,WAAa,IACtB,QAAO;EAET,IAAM,IAAW,SAAS,cAAc,WAAW;AAMnD,EALA,EAAS,QAAQ,GACjB,EAAS,MAAM,WAAW,SAC1B,EAAS,MAAM,UAAU,KACzB,SAAS,KAAK,YAAY,EAAS,EACnC,EAAS,OAAO,EAChB,EAAS,QAAQ;EACjB,IAAM,IAAY,SAAS,YAAY,OAAO;AAE9C,SADA,SAAS,KAAK,YAAY,EAAS,EAC5B;SACD;AACN,SAAO;;;AAIX,SAAgB,IAA+B;CAC7C,IAAM,EAAE,cAAW,gBAAa,eAAY,mBAAgB,qBAC1D,GAAqB,EACjB,EAAE,iBAAc,GAAa,EAC7B,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,CAAC,GAAQ,KAAa,EAAwB,KAAK,EAEnD,IAAS,QAA0B;EACvC,IAAM,IAA4B,EAAS,KAAK,OAAY;GAC1D,MAAM;GACN,MAAM,aAAa,EAAO;GAC1B,WAAW,aAAa,EAAO,KAAK,oBAAoB,EAAO,KAAK,eAAe,EAAO,KAAK;GAC/F,aAAa,YAAY,EAAS,EAAO,KAAK,CAAC,WAAW,EAAO,OAAO;GACzE,EAAE,EACG,IAA4B,EAAS,KAAK,OAAY;GAC1D,MAAM;GACN,MAAM,aAAa,EAAO;GAC1B,WAAW,aAAa,EAAO,KAAK,6BAA6B,EAAO,KAAK,eAAe,EAAO,KAAK;GACxG,aAAa,sBAAsB,EAAS,EAAO,KAAK,CAAC,WAAW,EAAO,OAAO;GACnF,EAAE,EACG,IAA4B,EAAS,KAAK,OAAY;GAC1D,MAAM;GACN,MAAM,aAAa,EAAO;GAC1B,WAAW,aAAa,EAAO,KAAK;GACpC,aAAa,YAAY,EAAS,EAAO,KAAK,CAAC,WAAW,EAAO,OAAO;GACzE,EAAE;AAEH,SAAO;GACL;IACE,IAAI;IACJ,MAAM;IACN,aAAa;IACb,YAAY,CACV;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACX,aAAa,iDAAiD,EAAU,OAAO,cAAc,EAAY,OAAO,iBAAiB,EAAW,OAAO,eAAe,EAAe,OAAO,oBAAoB,EAAc,OAAO;KAClO,CACF;IACF;GACD;IACE,IAAI;IACJ,MAAM;IACN,aAAa;IACb,YAAY;IACb;GACD;IACE,IAAI;IACJ,MAAM;IACN,aAAa;IACb,YAAY;IACb;GACD;IACE,IAAI;IACJ,MAAM;IACN,aAAa;IACb,YAAY;IACb;GACF;IACA;EACD,EAAW;EACX,EAAU;EACV,EAAY;EACZ,EAAc;EACd,EAAe;EAChB,CAAC,EAEI,IAAkB,QAChB,EAAO,QAAQ,GAAK,MAAU,IAAM,EAAM,WAAW,QAAQ,EAAE,EACrE,CAAC,EAAO,CACT,EAEK,IAAiB,QAAc;EACnC,IAAM,IAAO,EAAO,MAAM,CAAC,aAAa;AAIxC,SAHK,IAGE,EACJ,KAAK,OAAW;GACf,GAAG;GACH,YAAY,EAAM,WAAW,QAC1B,MACC,EAAG,KAAK,aAAa,CAAC,SAAS,EAAK,IACpC,EAAG,UAAU,aAAa,CAAC,SAAS,EAAK,IACzC,EAAG,YAAY,aAAa,CAAC,SAAS,EAAK,CAC9C;GACF,EAAE,CACF,QAAQ,MAAU,EAAM,WAAW,SAAS,EAAE,GAZxC;IAaR,CAAC,GAAQ,EAAO,CAAC,EAEd,IAAa,OAAO,MAAkB;AAE1C,EADW,MAAM,EAAgB,EAAM,IAErC,EAAU,EAAM,EAChB,EAAU,uBAAuB,UAAU,EAC3C,OAAO,iBAAiB,GAAW,MAAa,MAAY,IAAQ,OAAO,EAAS,EAAE,KAAK,IAE3F,EAAU,+BAA+B,QAAQ;IAI/C,KAAiB,MAAe;AAEpC,GADe,OAAO,WAAa,MAAc,SAAS,eAAe,SAAS,IAAK,GAAG,OAClF,eAAe;GAAE,UAAU;GAAU,OAAO;GAAS,CAAC;;AAoBhE,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA;KACE,kBAAC,MAAD;MAAI,WAAU;gBACZ,kBAAC,GAAD,EAAA,UAAc,qBAAgC,CAAA;MAC3C,CAAA;KACL,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAEvC,CAAA;KACJ,kBAAC,GAAD;MAAa,WAAU;gBAAO;MAGhB,CAAA;KACV,EAAA,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAO,SAAQ;MAAY,WAAU;gBAClC;MACK,CAAA,EACR,kBAAC,GAAD;MACE,MAAK;MACL,SAAQ;MACR,cAAW;MACX,eAAe,KAAK,EAAW,EAAS;gBAJ1C,CAMG,MAAW,IACV,kBAAC,GAAD,EAAO,WAAU,yCAA0C,CAAA,GAE3D,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EACjC,gBAEK;QACL;OACF;;GAEN,kBAAC,OAAD;IAAK,WAAU;cApDD;KAChB;MAAE,MAAM;MAAS,OAAO;MAAY,OAAO;MAAW,OAAO;MAAyB;KACtF;MACE,MAAM;MACN,OAAO;MACP,OAAO;MACP,OAAO;MACR;KACD;MAAE,MAAM;MAAM,OAAO;MAAQ,OAAO;MAAgB,OAAO;MAA4B;KACvF;MACE,MAAM;MACN,OAAO;MACP,OAAO,OAAO,EAAgB;MAC9B,OAAO;MACR;KACF,CAsCgB,KAAK,MACd,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KAAa,WAAU;eAAvB,CACE,kBAAC,EAAK,MAAN,EAAW,WAAW,WAAW,EAAK,SAAW,CAAA,EACjD,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBAA+B,EAAK;OAAU,CAAA,EAC3D,kBAAC,KAAD;OAAG,WAAU;iBAAgC,EAAK;OAAU,CAAA,CACxD;QACM;QACT,EARI,EAAK,MAQT,CACP;IACE,CAAA;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;gBAA6B;MAAa,CAAA,EACzD,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAO,KAAK,MACX,kBAAC,UAAD;OAEE,MAAK;OACL,cAAY,WAAW,EAAM;OAC7B,eAAe,EAAc,EAAM,GAAG;OACtC,WAAU;iBALZ;QAOE,kBAAC,GAAD,EAAU,WAAU,+BAAgC,CAAA;QACpD,kBAAC,QAAD,EAAA,UAAO,EAAM,MAAY,CAAA;QACzB,kBAAC,GAAD;SAAO,SAAQ;SAAU,WAAU;mBAChC,EAAM,WAAW;SACZ,CAAA;QACR,kBAAC,GAAD,EAAc,WAAU,+BAAgC,CAAA;QACjD;SAZF,EAAM,GAYJ,CACT;MACE,CAAA,CACQ,EAAA,CAAA,EAEhB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAW,WAAU;gBAAU;MAA0B,CAAA,EAC9C,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB,CACE,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CAAoC,0BAAuB,UAAiB;;OACxE,CAAA,EACN,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAIvC,CAAA,CACQ;QACT,EAAA,CAAA,CACH;QAEN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,wEAAyE,CAAA,EAC3F,kBAAC,GAAD;QACE,aAAY;QACZ,WAAU;QACV,OAAO;QACP,WAAW,MAAU,EAAU,EAAM,OAAO,MAAM;QAClD,CAAA,CACE;;MAEL,EAAe,KAAK,MACnB,kBAAC,GAAD;OAAqB,IAAI,SAAS,EAAM;OAAM,WAAU;iBAAxD,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,+BAAgC,CAAA,EACpD,kBAAC,GAAD;SAAW,WAAU;mBAAa,EAAM;SAAiB,CAAA,CACrD;WACN,kBAAC,GAAD,EAAA,UAAA;QACG,EAAM;QAAY;QAAI,EAAM,WAAW;QAAO;QAC/B,EAAA,CAAA,CACP,EAAA,CAAA,EACb,kBAAC,GAAD;QAAa,WAAU;kBACpB,EAAM,WAAW,KAAK,GAAI,MACzB,kBAAC,OAAD;SAEE,WAAW,2DAA2D,IAAQ,EAAM,WAAW,SAAS,IAAI,aAAa;mBAF3H;UAIE,kBAAC,GAAD;WACE,WAAW,GAAG,EAAW,EAAG,MAAM;qBAEjC,EAAG;WACE,CAAA;UACR,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAoC,EAAG;YAAiB,CAAA,EACxE,kBAAC,QAAD;YAAM,WAAU;sBAA+B,EAAG;YAAmB,CAAA,CACjE;;UACN,kBAAC,GAAD;WACE,SAAQ;WACR,MAAK;WACL,WAAU;WACV,cAAY,QAAQ,EAAG,KAAK;WAC5B,eAAe,KAAK,EAAW,EAAG,KAAK;qBAEtC,MAAW,EAAG,OACb,kBAAC,GAAD,EAAO,WAAU,oCAAqC,CAAA,GAEtD,kBAAC,GAAD,EAAM,WAAU,+BAAgC,CAAA;WAE3C,CAAA;UACL;WAzBC,EAAG,KAyBJ,CACN;QACU,CAAA,CACT;SAzCI,EAAM,GAyCV,CACP;MAED,EAAe,WAAW,KACzB,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD;QACE,cAAa;QACb,OAAM;QACN,aAAY;QACZ,CAAA;OACE,CAAA;MAEJ;OACF;;GACF"}
|