@burdenoff/microfe-crewfoundry 2026.1013.2 → 2026.1029.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/crewfoundry/CrewFoundryRoot.d.ts.map +1 -1
- package/dist/crewfoundry/CrewFoundryRoot.js +160 -256
- package/dist/crewfoundry/CrewFoundryRoot.js.map +1 -1
- package/dist/crewfoundry/CrewFoundryRoutes.d.ts.map +1 -1
- package/dist/crewfoundry/CrewFoundryRoutes.js +152 -192
- package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
- package/dist/crewfoundry/components/InlineError.d.ts +5 -0
- package/dist/crewfoundry/components/InlineError.d.ts.map +1 -0
- package/dist/crewfoundry/components/InlineError.js +17 -0
- package/dist/crewfoundry/components/InlineError.js.map +1 -0
- package/dist/crewfoundry/components/marketplace/BookServiceModal.d.ts +14 -0
- package/dist/crewfoundry/components/marketplace/BookServiceModal.d.ts.map +1 -0
- package/dist/crewfoundry/components/marketplace/BookServiceModal.js +75 -0
- package/dist/crewfoundry/components/marketplace/BookServiceModal.js.map +1 -0
- package/dist/crewfoundry/components/marketplace/MarketplaceTabs.d.ts +24 -0
- package/dist/crewfoundry/components/marketplace/MarketplaceTabs.d.ts.map +1 -0
- package/dist/crewfoundry/components/marketplace/MarketplaceTabs.js +47 -0
- package/dist/crewfoundry/components/marketplace/MarketplaceTabs.js.map +1 -0
- package/dist/crewfoundry/components/marketplace/ServiceListingModal.d.ts +12 -0
- package/dist/crewfoundry/components/marketplace/ServiceListingModal.d.ts.map +1 -0
- package/dist/crewfoundry/components/marketplace/ServiceListingModal.js +123 -0
- package/dist/crewfoundry/components/marketplace/ServiceListingModal.js.map +1 -0
- package/dist/crewfoundry/components/viz/CertificateCard.js +4 -118
- package/dist/crewfoundry/components/viz/PathSteps.js +3 -68
- package/dist/crewfoundry/components/viz/lib/geometry.js +5 -13
- package/dist/crewfoundry/components/viz/lib/geometry.js.map +1 -1
- package/dist/crewfoundry/lib/analytics.d.ts +1 -6
- package/dist/crewfoundry/lib/analytics.d.ts.map +1 -1
- package/dist/crewfoundry/lib/analytics.js +3 -18
- package/dist/crewfoundry/lib/analytics.js.map +1 -1
- package/dist/crewfoundry/lib/companyFinance.d.ts +3 -7
- package/dist/crewfoundry/lib/companyFinance.d.ts.map +1 -1
- package/dist/crewfoundry/lib/companyFinance.js +3 -8
- package/dist/crewfoundry/lib/companyFinance.js.map +1 -1
- package/dist/crewfoundry/lib/learning.d.ts +12 -0
- package/dist/crewfoundry/lib/learning.d.ts.map +1 -0
- package/dist/crewfoundry/lib/learning.js +26 -0
- package/dist/crewfoundry/lib/learning.js.map +1 -0
- package/dist/crewfoundry/lib/marketplace.d.ts +30 -0
- package/dist/crewfoundry/lib/marketplace.d.ts.map +1 -0
- package/dist/crewfoundry/lib/marketplace.js +91 -0
- package/dist/crewfoundry/lib/marketplace.js.map +1 -0
- package/dist/crewfoundry/lib/useEnsureLoaded.d.ts +7 -0
- package/dist/crewfoundry/lib/useEnsureLoaded.d.ts.map +1 -0
- package/dist/crewfoundry/lib/useEnsureLoaded.js +25 -0
- package/dist/crewfoundry/lib/useEnsureLoaded.js.map +1 -0
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +12 -25
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +145 -157
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +14 -14
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +14 -14
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js +71 -33
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +247 -173
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.d.ts +12 -0
- package/dist/crewfoundry/pages/LearningCoursesPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +307 -293
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningEnrollmentsPagePage.d.ts +2 -0
- package/dist/crewfoundry/pages/LearningEnrollmentsPagePage.d.ts.map +1 -0
- package/dist/crewfoundry/pages/LearningEnrollmentsPagePage.js +223 -0
- package/dist/crewfoundry/pages/LearningEnrollmentsPagePage.js.map +1 -0
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.d.ts +4 -0
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js +115 -160
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js +165 -75
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceEscrowPagePage.d.ts +7 -0
- package/dist/crewfoundry/pages/MarketplaceEscrowPagePage.d.ts.map +1 -0
- package/dist/crewfoundry/pages/MarketplaceEscrowPagePage.js +175 -0
- package/dist/crewfoundry/pages/MarketplaceEscrowPagePage.js.map +1 -0
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +182 -223
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js +168 -227
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +127 -290
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.d.ts +138 -78
- package/dist/crewfoundry/store/crewfoundryStore.d.ts.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +338 -244
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/dist/crewfoundry/utils/dateUtils.d.ts +5 -0
- package/dist/crewfoundry/utils/dateUtils.d.ts.map +1 -1
- package/dist/crewfoundry/utils/dateUtils.js +10 -1
- package/dist/crewfoundry/utils/dateUtils.js.map +1 -1
- package/dist/generated/global-types.d.ts +5145 -1627
- package/dist/generated/global-types.d.ts.map +1 -1
- package/dist/generated/wspace-types.d.ts +100373 -34602
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/dist/utils/pageContext.d.ts.map +1 -1
- package/dist/utils/pageContext.js +0 -1
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +1 -1
- package/dist/crewfoundry/components/viz/CertificateCard.js.map +0 -1
- package/dist/crewfoundry/components/viz/PathSteps.js.map +0 -1
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js +0 -53
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +0 -107
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js +0 -62
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js +0 -37
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +0 -111
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +0 -309
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/LearningLearningPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.js +0 -200
- package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +0 -190
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +0 -230
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +0 -293
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js +0 -163
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.d.ts +0 -2
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js +0 -365
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +0 -224
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +0 -180
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js +0 -38
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +0 -204
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js +0 -55
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +0 -335
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js +0 -160
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js +0 -80
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js.map +0 -1
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.d.ts +0 -2
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.d.ts.map +0 -1
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js +0 -191
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js.map +0 -1
- package/dist/crewfoundry/utils/courseProgress.d.ts +0 -33
- package/dist/crewfoundry/utils/courseProgress.d.ts.map +0 -1
- package/dist/crewfoundry/utils/courseProgress.js +0 -46
- package/dist/crewfoundry/utils/courseProgress.js.map +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/crewfoundry/lib/learning.ts
|
|
2
|
+
var e = {
|
|
3
|
+
not_started: "Not started",
|
|
4
|
+
in_progress: "In progress",
|
|
5
|
+
completed: "Completed"
|
|
6
|
+
}, t = Object.keys(e).map((t) => ({
|
|
7
|
+
value: t,
|
|
8
|
+
label: e[t]
|
|
9
|
+
}));
|
|
10
|
+
function n(e) {
|
|
11
|
+
if (!e || e <= 0) return "Self-paced";
|
|
12
|
+
let t = Math.floor(e / 60), n = e % 60;
|
|
13
|
+
return t === 0 ? `${n} min` : n === 0 ? `${t} h` : `${t} h ${n} min`;
|
|
14
|
+
}
|
|
15
|
+
function r(e) {
|
|
16
|
+
try {
|
|
17
|
+
let t = new URL(e);
|
|
18
|
+
return t.protocol === "https:" || t.protocol === "http:";
|
|
19
|
+
} catch {
|
|
20
|
+
return !1;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { e as ENROLLMENT_STATUS_LABEL, t as ENROLLMENT_STATUS_OPTIONS, n as formatDuration, r as isSafeContentUrl };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=learning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learning.js","names":[],"sources":["../../../src/crewfoundry/lib/learning.ts"],"sourcesContent":["/**\n * Pure helpers for the Learning & Development pages (BOFF-3401).\n */\nimport type { CrewEnrollmentStatus } from '../store/crewfoundryStore';\n\nexport const ENROLLMENT_STATUS_LABEL: Record<CrewEnrollmentStatus, string> = {\n not_started: 'Not started',\n in_progress: 'In progress',\n completed: 'Completed',\n};\n\nexport const ENROLLMENT_STATUS_OPTIONS = (\n Object.keys(ENROLLMENT_STATUS_LABEL) as CrewEnrollmentStatus[]\n).map((value) => ({ value, label: ENROLLMENT_STATUS_LABEL[value] }));\n\n/** \"45 min\", \"2 h\", \"1 h 30 min\"; \"Self-paced\" when no duration is recorded. */\nexport function formatDuration(minutes: number | null | undefined): string {\n if (!minutes || minutes <= 0) return 'Self-paced';\n const hours = Math.floor(minutes / 60);\n const rest = minutes % 60;\n if (hours === 0) return `${rest} min`;\n return rest === 0 ? `${hours} h` : `${hours} h ${rest} min`;\n}\n\n/** Only http(s) links are accepted as course content (no javascript:/data: URLs). */\nexport function isSafeContentUrl(value: string): boolean {\n try {\n const url = new URL(value);\n return url.protocol === 'https:' || url.protocol === 'http:';\n } catch {\n return false;\n }\n}\n"],"mappings":";AAKA,IAAa,IAAgE;CAC3E,aAAa;CACb,aAAa;CACb,WAAW;CACZ,EAEY,IACX,OAAO,KAAK,EAAwB,CACpC,KAAK,OAAW;CAAE;CAAO,OAAO,EAAwB;CAAQ,EAAE;AAGpE,SAAgB,EAAe,GAA4C;AACzE,KAAI,CAAC,KAAW,KAAW,EAAG,QAAO;CACrC,IAAM,IAAQ,KAAK,MAAM,IAAU,GAAG,EAChC,IAAO,IAAU;AAEvB,QADI,MAAU,IAAU,GAAG,EAAK,QACzB,MAAS,IAAI,GAAG,EAAM,MAAM,GAAG,EAAM,KAAK,EAAK;;AAIxD,SAAgB,EAAiB,GAAwB;AACvD,KAAI;EACF,IAAM,IAAM,IAAI,IAAI,EAAM;AAC1B,SAAO,EAAI,aAAa,YAAY,EAAI,aAAa;SAC/C;AACN,SAAO"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CrewBooking, CrewBookingStatus, CrewEscrowStatus, CrewServiceListing } from '../store/crewfoundryStore';
|
|
2
|
+
|
|
3
|
+
export type BookingRole = 'provider' | 'client';
|
|
4
|
+
/** Roles the actor holds on a booking (both when they booked their own service). */
|
|
5
|
+
export declare function bookingRoles(booking: CrewBooking, actorId: string | undefined): BookingRole[];
|
|
6
|
+
/** Next statuses this actor may move the booking to, in workflow order. */
|
|
7
|
+
export declare function allowedBookingTransitions(booking: CrewBooking, actorId: string | undefined): CrewBookingStatus[];
|
|
8
|
+
export declare const BOOKING_ACTION_LABEL: Record<CrewBookingStatus, string>;
|
|
9
|
+
export declare const BOOKING_STATUS_LABEL: Record<CrewBookingStatus, string>;
|
|
10
|
+
export declare const ESCROW_STATUS_LABEL: Record<CrewEscrowStatus, string>;
|
|
11
|
+
/** Escrow ledger rows that can still be released or cancelled. */
|
|
12
|
+
export declare const isEscrowOpen: (status: CrewEscrowStatus) => boolean;
|
|
13
|
+
export declare const RATE_UNIT_OPTIONS: {
|
|
14
|
+
label: string;
|
|
15
|
+
value: string;
|
|
16
|
+
}[];
|
|
17
|
+
export declare const CURRENCY_OPTIONS: {
|
|
18
|
+
label: string;
|
|
19
|
+
value: string;
|
|
20
|
+
}[];
|
|
21
|
+
/** Formats an amount in its ISO currency, falling back to "<amount> <code>". */
|
|
22
|
+
export declare function formatMoney(amount: number, currency: string): string;
|
|
23
|
+
/** "$120 / hour", or just "$900" for a fixed-price listing. */
|
|
24
|
+
export declare function formatRate(item: Pick<CrewServiceListing, 'rate' | 'rateUnit' | 'currency'>): string;
|
|
25
|
+
/** Sum of amounts grouped by currency, e.g. "$300 · €120" (never mixes currencies). */
|
|
26
|
+
export declare function sumByCurrency(rows: Array<{
|
|
27
|
+
amount: number;
|
|
28
|
+
currency: string;
|
|
29
|
+
}>): string;
|
|
30
|
+
//# sourceMappingURL=marketplace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketplace.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/lib/marketplace.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;AAahD,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,EAAE,CAM7F;AAED,2EAA2E;AAC3E,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,iBAAiB,EAAE,CAMrB;AAED,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAKlE,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAKlE,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAKhE,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,YAAY,GAAI,QAAQ,gBAAgB,KAAG,OACR,CAAC;AAEjD,eAAO,MAAM,iBAAiB;;;GAM7B,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;GAG1B,CAAC;AAEJ,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUpE;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CACxB,IAAI,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC,GAC/D,MAAM,CAIR;AAED,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,MAAM,CAOvF"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
//#region src/crewfoundry/lib/marketplace.ts
|
|
2
|
+
var e = {
|
|
3
|
+
requested: {
|
|
4
|
+
confirmed: ["provider"],
|
|
5
|
+
cancelled: ["provider", "client"]
|
|
6
|
+
},
|
|
7
|
+
confirmed: {
|
|
8
|
+
completed: ["provider"],
|
|
9
|
+
cancelled: ["provider", "client"]
|
|
10
|
+
},
|
|
11
|
+
completed: {},
|
|
12
|
+
cancelled: {}
|
|
13
|
+
};
|
|
14
|
+
function t(e, t) {
|
|
15
|
+
if (!t) return [];
|
|
16
|
+
let n = [];
|
|
17
|
+
return e.providerActorId === t && n.push("provider"), e.clientActorId === t && n.push("client"), n;
|
|
18
|
+
}
|
|
19
|
+
function n(n, r) {
|
|
20
|
+
let i = t(n, r), a = e[n.status] ?? {};
|
|
21
|
+
return Object.keys(a).filter((e) => (a[e] ?? []).some((e) => i.includes(e)));
|
|
22
|
+
}
|
|
23
|
+
var r = {
|
|
24
|
+
requested: "Requested",
|
|
25
|
+
confirmed: "Confirm",
|
|
26
|
+
completed: "Mark completed",
|
|
27
|
+
cancelled: "Cancel booking"
|
|
28
|
+
}, i = {
|
|
29
|
+
requested: "Requested",
|
|
30
|
+
confirmed: "Confirmed",
|
|
31
|
+
completed: "Completed",
|
|
32
|
+
cancelled: "Cancelled"
|
|
33
|
+
}, a = {
|
|
34
|
+
pending_hold: "Pending hold",
|
|
35
|
+
held: "Held",
|
|
36
|
+
released: "Released",
|
|
37
|
+
cancelled: "Cancelled"
|
|
38
|
+
}, o = (e) => e === "pending_hold" || e === "held", s = [
|
|
39
|
+
{
|
|
40
|
+
label: "Per hour",
|
|
41
|
+
value: "hour"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
label: "Per day",
|
|
45
|
+
value: "day"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
label: "Per week",
|
|
49
|
+
value: "week"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
label: "Per month",
|
|
53
|
+
value: "month"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
label: "Fixed price",
|
|
57
|
+
value: "fixed"
|
|
58
|
+
}
|
|
59
|
+
], c = [
|
|
60
|
+
"USD",
|
|
61
|
+
"EUR",
|
|
62
|
+
"GBP",
|
|
63
|
+
"INR"
|
|
64
|
+
].map((e) => ({
|
|
65
|
+
label: e,
|
|
66
|
+
value: e
|
|
67
|
+
}));
|
|
68
|
+
function l(e, t) {
|
|
69
|
+
try {
|
|
70
|
+
return new Intl.NumberFormat(void 0, {
|
|
71
|
+
style: "currency",
|
|
72
|
+
currency: t,
|
|
73
|
+
maximumFractionDigits: 2
|
|
74
|
+
}).format(e);
|
|
75
|
+
} catch {
|
|
76
|
+
return `${e.toLocaleString()} ${t}`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function u(e) {
|
|
80
|
+
let t = l(e.rate, e.currency), n = e.rateUnit.trim().toLowerCase();
|
|
81
|
+
return n === "fixed" || n === "" ? t : `${t} / ${n}`;
|
|
82
|
+
}
|
|
83
|
+
function d(e) {
|
|
84
|
+
let t = /* @__PURE__ */ new Map();
|
|
85
|
+
for (let n of e) t.set(n.currency, (t.get(n.currency) ?? 0) + n.amount);
|
|
86
|
+
return t.size === 0 ? l(0, "USD") : [...t].map(([e, t]) => l(t, e)).join(" · ");
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
export { r as BOOKING_ACTION_LABEL, i as BOOKING_STATUS_LABEL, c as CURRENCY_OPTIONS, a as ESCROW_STATUS_LABEL, s as RATE_UNIT_OPTIONS, n as allowedBookingTransitions, l as formatMoney, u as formatRate, o as isEscrowOpen, d as sumByCurrency };
|
|
90
|
+
|
|
91
|
+
//# sourceMappingURL=marketplace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketplace.js","names":[],"sources":["../../../src/crewfoundry/lib/marketplace.ts"],"sourcesContent":["/**\n * Pure helpers for the talent-marketplace pages (BOFF-3401). Mirrors the\n * booking workflow enforced by wspace-crewfoundry-svc's MarketplaceService so\n * the UI only offers transitions the service will accept; the service stays\n * the authority and rejects anything else.\n */\nimport type {\n CrewBooking,\n CrewBookingStatus,\n CrewEscrowStatus,\n CrewServiceListing,\n} from '../store/crewfoundryStore';\n\nexport type BookingRole = 'provider' | 'client';\n\n/** Legal next statuses per current status, and which role may move there. */\nconst BOOKING_TRANSITIONS: Record<\n CrewBookingStatus,\n Partial<Record<CrewBookingStatus, BookingRole[]>>\n> = {\n requested: { confirmed: ['provider'], cancelled: ['provider', 'client'] },\n confirmed: { completed: ['provider'], cancelled: ['provider', 'client'] },\n completed: {},\n cancelled: {},\n};\n\n/** Roles the actor holds on a booking (both when they booked their own service). */\nexport function bookingRoles(booking: CrewBooking, actorId: string | undefined): BookingRole[] {\n if (!actorId) return [];\n const roles: BookingRole[] = [];\n if (booking.providerActorId === actorId) roles.push('provider');\n if (booking.clientActorId === actorId) roles.push('client');\n return roles;\n}\n\n/** Next statuses this actor may move the booking to, in workflow order. */\nexport function allowedBookingTransitions(\n booking: CrewBooking,\n actorId: string | undefined\n): CrewBookingStatus[] {\n const roles = bookingRoles(booking, actorId);\n const next = BOOKING_TRANSITIONS[booking.status] ?? {};\n return (Object.keys(next) as CrewBookingStatus[]).filter((status) =>\n (next[status] ?? []).some((role) => roles.includes(role))\n );\n}\n\nexport const BOOKING_ACTION_LABEL: Record<CrewBookingStatus, string> = {\n requested: 'Requested',\n confirmed: 'Confirm',\n completed: 'Mark completed',\n cancelled: 'Cancel booking',\n};\n\nexport const BOOKING_STATUS_LABEL: Record<CrewBookingStatus, string> = {\n requested: 'Requested',\n confirmed: 'Confirmed',\n completed: 'Completed',\n cancelled: 'Cancelled',\n};\n\nexport const ESCROW_STATUS_LABEL: Record<CrewEscrowStatus, string> = {\n pending_hold: 'Pending hold',\n held: 'Held',\n released: 'Released',\n cancelled: 'Cancelled',\n};\n\n/** Escrow ledger rows that can still be released or cancelled. */\nexport const isEscrowOpen = (status: CrewEscrowStatus): boolean =>\n status === 'pending_hold' || status === 'held';\n\nexport const RATE_UNIT_OPTIONS = [\n { label: 'Per hour', value: 'hour' },\n { label: 'Per day', value: 'day' },\n { label: 'Per week', value: 'week' },\n { label: 'Per month', value: 'month' },\n { label: 'Fixed price', value: 'fixed' },\n];\n\nexport const CURRENCY_OPTIONS = ['USD', 'EUR', 'GBP', 'INR'].map((code) => ({\n label: code,\n value: code,\n}));\n\n/** Formats an amount in its ISO currency, falling back to \"<amount> <code>\". */\nexport function formatMoney(amount: number, currency: string): string {\n try {\n return new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency,\n maximumFractionDigits: 2,\n }).format(amount);\n } catch {\n return `${amount.toLocaleString()} ${currency}`;\n }\n}\n\n/** \"$120 / hour\", or just \"$900\" for a fixed-price listing. */\nexport function formatRate(\n item: Pick<CrewServiceListing, 'rate' | 'rateUnit' | 'currency'>\n): string {\n const money = formatMoney(item.rate, item.currency);\n const unit = item.rateUnit.trim().toLowerCase();\n return unit === 'fixed' || unit === '' ? money : `${money} / ${unit}`;\n}\n\n/** Sum of amounts grouped by currency, e.g. \"$300 · €120\" (never mixes currencies). */\nexport function sumByCurrency(rows: Array<{ amount: number; currency: string }>): string {\n const totals = new Map<string, number>();\n for (const row of rows) {\n totals.set(row.currency, (totals.get(row.currency) ?? 0) + row.amount);\n }\n if (totals.size === 0) return formatMoney(0, 'USD');\n return [...totals].map(([currency, amount]) => formatMoney(amount, currency)).join(' · ');\n}\n"],"mappings":";AAgBA,IAAM,IAGF;CACF,WAAW;EAAE,WAAW,CAAC,WAAW;EAAE,WAAW,CAAC,YAAY,SAAS;EAAE;CACzE,WAAW;EAAE,WAAW,CAAC,WAAW;EAAE,WAAW,CAAC,YAAY,SAAS;EAAE;CACzE,WAAW,EAAE;CACb,WAAW,EAAE;CACd;AAGD,SAAgB,EAAa,GAAsB,GAA4C;AAC7F,KAAI,CAAC,EAAS,QAAO,EAAE;CACvB,IAAM,IAAuB,EAAE;AAG/B,QAFI,EAAQ,oBAAoB,KAAS,EAAM,KAAK,WAAW,EAC3D,EAAQ,kBAAkB,KAAS,EAAM,KAAK,SAAS,EACpD;;AAIT,SAAgB,EACd,GACA,GACqB;CACrB,IAAM,IAAQ,EAAa,GAAS,EAAQ,EACtC,IAAO,EAAoB,EAAQ,WAAW,EAAE;AACtD,QAAQ,OAAO,KAAK,EAAK,CAAyB,QAAQ,OACvD,EAAK,MAAW,EAAE,EAAE,MAAM,MAAS,EAAM,SAAS,EAAK,CAAC,CAC1D;;AAGH,IAAa,IAA0D;CACrE,WAAW;CACX,WAAW;CACX,WAAW;CACX,WAAW;CACZ,EAEY,IAA0D;CACrE,WAAW;CACX,WAAW;CACX,WAAW;CACX,WAAW;CACZ,EAEY,IAAwD;CACnE,cAAc;CACd,MAAM;CACN,UAAU;CACV,WAAW;CACZ,EAGY,KAAgB,MAC3B,MAAW,kBAAkB,MAAW,QAE7B,IAAoB;CAC/B;EAAE,OAAO;EAAY,OAAO;EAAQ;CACpC;EAAE,OAAO;EAAW,OAAO;EAAO;CAClC;EAAE,OAAO;EAAY,OAAO;EAAQ;CACpC;EAAE,OAAO;EAAa,OAAO;EAAS;CACtC;EAAE,OAAO;EAAe,OAAO;EAAS;CACzC,EAEY,IAAmB;CAAC;CAAO;CAAO;CAAO;CAAM,CAAC,KAAK,OAAU;CAC1E,OAAO;CACP,OAAO;CACR,EAAE;AAGH,SAAgB,EAAY,GAAgB,GAA0B;AACpE,KAAI;AACF,SAAO,IAAI,KAAK,aAAa,KAAA,GAAW;GACtC,OAAO;GACP;GACA,uBAAuB;GACxB,CAAC,CAAC,OAAO,EAAO;SACX;AACN,SAAO,GAAG,EAAO,gBAAgB,CAAC,GAAG;;;AAKzC,SAAgB,EACd,GACQ;CACR,IAAM,IAAQ,EAAY,EAAK,MAAM,EAAK,SAAS,EAC7C,IAAO,EAAK,SAAS,MAAM,CAAC,aAAa;AAC/C,QAAO,MAAS,WAAW,MAAS,KAAK,IAAQ,GAAG,EAAM,KAAK;;AAIjE,SAAgB,EAAc,GAA2D;CACvF,IAAM,oBAAS,IAAI,KAAqB;AACxC,MAAK,IAAM,KAAO,EAChB,GAAO,IAAI,EAAI,WAAW,EAAO,IAAI,EAAI,SAAS,IAAI,KAAK,EAAI,OAAO;AAGxE,QADI,EAAO,SAAS,IAAU,EAAY,GAAG,MAAM,GAC5C,CAAC,GAAG,EAAO,CAAC,KAAK,CAAC,GAAU,OAAY,EAAY,GAAQ,EAAS,CAAC,CAAC,KAAK,MAAM"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run a lazy store fetch once the module has its workspace context
|
|
3
|
+
* (`initialized`) and the slice has not been loaded yet. Returns the load
|
|
4
|
+
* error, if any, so the page can render it instead of a silent empty state.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useEnsureLoaded(loaded: boolean, load: () => Promise<void>): string | null;
|
|
7
|
+
//# sourceMappingURL=useEnsureLoaded.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEnsureLoaded.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/lib/useEnsureLoaded.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAoBzF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
2
|
+
import { useEffect as t, useState as n } from "react";
|
|
3
|
+
//#region src/crewfoundry/lib/useEnsureLoaded.ts
|
|
4
|
+
function r(r, i) {
|
|
5
|
+
let a = e((e) => e.initialized), [o, s] = n(null);
|
|
6
|
+
return t(() => {
|
|
7
|
+
if (!a || r) return;
|
|
8
|
+
let e = !1;
|
|
9
|
+
return i().then(() => {
|
|
10
|
+
e || s(null);
|
|
11
|
+
}).catch((t) => {
|
|
12
|
+
e || s(t instanceof Error ? t.message : "Unable to load data");
|
|
13
|
+
}), () => {
|
|
14
|
+
e = !0;
|
|
15
|
+
};
|
|
16
|
+
}, [
|
|
17
|
+
a,
|
|
18
|
+
r,
|
|
19
|
+
i
|
|
20
|
+
]), o;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { r as useEnsureLoaded };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=useEnsureLoaded.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEnsureLoaded.js","names":[],"sources":["../../../src/crewfoundry/lib/useEnsureLoaded.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\n/**\n * Run a lazy store fetch once the module has its workspace context\n * (`initialized`) and the slice has not been loaded yet. Returns the load\n * error, if any, so the page can render it instead of a silent empty state.\n */\nexport function useEnsureLoaded(loaded: boolean, load: () => Promise<void>): string | null {\n const initialized = useCrewFoundryStore((state) => state.initialized);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!initialized || loaded) return;\n let cancelled = false;\n load()\n .then(() => {\n if (!cancelled) setError(null);\n })\n .catch((err: unknown) => {\n if (!cancelled) setError(err instanceof Error ? err.message : 'Unable to load data');\n });\n return () => {\n cancelled = true;\n };\n }, [initialized, loaded, load]);\n\n return error;\n}\n"],"mappings":";;;AAQA,SAAgB,EAAgB,GAAiB,GAA0C;CACzF,IAAM,IAAc,GAAqB,MAAU,EAAM,YAAY,EAC/D,CAAC,GAAO,KAAY,EAAwB,KAAK;AAiBvD,QAfA,QAAgB;AACd,MAAI,CAAC,KAAe,EAAQ;EAC5B,IAAI,IAAY;AAQhB,SAPA,GAAM,CACH,WAAW;AACV,GAAK,KAAW,EAAS,KAAK;IAC9B,CACD,OAAO,MAAiB;AACvB,GAAK,KAAW,EAAS,aAAe,QAAQ,EAAI,UAAU,sBAAsB;IACpF,QACS;AACX,OAAY;;IAEb;EAAC;EAAa;EAAQ;EAAK,CAAC,EAExB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsFinancialAnalyticsPagePage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.tsx"],"names":[],"mappings":"AA+BA,wBAAgB,mCAAmC,
|
|
1
|
+
{"version":3,"file":"AnalyticsFinancialAnalyticsPagePage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.tsx"],"names":[],"mappings":"AA+BA,wBAAgB,mCAAmC,gCAoSlD"}
|
|
@@ -10,7 +10,7 @@ import { Badge as f, Card as p, CardContent as m, CardDescription as h, CardHead
|
|
|
10
10
|
import { usePagination as T } from "@burdenoff/fe-libs/shared/hooks";
|
|
11
11
|
//#region src/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.tsx
|
|
12
12
|
function E() {
|
|
13
|
-
let { employees: E, departments: D, payrollRecords: O,
|
|
13
|
+
let { employees: E, departments: D, payrollRecords: O, clients: k, projects: A } = e(), j = i(() => {
|
|
14
14
|
let e = O.reduce((e, t) => {
|
|
15
15
|
let n = new Date(t.payDate).toLocaleString("en-US", { month: "short" }), r = e[n] || {
|
|
16
16
|
gross: 0,
|
|
@@ -39,22 +39,13 @@ function E() {
|
|
|
39
39
|
category: "Project Spend",
|
|
40
40
|
amount: A.reduce((e, t) => e + t.spent, 0),
|
|
41
41
|
icon: c
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
category: "Collected Invoices",
|
|
45
|
-
amount: k.filter((e) => e.status === "paid").reduce((e, t) => e + t.amount, 0),
|
|
46
|
-
icon: o
|
|
47
42
|
}
|
|
48
43
|
], t = e.reduce((e, t) => e + t.amount, 0) || 1;
|
|
49
44
|
return e.map((e) => ({
|
|
50
45
|
...e,
|
|
51
46
|
percentage: Math.round(e.amount / t * 100)
|
|
52
47
|
}));
|
|
53
|
-
}, [
|
|
54
|
-
k,
|
|
55
|
-
O,
|
|
56
|
-
A
|
|
57
|
-
]), N = E.reduce((e, t) => e + t.salary, 0), P = Math.round(N / 12), F = k.reduce((e, t) => e + t.amount, 0), I = k.filter((e) => e.status === "paid").reduce((e, t) => e + t.amount, 0), L = A.reduce((e, t) => e + t.budget, 0), R = A.reduce((e, t) => e + t.spent, 0), z = j.map((e) => ({
|
|
48
|
+
}, [O, A]), N = E.reduce((e, t) => e + t.salary, 0), P = Math.round(N / 12), F = k.reduce((e, t) => e + (t.revenue || 0), 0), I = k.filter((e) => e.status === "active").length, L = A.reduce((e, t) => e + t.budget, 0), R = A.reduce((e, t) => e + t.spent, 0), z = j.map((e) => ({
|
|
58
49
|
label: e.month,
|
|
59
50
|
value: e.gross
|
|
60
51
|
})), B = j.map((e) => e.net), V = M.filter((e) => e.amount > 0).map((e) => ({
|
|
@@ -68,7 +59,7 @@ function E() {
|
|
|
68
59
|
budget: e.budget,
|
|
69
60
|
headcount: t.length
|
|
70
61
|
};
|
|
71
|
-
})].sort((e, t) => t.salary - e.salary), W = D.reduce((e, t) => e + t.budget, 0), G = [...k].filter((e) => e.
|
|
62
|
+
})].sort((e, t) => t.salary - e.salary), W = D.reduce((e, t) => e + t.budget, 0), G = [...k].filter((e) => (e.revenue || 0) > 0).sort((e, t) => t.revenue - e.revenue), { page: K, pageSize: q, offset: J, setPage: Y } = T({ initialPageSize: 6 }), X = G.slice(J, J + q);
|
|
72
63
|
return /* @__PURE__ */ d("div", {
|
|
73
64
|
className: "space-y-6 p-6",
|
|
74
65
|
children: [
|
|
@@ -142,7 +133,7 @@ function E() {
|
|
|
142
133
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
143
134
|
children: [/* @__PURE__ */ u(_, {
|
|
144
135
|
className: "text-sm font-medium",
|
|
145
|
-
children: "
|
|
136
|
+
children: "Client Revenue"
|
|
146
137
|
}), /* @__PURE__ */ u(o, { className: "h-4 w-4 text-text-secondary" })]
|
|
147
138
|
}), /* @__PURE__ */ d(m, { children: [/* @__PURE__ */ d("div", {
|
|
148
139
|
className: "text-2xl font-bold tabular-nums",
|
|
@@ -153,11 +144,7 @@ function E() {
|
|
|
153
144
|
]
|
|
154
145
|
}), /* @__PURE__ */ d("p", {
|
|
155
146
|
className: "text-xs text-text-secondary",
|
|
156
|
-
children: [
|
|
157
|
-
"$",
|
|
158
|
-
(I / 1e3).toFixed(1),
|
|
159
|
-
"K collected"
|
|
160
|
-
]
|
|
147
|
+
children: [I, " active clients"]
|
|
161
148
|
})] })]
|
|
162
149
|
}),
|
|
163
150
|
/* @__PURE__ */ d(v, {
|
|
@@ -204,29 +191,29 @@ function E() {
|
|
|
204
191
|
}) : /* @__PURE__ */ u("p", {
|
|
205
192
|
className: "py-6 text-center text-sm text-text-secondary",
|
|
206
193
|
children: "No tracked spend yet."
|
|
207
|
-
}) })] }), /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ d(g, { children: [/* @__PURE__ */ u(_, { children: "
|
|
194
|
+
}) })] }), /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ d(g, { children: [/* @__PURE__ */ u(_, { children: "Revenue by Client" }), /* @__PURE__ */ u(h, { children: "Revenue recorded against each client" })] }), /* @__PURE__ */ d(m, {
|
|
208
195
|
className: "space-y-3",
|
|
209
196
|
children: [
|
|
210
197
|
G.length === 0 && /* @__PURE__ */ u(b, {
|
|
211
198
|
illustration: "empty-data",
|
|
212
|
-
title: "No
|
|
213
|
-
description: "
|
|
199
|
+
title: "No client revenue yet",
|
|
200
|
+
description: "Record revenue on your clients under Company → Client Management."
|
|
214
201
|
}),
|
|
215
202
|
X.map((e) => /* @__PURE__ */ d("div", {
|
|
216
203
|
className: "flex items-center justify-between rounded border p-3",
|
|
217
204
|
children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("p", {
|
|
218
205
|
className: "text-sm font-medium",
|
|
219
|
-
children: e.
|
|
206
|
+
children: e.name
|
|
220
207
|
}), /* @__PURE__ */ u("p", {
|
|
221
208
|
className: "text-xs text-text-secondary",
|
|
222
|
-
children: e.
|
|
209
|
+
children: e.industry
|
|
223
210
|
})] }), /* @__PURE__ */ d("div", {
|
|
224
211
|
className: "text-right",
|
|
225
212
|
children: [/* @__PURE__ */ d("p", {
|
|
226
213
|
className: "text-sm font-medium",
|
|
227
|
-
children: ["$", e.
|
|
214
|
+
children: ["$", e.revenue.toLocaleString()]
|
|
228
215
|
}), /* @__PURE__ */ u(f, {
|
|
229
|
-
variant:
|
|
216
|
+
variant: "secondary",
|
|
230
217
|
className: "text-[10px]",
|
|
231
218
|
children: t(e.status)
|
|
232
219
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsFinancialAnalyticsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n type ResponsiveTableColumn,\n Separator,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { DollarSign, FileText, Receipt, TrendingUp, Wallet } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\nimport { DonutChart, LineChart } from '../components/viz';\nimport type { LabeledValue, Segment } from '../components/viz';\n\ntype DeptCostRow = {\n name: string;\n salary: number;\n budget: number;\n headcount: number;\n};\n\nexport function AnalyticsFinancialAnalyticsPagePage() {\n const { employees, departments, payrollRecords, invoices, projects } = useCrewFoundryStore();\n\n const monthlyPayrollTrend = useMemo(() => {\n const byPeriod = payrollRecords.reduce<\n Record<string, { gross: number; net: number; deductions: number }>\n >((acc, record) => {\n const month = new Date(record.payDate).toLocaleString('en-US', { month: 'short' });\n const current = acc[month] || { gross: 0, net: 0, deductions: 0 };\n current.gross += record.grossPay;\n current.net += record.netPay;\n current.deductions += record.deductions;\n acc[month] = current;\n return acc;\n }, {});\n return Object.entries(byPeriod)\n .map(([month, value]) => ({ month, ...value }))\n .slice(-6);\n }, [payrollRecords]);\n\n // Real spend lines only (no invented budget coefficients).\n const spendByCategory = useMemo(() => {\n const items = [\n {\n category: 'Gross Payroll',\n amount: payrollRecords.reduce((sum, record) => sum + record.grossPay, 0),\n icon: Wallet,\n },\n {\n category: 'Deductions',\n amount: payrollRecords.reduce((sum, record) => sum + record.deductions, 0),\n icon: Receipt,\n },\n {\n category: 'Project Spend',\n amount: projects.reduce((sum, project) => sum + project.spent, 0),\n icon: TrendingUp,\n },\n {\n category: 'Collected Invoices',\n amount: invoices\n .filter((invoice) => invoice.status === 'paid')\n .reduce((sum, invoice) => sum + invoice.amount, 0),\n icon: FileText,\n },\n ];\n const total = items.reduce((sum, item) => sum + item.amount, 0) || 1;\n return items.map((item) => ({ ...item, percentage: Math.round((item.amount / total) * 100) }));\n }, [invoices, payrollRecords, projects]);\n\n const totalPayroll = employees.reduce((sum, e) => sum + e.salary, 0);\n const monthlyPayroll = Math.round(totalPayroll / 12);\n const totalInvoiced = invoices.reduce((sum, inv) => sum + inv.amount, 0);\n const paidInvoices = invoices\n .filter((i) => i.status === 'paid')\n .reduce((s, i) => s + i.amount, 0);\n const totalProjectBudget = projects.reduce((s, p) => s + p.budget, 0);\n const totalProjectSpent = projects.reduce((s, p) => s + p.spent, 0);\n\n const grossSeries: LabeledValue[] = monthlyPayrollTrend.map((m) => ({\n label: m.month,\n value: m.gross,\n }));\n const netCompare = monthlyPayrollTrend.map((m) => m.net);\n const spendSegments: Segment[] = spendByCategory\n .filter((category) => category.amount > 0)\n .map((category) => ({ label: category.category, value: category.amount }));\n const projectUtilization =\n totalProjectBudget > 0 ? Math.round((totalProjectSpent / totalProjectBudget) * 100) : 0;\n\n const deptCost: DeptCostRow[] = departments.map((d) => {\n const deptEmps = employees.filter((e) => e.department === d.name);\n const totalSal = deptEmps.reduce((s, e) => s + e.salary, 0);\n return { name: d.name, salary: totalSal, budget: d.budget, headcount: deptEmps.length };\n });\n const sortedDeptCost = [...deptCost].sort((a, b) => b.salary - a.salary);\n const totalDeptBudget = departments.reduce((s, d) => s + d.budget, 0);\n\n // Outstanding invoices = anything not fully paid, matching the card title.\n const outstandingInvoices = [...invoices]\n .filter((invoice) => invoice.status !== 'paid')\n .sort((a, b) => a.dueDate.localeCompare(b.dueDate));\n const {\n page: invoicePage,\n pageSize: invoicePageSize,\n offset: invoiceOffset,\n setPage: setInvoicePage,\n } = usePagination({ initialPageSize: 6 });\n const invoicePageItems = outstandingInvoices.slice(\n invoiceOffset,\n invoiceOffset + invoicePageSize\n );\n\n const deptCostColumns: ResponsiveTableColumn<DeptCostRow>[] = [\n {\n key: 'name',\n header: 'Department',\n priority: 'primary',\n cell: (d) => <span className=\"font-medium\">{d.name}</span>,\n },\n {\n key: 'headcount',\n header: 'Headcount',\n priority: 'secondary',\n cell: (d) => <span className=\"md:block md:text-right\">{d.headcount}</span>,\n },\n {\n key: 'salary',\n header: 'Total Salary',\n priority: 'secondary',\n cell: (d) => <span className=\"md:block md:text-right\">${(d.salary / 1000).toFixed(0)}K</span>,\n },\n {\n key: 'budget',\n header: 'Dept Budget',\n priority: 'secondary',\n cell: (d) => (\n <span className=\"md:block md:text-right\">${(d.budget / 1000000).toFixed(1)}M</span>\n ),\n },\n {\n key: 'ratio',\n header: 'Salary/Budget %',\n priority: 'primary',\n cell: (d) => {\n const ratio = d.budget > 0 ? Math.round((d.salary / d.budget) * 100) : 0;\n return (\n <span className=\"md:block md:text-right\">\n <Badge variant={ratio > 50 ? 'destructive' : 'default'} className=\"text-[10px]\">\n {ratio}%\n </Badge>\n </span>\n );\n },\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>Financial Analytics</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Workforce financial metrics and cost analysis\n </p>\n <PagePurpose className=\"mt-1\">\n Understand the money side of your workforce — payroll, project budgets, and spend trends\n — so you can plan headcount and control costs with confidence.\n </PagePurpose>\n </div>\n </div>\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\">Monthly Payroll</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 ${(monthlyPayroll / 1000).toFixed(0)}K\n </div>\n <p className=\"text-xs text-text-secondary\">Annual salary ÷ 12 months</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\">Annual Salary Cost</CardTitle>\n <Wallet className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n ${(totalPayroll / 1000000).toFixed(1)}M\n </div>\n <p className=\"text-xs text-text-secondary\">{employees.length} employees</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\">Total Invoiced</CardTitle>\n <FileText className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n ${(totalInvoiced / 1000).toFixed(1)}K\n </div>\n <p className=\"text-xs text-text-secondary\">\n ${(paidInvoices / 1000).toFixed(1)}K collected\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\">Project Budget</CardTitle>\n <TrendingUp className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n ${(totalProjectBudget / 1000000).toFixed(1)}M\n </div>\n <p className=\"text-xs text-text-secondary\">{projectUtilization}% utilized</p>\n </CardContent>\n </GlassCard>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Payroll Trend</CardTitle>\n <CardDescription>Monthly gross payroll over the last 6 months</CardDescription>\n </CardHeader>\n <CardContent>\n {grossSeries.length > 0 ? (\n <LineChart\n series={grossSeries}\n compare={netCompare}\n seriesLabel=\"Gross pay\"\n compareLabel=\"Net pay\"\n height={220}\n valueFormatter={(value) => `$${(value / 1000).toFixed(0)}K`}\n />\n ) : (\n <p className=\"py-6 text-center text-sm text-text-secondary\">No payroll records yet.</p>\n )}\n </CardContent>\n </Card>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Spend by Category</CardTitle>\n <CardDescription>Share of tracked workforce spend</CardDescription>\n </CardHeader>\n <CardContent>\n {spendSegments.length > 0 ? (\n <DonutChart\n segments={spendSegments}\n centerLabel={`$${(spendSegments.reduce((sum, s) => sum + s.value, 0) / 1000).toFixed(0)}K`}\n centerCaption=\"Total spend\"\n valueFormatter={(value) => `$${(value / 1000).toFixed(0)}K`}\n />\n ) : (\n <p className=\"py-6 text-center text-sm text-text-secondary\">No tracked spend yet.</p>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Outstanding Invoices</CardTitle>\n <CardDescription>Unpaid invoices requiring attention</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {outstandingInvoices.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No outstanding invoices\"\n description=\"Every invoice has been paid. New unpaid invoices will appear here.\"\n />\n )}\n {invoicePageItems.map((inv) => (\n <div key={inv.id} className=\"flex items-center justify-between rounded border p-3\">\n <div>\n <p className=\"text-sm font-medium\">{inv.number}</p>\n <p className=\"text-xs text-text-secondary\">{inv.clientName}</p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-sm font-medium\">${inv.amount.toLocaleString()}</p>\n <Badge\n variant={inv.status === 'overdue' ? 'destructive' : 'secondary'}\n className=\"text-[10px]\"\n >\n {formatEnumLabel(inv.status)}\n </Badge>\n </div>\n </div>\n ))}\n {outstandingInvoices.length > invoicePageSize && (\n <Pagination\n page={invoicePage}\n pageSize={invoicePageSize}\n totalItems={outstandingInvoices.length}\n onPageChange={setInvoicePage}\n />\n )}\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Department Cost Analysis</CardTitle>\n <CardDescription>Total salary cost and budget allocation by department</CardDescription>\n </CardHeader>\n <CardContent>\n <ResponsiveTable columns={deptCostColumns} data={sortedDeptCost} rowKey={(d) => d.name} />\n <Separator className=\"my-3\" />\n <div className=\"flex flex-wrap items-center justify-between gap-2 text-sm font-bold\">\n <span>Total</span>\n <span>{employees.length} employees</span>\n <span>${(totalPayroll / 1000000).toFixed(1)}M salary</span>\n <span>${(totalDeptBudget / 1000000).toFixed(1)}M budget</span>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AnalyticsFinancialAnalyticsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n type ResponsiveTableColumn,\n Separator,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { DollarSign, FileText, Receipt, TrendingUp, Wallet } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\nimport { DonutChart, LineChart } from '../components/viz';\nimport type { LabeledValue, Segment } from '../components/viz';\n\ntype DeptCostRow = {\n name: string;\n salary: number;\n budget: number;\n headcount: number;\n};\n\nexport function AnalyticsFinancialAnalyticsPagePage() {\n const { employees, departments, payrollRecords, clients, projects } = useCrewFoundryStore();\n\n const monthlyPayrollTrend = useMemo(() => {\n const byPeriod = payrollRecords.reduce<\n Record<string, { gross: number; net: number; deductions: number }>\n >((acc, record) => {\n const month = new Date(record.payDate).toLocaleString('en-US', { month: 'short' });\n const current = acc[month] || { gross: 0, net: 0, deductions: 0 };\n current.gross += record.grossPay;\n current.net += record.netPay;\n current.deductions += record.deductions;\n acc[month] = current;\n return acc;\n }, {});\n return Object.entries(byPeriod)\n .map(([month, value]) => ({ month, ...value }))\n .slice(-6);\n }, [payrollRecords]);\n\n // Real spend lines only (no invented budget coefficients).\n const spendByCategory = useMemo(() => {\n const items = [\n {\n category: 'Gross Payroll',\n amount: payrollRecords.reduce((sum, record) => sum + record.grossPay, 0),\n icon: Wallet,\n },\n {\n category: 'Deductions',\n amount: payrollRecords.reduce((sum, record) => sum + record.deductions, 0),\n icon: Receipt,\n },\n {\n category: 'Project Spend',\n amount: projects.reduce((sum, project) => sum + project.spent, 0),\n icon: TrendingUp,\n },\n ];\n const total = items.reduce((sum, item) => sum + item.amount, 0) || 1;\n return items.map((item) => ({ ...item, percentage: Math.round((item.amount / total) * 100) }));\n }, [payrollRecords, projects]);\n\n const totalPayroll = employees.reduce((sum, e) => sum + e.salary, 0);\n const monthlyPayroll = Math.round(totalPayroll / 12);\n // Client revenue is recorded on each CrewClient (there is no invoicing in\n // CrewFoundry; billing for the workspace itself lives in the Billing app).\n const totalClientRevenue = clients.reduce((sum, client) => sum + (client.revenue || 0), 0);\n const activeClientCount = clients.filter((client) => client.status === 'active').length;\n const totalProjectBudget = projects.reduce((s, p) => s + p.budget, 0);\n const totalProjectSpent = projects.reduce((s, p) => s + p.spent, 0);\n\n const grossSeries: LabeledValue[] = monthlyPayrollTrend.map((m) => ({\n label: m.month,\n value: m.gross,\n }));\n const netCompare = monthlyPayrollTrend.map((m) => m.net);\n const spendSegments: Segment[] = spendByCategory\n .filter((category) => category.amount > 0)\n .map((category) => ({ label: category.category, value: category.amount }));\n const projectUtilization =\n totalProjectBudget > 0 ? Math.round((totalProjectSpent / totalProjectBudget) * 100) : 0;\n\n const deptCost: DeptCostRow[] = departments.map((d) => {\n const deptEmps = employees.filter((e) => e.department === d.name);\n const totalSal = deptEmps.reduce((s, e) => s + e.salary, 0);\n return { name: d.name, salary: totalSal, budget: d.budget, headcount: deptEmps.length };\n });\n const sortedDeptCost = [...deptCost].sort((a, b) => b.salary - a.salary);\n const totalDeptBudget = departments.reduce((s, d) => s + d.budget, 0);\n\n const clientsByRevenue = [...clients]\n .filter((client) => (client.revenue || 0) > 0)\n .sort((a, b) => b.revenue - a.revenue);\n const {\n page: clientPage,\n pageSize: clientPageSize,\n offset: clientOffset,\n setPage: setClientPage,\n } = usePagination({ initialPageSize: 6 });\n const clientPageItems = clientsByRevenue.slice(clientOffset, clientOffset + clientPageSize);\n\n const deptCostColumns: ResponsiveTableColumn<DeptCostRow>[] = [\n {\n key: 'name',\n header: 'Department',\n priority: 'primary',\n cell: (d) => <span className=\"font-medium\">{d.name}</span>,\n },\n {\n key: 'headcount',\n header: 'Headcount',\n priority: 'secondary',\n cell: (d) => <span className=\"md:block md:text-right\">{d.headcount}</span>,\n },\n {\n key: 'salary',\n header: 'Total Salary',\n priority: 'secondary',\n cell: (d) => <span className=\"md:block md:text-right\">${(d.salary / 1000).toFixed(0)}K</span>,\n },\n {\n key: 'budget',\n header: 'Dept Budget',\n priority: 'secondary',\n cell: (d) => (\n <span className=\"md:block md:text-right\">${(d.budget / 1000000).toFixed(1)}M</span>\n ),\n },\n {\n key: 'ratio',\n header: 'Salary/Budget %',\n priority: 'primary',\n cell: (d) => {\n const ratio = d.budget > 0 ? Math.round((d.salary / d.budget) * 100) : 0;\n return (\n <span className=\"md:block md:text-right\">\n <Badge variant={ratio > 50 ? 'destructive' : 'default'} className=\"text-[10px]\">\n {ratio}%\n </Badge>\n </span>\n );\n },\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>Financial Analytics</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Workforce financial metrics and cost analysis\n </p>\n <PagePurpose className=\"mt-1\">\n Understand the money side of your workforce — payroll, project budgets, and spend trends\n — so you can plan headcount and control costs with confidence.\n </PagePurpose>\n </div>\n </div>\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\">Monthly Payroll</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 ${(monthlyPayroll / 1000).toFixed(0)}K\n </div>\n <p className=\"text-xs text-text-secondary\">Annual salary ÷ 12 months</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\">Annual Salary Cost</CardTitle>\n <Wallet className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n ${(totalPayroll / 1000000).toFixed(1)}M\n </div>\n <p className=\"text-xs text-text-secondary\">{employees.length} employees</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\">Client Revenue</CardTitle>\n <FileText className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n ${(totalClientRevenue / 1000).toFixed(1)}K\n </div>\n <p className=\"text-xs text-text-secondary\">{activeClientCount} active clients</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\">Project Budget</CardTitle>\n <TrendingUp className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n ${(totalProjectBudget / 1000000).toFixed(1)}M\n </div>\n <p className=\"text-xs text-text-secondary\">{projectUtilization}% utilized</p>\n </CardContent>\n </GlassCard>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Payroll Trend</CardTitle>\n <CardDescription>Monthly gross payroll over the last 6 months</CardDescription>\n </CardHeader>\n <CardContent>\n {grossSeries.length > 0 ? (\n <LineChart\n series={grossSeries}\n compare={netCompare}\n seriesLabel=\"Gross pay\"\n compareLabel=\"Net pay\"\n height={220}\n valueFormatter={(value) => `$${(value / 1000).toFixed(0)}K`}\n />\n ) : (\n <p className=\"py-6 text-center text-sm text-text-secondary\">No payroll records yet.</p>\n )}\n </CardContent>\n </Card>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Spend by Category</CardTitle>\n <CardDescription>Share of tracked workforce spend</CardDescription>\n </CardHeader>\n <CardContent>\n {spendSegments.length > 0 ? (\n <DonutChart\n segments={spendSegments}\n centerLabel={`$${(spendSegments.reduce((sum, s) => sum + s.value, 0) / 1000).toFixed(0)}K`}\n centerCaption=\"Total spend\"\n valueFormatter={(value) => `$${(value / 1000).toFixed(0)}K`}\n />\n ) : (\n <p className=\"py-6 text-center text-sm text-text-secondary\">No tracked spend yet.</p>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Revenue by Client</CardTitle>\n <CardDescription>Revenue recorded against each client</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {clientsByRevenue.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No client revenue yet\"\n description=\"Record revenue on your clients under Company → Client Management.\"\n />\n )}\n {clientPageItems.map((client) => (\n <div key={client.id} className=\"flex items-center justify-between rounded border p-3\">\n <div>\n <p className=\"text-sm font-medium\">{client.name}</p>\n <p className=\"text-xs text-text-secondary\">{client.industry}</p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-sm font-medium\">${client.revenue.toLocaleString()}</p>\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n {formatEnumLabel(client.status)}\n </Badge>\n </div>\n </div>\n ))}\n {clientsByRevenue.length > clientPageSize && (\n <Pagination\n page={clientPage}\n pageSize={clientPageSize}\n totalItems={clientsByRevenue.length}\n onPageChange={setClientPage}\n />\n )}\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Department Cost Analysis</CardTitle>\n <CardDescription>Total salary cost and budget allocation by department</CardDescription>\n </CardHeader>\n <CardContent>\n <ResponsiveTable columns={deptCostColumns} data={sortedDeptCost} rowKey={(d) => d.name} />\n <Separator className=\"my-3\" />\n <div className=\"flex flex-wrap items-center justify-between gap-2 text-sm font-bold\">\n <span>Total</span>\n <span>{employees.length} employees</span>\n <span>${(totalPayroll / 1000000).toFixed(1)}M salary</span>\n <span>${(totalDeptBudget / 1000000).toFixed(1)}M budget</span>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommunicationsAnnouncementsPagePage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/CommunicationsAnnouncementsPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CommunicationsAnnouncementsPagePage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/CommunicationsAnnouncementsPagePage.tsx"],"names":[],"mappings":"AAiHA,wBAAgB,mCAAmC,gCAiVlD"}
|