@burdenoff/microfe-crewfoundry 2026.703.2 → 2026.704.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/pages/AdminAdminPagePage.js +117 -164
- package/dist/crewfoundry/pages/AdminAdminPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +99 -82
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +160 -192
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +238 -231
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +196 -166
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js +45 -147
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsDirectoryPagePage.js +20 -11
- package/dist/crewfoundry/pages/CommunicationsDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js +45 -152
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +50 -138
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js +149 -67
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js +50 -201
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +205 -136
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js +25 -31
- package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js +118 -104
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +117 -58
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js +90 -94
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +210 -191
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js +213 -180
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js +133 -264
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js.map +1 -1
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js +279 -212
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +131 -105
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +167 -148
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +3 -3
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +13 -5
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +151 -152
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +38 -21
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +3 -3
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js +134 -127
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +163 -132
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js +202 -160
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +104 -91
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js +29 -147
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +22 -106
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +74 -74
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +101 -97
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +64 -47
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js +111 -121
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.js +131 -110
- package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +65 -64
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +58 -43
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +66 -82
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js +38 -88
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js +59 -65
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js +209 -323
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +175 -220
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +74 -59
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +96 -80
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js +28 -100
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js +27 -20
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +73 -73
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +62 -56
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js +40 -138
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +126 -93
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js +99 -77
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js +73 -74
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js +1 -1
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +122 -122
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +130 -113
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js +68 -59
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +73 -62
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +82 -58
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js +153 -153
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +63 -48
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HiringJobDetailsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HiringJobDetailsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useState } from 'react';\nimport {\n Briefcase,\n Calendar,\n CheckCircle,\n DollarSign,\n MapPin,\n Pencil,\n Share2,\n Trash2,\n Users,\n} from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useCrewFoundryStore, type JobPosting } from '../store/crewfoundryStore';\nimport { FormModal, type FieldConfig, type FormValues } from '../components/forms/FormModal';\nimport { ConfirmDialog } from '../components/forms/ConfirmDialog';\nimport { getNumber, getTags, getText } from '../components/forms/formValues';\n\nconst JOB_FIELDS: FieldConfig[] = [\n { name: 'title', label: 'Job Title', type: 'text', required: true, colSpan: 2 },\n { name: 'department', label: 'Department', type: 'text', required: true },\n { name: 'location', label: 'Location', type: 'text', required: true },\n {\n name: 'type',\n label: 'Employment Type',\n type: 'select',\n options: [\n { label: 'Full time', value: 'full_time' },\n { label: 'Part time', value: 'part_time' },\n { label: 'Contract', value: 'contract' },\n { label: 'Remote', value: 'remote' },\n ],\n },\n {\n name: 'experienceLevel',\n label: 'Experience Level',\n type: 'select',\n options: [\n { label: 'Entry', value: 'entry' },\n { label: 'Mid', value: 'mid' },\n { label: 'Senior', value: 'senior' },\n { label: 'Lead', value: 'lead' },\n { label: 'Executive', value: 'executive' },\n ],\n },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n options: [\n { label: 'Draft', value: 'draft' },\n { label: 'Active', value: 'active' },\n { label: 'Paused', value: 'paused' },\n { label: 'Closed', value: 'closed' },\n { label: 'Filled', value: 'filled' },\n ],\n },\n { name: 'salaryMin', label: 'Salary Min ($)', type: 'number' },\n { name: 'salaryMax', label: 'Salary Max ($)', type: 'number' },\n { name: 'deadline', label: 'Application Deadline', type: 'date' },\n { name: 'description', label: 'Description', type: 'textarea', colSpan: 2 },\n { name: 'requirements', label: 'Requirements', type: 'tags' },\n { name: 'benefits', label: 'Benefits', type: 'tags' },\n];\n\nexport function HiringJobDetailsPagePage() {\n const navigate = useNavigate();\n const { showToast } = useGlobalUi();\n const { jobPostings, candidates, updateJobPosting, removeJobPosting } = useCrewFoundryStore();\n const job = jobPostings[0]; // Show first job as detail view\n const [editOpen, setEditOpen] = useState(false);\n const [deleteOpen, setDeleteOpen] = useState(false);\n\n if (!job) {\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No job posting found\"\n description=\"This job posting is no longer available.\"\n />\n </div>\n );\n }\n\n const jobCandidates = candidates.filter((c) => c.position === job.title);\n\n const editInitial: FormValues = {\n title: job.title,\n department: job.department,\n location: job.location,\n type: job.type,\n experienceLevel: job.experienceLevel,\n status: job.status,\n salaryMin: job.salaryMin,\n salaryMax: job.salaryMax,\n deadline: job.deadline,\n description: job.description,\n requirements: job.requirements,\n benefits: job.benefits,\n };\n\n const handleEditSubmit = async (values: FormValues) => {\n const updates: Partial<JobPosting> = {\n title: getText(values, 'title'),\n department: getText(values, 'department'),\n location: getText(values, 'location'),\n type: values.type as JobPosting['type'],\n experienceLevel: values.experienceLevel as JobPosting['experienceLevel'],\n status: values.status as JobPosting['status'],\n salaryMin: getNumber(values, 'salaryMin'),\n salaryMax: getNumber(values, 'salaryMax'),\n deadline: getText(values, 'deadline'),\n description: getText(values, 'description'),\n requirements: getTags(values, 'requirements'),\n benefits: getTags(values, 'benefits'),\n };\n await updateJobPosting(job.id, updates);\n showToast('Job posting updated', 'success');\n };\n\n const handleDelete = async () => {\n await removeJobPosting(job.id);\n showToast('Job posting deleted', 'success');\n navigate('../jobs-page');\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"flex items-center gap-2 mb-1\">\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{job.title}</GradientText>\n </h1>\n <Badge variant={job.status === 'active' ? 'default' : 'secondary'}>{job.status}</Badge>\n </div>\n <div className=\"flex items-center gap-4 text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Briefcase className=\"h-3 w-3\" />\n {job.department}\n </span>\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3 w-3\" />\n {job.location}\n </span>\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n Posted {job.postedDate}\n </span>\n </div>\n <PagePurpose className=\"mt-2\">\n Everything about this role in one place — review applicants, requirements, and\n compensation here to decide who to interview and keep the posting current.\n </PagePurpose>\n </div>\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => showToast('Sharing job postings is coming soon', 'info')}\n >\n <Share2 className=\"h-4 w-4 mr-1\" />\n Share\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setEditOpen(true)}>\n <Pencil className=\"h-4 w-4 mr-1\" />\n Edit Posting\n </Button>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n aria-label=\"Delete job posting\"\n onClick={() => setDeleteOpen(true)}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n <NextSteps\n storageKey=\"crewfoundry-job-details\"\n steps={[\n {\n id: 'applicants',\n label: 'Review applicants',\n description: 'Screen the candidates who applied for this role.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hiring/applications-page'),\n },\n {\n id: 'interviews',\n label: 'Schedule interviews',\n description: 'Set up conversations with promising candidates.',\n icon: <Calendar className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hiring/interviews-page'),\n },\n {\n id: 'candidates',\n label: 'Browse your talent pool',\n description: 'Source more candidates that fit this position.',\n icon: <Briefcase className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hiring/candidates-page'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"p-4 text-center\">\n <Users className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-2xl font-bold tabular-nums\">{job.applicants}</p>\n <p className=\"text-xs text-text-secondary\">Applicants</p>\n </CardContent>\n </GlassCard>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <DollarSign className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">\n ${(job.salaryMin / 1000).toFixed(0)}K-${(job.salaryMax / 1000).toFixed(0)}K\n </p>\n <p className=\"text-xs text-text-secondary\">Salary Range</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Calendar className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{job.deadline}</p>\n <p className=\"text-xs text-text-secondary\">Deadline</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <CheckCircle className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{job.experienceLevel}</p>\n <p className=\"text-xs text-text-secondary\">Level</p>\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Description</CardTitle>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-text-secondary\">{job.description}</p>\n </CardContent>\n </Card>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Requirements</CardTitle>\n </CardHeader>\n <CardContent>\n <ul className=\"space-y-2\">\n {job.requirements.map((req, idx) => (\n <li key={idx} className=\"flex items-start gap-2 text-sm\">\n <CheckCircle className=\"h-4 w-4 text-status-success-text mt-0.5 flex-shrink-0\" />\n {req}\n </li>\n ))}\n </ul>\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Benefits</CardTitle>\n </CardHeader>\n <CardContent>\n <ul className=\"space-y-2\">\n {job.benefits.map((ben, idx) => (\n <li key={idx} className=\"flex items-start gap-2 text-sm\">\n <CheckCircle className=\"h-4 w-4 text-status-info-text mt-0.5 flex-shrink-0\" />\n {ben}\n </li>\n ))}\n </ul>\n </CardContent>\n </Card>\n </div>\n\n {jobCandidates.length > 0 && (\n <Card>\n <CardHeader>\n <CardTitle>Applicants for this Role</CardTitle>\n <CardDescription>{jobCandidates.length} candidates</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-5 gap-2 text-xs font-medium text-text-secondary border-b pb-2 mb-2\">\n <span>Name</span>\n <span>Source</span>\n <span className=\"text-right\">Experience</span>\n <span className=\"text-center\">Rating</span>\n <span className=\"text-center\">Status</span>\n </div>\n {jobCandidates.map((c) => (\n <div\n key={c.id}\n className=\"grid grid-cols-5 gap-2 py-2 border-b last:border-0 text-sm\"\n >\n <span className=\"font-medium\">\n {c.firstName} {c.lastName}\n </span>\n <span className=\"text-text-secondary\">{c.source}</span>\n <span className=\"text-right\">{c.experience} yrs</span>\n <div className=\"text-center\">{c.rating}/5</div>\n <div className=\"text-center\">\n <Badge\n variant={c.status === 'hired' ? 'default' : 'secondary'}\n className=\"text-[10px]\"\n >\n {c.status}\n </Badge>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n )}\n\n <FormModal\n open={editOpen}\n onOpenChange={setEditOpen}\n title=\"Edit Job Posting\"\n description=\"Update the role details, compensation, and status.\"\n fields={JOB_FIELDS}\n initialValues={editInitial}\n submitLabel=\"Save changes\"\n onSubmit={handleEditSubmit}\n />\n <ConfirmDialog\n open={deleteOpen}\n onOpenChange={setDeleteOpen}\n title=\"Delete job posting\"\n description={`Permanently remove “${job.title}”? This cannot be undone.`}\n confirmLabel=\"Delete\"\n destructive\n onConfirm={handleDelete}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HiringJobDetailsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HiringJobDetailsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { useState } from 'react';\nimport {\n Briefcase,\n Calendar,\n CheckCircle,\n DollarSign,\n MapPin,\n Pencil,\n Share2,\n Trash2,\n Users,\n} from 'lucide-react';\nimport { useNavigate, useSearchParams } from 'react-router-dom';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useCrewFoundryStore, type Candidate, type JobPosting } from '../store/crewfoundryStore';\nimport { FormModal, type FieldConfig, type FormValues } from '../components/forms/FormModal';\nimport { ConfirmDialog } from '../components/forms/ConfirmDialog';\nimport { getNumber, getTags, getText } from '../components/forms/formValues';\n\nconst JOB_FIELDS: FieldConfig[] = [\n { name: 'title', label: 'Job Title', type: 'text', required: true, colSpan: 2 },\n { name: 'department', label: 'Department', type: 'text', required: true },\n { name: 'location', label: 'Location', type: 'text', required: true },\n {\n name: 'type',\n label: 'Employment Type',\n type: 'select',\n options: [\n { label: 'Full time', value: 'full_time' },\n { label: 'Part time', value: 'part_time' },\n { label: 'Contract', value: 'contract' },\n { label: 'Remote', value: 'remote' },\n ],\n },\n {\n name: 'experienceLevel',\n label: 'Experience Level',\n type: 'select',\n options: [\n { label: 'Entry', value: 'entry' },\n { label: 'Mid', value: 'mid' },\n { label: 'Senior', value: 'senior' },\n { label: 'Lead', value: 'lead' },\n { label: 'Executive', value: 'executive' },\n ],\n },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n options: [\n { label: 'Draft', value: 'draft' },\n { label: 'Active', value: 'active' },\n { label: 'Paused', value: 'paused' },\n { label: 'Closed', value: 'closed' },\n { label: 'Filled', value: 'filled' },\n ],\n },\n { name: 'salaryMin', label: 'Salary Min ($)', type: 'number' },\n { name: 'salaryMax', label: 'Salary Max ($)', type: 'number' },\n { name: 'deadline', label: 'Application Deadline', type: 'date' },\n { name: 'description', label: 'Description', type: 'textarea', colSpan: 2 },\n { name: 'requirements', label: 'Requirements', type: 'tags' },\n { name: 'benefits', label: 'Benefits', type: 'tags' },\n];\n\nconst APPLICANT_COLUMNS: ResponsiveTableColumn<Candidate>[] = [\n {\n key: 'name',\n header: 'Name',\n priority: 'primary',\n cell: (c) => (\n <span className=\"font-medium\">\n {c.firstName} {c.lastName}\n </span>\n ),\n },\n {\n key: 'source',\n header: 'Source',\n priority: 'secondary',\n cell: (c) => <span className=\"text-text-secondary\">{c.source}</span>,\n },\n {\n key: 'experience',\n header: 'Experience',\n priority: 'secondary',\n cell: (c) => <span>{c.experience} yrs</span>,\n },\n {\n key: 'rating',\n header: 'Rating',\n priority: 'secondary',\n cell: (c) => <span>{c.rating}/5</span>,\n },\n {\n key: 'status',\n header: 'Status',\n priority: 'secondary',\n cell: (c) => (\n <Badge variant={c.status === 'hired' ? 'default' : 'secondary'} className=\"text-[10px]\">\n {c.status}\n </Badge>\n ),\n },\n];\n\nexport function HiringJobDetailsPagePage() {\n const navigate = useNavigate();\n const [searchParams] = useSearchParams();\n const { showToast } = useGlobalUi();\n const { jobPostings, candidates, updateJobPosting, removeJobPosting } = useCrewFoundryStore();\n const jobId = searchParams.get('id');\n const job = jobId ? jobPostings.find((j) => j.id === jobId) : jobPostings[0];\n const [editOpen, setEditOpen] = useState(false);\n const [deleteOpen, setDeleteOpen] = useState(false);\n\n if (!job) {\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No job posting found\"\n description=\"This job posting is no longer available.\"\n />\n </div>\n );\n }\n\n const jobCandidates = candidates.filter((c) => c.position === job.title);\n\n const editInitial: FormValues = {\n title: job.title,\n department: job.department,\n location: job.location,\n type: job.type,\n experienceLevel: job.experienceLevel,\n status: job.status,\n salaryMin: job.salaryMin,\n salaryMax: job.salaryMax,\n deadline: job.deadline,\n description: job.description,\n requirements: job.requirements,\n benefits: job.benefits,\n };\n\n const handleEditSubmit = async (values: FormValues) => {\n const updates: Partial<JobPosting> = {\n title: getText(values, 'title'),\n department: getText(values, 'department'),\n location: getText(values, 'location'),\n type: values.type as JobPosting['type'],\n experienceLevel: values.experienceLevel as JobPosting['experienceLevel'],\n status: values.status as JobPosting['status'],\n salaryMin: getNumber(values, 'salaryMin'),\n salaryMax: getNumber(values, 'salaryMax'),\n deadline: getText(values, 'deadline'),\n description: getText(values, 'description'),\n requirements: getTags(values, 'requirements'),\n benefits: getTags(values, 'benefits'),\n };\n await updateJobPosting(job.id, updates);\n showToast('Job posting updated', 'success');\n };\n\n const handleDelete = async () => {\n await removeJobPosting(job.id);\n showToast('Job posting deleted', 'success');\n navigate('../jobs-page');\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"flex items-center gap-2 mb-1\">\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{job.title}</GradientText>\n </h1>\n <Badge variant={job.status === 'active' ? 'default' : 'secondary'}>{job.status}</Badge>\n </div>\n <div className=\"flex items-center gap-4 text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Briefcase className=\"h-3 w-3\" />\n {job.department}\n </span>\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3 w-3\" />\n {job.location}\n </span>\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n Posted {job.postedDate}\n </span>\n </div>\n <PagePurpose className=\"mt-2\">\n Everything about this role in one place — review applicants, requirements, and\n compensation here to decide who to interview and keep the posting current.\n </PagePurpose>\n </div>\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => showToast('Sharing job postings is coming soon', 'info')}\n >\n <Share2 className=\"h-4 w-4 mr-1\" />\n Share\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setEditOpen(true)}>\n <Pencil className=\"h-4 w-4 mr-1\" />\n Edit Posting\n </Button>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n aria-label=\"Delete job posting\"\n onClick={() => setDeleteOpen(true)}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n <NextSteps\n storageKey=\"crewfoundry-job-details\"\n steps={[\n {\n id: 'applicants',\n label: 'Review applicants',\n description: 'Screen the candidates who applied for this role.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hiring/applications-page'),\n },\n {\n id: 'interviews',\n label: 'Schedule interviews',\n description: 'Set up conversations with promising candidates.',\n icon: <Calendar className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hiring/interviews-page'),\n },\n {\n id: 'candidates',\n label: 'Browse your talent pool',\n description: 'Source more candidates that fit this position.',\n icon: <Briefcase className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hiring/candidates-page'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"p-4 text-center\">\n <Users className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-2xl font-bold tabular-nums\">{job.applicants}</p>\n <p className=\"text-xs text-text-secondary\">Applicants</p>\n </CardContent>\n </GlassCard>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <DollarSign className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">\n ${(job.salaryMin / 1000).toFixed(0)}K-${(job.salaryMax / 1000).toFixed(0)}K\n </p>\n <p className=\"text-xs text-text-secondary\">Salary Range</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Calendar className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{job.deadline}</p>\n <p className=\"text-xs text-text-secondary\">Deadline</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <CheckCircle className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{job.experienceLevel}</p>\n <p className=\"text-xs text-text-secondary\">Level</p>\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Description</CardTitle>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-text-secondary\">{job.description}</p>\n </CardContent>\n </Card>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Requirements</CardTitle>\n </CardHeader>\n <CardContent>\n <ul className=\"space-y-2\">\n {job.requirements.map((req, idx) => (\n <li key={idx} className=\"flex items-start gap-2 text-sm\">\n <CheckCircle className=\"h-4 w-4 text-status-success-text mt-0.5 flex-shrink-0\" />\n {req}\n </li>\n ))}\n </ul>\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Benefits</CardTitle>\n </CardHeader>\n <CardContent>\n <ul className=\"space-y-2\">\n {job.benefits.map((ben, idx) => (\n <li key={idx} className=\"flex items-start gap-2 text-sm\">\n <CheckCircle className=\"h-4 w-4 text-status-info-text mt-0.5 flex-shrink-0\" />\n {ben}\n </li>\n ))}\n </ul>\n </CardContent>\n </Card>\n </div>\n\n {jobCandidates.length > 0 && (\n <Card>\n <CardHeader>\n <CardTitle>Applicants for this Role</CardTitle>\n <CardDescription>{jobCandidates.length} candidates</CardDescription>\n </CardHeader>\n <CardContent>\n <ResponsiveTable\n data={jobCandidates}\n rowKey={(c) => c.id}\n columns={APPLICANT_COLUMNS}\n />\n </CardContent>\n </Card>\n )}\n\n <FormModal\n open={editOpen}\n onOpenChange={setEditOpen}\n title=\"Edit Job Posting\"\n description=\"Update the role details, compensation, and status.\"\n fields={JOB_FIELDS}\n initialValues={editInitial}\n submitLabel=\"Save changes\"\n onSubmit={handleEditSubmit}\n />\n <ConfirmDialog\n open={deleteOpen}\n onOpenChange={setDeleteOpen}\n title=\"Delete job posting\"\n description={`Permanently remove “${job.title}”? This cannot be undone.`}\n confirmLabel=\"Delete\"\n destructive\n onConfirm={handleDelete}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -3,14 +3,15 @@ import { useState as t } from "react";
|
|
|
3
3
|
import { Briefcase as n, MapPin as r, Plus as i, Search as a, Users as o } from "lucide-react";
|
|
4
4
|
import { useNavigate as s } from "react-router-dom";
|
|
5
5
|
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
6
|
-
import { Badge as u, Button as d, CardContent as f, CardDescription as p, CardHeader as m, CardTitle as h, GlassCard as g, GradientText as _, IllustratedEmptyState as v, Input as y, PagePurpose as b } from "@burdenoff/fe-libs/ui";
|
|
7
|
-
import {
|
|
6
|
+
import { Badge as u, Button as d, CardContent as f, CardDescription as p, CardHeader as m, CardTitle as h, GlassCard as g, GradientText as _, IllustratedEmptyState as v, Input as y, PagePurpose as b, Pagination as x } from "@burdenoff/fe-libs/ui";
|
|
7
|
+
import { usePagination as S } from "@burdenoff/fe-libs/shared/hooks";
|
|
8
|
+
import { useI18n as C } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
8
9
|
//#region src/crewfoundry/pages/HiringJobsPagePage.tsx
|
|
9
|
-
function
|
|
10
|
-
let { t:
|
|
11
|
-
let n =
|
|
10
|
+
function w() {
|
|
11
|
+
let { t: w } = C(), T = s(), { jobPostings: E } = e(), [D, O] = t(""), { page: k, pageSize: A, offset: j, setPage: M } = S({ initialPageSize: 12 }), N = (e, t) => {
|
|
12
|
+
let n = w(e);
|
|
12
13
|
return n === e ? t : n;
|
|
13
|
-
},
|
|
14
|
+
}, P = E.filter((e) => `${e.title} ${e.department} ${e.location}`.toLowerCase().includes(D.toLowerCase())), F = P.slice(j, j + A), I = (e) => T(`../job-details-page?id=${encodeURIComponent(e)}`), L = E.filter((e) => e.status === "active").length, R = E.reduce((e, t) => e + t.applicants, 0);
|
|
14
15
|
return /* @__PURE__ */ l("div", {
|
|
15
16
|
className: "space-y-6 p-6",
|
|
16
17
|
children: [
|
|
@@ -19,19 +20,19 @@ function S() {
|
|
|
19
20
|
children: [/* @__PURE__ */ l("div", { children: [
|
|
20
21
|
/* @__PURE__ */ c("h1", {
|
|
21
22
|
className: "text-2xl font-semibold",
|
|
22
|
-
children: /* @__PURE__ */ c(_, { children:
|
|
23
|
+
children: /* @__PURE__ */ c(_, { children: N("crewfoundry.hiringJobs.title", "Job Postings") })
|
|
23
24
|
}),
|
|
24
25
|
/* @__PURE__ */ l("p", {
|
|
25
26
|
className: "text-sm text-text-secondary",
|
|
26
27
|
children: [
|
|
27
|
-
|
|
28
|
+
L,
|
|
28
29
|
" ",
|
|
29
|
-
|
|
30
|
+
N("crewfoundry.hiringJobs.summary.activePositions", "active positions"),
|
|
30
31
|
" ·",
|
|
31
32
|
" ",
|
|
32
|
-
|
|
33
|
+
R,
|
|
33
34
|
" ",
|
|
34
|
-
|
|
35
|
+
N("crewfoundry.hiringJobs.summary.totalApplicants", "total applicants")
|
|
35
36
|
]
|
|
36
37
|
}),
|
|
37
38
|
/* @__PURE__ */ c(b, {
|
|
@@ -40,29 +41,39 @@ function S() {
|
|
|
40
41
|
})
|
|
41
42
|
] }), /* @__PURE__ */ l(d, {
|
|
42
43
|
size: "sm",
|
|
43
|
-
onClick: () =>
|
|
44
|
-
children: [/* @__PURE__ */ c(i, { className: "h-4 w-4 mr-1" }),
|
|
44
|
+
onClick: () => T("../create-job-page"),
|
|
45
|
+
children: [/* @__PURE__ */ c(i, { className: "h-4 w-4 mr-1" }), N("crewfoundry.hiringJobs.actions.postNewJob", "Post New Job")]
|
|
45
46
|
})]
|
|
46
47
|
}),
|
|
47
48
|
/* @__PURE__ */ l("div", {
|
|
48
49
|
className: "relative max-w-sm",
|
|
49
50
|
children: [/* @__PURE__ */ c(a, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ c(y, {
|
|
50
|
-
placeholder:
|
|
51
|
+
placeholder: N("crewfoundry.hiringJobs.searchPlaceholder", "Search positions..."),
|
|
51
52
|
className: "pl-9",
|
|
52
|
-
value:
|
|
53
|
-
onChange: (e) =>
|
|
53
|
+
value: D,
|
|
54
|
+
onChange: (e) => {
|
|
55
|
+
O(e.target.value), M(1);
|
|
56
|
+
}
|
|
54
57
|
})]
|
|
55
58
|
}),
|
|
56
|
-
|
|
59
|
+
P.length === 0 && /* @__PURE__ */ c(v, {
|
|
57
60
|
illustration: "empty-search",
|
|
58
61
|
title: "No job postings found",
|
|
59
62
|
description: "Try adjusting your search, or create a new job posting."
|
|
60
63
|
}),
|
|
61
64
|
/* @__PURE__ */ c("div", {
|
|
62
65
|
className: "grid gap-4 md:grid-cols-2",
|
|
63
|
-
children:
|
|
66
|
+
children: F.map((e, t) => /* @__PURE__ */ l(g, {
|
|
64
67
|
treatment: t === 0 ? "glass" : "plain",
|
|
65
68
|
glow: t === 0,
|
|
69
|
+
role: "button",
|
|
70
|
+
tabIndex: 0,
|
|
71
|
+
"aria-label": `View ${e.title}`,
|
|
72
|
+
className: "cursor-pointer transition-shadow hover:shadow-elevation-2 focus-visible:outline-none focus-visible:shadow-[var(--shadow-focus)]",
|
|
73
|
+
onClick: () => I(e.id),
|
|
74
|
+
onKeyDown: (t) => {
|
|
75
|
+
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), I(e.id));
|
|
76
|
+
},
|
|
66
77
|
children: [/* @__PURE__ */ l(m, { children: [/* @__PURE__ */ l("div", {
|
|
67
78
|
className: "flex items-center justify-between",
|
|
68
79
|
children: [/* @__PURE__ */ c(h, {
|
|
@@ -89,7 +100,7 @@ function S() {
|
|
|
89
100
|
/* @__PURE__ */ c(o, { className: "h-3 w-3" }),
|
|
90
101
|
e.applicants,
|
|
91
102
|
" ",
|
|
92
|
-
|
|
103
|
+
N("crewfoundry.hiringJobs.card.applicants", "applicants")
|
|
93
104
|
]
|
|
94
105
|
}),
|
|
95
106
|
/* @__PURE__ */ l("div", {
|
|
@@ -117,17 +128,23 @@ function S() {
|
|
|
117
128
|
children: e.experienceLevel
|
|
118
129
|
})]
|
|
119
130
|
}), /* @__PURE__ */ l("span", { children: [
|
|
120
|
-
|
|
131
|
+
N("crewfoundry.hiringJobs.card.deadline", "Deadline"),
|
|
121
132
|
": ",
|
|
122
133
|
e.deadline
|
|
123
134
|
] })]
|
|
124
135
|
})] })]
|
|
125
136
|
}, e.id))
|
|
137
|
+
}),
|
|
138
|
+
P.length > A && /* @__PURE__ */ c(x, {
|
|
139
|
+
page: k,
|
|
140
|
+
pageSize: A,
|
|
141
|
+
totalItems: P.length,
|
|
142
|
+
onPageChange: M
|
|
126
143
|
})
|
|
127
144
|
]
|
|
128
145
|
});
|
|
129
146
|
}
|
|
130
147
|
//#endregion
|
|
131
|
-
export {
|
|
148
|
+
export { w as HiringJobsPagePage };
|
|
132
149
|
|
|
133
150
|
//# sourceMappingURL=HiringJobsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HiringJobsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HiringJobsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Badge,\n Button,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Briefcase, MapPin, Plus, Search, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function HiringJobsPagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { jobPostings } = useCrewFoundryStore();\n const [search, setSearch] = useState('');\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n\n const filtered = jobPostings.filter((j) =>\n `${j.title} ${j.department} ${j.location}`.toLowerCase().includes(search.toLowerCase())\n );\n const activeJobs = jobPostings.filter((j) => j.status === 'active').length;\n const totalApplicants = jobPostings.reduce((s, j) => s + j.applicants, 0);\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\">\n <GradientText>{t('crewfoundry.hiringJobs.title', 'Job Postings')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {activeJobs} {t('crewfoundry.hiringJobs.summary.activePositions', 'active positions')} ·{' '}\n {totalApplicants}{' '}\n {t('crewfoundry.hiringJobs.summary.totalApplicants', 'total applicants')}\n </p>\n <PagePurpose className=\"mt-1\">All your open and past job postings in one place — use it to monitor applicant volume and manage what roles you're actively hiring for.</PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => navigate('../create-job-page')}>\n <Plus className=\"h-4 w-4 mr-1\" />\n {t('crewfoundry.hiringJobs.actions.postNewJob', 'Post New Job')}\n </Button>\n </div>\n\n <div className=\"relative max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder={t('crewfoundry.hiringJobs.searchPlaceholder', 'Search positions...')}\n className=\"pl-9\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n\n {filtered.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No job postings found\"\n description=\"Try adjusting your search, or create a new job posting.\"\n />\n )}\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n {
|
|
1
|
+
{"version":3,"file":"HiringJobsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HiringJobsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Badge,\n Button,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { Briefcase, MapPin, Plus, Search, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function HiringJobsPagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { jobPostings } = useCrewFoundryStore();\n const [search, setSearch] = useState('');\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 12 });\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n\n const filtered = jobPostings.filter((j) =>\n `${j.title} ${j.department} ${j.location}`.toLowerCase().includes(search.toLowerCase())\n );\n const paged = filtered.slice(offset, offset + pageSize);\n const openJob = (id: string) => navigate(`../job-details-page?id=${encodeURIComponent(id)}`);\n const activeJobs = jobPostings.filter((j) => j.status === 'active').length;\n const totalApplicants = jobPostings.reduce((s, j) => s + j.applicants, 0);\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\">\n <GradientText>{t('crewfoundry.hiringJobs.title', 'Job Postings')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {activeJobs} {t('crewfoundry.hiringJobs.summary.activePositions', 'active positions')} ·{' '}\n {totalApplicants}{' '}\n {t('crewfoundry.hiringJobs.summary.totalApplicants', 'total applicants')}\n </p>\n <PagePurpose className=\"mt-1\">All your open and past job postings in one place — use it to monitor applicant volume and manage what roles you're actively hiring for.</PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => navigate('../create-job-page')}>\n <Plus className=\"h-4 w-4 mr-1\" />\n {t('crewfoundry.hiringJobs.actions.postNewJob', 'Post New Job')}\n </Button>\n </div>\n\n <div className=\"relative max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder={t('crewfoundry.hiringJobs.searchPlaceholder', 'Search positions...')}\n className=\"pl-9\"\n value={search}\n onChange={(e) => {\n setSearch(e.target.value);\n setPage(1);\n }}\n />\n </div>\n\n {filtered.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No job postings found\"\n description=\"Try adjusting your search, or create a new job posting.\"\n />\n )}\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n {paged.map((job, _idx) => (\n <GlassCard\n key={job.id}\n treatment={_idx === 0 ? 'glass' : 'plain'}\n glow={_idx === 0}\n role=\"button\"\n tabIndex={0}\n aria-label={`View ${job.title}`}\n className=\"cursor-pointer transition-shadow hover:shadow-elevation-2 focus-visible:outline-none focus-visible:shadow-[var(--shadow-focus)]\"\n onClick={() => openJob(job.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n openJob(job.id);\n }\n }}\n >\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-lg\">{job.title}</CardTitle>\n <Badge\n variant={\n job.status === 'active'\n ? 'default'\n : job.status === 'paused'\n ? 'secondary'\n : 'outline'\n }\n >\n {job.status}\n </Badge>\n </div>\n <CardDescription>{job.description}</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 gap-3 mb-3\">\n <div className=\"flex items-center gap-1 text-sm text-text-secondary\">\n <Briefcase className=\"h-3 w-3\" />\n {job.department}\n </div>\n <div className=\"flex items-center gap-1 text-sm text-text-secondary\">\n <MapPin className=\"h-3 w-3\" />\n {job.location}\n </div>\n <div className=\"flex items-center gap-1 text-sm text-text-secondary\">\n <Users className=\"h-3 w-3\" />\n {job.applicants} {t('crewfoundry.hiringJobs.card.applicants', 'applicants')}\n </div>\n <div className=\"text-sm text-text-secondary\">\n ${(job.salaryMin / 1000).toFixed(0)}K — ${(job.salaryMax / 1000).toFixed(0)}K\n </div>\n </div>\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <div className=\"flex gap-1\">\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {job.type.replace('_', ' ')}\n </Badge>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {job.experienceLevel}\n </Badge>\n </div>\n <span>\n {t('crewfoundry.hiringJobs.card.deadline', 'Deadline')}: {job.deadline}\n </span>\n </div>\n </CardContent>\n </GlassCard>\n ))}\n </div>\n\n {filtered.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={filtered.length}\n onPageChange={setPage}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -219,9 +219,9 @@ function A() {
|
|
|
219
219
|
}), /* @__PURE__ */ g("span", {
|
|
220
220
|
className: "text-text-secondary",
|
|
221
221
|
children: [
|
|
222
|
-
"Cost/Head:
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
"Cost/Head:",
|
|
223
|
+
" ",
|
|
224
|
+
e.employeeCount > 0 ? `$${Math.round(e.budget / e.employeeCount / 1e3)}K` : "—"
|
|
225
225
|
]
|
|
226
226
|
})]
|
|
227
227
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HrDepartmentsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HrDepartmentsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n PagePurpose,\n Separator,\n} from '@burdenoff/fe-libs/ui';\nimport { Building2, DollarSign, MapPin, Pencil, Plus, Trash2, Users } from 'lucide-react';\nimport { useCrewFoundryStore, type Department } from '../store/crewfoundryStore';\nimport { FormModal, useFormModal, type FieldConfig, type FormValues } from '../components/forms/FormModal';\nimport { ConfirmDialog } from '../components/forms/ConfirmDialog';\nimport { getNumber, getText, newClientId } from '../components/forms/formValues';\n\nconst DEPARTMENT_FIELDS: FieldConfig[] = [\n { name: 'name', label: 'Department name', type: 'text', required: true, colSpan: 2 },\n { name: 'headName', label: 'Department head', type: 'text', required: true },\n { name: 'location', label: 'Location', type: 'text', required: true },\n { name: 'budget', label: 'Annual budget', type: 'number', required: true },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n required: true,\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Restructuring', value: 'restructuring' },\n ],\n },\n];\n\nconst toFormValues = (department: Department): FormValues => ({\n name: department.name,\n headName: department.headName,\n location: department.location,\n budget: department.budget,\n status: department.status,\n});\n\nexport function HrDepartmentsPagePage() {\n const { departments, employees, addDepartment, updateDepartment, removeDepartment } =\n useCrewFoundryStore();\n const form = useFormModal<Department>();\n const [deleting, setDeleting] = useState<Department | null>(null);\n\n const totalBudget = departments.reduce((s, d) => s + d.budget, 0);\n const totalHeadcount = departments.reduce((s, d) => s + d.employeeCount, 0);\n\n const editing = form.context;\n\n const handleSubmit = async (values: FormValues) => {\n const payload: Department = {\n id: editing?.id ?? newClientId(),\n name: getText(values, 'name'),\n headId: editing?.headId ?? '',\n headName: getText(values, 'headName'),\n employeeCount: editing?.employeeCount ?? 0,\n budget: getNumber(values, 'budget'),\n location: getText(values, 'location'),\n status: getText(values, 'status') as Department['status'],\n };\n if (editing) {\n await updateDepartment(editing.id, payload);\n } else {\n await addDepartment(payload);\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\">\n <GradientText>Departments</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Organizational structure and department management\n </p>\n <PagePurpose className=\"mt-1\">Organize your company into departments — set up structure, assign heads, and see how headcount is distributed across the org.</PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => form.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add Department\n </Button>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\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\">Total Departments</CardTitle>\n <Building2 className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{departments.length}</div>\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\">Total Headcount</CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{totalHeadcount}</div>\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\">Total Budget</CardTitle>\n <DollarSign className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n ${(totalBudget / 1000000).toFixed(1)}M\n </div>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n {departments.map((dept) => {\n const deptEmps = employees.filter((e) => e.department === dept.name);\n const avgSalary =\n deptEmps.length > 0\n ? Math.round(deptEmps.reduce((s, e) => s + e.salary, 0) / deptEmps.length)\n : 0;\n const avgPerf =\n deptEmps.length > 0\n ? (deptEmps.reduce((s, e) => s + e.performanceScore, 0) / deptEmps.length).toFixed(1)\n : '0';\n\n return (\n <Card key={dept.id}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-lg\">{dept.name}</CardTitle>\n <div className=\"flex items-center gap-1\">\n <Badge variant={dept.status === 'active' ? 'default' : 'secondary'}>\n {dept.status}\n </Badge>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Edit ${dept.name}`}\n onClick={() => form.openModal(dept)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Delete ${dept.name}`}\n onClick={() => setDeleting(dept)}\n >\n <Trash2 className=\"h-4 w-4 text-status-error-text\" />\n </Button>\n </div>\n </div>\n <CardDescription className=\"flex items-center gap-1\">\n <MapPin className=\"h-3 w-3\" />\n {dept.location}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 gap-4 mb-4\">\n <div>\n <p className=\"text-xs text-text-secondary\">Department Head</p>\n <p className=\"text-sm font-medium\">{dept.headName}</p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Headcount</p>\n <p className=\"text-sm font-medium\">{dept.employeeCount} employees</p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Annual Budget</p>\n <p className=\"text-sm font-medium\">${(dept.budget / 1000000).toFixed(1)}M</p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Avg Salary</p>\n <p className=\"text-sm font-medium\">${avgSalary.toLocaleString()}</p>\n </div>\n </div>\n <Separator className=\"mb-3\" />\n <div className=\"flex items-center justify-between text-xs\">\n <span className=\"text-text-secondary\">Avg Performance: {avgPerf}/5</span>\n <span className=\"text-text-secondary\">\n Cost/Head: ${Math.round(dept.budget / dept.employeeCount / 1000)}K\n </span>\n </div>\n </CardContent>\n </Card>\n );\n })}\n </div>\n\n <FormModal\n open={form.open}\n onOpenChange={form.onOpenChange}\n title={editing ? 'Edit department' : 'Add department'}\n description={\n editing\n ? 'Update this department’s details.'\n : 'Create a new department in your organization.'\n }\n fields={DEPARTMENT_FIELDS}\n initialValues={editing ? toFormValues(editing) : undefined}\n submitLabel={editing ? 'Save changes' : 'Add department'}\n onSubmit={handleSubmit}\n />\n\n <ConfirmDialog\n open={deleting !== null}\n onOpenChange={(open) => {\n if (!open) {\n setDeleting(null);\n }\n }}\n title=\"Delete department?\"\n description={\n deleting\n ? `${deleting.name} will be removed. This cannot be undone.`\n : undefined\n }\n confirmLabel=\"Delete\"\n destructive\n onConfirm={async () => {\n if (deleting) {\n await removeDepartment(deleting.id);\n setDeleting(null);\n }\n }}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HrDepartmentsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HrDepartmentsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n PagePurpose,\n Separator,\n} from '@burdenoff/fe-libs/ui';\nimport { Building2, DollarSign, MapPin, Pencil, Plus, Trash2, Users } from 'lucide-react';\nimport { useCrewFoundryStore, type Department } from '../store/crewfoundryStore';\nimport { FormModal, useFormModal, type FieldConfig, type FormValues } from '../components/forms/FormModal';\nimport { ConfirmDialog } from '../components/forms/ConfirmDialog';\nimport { getNumber, getText, newClientId } from '../components/forms/formValues';\n\nconst DEPARTMENT_FIELDS: FieldConfig[] = [\n { name: 'name', label: 'Department name', type: 'text', required: true, colSpan: 2 },\n { name: 'headName', label: 'Department head', type: 'text', required: true },\n { name: 'location', label: 'Location', type: 'text', required: true },\n { name: 'budget', label: 'Annual budget', type: 'number', required: true },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n required: true,\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Restructuring', value: 'restructuring' },\n ],\n },\n];\n\nconst toFormValues = (department: Department): FormValues => ({\n name: department.name,\n headName: department.headName,\n location: department.location,\n budget: department.budget,\n status: department.status,\n});\n\nexport function HrDepartmentsPagePage() {\n const { departments, employees, addDepartment, updateDepartment, removeDepartment } =\n useCrewFoundryStore();\n const form = useFormModal<Department>();\n const [deleting, setDeleting] = useState<Department | null>(null);\n\n const totalBudget = departments.reduce((s, d) => s + d.budget, 0);\n const totalHeadcount = departments.reduce((s, d) => s + d.employeeCount, 0);\n\n const editing = form.context;\n\n const handleSubmit = async (values: FormValues) => {\n const payload: Department = {\n id: editing?.id ?? newClientId(),\n name: getText(values, 'name'),\n headId: editing?.headId ?? '',\n headName: getText(values, 'headName'),\n employeeCount: editing?.employeeCount ?? 0,\n budget: getNumber(values, 'budget'),\n location: getText(values, 'location'),\n status: getText(values, 'status') as Department['status'],\n };\n if (editing) {\n await updateDepartment(editing.id, payload);\n } else {\n await addDepartment(payload);\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\">\n <GradientText>Departments</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Organizational structure and department management\n </p>\n <PagePurpose className=\"mt-1\">Organize your company into departments — set up structure, assign heads, and see how headcount is distributed across the org.</PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => form.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add Department\n </Button>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\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\">Total Departments</CardTitle>\n <Building2 className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{departments.length}</div>\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\">Total Headcount</CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{totalHeadcount}</div>\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\">Total Budget</CardTitle>\n <DollarSign className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n ${(totalBudget / 1000000).toFixed(1)}M\n </div>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n {departments.map((dept) => {\n const deptEmps = employees.filter((e) => e.department === dept.name);\n const avgSalary =\n deptEmps.length > 0\n ? Math.round(deptEmps.reduce((s, e) => s + e.salary, 0) / deptEmps.length)\n : 0;\n const avgPerf =\n deptEmps.length > 0\n ? (deptEmps.reduce((s, e) => s + e.performanceScore, 0) / deptEmps.length).toFixed(1)\n : '0';\n\n return (\n <Card key={dept.id}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-lg\">{dept.name}</CardTitle>\n <div className=\"flex items-center gap-1\">\n <Badge variant={dept.status === 'active' ? 'default' : 'secondary'}>\n {dept.status}\n </Badge>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Edit ${dept.name}`}\n onClick={() => form.openModal(dept)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Delete ${dept.name}`}\n onClick={() => setDeleting(dept)}\n >\n <Trash2 className=\"h-4 w-4 text-status-error-text\" />\n </Button>\n </div>\n </div>\n <CardDescription className=\"flex items-center gap-1\">\n <MapPin className=\"h-3 w-3\" />\n {dept.location}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 gap-4 mb-4\">\n <div>\n <p className=\"text-xs text-text-secondary\">Department Head</p>\n <p className=\"text-sm font-medium\">{dept.headName}</p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Headcount</p>\n <p className=\"text-sm font-medium\">{dept.employeeCount} employees</p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Annual Budget</p>\n <p className=\"text-sm font-medium\">${(dept.budget / 1000000).toFixed(1)}M</p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Avg Salary</p>\n <p className=\"text-sm font-medium\">${avgSalary.toLocaleString()}</p>\n </div>\n </div>\n <Separator className=\"mb-3\" />\n <div className=\"flex items-center justify-between text-xs\">\n <span className=\"text-text-secondary\">Avg Performance: {avgPerf}/5</span>\n <span className=\"text-text-secondary\">\n Cost/Head:{' '}\n {dept.employeeCount > 0\n ? `$${Math.round(dept.budget / dept.employeeCount / 1000)}K`\n : '—'}\n </span>\n </div>\n </CardContent>\n </Card>\n );\n })}\n </div>\n\n <FormModal\n open={form.open}\n onOpenChange={form.onOpenChange}\n title={editing ? 'Edit department' : 'Add department'}\n description={\n editing\n ? 'Update this department’s details.'\n : 'Create a new department in your organization.'\n }\n fields={DEPARTMENT_FIELDS}\n initialValues={editing ? toFormValues(editing) : undefined}\n submitLabel={editing ? 'Save changes' : 'Add department'}\n onSubmit={handleSubmit}\n />\n\n <ConfirmDialog\n open={deleting !== null}\n onOpenChange={(open) => {\n if (!open) {\n setDeleting(null);\n }\n }}\n title=\"Delete department?\"\n description={\n deleting\n ? `${deleting.name} will be removed. This cannot be undone.`\n : undefined\n }\n confirmLabel=\"Delete\"\n destructive\n onConfirm={async () => {\n if (deleting) {\n await removeDepartment(deleting.id);\n setDeleting(null);\n }\n }}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|