@optifye/dashboard-core 6.10.31 → 6.10.33
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/index.css +352 -6
- package/dist/index.d.mts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +959 -135
- package/dist/index.mjs +959 -136
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7667,6 +7667,27 @@ var weeklyTopPerformerService = {
|
|
|
7667
7667
|
return data?.top_performer ?? null;
|
|
7668
7668
|
}
|
|
7669
7669
|
};
|
|
7670
|
+
|
|
7671
|
+
// src/lib/services/lineLeaderboardService.ts
|
|
7672
|
+
var lineLeaderboardService = {
|
|
7673
|
+
async getLineLeaderboard(supabase, params) {
|
|
7674
|
+
const searchParams = new URLSearchParams();
|
|
7675
|
+
searchParams.set("company_id", params.companyId);
|
|
7676
|
+
searchParams.set("start_date", params.startDate);
|
|
7677
|
+
searchParams.set("end_date", params.endDate);
|
|
7678
|
+
if (params.lineIds && params.lineIds.length > 0) {
|
|
7679
|
+
searchParams.set("line_ids", params.lineIds.join(","));
|
|
7680
|
+
}
|
|
7681
|
+
if (typeof params.limit === "number") {
|
|
7682
|
+
searchParams.set("limit", params.limit.toString());
|
|
7683
|
+
}
|
|
7684
|
+
const data = await fetchBackendJson(
|
|
7685
|
+
supabase,
|
|
7686
|
+
`/api/dashboard/line-leaderboard?${searchParams.toString()}`
|
|
7687
|
+
);
|
|
7688
|
+
return data?.entries ?? [];
|
|
7689
|
+
}
|
|
7690
|
+
};
|
|
7670
7691
|
var SupabaseContext = React25.createContext(void 0);
|
|
7671
7692
|
var SupabaseProvider = ({ client, children }) => {
|
|
7672
7693
|
_setSupabaseInstance(client);
|
|
@@ -10202,9 +10223,25 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10202
10223
|
const inFlightFetchKeyRef = React25.useRef(null);
|
|
10203
10224
|
const updateQueueRef = React25.useRef(false);
|
|
10204
10225
|
const onLineMetricsUpdateRef = React25.useRef(onLineMetricsUpdate);
|
|
10226
|
+
const shiftGroupsRef = React25.useRef(shiftGroups);
|
|
10227
|
+
const operationalShiftKeyRef = React25.useRef(operationalShiftKey);
|
|
10228
|
+
const configuredLineIdsRef = React25.useRef(configuredLineIds);
|
|
10229
|
+
const userAccessibleLineIdsRef = React25.useRef(userAccessibleLineIds);
|
|
10205
10230
|
React25.useEffect(() => {
|
|
10206
10231
|
onLineMetricsUpdateRef.current = onLineMetricsUpdate;
|
|
10207
10232
|
}, [onLineMetricsUpdate]);
|
|
10233
|
+
React25.useEffect(() => {
|
|
10234
|
+
shiftGroupsRef.current = shiftGroups;
|
|
10235
|
+
}, [shiftGroups]);
|
|
10236
|
+
React25.useEffect(() => {
|
|
10237
|
+
operationalShiftKeyRef.current = operationalShiftKey;
|
|
10238
|
+
}, [operationalShiftKey]);
|
|
10239
|
+
React25.useEffect(() => {
|
|
10240
|
+
configuredLineIdsRef.current = configuredLineIds;
|
|
10241
|
+
}, [configuredLineIds]);
|
|
10242
|
+
React25.useEffect(() => {
|
|
10243
|
+
userAccessibleLineIdsRef.current = userAccessibleLineIds;
|
|
10244
|
+
}, [userAccessibleLineIds]);
|
|
10208
10245
|
const companySpecificMetricsTable = React25.useMemo(
|
|
10209
10246
|
() => getCompanyMetricsTableName(entityConfig.companyId, "performance_metrics"),
|
|
10210
10247
|
[entityConfig.companyId]
|
|
@@ -10535,8 +10572,29 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10535
10572
|
if (!supabase || shiftLoading || isTimezoneLoading) return;
|
|
10536
10573
|
fetchAllMetrics({ force: true, reason: "shift-change" });
|
|
10537
10574
|
}, [isFactoryView, shiftGroupsKey, supabase, shiftLoading, isTimezoneLoading, fetchAllMetrics]);
|
|
10575
|
+
const subscriptionKey = React25.useMemo(() => {
|
|
10576
|
+
if (!supabase || !entityConfig?.companyId) return null;
|
|
10577
|
+
if (shiftLoading || isTimezoneLoading) return null;
|
|
10578
|
+
const isFactory = lineId === (entityConfig.factoryViewId || "factory");
|
|
10579
|
+
if (isFactory && shiftGroups.length === 0) return null;
|
|
10580
|
+
const shiftGroupsKeyPart = isFactory ? shiftGroups.map((g) => `${g.date}-${g.shiftId}-${g.lineIds.join("_")}`).join("|") : operationalShiftKey;
|
|
10581
|
+
return `${lineId}|${entityConfig.companyId}|${shiftGroupsKeyPart}`;
|
|
10582
|
+
}, [
|
|
10583
|
+
supabase,
|
|
10584
|
+
entityConfig?.companyId,
|
|
10585
|
+
entityConfig?.factoryViewId,
|
|
10586
|
+
lineId,
|
|
10587
|
+
shiftLoading,
|
|
10588
|
+
isTimezoneLoading,
|
|
10589
|
+
shiftGroups,
|
|
10590
|
+
operationalShiftKey
|
|
10591
|
+
]);
|
|
10538
10592
|
React25.useEffect(() => {
|
|
10539
10593
|
const currentLineIdToUse = lineIdRef.current;
|
|
10594
|
+
if (!subscriptionKey) {
|
|
10595
|
+
logDebug("[useDashboardMetrics] Realtime setup skipped: subscriptionKey not ready (config still loading)");
|
|
10596
|
+
return;
|
|
10597
|
+
}
|
|
10540
10598
|
if (!currentLineIdToUse || !supabase || companySpecificMetricsTable.includes("unknown_company") || !entityConfig.companyId) {
|
|
10541
10599
|
logDebug("[useDashboardMetrics] Realtime setup skipped:", {
|
|
10542
10600
|
lineId: currentLineIdToUse,
|
|
@@ -10549,18 +10607,22 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10549
10607
|
const factoryViewIdentifier = entityConfig.factoryViewId || "factory";
|
|
10550
10608
|
const isFactory = currentLineIdToUse === factoryViewIdentifier;
|
|
10551
10609
|
const channels = [];
|
|
10610
|
+
const currentShiftGroups = shiftGroupsRef.current;
|
|
10611
|
+
const currentUserAccessibleLineIds = userAccessibleLineIdsRef.current;
|
|
10612
|
+
const currentConfiguredLineIds = configuredLineIdsRef.current;
|
|
10552
10613
|
logDebug("[useDashboardMetrics] Realtime setup starting:", {
|
|
10553
10614
|
lineId: currentLineIdToUse,
|
|
10554
10615
|
isFactory,
|
|
10555
|
-
shiftGroupsCount:
|
|
10616
|
+
shiftGroupsCount: currentShiftGroups.length,
|
|
10556
10617
|
companySpecificMetricsTable,
|
|
10557
|
-
configuredLineMetricsTable
|
|
10618
|
+
configuredLineMetricsTable,
|
|
10619
|
+
subscriptionKey
|
|
10558
10620
|
});
|
|
10559
|
-
if (isFactory &&
|
|
10621
|
+
if (isFactory && currentShiftGroups.length > 0) {
|
|
10560
10622
|
logDebug("[useDashboardMetrics] Setting up group subscriptions:", {
|
|
10561
|
-
groupCount:
|
|
10623
|
+
groupCount: currentShiftGroups.length
|
|
10562
10624
|
});
|
|
10563
|
-
|
|
10625
|
+
currentShiftGroups.forEach((group, index) => {
|
|
10564
10626
|
const groupLineIds = group.lineIds.filter((id3) => id3 && id3 !== factoryViewIdentifier);
|
|
10565
10627
|
if (groupLineIds.length === 0) {
|
|
10566
10628
|
logDebug("[useDashboardMetrics] Skipping group subscription: no line IDs after filtering", {
|
|
@@ -10579,6 +10641,18 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10579
10641
|
{ event: "*", schema, table: companySpecificMetricsTable, filter: filter2 },
|
|
10580
10642
|
(payload) => {
|
|
10581
10643
|
const payloadData = payload.new || payload.old;
|
|
10644
|
+
console.log("[useDashboardMetrics] \u{1F4E1} WS_METRICS payload received:", {
|
|
10645
|
+
eventType: payload.eventType,
|
|
10646
|
+
lineId: payloadData?.line_id,
|
|
10647
|
+
workspaceId: payloadData?.workspace_id,
|
|
10648
|
+
date: payloadData?.date,
|
|
10649
|
+
shiftId: payloadData?.shift_id,
|
|
10650
|
+
expectedDate: group.date,
|
|
10651
|
+
expectedShiftId: group.shiftId,
|
|
10652
|
+
dateMatch: payloadData?.date === group.date,
|
|
10653
|
+
shiftMatch: payloadData?.shift_id === group.shiftId,
|
|
10654
|
+
efficiency: payloadData?.efficiency
|
|
10655
|
+
});
|
|
10582
10656
|
logDebug("[useDashboardMetrics] WS realtime payload:", {
|
|
10583
10657
|
channel: wsChannelName,
|
|
10584
10658
|
eventType: payload.eventType,
|
|
@@ -10589,10 +10663,19 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10589
10663
|
shiftId: payloadData?.shift_id
|
|
10590
10664
|
});
|
|
10591
10665
|
if (payloadData?.date === group.date && payloadData?.shift_id === group.shiftId) {
|
|
10666
|
+
console.log("[useDashboardMetrics] \u2705 WS Date/shift match - triggering update");
|
|
10592
10667
|
queueUpdate();
|
|
10668
|
+
} else {
|
|
10669
|
+
console.log("[useDashboardMetrics] \u274C WS Date/shift mismatch - update SKIPPED");
|
|
10593
10670
|
}
|
|
10594
10671
|
}
|
|
10595
10672
|
).subscribe((status) => {
|
|
10673
|
+
console.log("[useDashboardMetrics] \u{1F4F6} WS metrics subscription:", {
|
|
10674
|
+
channel: wsChannelName,
|
|
10675
|
+
status,
|
|
10676
|
+
table: companySpecificMetricsTable,
|
|
10677
|
+
filter: filter2
|
|
10678
|
+
});
|
|
10596
10679
|
logDebug("[useDashboardMetrics] WS subscription status:", {
|
|
10597
10680
|
channel: wsChannelName,
|
|
10598
10681
|
status
|
|
@@ -10605,6 +10688,17 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10605
10688
|
{ event: "*", schema, table: configuredLineMetricsTable, filter: filter2 },
|
|
10606
10689
|
(payload) => {
|
|
10607
10690
|
const payloadData = payload.new || payload.old;
|
|
10691
|
+
console.log("[useDashboardMetrics] \u{1F4E1} LINE_METRICS payload received:", {
|
|
10692
|
+
eventType: payload.eventType,
|
|
10693
|
+
lineId: payloadData?.line_id,
|
|
10694
|
+
date: payloadData?.date,
|
|
10695
|
+
shiftId: payloadData?.shift_id,
|
|
10696
|
+
expectedDate: group.date,
|
|
10697
|
+
expectedShiftId: group.shiftId,
|
|
10698
|
+
dateMatch: payloadData?.date === group.date,
|
|
10699
|
+
shiftMatch: payloadData?.shift_id === group.shiftId,
|
|
10700
|
+
avgEfficiency: payloadData?.avg_efficiency
|
|
10701
|
+
});
|
|
10608
10702
|
logDebug("[useDashboardMetrics] Line metrics realtime payload:", {
|
|
10609
10703
|
channel: lmChannelName,
|
|
10610
10704
|
eventType: payload.eventType,
|
|
@@ -10614,11 +10708,20 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10614
10708
|
shiftId: payloadData?.shift_id
|
|
10615
10709
|
});
|
|
10616
10710
|
if (payloadData?.date === group.date && payloadData?.shift_id === group.shiftId) {
|
|
10711
|
+
console.log("[useDashboardMetrics] \u2705 Date/shift match - triggering update");
|
|
10617
10712
|
queueUpdate();
|
|
10618
10713
|
onLineMetricsUpdateRef.current?.();
|
|
10714
|
+
} else {
|
|
10715
|
+
console.log("[useDashboardMetrics] \u274C Date/shift mismatch - update SKIPPED");
|
|
10619
10716
|
}
|
|
10620
10717
|
}
|
|
10621
10718
|
).subscribe((status) => {
|
|
10719
|
+
console.log("[useDashboardMetrics] \u{1F4F6} Line metrics subscription:", {
|
|
10720
|
+
channel: lmChannelName,
|
|
10721
|
+
status,
|
|
10722
|
+
table: configuredLineMetricsTable,
|
|
10723
|
+
filter: filter2
|
|
10724
|
+
});
|
|
10622
10725
|
logDebug("[useDashboardMetrics] Line metrics subscription status:", {
|
|
10623
10726
|
channel: lmChannelName,
|
|
10624
10727
|
status
|
|
@@ -10654,11 +10757,11 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10654
10757
|
} else {
|
|
10655
10758
|
logDebug("[useDashboardMetrics] Using single-shift subscriptions:", {
|
|
10656
10759
|
isFactory,
|
|
10657
|
-
shiftGroupsCount:
|
|
10760
|
+
shiftGroupsCount: currentShiftGroups.length
|
|
10658
10761
|
});
|
|
10659
10762
|
const currentShiftDetails = shiftConfig ? getCurrentShift(defaultTimezone, shiftConfig) : getCurrentShift(defaultTimezone, staticShiftConfig);
|
|
10660
10763
|
const operationalDateForSubscription = currentShiftDetails.date;
|
|
10661
|
-
const targetLineIds = isFactory ?
|
|
10764
|
+
const targetLineIds = isFactory ? currentUserAccessibleLineIds || currentConfiguredLineIds : [currentLineIdToUse];
|
|
10662
10765
|
const filteredLineIds = targetLineIds.filter((id3) => id3 && id3 !== factoryViewIdentifier);
|
|
10663
10766
|
if (filteredLineIds.length === 0) {
|
|
10664
10767
|
logDebug("[useDashboardMetrics] Realtime setup skipped: no line IDs after filtering", {
|
|
@@ -10683,6 +10786,20 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10683
10786
|
{ event: "*", schema, table, filter: filter2 },
|
|
10684
10787
|
(payload) => {
|
|
10685
10788
|
const payloadData = payload.new || payload.old;
|
|
10789
|
+
console.log(`[useDashboardMetrics] \u{1F4E1} ${table.toUpperCase()} payload received (single-line):`, {
|
|
10790
|
+
eventType: payload.eventType,
|
|
10791
|
+
table: payload.table,
|
|
10792
|
+
lineId: payloadData?.line_id,
|
|
10793
|
+
workspaceId: payloadData?.workspace_id,
|
|
10794
|
+
date: payloadData?.date,
|
|
10795
|
+
shiftId: payloadData?.shift_id,
|
|
10796
|
+
expectedDate: operationalDateForSubscription,
|
|
10797
|
+
expectedShiftId: currentShiftDetails.shiftId,
|
|
10798
|
+
dateMatch: payloadData?.date === operationalDateForSubscription,
|
|
10799
|
+
shiftMatch: payloadData?.shift_id === currentShiftDetails.shiftId,
|
|
10800
|
+
avgEfficiency: payloadData?.avg_efficiency,
|
|
10801
|
+
efficiency: payloadData?.efficiency
|
|
10802
|
+
});
|
|
10686
10803
|
logDebug("[useDashboardMetrics] Subscription payload:", {
|
|
10687
10804
|
channel: channelName,
|
|
10688
10805
|
eventType: payload.eventType,
|
|
@@ -10693,10 +10810,21 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10693
10810
|
shiftId: payloadData?.shift_id
|
|
10694
10811
|
});
|
|
10695
10812
|
if (payloadData?.date === operationalDateForSubscription && payloadData?.shift_id === currentShiftDetails.shiftId) {
|
|
10813
|
+
console.log(`[useDashboardMetrics] \u2705 ${table} Date/shift match - triggering update`);
|
|
10696
10814
|
callback();
|
|
10815
|
+
} else {
|
|
10816
|
+
console.log(`[useDashboardMetrics] \u274C ${table} Date/shift mismatch - update SKIPPED`);
|
|
10697
10817
|
}
|
|
10698
10818
|
}
|
|
10699
10819
|
).subscribe((status) => {
|
|
10820
|
+
console.log(`[useDashboardMetrics] \u{1F4F6} ${table} subscription:`, {
|
|
10821
|
+
channel: channelName,
|
|
10822
|
+
status,
|
|
10823
|
+
table,
|
|
10824
|
+
filter: filter2,
|
|
10825
|
+
expectedDate: operationalDateForSubscription,
|
|
10826
|
+
expectedShiftId: currentShiftDetails.shiftId
|
|
10827
|
+
});
|
|
10700
10828
|
logDebug("[useDashboardMetrics] Subscription status:", {
|
|
10701
10829
|
channel: channelName,
|
|
10702
10830
|
status
|
|
@@ -10718,6 +10846,10 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10718
10846
|
});
|
|
10719
10847
|
};
|
|
10720
10848
|
}, [
|
|
10849
|
+
// CRITICAL: Use subscriptionKey as the primary dependency for subscription recreation
|
|
10850
|
+
// This ensures subscriptions are only recreated when the actual subscription parameters change,
|
|
10851
|
+
// not during every transient state update during initial load
|
|
10852
|
+
subscriptionKey,
|
|
10721
10853
|
supabase,
|
|
10722
10854
|
queueUpdate,
|
|
10723
10855
|
companySpecificMetricsTable,
|
|
@@ -10728,10 +10860,10 @@ var useDashboardMetrics = ({ onLineMetricsUpdate, lineId, userAccessibleLineIds
|
|
|
10728
10860
|
defaultTimezone,
|
|
10729
10861
|
shiftConfig,
|
|
10730
10862
|
staticShiftConfig,
|
|
10731
|
-
shiftGroups
|
|
10732
|
-
|
|
10733
|
-
lineId
|
|
10734
|
-
userAccessibleLineIds
|
|
10863
|
+
// NOTE: shiftGroups and operationalShiftKey removed - they're accessed via refs
|
|
10864
|
+
// to prevent subscription churn. subscriptionKey encapsulates their stable state.
|
|
10865
|
+
lineId
|
|
10866
|
+
// NOTE: userAccessibleLineIds removed - accessed via ref
|
|
10735
10867
|
]);
|
|
10736
10868
|
const isMetricsForActiveLine = metricsLineId === lineId;
|
|
10737
10869
|
const safeMetrics = isMetricsForActiveLine ? metrics2 : { workspaceMetrics: [], lineMetrics: [], metadata: void 0, efficiencyLegend: DEFAULT_EFFICIENCY_LEGEND };
|
|
@@ -12674,6 +12806,10 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
|
|
|
12674
12806
|
return;
|
|
12675
12807
|
}
|
|
12676
12808
|
if (data.type === Hls__default.default.ErrorTypes.NETWORK_ERROR && (data.details === Hls__default.default.ErrorDetails.MANIFEST_LOAD_TIMEOUT || data.details === Hls__default.default.ErrorDetails.MANIFEST_LOAD_ERROR)) {
|
|
12809
|
+
if (data.response?.code === 404 && isR2StreamRef.current) {
|
|
12810
|
+
markStaleStream("manifest 404");
|
|
12811
|
+
return;
|
|
12812
|
+
}
|
|
12677
12813
|
scheduleManifestRetry("manifest load timeout");
|
|
12678
12814
|
return;
|
|
12679
12815
|
}
|
|
@@ -12682,7 +12818,7 @@ function useHlsStream(videoRef, { src, shouldPlay, onFatalError, hlsConfig }) {
|
|
|
12682
12818
|
if (data.response?.code === 404) {
|
|
12683
12819
|
if (data.details === Hls__default.default.ErrorDetails.MANIFEST_LOAD_ERROR || data.details === Hls__default.default.ErrorDetails.LEVEL_LOAD_ERROR) {
|
|
12684
12820
|
if (isR2StreamRef.current) {
|
|
12685
|
-
|
|
12821
|
+
markStaleStream("manifest 404");
|
|
12686
12822
|
return;
|
|
12687
12823
|
}
|
|
12688
12824
|
hardRestart("404 manifest hard restart");
|
|
@@ -13711,7 +13847,7 @@ var useActiveBreaks = (lineIds) => {
|
|
|
13711
13847
|
const [isLoading, setIsLoading] = React25.useState(true);
|
|
13712
13848
|
const [error, setError] = React25.useState(null);
|
|
13713
13849
|
const supabase = useSupabase();
|
|
13714
|
-
const
|
|
13850
|
+
const parseTimeToMinutes3 = (timeStr) => {
|
|
13715
13851
|
const [hours, minutes] = timeStr.split(":").map(Number);
|
|
13716
13852
|
return hours * 60 + minutes;
|
|
13717
13853
|
};
|
|
@@ -13720,8 +13856,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
13720
13856
|
return now4.getHours() * 60 + now4.getMinutes();
|
|
13721
13857
|
};
|
|
13722
13858
|
const isTimeInBreak = (breakStart, breakEnd, currentMinutes) => {
|
|
13723
|
-
const startMinutes =
|
|
13724
|
-
const endMinutes =
|
|
13859
|
+
const startMinutes = parseTimeToMinutes3(breakStart);
|
|
13860
|
+
const endMinutes = parseTimeToMinutes3(breakEnd);
|
|
13725
13861
|
if (endMinutes < startMinutes) {
|
|
13726
13862
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
13727
13863
|
} else {
|
|
@@ -13729,8 +13865,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
13729
13865
|
}
|
|
13730
13866
|
};
|
|
13731
13867
|
const calculateBreakProgress = (breakStart, breakEnd, currentMinutes) => {
|
|
13732
|
-
const startMinutes =
|
|
13733
|
-
const endMinutes =
|
|
13868
|
+
const startMinutes = parseTimeToMinutes3(breakStart);
|
|
13869
|
+
const endMinutes = parseTimeToMinutes3(breakEnd);
|
|
13734
13870
|
let elapsedMinutes = 0;
|
|
13735
13871
|
let remainingMinutes = 0;
|
|
13736
13872
|
if (endMinutes < startMinutes) {
|
|
@@ -13748,8 +13884,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
13748
13884
|
return { elapsedMinutes, remainingMinutes };
|
|
13749
13885
|
};
|
|
13750
13886
|
const isTimeInShift = (startTime, endTime, currentMinutes) => {
|
|
13751
|
-
const startMinutes =
|
|
13752
|
-
const endMinutes =
|
|
13887
|
+
const startMinutes = parseTimeToMinutes3(startTime);
|
|
13888
|
+
const endMinutes = parseTimeToMinutes3(endTime);
|
|
13753
13889
|
if (endMinutes < startMinutes) {
|
|
13754
13890
|
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
|
13755
13891
|
} else {
|
|
@@ -13809,8 +13945,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
13809
13945
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
13810
13946
|
let duration = breakItem.duration || 0;
|
|
13811
13947
|
if (!duration || duration === 0) {
|
|
13812
|
-
const startMinutes =
|
|
13813
|
-
const endMinutes =
|
|
13948
|
+
const startMinutes = parseTimeToMinutes3(startTime);
|
|
13949
|
+
const endMinutes = parseTimeToMinutes3(endTime);
|
|
13814
13950
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
13815
13951
|
}
|
|
13816
13952
|
return {
|
|
@@ -13826,8 +13962,8 @@ var useActiveBreaks = (lineIds) => {
|
|
|
13826
13962
|
const endTime = breakItem.end || breakItem.endTime || "00:00";
|
|
13827
13963
|
let duration = breakItem.duration || 0;
|
|
13828
13964
|
if (!duration || duration === 0) {
|
|
13829
|
-
const startMinutes =
|
|
13830
|
-
const endMinutes =
|
|
13965
|
+
const startMinutes = parseTimeToMinutes3(startTime);
|
|
13966
|
+
const endMinutes = parseTimeToMinutes3(endTime);
|
|
13831
13967
|
duration = endMinutes < startMinutes ? endMinutes + 24 * 60 - startMinutes : endMinutes - startMinutes;
|
|
13832
13968
|
}
|
|
13833
13969
|
return {
|
|
@@ -15846,6 +15982,13 @@ var useSupervisorsByLineIds = (lineIds, options) => {
|
|
|
15846
15982
|
refetch: fetchSupervisors
|
|
15847
15983
|
};
|
|
15848
15984
|
};
|
|
15985
|
+
var DEBUG_DASHBOARD = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
|
|
15986
|
+
var logIdleTimeReasonsDebug = (...args) => {
|
|
15987
|
+
if (DEBUG_DASHBOARD) {
|
|
15988
|
+
console.log(...args);
|
|
15989
|
+
}
|
|
15990
|
+
};
|
|
15991
|
+
var nowMs = () => typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
15849
15992
|
function useIdleTimeReasons({
|
|
15850
15993
|
workspaceId,
|
|
15851
15994
|
lineId,
|
|
@@ -15865,23 +16008,44 @@ function useIdleTimeReasons({
|
|
|
15865
16008
|
const lastRequestKeyRef = React25.useRef("");
|
|
15866
16009
|
const fetchData = React25.useCallback(async () => {
|
|
15867
16010
|
if (!workspaceId && !lineId) {
|
|
16011
|
+
logIdleTimeReasonsDebug("[useIdleTimeReasons] Skipping fetch (missing id)", {
|
|
16012
|
+
requestKey,
|
|
16013
|
+
workspaceId,
|
|
16014
|
+
lineId
|
|
16015
|
+
});
|
|
15868
16016
|
setError("At least one of workspaceId or lineId is required");
|
|
15869
16017
|
setIsFetching(false);
|
|
15870
16018
|
return;
|
|
15871
16019
|
}
|
|
15872
16020
|
const token = session?.access_token;
|
|
15873
16021
|
if (!token) {
|
|
16022
|
+
logIdleTimeReasonsDebug("[useIdleTimeReasons] Skipping fetch (no auth token)", {
|
|
16023
|
+
requestKey,
|
|
16024
|
+
workspaceId,
|
|
16025
|
+
lineId
|
|
16026
|
+
});
|
|
15874
16027
|
setError("Not authenticated");
|
|
15875
16028
|
setIsFetching(false);
|
|
15876
16029
|
return;
|
|
15877
16030
|
}
|
|
15878
16031
|
const currentRequestKey = requestKey;
|
|
15879
16032
|
lastRequestKeyRef.current = currentRequestKey;
|
|
16033
|
+
const startedAt = nowMs();
|
|
16034
|
+
logIdleTimeReasonsDebug("[useIdleTimeReasons] Fetch start", {
|
|
16035
|
+
requestKey: currentRequestKey,
|
|
16036
|
+
workspaceId,
|
|
16037
|
+
lineId,
|
|
16038
|
+
date,
|
|
16039
|
+
shiftId,
|
|
16040
|
+
startDate,
|
|
16041
|
+
endDate
|
|
16042
|
+
});
|
|
15880
16043
|
setIsFetching(true);
|
|
15881
16044
|
if (!keepPreviousData) {
|
|
15882
16045
|
setData(null);
|
|
15883
16046
|
}
|
|
15884
16047
|
setError(null);
|
|
16048
|
+
let errorMessage = null;
|
|
15885
16049
|
try {
|
|
15886
16050
|
const result = await fetchIdleTimeReasons({
|
|
15887
16051
|
workspaceId,
|
|
@@ -15898,22 +16062,32 @@ function useIdleTimeReasons({
|
|
|
15898
16062
|
}
|
|
15899
16063
|
} catch (err) {
|
|
15900
16064
|
console.error("[useIdleTimeReasons] Error:", err);
|
|
16065
|
+
errorMessage = err instanceof Error ? err.message : "Failed to fetch idle time reasons";
|
|
15901
16066
|
if (isMountedRef.current && lastRequestKeyRef.current === currentRequestKey) {
|
|
15902
|
-
setError(
|
|
16067
|
+
setError(errorMessage);
|
|
15903
16068
|
}
|
|
15904
16069
|
} finally {
|
|
15905
16070
|
if (isMountedRef.current && lastRequestKeyRef.current === currentRequestKey) {
|
|
15906
16071
|
setIsFetching(false);
|
|
15907
16072
|
}
|
|
16073
|
+
const fetchEndAt = nowMs();
|
|
16074
|
+
const elapsedMs = startedAt ? Math.round(fetchEndAt - startedAt) : null;
|
|
16075
|
+
logIdleTimeReasonsDebug("[useIdleTimeReasons] Fetch end", {
|
|
16076
|
+
requestKey: currentRequestKey,
|
|
16077
|
+
elapsedMs,
|
|
16078
|
+
error: errorMessage
|
|
16079
|
+
});
|
|
15908
16080
|
}
|
|
15909
16081
|
}, [workspaceId, lineId, date, shiftId, startDate, endDate, session?.access_token, requestKey, keepPreviousData]);
|
|
15910
16082
|
React25.useEffect(() => {
|
|
15911
16083
|
isMountedRef.current = true;
|
|
15912
16084
|
if (!enabled) {
|
|
16085
|
+
logIdleTimeReasonsDebug("[useIdleTimeReasons] Disabled", { requestKey });
|
|
15913
16086
|
setIsFetching(false);
|
|
15914
16087
|
} else if (session?.access_token) {
|
|
15915
16088
|
fetchData();
|
|
15916
16089
|
} else {
|
|
16090
|
+
logIdleTimeReasonsDebug("[useIdleTimeReasons] Waiting for auth token", { requestKey });
|
|
15917
16091
|
setError("Not authenticated");
|
|
15918
16092
|
setIsFetching(false);
|
|
15919
16093
|
}
|
|
@@ -30608,9 +30782,9 @@ var MapGridView = React25__namespace.default.memo(({
|
|
|
30608
30782
|
}, [workspaces]);
|
|
30609
30783
|
const getPerformanceColor = React25.useCallback((efficiency) => {
|
|
30610
30784
|
const color2 = getEfficiencyColor(efficiency, effectiveLegend);
|
|
30611
|
-
if (color2 === "green") return "
|
|
30612
|
-
if (color2 === "yellow") return "
|
|
30613
|
-
return "
|
|
30785
|
+
if (color2 === "green") return "bg-green-500 text-white border-green-600";
|
|
30786
|
+
if (color2 === "yellow") return "bg-yellow-400 text-white border-yellow-500";
|
|
30787
|
+
return "bg-red-500 text-white border-red-600";
|
|
30614
30788
|
}, [effectiveLegend]);
|
|
30615
30789
|
const prewarmClipsInit = React25.useCallback((workspace) => {
|
|
30616
30790
|
if (!dashboardConfig?.s3Config) return;
|
|
@@ -30678,52 +30852,52 @@ var MapGridView = React25__namespace.default.memo(({
|
|
|
30678
30852
|
/* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsx("pattern", { id: "grid", width: "40", height: "40", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 40 0 L 0 0 0 40", fill: "none", stroke: "gray", strokeWidth: "0.5" }) }) }),
|
|
30679
30853
|
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: "100%", height: "100%", fill: "url(#grid)" })
|
|
30680
30854
|
] }) }),
|
|
30681
|
-
|
|
30855
|
+
workspacePositions.map((position) => {
|
|
30682
30856
|
const wsKey = position.id.toUpperCase();
|
|
30683
30857
|
const workspace = workspaceMetricsMap.get(wsKey);
|
|
30684
|
-
|
|
30685
|
-
const
|
|
30686
|
-
|
|
30687
|
-
|
|
30688
|
-
|
|
30689
|
-
|
|
30690
|
-
|
|
30858
|
+
const isInactivePlaceholder = position.id.startsWith("INACTIVE");
|
|
30859
|
+
const effectiveWorkspace = workspace || {
|
|
30860
|
+
workspace_name: position.id,
|
|
30861
|
+
// Fallback to config ID
|
|
30862
|
+
workspace_uuid: position.id,
|
|
30863
|
+
// Use config ID as temporary UUID
|
|
30864
|
+
line_id: "",
|
|
30865
|
+
efficiency: 0,
|
|
30866
|
+
show_exclamation: false
|
|
30867
|
+
};
|
|
30868
|
+
const workspaceId = effectiveWorkspace.workspace_uuid || effectiveWorkspace.workspace_name;
|
|
30869
|
+
const workspaceKey = `${effectiveWorkspace.line_id || "unknown"}-${workspaceId}`;
|
|
30870
|
+
const isConveyorRow = position.size === "conveyor_row";
|
|
30871
|
+
const performanceColor = isInactivePlaceholder || isConveyorRow ? "bg-slate-200 border-slate-300 text-slate-500" : getPerformanceColor(effectiveWorkspace.efficiency);
|
|
30872
|
+
!isInactivePlaceholder && !isConveyorRow && (effectiveWorkspace.show_exclamation ?? (effectiveWorkspace.efficiency < 50 && effectiveWorkspace.efficiency >= 10));
|
|
30873
|
+
const configLabel = position.label;
|
|
30874
|
+
const workspaceDisplayName = configLabel || (isInactivePlaceholder ? "INACTIVE" : displayNames[`${effectiveWorkspace.line_id}_${effectiveWorkspace.workspace_name}`] || getWorkspaceDisplayName(effectiveWorkspace.workspace_name, effectiveWorkspace.line_id) || position.id);
|
|
30691
30875
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
30692
30876
|
motion.div,
|
|
30693
30877
|
{
|
|
30694
30878
|
initial: { opacity: 0, scale: 0.8 },
|
|
30695
30879
|
animate: { opacity: 1, scale: 1 },
|
|
30696
30880
|
transition: { duration: 0.3 },
|
|
30697
|
-
className:
|
|
30881
|
+
className: `absolute ${isInactivePlaceholder || isConveyorRow ? "cursor-default" : "cursor-pointer"}`,
|
|
30698
30882
|
style: {
|
|
30699
30883
|
left: `${position.x}%`,
|
|
30700
30884
|
top: `${position.y}%`,
|
|
30701
30885
|
transform: "translate(-50%, -50%)"
|
|
30702
30886
|
},
|
|
30703
|
-
onClick: () => handleWorkspaceClick(workspace),
|
|
30704
|
-
onMouseEnter: () => onWorkspaceHover?.(workspaceId),
|
|
30705
|
-
onMouseLeave: () => onWorkspaceHoverEnd?.(workspaceId),
|
|
30706
|
-
children: /* @__PURE__ */ jsxRuntime.
|
|
30887
|
+
onClick: () => !isInactivePlaceholder && !isConveyorRow && workspace && handleWorkspaceClick(workspace),
|
|
30888
|
+
onMouseEnter: () => !isInactivePlaceholder && !isConveyorRow && onWorkspaceHover?.(workspaceId),
|
|
30889
|
+
onMouseLeave: () => !isInactivePlaceholder && !isConveyorRow && onWorkspaceHoverEnd?.(workspaceId),
|
|
30890
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
30707
30891
|
"div",
|
|
30708
30892
|
{
|
|
30709
30893
|
className: `
|
|
30710
|
-
relative
|
|
30711
|
-
|
|
30894
|
+
relative
|
|
30895
|
+
rounded-lg border-2 shadow-sm
|
|
30896
|
+
${!isInactivePlaceholder && !isConveyorRow ? "shadow-lg hover:shadow-xl transition-all duration-200 hover:scale-105" : ""}
|
|
30712
30897
|
${performanceColor}
|
|
30713
|
-
${position.size === "conveyor" ? "w-32 h-24" : position.size === "large" ? "w-40 h-32" : "w-36 h-28"}
|
|
30898
|
+
${position.size === "conveyor" ? "w-32 h-24" : position.size === "large" ? "w-40 h-32" : position.size === "small_square" ? "w-16 h-16" : position.size === "wide_rectangle" ? "w-32 h-16" : position.size === "conveyor_row" ? "w-3/4 h-16" : "w-36 h-28"}
|
|
30714
30899
|
`,
|
|
30715
|
-
children:
|
|
30716
|
-
showExclamation && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-2 -left-2 z-30", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
30717
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -inset-1 bg-red-400/50 rounded-full blur-sm animate-pulse" }),
|
|
30718
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -inset-0.5 bg-red-500/30 rounded-full blur-md animate-ping [animation-duration:1.5s]" }),
|
|
30719
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-[#E34329] w-5 h-5 rounded-full flex items-center justify-center text-white font-bold text-xs shadow-lg ring-2 ring-red-400/40 border border-red-400/80 animate-pulse", children: "!" })
|
|
30720
|
-
] }) }),
|
|
30721
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 left-0 right-0 px-2 py-1.5 border-b border-gray-200", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-bold text-gray-800 truncate text-center leading-tight", children: workspaceDisplayName }) }),
|
|
30722
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 px-2 py-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-2xl font-bold text-gray-900", children: [
|
|
30723
|
-
Math.round(workspace.efficiency),
|
|
30724
|
-
"%"
|
|
30725
|
-
] }) }) })
|
|
30726
|
-
]
|
|
30900
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute inset-0 px-2 py-1.5 flex items-center justify-center`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: `text-xs font-bold ${isInactivePlaceholder ? "text-gray-400" : isConveyorRow ? "text-gray-400 text-lg tracking-widest uppercase" : "text-white"} text-center leading-tight whitespace-normal break-words w-full`, children: workspaceDisplayName }) })
|
|
30727
30901
|
}
|
|
30728
30902
|
)
|
|
30729
30903
|
},
|
|
@@ -40654,7 +40828,7 @@ var LineMonthlyHistory = ({
|
|
|
40654
40828
|
const averages = (analysisMonthlyData || []).reduce(
|
|
40655
40829
|
(acc, day) => {
|
|
40656
40830
|
const shiftData = getShiftData2(day, selectedShiftId);
|
|
40657
|
-
if (!shiftData || shiftData?.avg_efficiency <
|
|
40831
|
+
if (!shiftData || shiftData?.avg_efficiency < 5) {
|
|
40658
40832
|
return acc;
|
|
40659
40833
|
}
|
|
40660
40834
|
return {
|
|
@@ -41116,7 +41290,7 @@ var LineMonthlyPdfGenerator = ({
|
|
|
41116
41290
|
});
|
|
41117
41291
|
const validShifts = validDays.map(
|
|
41118
41292
|
(day) => getLineShiftData2(day, selectedShiftId)
|
|
41119
|
-
).filter((shift) => shift.avg_efficiency
|
|
41293
|
+
).filter((shift) => shift.avg_efficiency >= 5);
|
|
41120
41294
|
const monthlyMetrics = validShifts.length > 0 ? {
|
|
41121
41295
|
avgEfficiency: validShifts.reduce((sum, shift) => sum + shift.avg_efficiency, 0) / validShifts.length,
|
|
41122
41296
|
avgUnderperforming: validShifts.reduce((sum, shift) => sum + shift.underperforming_workspaces, 0) / validShifts.length,
|
|
@@ -41484,7 +41658,7 @@ var LinePdfGenerator = ({
|
|
|
41484
41658
|
doc.setLineWidth(0.8);
|
|
41485
41659
|
doc.line(20, 118, 190, 118);
|
|
41486
41660
|
const hourlyOverviewStartY = 123;
|
|
41487
|
-
const
|
|
41661
|
+
const parseTimeToMinutes3 = (timeStr) => {
|
|
41488
41662
|
const [hours, minutes] = timeStr.split(":");
|
|
41489
41663
|
const hour = parseInt(hours, 10);
|
|
41490
41664
|
const minute = parseInt(minutes || "0", 10);
|
|
@@ -41517,7 +41691,7 @@ var LinePdfGenerator = ({
|
|
|
41517
41691
|
};
|
|
41518
41692
|
};
|
|
41519
41693
|
const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
|
|
41520
|
-
const startMinutes =
|
|
41694
|
+
const startMinutes = parseTimeToMinutes3(startTimeStr);
|
|
41521
41695
|
if (Number.isNaN(startMinutes)) {
|
|
41522
41696
|
return [];
|
|
41523
41697
|
}
|
|
@@ -41525,7 +41699,7 @@ var LinePdfGenerator = ({
|
|
|
41525
41699
|
const defaultHours = 11;
|
|
41526
41700
|
return Array.from({ length: defaultHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
41527
41701
|
}
|
|
41528
|
-
const endMinutes =
|
|
41702
|
+
const endMinutes = parseTimeToMinutes3(endTimeStr);
|
|
41529
41703
|
if (Number.isNaN(endMinutes)) {
|
|
41530
41704
|
const fallbackHours = 11;
|
|
41531
41705
|
return Array.from({ length: fallbackHours }, (_, i) => buildRange(startMinutes + i * 60, 60));
|
|
@@ -54572,6 +54746,376 @@ var KPIDetailViewWithDisplayNames = withSelectedLineDisplayNames(KPIDetailView);
|
|
|
54572
54746
|
var KPIDetailView_default = KPIDetailViewWithDisplayNames;
|
|
54573
54747
|
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
54574
54748
|
var resolveCompanyId = (...candidates) => candidates.find(isNonEmptyString);
|
|
54749
|
+
var parseTimeToMinutes2 = (value) => {
|
|
54750
|
+
if (!value) return null;
|
|
54751
|
+
const [hourStr, minuteStr] = value.split(":");
|
|
54752
|
+
const hour = Number.parseInt(hourStr ?? "", 10);
|
|
54753
|
+
const minute = Number.parseInt(minuteStr ?? "", 10);
|
|
54754
|
+
if (!Number.isFinite(hour) || !Number.isFinite(minute)) return null;
|
|
54755
|
+
return hour * 60 + minute;
|
|
54756
|
+
};
|
|
54757
|
+
var getShiftEndDate = (shift, timezone) => {
|
|
54758
|
+
if (!shift?.date) return null;
|
|
54759
|
+
const startTime = shift.startTime || "06:00";
|
|
54760
|
+
const endTime = shift.endTime || "18:00";
|
|
54761
|
+
const startMinutes = parseTimeToMinutes2(startTime);
|
|
54762
|
+
const endMinutes = parseTimeToMinutes2(endTime);
|
|
54763
|
+
if (startMinutes === null || endMinutes === null) return null;
|
|
54764
|
+
const shiftStartDate = dateFnsTz.fromZonedTime(`${shift.date}T${startTime}:00`, timezone);
|
|
54765
|
+
let durationMinutes = endMinutes - startMinutes;
|
|
54766
|
+
if (durationMinutes <= 0) durationMinutes += 24 * 60;
|
|
54767
|
+
return dateFns.addMinutes(shiftStartDate, durationMinutes);
|
|
54768
|
+
};
|
|
54769
|
+
var getMonthDateInfo = (timezone) => {
|
|
54770
|
+
const zonedNow = dateFnsTz.toZonedTime(/* @__PURE__ */ new Date(), timezone);
|
|
54771
|
+
const year = zonedNow.getFullYear();
|
|
54772
|
+
const monthIndex = zonedNow.getMonth();
|
|
54773
|
+
const day = zonedNow.getDate();
|
|
54774
|
+
const startDate = buildDateKey(year, monthIndex, 1);
|
|
54775
|
+
const endDate = buildDateKey(year, monthIndex, day);
|
|
54776
|
+
const lastDay = new Date(year, monthIndex + 1, 0).getDate();
|
|
54777
|
+
const monthEndKey = buildDateKey(year, monthIndex, lastDay);
|
|
54778
|
+
const monthEndDate = dateFnsTz.fromZonedTime(`${monthEndKey}T23:59:59`, timezone);
|
|
54779
|
+
return { startDate, endDate, monthEndDate };
|
|
54780
|
+
};
|
|
54781
|
+
var LeaderboardCountdown = ({ targetDate, format: format7, finishedLabel = "Finished", placeholder = "--", onFinished }) => {
|
|
54782
|
+
const [time2, setTime] = React25.useState("");
|
|
54783
|
+
const hasFinishedRef = React25.useRef(false);
|
|
54784
|
+
React25.useEffect(() => {
|
|
54785
|
+
hasFinishedRef.current = false;
|
|
54786
|
+
}, [targetDate]);
|
|
54787
|
+
React25.useEffect(() => {
|
|
54788
|
+
if (!targetDate) {
|
|
54789
|
+
setTime(placeholder);
|
|
54790
|
+
return;
|
|
54791
|
+
}
|
|
54792
|
+
const tick = () => {
|
|
54793
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
54794
|
+
const diff = targetDate.getTime() - now4.getTime();
|
|
54795
|
+
if (diff <= 0) {
|
|
54796
|
+
setTime(finishedLabel);
|
|
54797
|
+
if (!hasFinishedRef.current && onFinished) {
|
|
54798
|
+
hasFinishedRef.current = true;
|
|
54799
|
+
onFinished();
|
|
54800
|
+
}
|
|
54801
|
+
return;
|
|
54802
|
+
}
|
|
54803
|
+
if (format7 === "days") {
|
|
54804
|
+
const days = Math.floor(diff / (1e3 * 60 * 60 * 24));
|
|
54805
|
+
const hours = Math.floor(diff % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
|
|
54806
|
+
setTime(`${days} days ${hours} hours`);
|
|
54807
|
+
return;
|
|
54808
|
+
}
|
|
54809
|
+
const totalSeconds = Math.floor(diff / 1e3);
|
|
54810
|
+
const h = Math.floor(totalSeconds / 3600);
|
|
54811
|
+
const m = Math.floor(totalSeconds % 3600 / 60);
|
|
54812
|
+
const s = totalSeconds % 60;
|
|
54813
|
+
setTime(`${h.toString().padStart(2, "0")}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`);
|
|
54814
|
+
};
|
|
54815
|
+
tick();
|
|
54816
|
+
const interval = setInterval(tick, 1e3);
|
|
54817
|
+
return () => clearInterval(interval);
|
|
54818
|
+
}, [targetDate, format7, finishedLabel, placeholder, onFinished]);
|
|
54819
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: time2 });
|
|
54820
|
+
};
|
|
54821
|
+
var LinesLeaderboard = ({
|
|
54822
|
+
lines,
|
|
54823
|
+
onLineClick,
|
|
54824
|
+
timeRange,
|
|
54825
|
+
setTimeRange,
|
|
54826
|
+
todayEfficiencyByLineId,
|
|
54827
|
+
monthlyEfficiencyByLineId,
|
|
54828
|
+
supervisorsByLineId,
|
|
54829
|
+
supervisorNamesByLineId,
|
|
54830
|
+
isLoadingToday,
|
|
54831
|
+
isLoadingMonthly,
|
|
54832
|
+
shiftEndDate,
|
|
54833
|
+
monthEndDate
|
|
54834
|
+
}) => {
|
|
54835
|
+
const formatEfficiency = (value) => typeof value === "number" && Number.isFinite(value) ? `${value.toFixed(1)}%` : "--";
|
|
54836
|
+
const handleTimeRangeChange = React25__namespace.default.useCallback((newRange) => {
|
|
54837
|
+
if (newRange === timeRange) return;
|
|
54838
|
+
trackCoreEvent("Leaderboard Time Range Changed", {
|
|
54839
|
+
from_range: timeRange,
|
|
54840
|
+
to_range: newRange,
|
|
54841
|
+
from_page: "leaderboard",
|
|
54842
|
+
lines_count: lines.length,
|
|
54843
|
+
has_monthly_data: monthlyEfficiencyByLineId ? monthlyEfficiencyByLineId.size > 0 : false
|
|
54844
|
+
});
|
|
54845
|
+
setTimeRange(newRange);
|
|
54846
|
+
}, [timeRange, lines.length, monthlyEfficiencyByLineId, setTimeRange]);
|
|
54847
|
+
const handleLeaderboardLineClick = React25__namespace.default.useCallback((item, clickSource) => {
|
|
54848
|
+
trackCoreEvent("Leaderboard Line Clicked", {
|
|
54849
|
+
line_id: item.line.id,
|
|
54850
|
+
line_name: item.line.line_name,
|
|
54851
|
+
rank: item.rank,
|
|
54852
|
+
efficiency: item.efficiency,
|
|
54853
|
+
time_range: timeRange,
|
|
54854
|
+
click_source: clickSource,
|
|
54855
|
+
from_page: "leaderboard",
|
|
54856
|
+
supervisor_name: item.supervisorName || "Unassigned"
|
|
54857
|
+
});
|
|
54858
|
+
onLineClick(item.line);
|
|
54859
|
+
}, [onLineClick, timeRange]);
|
|
54860
|
+
const viewLoadedTrackedRef = React25__namespace.default.useRef(null);
|
|
54861
|
+
const leaderboardData = React25__namespace.default.useMemo(() => {
|
|
54862
|
+
const loading = timeRange === "today" ? isLoadingToday : isLoadingMonthly;
|
|
54863
|
+
const efficiencyMap = timeRange === "today" ? todayEfficiencyByLineId : monthlyEfficiencyByLineId;
|
|
54864
|
+
return lines.map((line) => {
|
|
54865
|
+
const supervisors = supervisorsByLineId?.get(line.id) || [];
|
|
54866
|
+
const primarySupervisor = supervisors[0];
|
|
54867
|
+
const supervisorName = supervisorNamesByLineId.get(line.id) || primarySupervisor?.displayName || "Unassigned";
|
|
54868
|
+
const supervisorImage = primarySupervisor?.profilePhotoUrl || null;
|
|
54869
|
+
const hasEfficiency = efficiencyMap.has(line.id);
|
|
54870
|
+
const efficiency = loading ? null : hasEfficiency ? efficiencyMap.get(line.id) ?? 0 : timeRange === "monthly" ? 0 : null;
|
|
54871
|
+
const sortValue = typeof efficiency === "number" ? efficiency : -1;
|
|
54872
|
+
return {
|
|
54873
|
+
id: line.id,
|
|
54874
|
+
line,
|
|
54875
|
+
supervisorName,
|
|
54876
|
+
supervisorImage,
|
|
54877
|
+
supervisors,
|
|
54878
|
+
efficiency,
|
|
54879
|
+
sortValue
|
|
54880
|
+
};
|
|
54881
|
+
}).sort((a, b) => b.sortValue - a.sortValue).map((item, index) => ({ ...item, rank: index + 1 }));
|
|
54882
|
+
}, [
|
|
54883
|
+
lines,
|
|
54884
|
+
timeRange,
|
|
54885
|
+
todayEfficiencyByLineId,
|
|
54886
|
+
monthlyEfficiencyByLineId,
|
|
54887
|
+
supervisorsByLineId,
|
|
54888
|
+
supervisorNamesByLineId,
|
|
54889
|
+
isLoadingToday,
|
|
54890
|
+
isLoadingMonthly
|
|
54891
|
+
]);
|
|
54892
|
+
React25__namespace.default.useEffect(() => {
|
|
54893
|
+
const isLoading = timeRange === "today" ? isLoadingToday : isLoadingMonthly;
|
|
54894
|
+
const trackingKey = `${timeRange}-${leaderboardData.length}`;
|
|
54895
|
+
if (leaderboardData.length > 0 && !isLoading && viewLoadedTrackedRef.current !== trackingKey) {
|
|
54896
|
+
viewLoadedTrackedRef.current = trackingKey;
|
|
54897
|
+
const topLine = leaderboardData[0];
|
|
54898
|
+
const bottomLine = leaderboardData[leaderboardData.length - 1];
|
|
54899
|
+
trackCoreEvent("Leaderboard View Loaded", {
|
|
54900
|
+
time_range: timeRange,
|
|
54901
|
+
lines_count: leaderboardData.length,
|
|
54902
|
+
top_line_id: topLine?.line.id,
|
|
54903
|
+
top_line_name: topLine?.line.line_name,
|
|
54904
|
+
top_efficiency: topLine?.efficiency,
|
|
54905
|
+
bottom_line_id: bottomLine?.line.id,
|
|
54906
|
+
bottom_line_name: bottomLine?.line.line_name,
|
|
54907
|
+
bottom_efficiency: bottomLine?.efficiency,
|
|
54908
|
+
efficiency_spread: topLine && bottomLine && topLine.efficiency !== null && bottomLine.efficiency !== null ? (topLine.efficiency - bottomLine.efficiency).toFixed(1) : null,
|
|
54909
|
+
from_page: "kpis_overview"
|
|
54910
|
+
});
|
|
54911
|
+
}
|
|
54912
|
+
}, [timeRange, leaderboardData, isLoadingToday, isLoadingMonthly]);
|
|
54913
|
+
const topThree = leaderboardData.slice(0, 3);
|
|
54914
|
+
leaderboardData.slice(3);
|
|
54915
|
+
const countdownTarget = timeRange === "monthly" ? monthEndDate : shiftEndDate;
|
|
54916
|
+
const countdownFormat = timeRange === "monthly" ? "days" : "clock";
|
|
54917
|
+
const countdownFinishedLabel = timeRange === "monthly" ? "Finished" : "Shift Ended";
|
|
54918
|
+
const handleCountdownFinished = React25__namespace.default.useCallback(() => {
|
|
54919
|
+
trackCoreEvent("Leaderboard Countdown Finished", {
|
|
54920
|
+
countdown_type: timeRange === "monthly" ? "month_end" : "shift_end",
|
|
54921
|
+
time_range: timeRange,
|
|
54922
|
+
from_page: "leaderboard"
|
|
54923
|
+
});
|
|
54924
|
+
}, [timeRange]);
|
|
54925
|
+
const podiumOrder = [
|
|
54926
|
+
topThree[1],
|
|
54927
|
+
// 2nd
|
|
54928
|
+
topThree[0],
|
|
54929
|
+
// 1st
|
|
54930
|
+
topThree[2]
|
|
54931
|
+
// 3rd
|
|
54932
|
+
].filter(Boolean);
|
|
54933
|
+
const getRankColor = (rank) => {
|
|
54934
|
+
switch (rank) {
|
|
54935
|
+
case 1:
|
|
54936
|
+
return "from-yellow-50 to-yellow-100 border-yellow-200 text-yellow-800";
|
|
54937
|
+
case 2:
|
|
54938
|
+
return "from-gray-50 to-gray-100 border-gray-200 text-gray-700";
|
|
54939
|
+
case 3:
|
|
54940
|
+
return "from-orange-50 to-orange-100 border-orange-200 text-orange-800";
|
|
54941
|
+
default:
|
|
54942
|
+
return "bg-white border-gray-100";
|
|
54943
|
+
}
|
|
54944
|
+
};
|
|
54945
|
+
React25__namespace.default.useEffect(() => {
|
|
54946
|
+
const style = document.createElement("style");
|
|
54947
|
+
style.innerHTML = `
|
|
54948
|
+
@keyframes float {
|
|
54949
|
+
0% { transform: translateY(0px); }
|
|
54950
|
+
50% { transform: translateY(-8px); }
|
|
54951
|
+
100% { transform: translateY(0px); }
|
|
54952
|
+
}
|
|
54953
|
+
.animate-float-slow {
|
|
54954
|
+
animation: float 4s ease-in-out infinite;
|
|
54955
|
+
}
|
|
54956
|
+
.animate-float-medium {
|
|
54957
|
+
animation: float 3.5s ease-in-out infinite;
|
|
54958
|
+
animation-delay: 0.5s;
|
|
54959
|
+
}
|
|
54960
|
+
.animate-float-fast {
|
|
54961
|
+
animation: float 3s ease-in-out infinite;
|
|
54962
|
+
animation-delay: 1s;
|
|
54963
|
+
}
|
|
54964
|
+
`;
|
|
54965
|
+
document.head.appendChild(style);
|
|
54966
|
+
return () => {
|
|
54967
|
+
document.head.removeChild(style);
|
|
54968
|
+
};
|
|
54969
|
+
}, []);
|
|
54970
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full gap-4", children: [
|
|
54971
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-[70%] min-h-0", children: [
|
|
54972
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-none relative flex flex-col md:flex-row justify-center items-center gap-4 pt-2", children: [
|
|
54973
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex bg-gray-100/80 p-1 rounded-xl z-0", children: [
|
|
54974
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
54975
|
+
"button",
|
|
54976
|
+
{
|
|
54977
|
+
onClick: () => handleTimeRangeChange("today"),
|
|
54978
|
+
className: `px-8 py-2.5 text-sm font-bold rounded-lg transition-all duration-200 ${timeRange === "today" ? "bg-white text-slate-900 shadow-md ring-1 ring-black/5" : "text-slate-500 hover:text-slate-700"}`,
|
|
54979
|
+
children: "Daily"
|
|
54980
|
+
}
|
|
54981
|
+
),
|
|
54982
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
54983
|
+
"button",
|
|
54984
|
+
{
|
|
54985
|
+
onClick: () => handleTimeRangeChange("monthly"),
|
|
54986
|
+
className: `px-8 py-2.5 text-sm font-bold rounded-lg transition-all duration-200 ${timeRange === "monthly" ? "bg-white text-slate-900 shadow-md ring-1 ring-black/5" : "text-slate-500 hover:text-slate-700"}`,
|
|
54987
|
+
children: "Monthly"
|
|
54988
|
+
}
|
|
54989
|
+
)
|
|
54990
|
+
] }),
|
|
54991
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:absolute md:right-0 md:top-1/2 md:-translate-y-1/2 flex items-center gap-2.5 px-4 py-2 bg-white rounded-full shadow-sm border border-gray-100", children: [
|
|
54992
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "w-4 h-4 text-orange-500" }),
|
|
54993
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [
|
|
54994
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider", children: "Ends in" }),
|
|
54995
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-bold text-gray-900 tabular-nums tracking-tight font-mono", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
54996
|
+
LeaderboardCountdown,
|
|
54997
|
+
{
|
|
54998
|
+
targetDate: countdownTarget,
|
|
54999
|
+
format: countdownFormat,
|
|
55000
|
+
finishedLabel: countdownFinishedLabel,
|
|
55001
|
+
placeholder: timeRange === "monthly" ? "--" : "--:--:--",
|
|
55002
|
+
onFinished: handleCountdownFinished
|
|
55003
|
+
}
|
|
55004
|
+
) })
|
|
55005
|
+
] })
|
|
55006
|
+
] })
|
|
55007
|
+
] }),
|
|
55008
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 hidden sm:flex justify-center items-end gap-2 md:gap-4 lg:gap-6 xl:gap-10 pb-4 pt-4 min-h-0", children: podiumOrder.map((item, index) => {
|
|
55009
|
+
if (!item) return null;
|
|
55010
|
+
const isFirst = item.rank === 1;
|
|
55011
|
+
const isSecond = item.rank === 2;
|
|
55012
|
+
item.rank === 3;
|
|
55013
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
55014
|
+
"div",
|
|
55015
|
+
{
|
|
55016
|
+
onClick: () => handleLeaderboardLineClick(item, "podium"),
|
|
55017
|
+
className: `relative flex flex-col items-center cursor-pointer z-10 transition-transform hover:scale-105`,
|
|
55018
|
+
children: [
|
|
55019
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative -mb-4 z-20 ${isFirst ? "animate-float-slow" : isSecond ? "animate-float-medium" : "animate-float-fast"}`, children: [
|
|
55020
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute inset-0 rounded-full blur-xl opacity-40 ${isFirst ? "bg-yellow-400" : isSecond ? "bg-gray-400" : "bg-orange-400"}` }),
|
|
55021
|
+
item.supervisors && item.supervisors.length > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
55022
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex -space-x-3 md:-space-x-4", children: [
|
|
55023
|
+
item.supervisors.slice(0, 3).map((supervisor) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
55024
|
+
"div",
|
|
55025
|
+
{
|
|
55026
|
+
className: "relative inline-block w-10 h-10 md:w-12 md:h-12 lg:w-14 lg:h-14 xl:w-16 xl:h-16 rounded-full ring-2 ring-white bg-white shadow-sm z-0 hover:z-10 transition-all hover:scale-110 overflow-hidden",
|
|
55027
|
+
children: supervisor.profilePhotoUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
55028
|
+
"img",
|
|
55029
|
+
{
|
|
55030
|
+
src: supervisor.profilePhotoUrl,
|
|
55031
|
+
alt: supervisor.displayName,
|
|
55032
|
+
className: "w-full h-full object-cover rounded-full"
|
|
55033
|
+
}
|
|
55034
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs md:text-sm lg:text-base font-bold text-gray-600 uppercase", children: getInitials(supervisor.displayName) }) })
|
|
55035
|
+
},
|
|
55036
|
+
supervisor.userId
|
|
55037
|
+
)),
|
|
55038
|
+
item.supervisors.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-10 h-10 md:w-12 md:h-12 lg:w-14 lg:h-14 xl:w-16 xl:h-16 rounded-full ring-2 ring-white bg-gray-100 items-center justify-center text-xs md:text-sm font-medium text-gray-600 z-0", children: [
|
|
55039
|
+
"+",
|
|
55040
|
+
item.supervisors.length - 3
|
|
55041
|
+
] })
|
|
55042
|
+
] }),
|
|
55043
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute -bottom-2 md:-bottom-3 left-1/2 -translate-x-1/2 w-6 h-6 md:w-8 md:h-8 xl:w-10 xl:h-10 rounded-full flex items-center justify-center text-[10px] md:text-xs lg:text-sm xl:text-base font-extrabold text-white shadow-lg ${isFirst ? "bg-gradient-to-br from-yellow-400 to-yellow-600 ring-2 md:ring-4 ring-yellow-50" : isSecond ? "bg-gradient-to-br from-gray-400 to-gray-600 ring-2 md:ring-4 ring-gray-50" : "bg-gradient-to-br from-orange-400 to-orange-600 ring-2 md:ring-4 ring-orange-50"}`, children: item.rank })
|
|
55044
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative rounded-full p-1.5 bg-gradient-to-br ${isFirst ? "from-yellow-300 via-yellow-400 to-yellow-600 shadow-yellow-500/50" : isSecond ? "from-gray-300 via-gray-400 to-gray-500 shadow-gray-500/50" : "from-orange-300 via-orange-400 to-orange-600 shadow-orange-500/50"} shadow-xl`, children: [
|
|
55045
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-12 h-12 md:w-16 md:h-16 lg:w-20 lg:h-20 xl:w-24 xl:h-24 rounded-full bg-white flex items-center justify-center overflow-hidden border-2 border-white/50", children: item.supervisorImage ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: item.supervisorImage, alt: item.supervisorName, className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-base md:text-lg lg:text-xl xl:text-2xl font-bold ${isFirst ? "text-yellow-600" : isSecond ? "text-gray-600" : "text-orange-600"}`, children: getInitials(item.supervisorName) }) }) }),
|
|
55046
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `absolute -bottom-2 md:-bottom-3 left-1/2 -translate-x-1/2 w-6 h-6 md:w-8 md:h-8 xl:w-10 xl:h-10 rounded-full flex items-center justify-center text-[10px] md:text-xs lg:text-sm xl:text-base font-extrabold text-white shadow-lg ${isFirst ? "bg-gradient-to-br from-yellow-400 to-yellow-600 ring-2 md:ring-4 ring-yellow-50" : isSecond ? "bg-gradient-to-br from-gray-400 to-gray-600 ring-2 md:ring-4 ring-gray-50" : "bg-gradient-to-br from-orange-400 to-orange-600 ring-2 md:ring-4 ring-orange-50"}`, children: item.rank })
|
|
55047
|
+
] })
|
|
55048
|
+
] }),
|
|
55049
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
55050
|
+
"div",
|
|
55051
|
+
{
|
|
55052
|
+
className: `flex flex-col items-center w-32 md:w-40 lg:w-48 xl:w-60 px-2 md:px-3 xl:px-4 pb-3 md:pb-4 pt-8 md:pt-10 rounded-2xl border bg-gradient-to-b shadow-2xl backdrop-blur-sm ${getRankColor(item.rank)} ${isFirst ? "h-44 md:h-52 lg:h-60 xl:h-64" : isSecond ? "h-36 md:h-44 lg:h-52 xl:h-56" : "h-28 md:h-36 lg:h-44 xl:h-48"}`,
|
|
55053
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center w-full", children: [
|
|
55054
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: `font-bold text-gray-900 text-center line-clamp-1 mb-1 ${isFirst ? "text-xs md:text-sm lg:text-base xl:text-lg" : "text-[10px] md:text-xs lg:text-sm xl:text-base"}`, children: item.supervisorName }),
|
|
55055
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-gray-600 text-center line-clamp-1 font-medium opacity-80 bg-white/50 px-2 md:px-3 py-0.5 rounded-full ${isFirst ? "text-[9px] md:text-[10px] lg:text-xs xl:text-sm mb-2 md:mb-3" : "text-[8px] md:text-[9px] lg:text-[10px] xl:text-xs mb-1 md:mb-2"}`, children: item.line.line_name }),
|
|
55056
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center mt-auto", children: [
|
|
55057
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `font-bold uppercase tracking-widest mb-0.5 ${isFirst ? "text-yellow-700/70 text-[8px] md:text-[9px] lg:text-[10px] xl:text-xs" : isSecond ? "text-gray-600/70 text-[7px] md:text-[8px] lg:text-[9px] xl:text-[10px]" : "text-orange-700/70 text-[7px] md:text-[8px] lg:text-[9px] xl:text-[10px]"}`, children: "Efficiency" }),
|
|
55058
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `font-black tracking-tight leading-none ${isFirst ? "text-lg md:text-xl lg:text-2xl xl:text-3xl text-transparent bg-clip-text bg-gradient-to-br from-yellow-600 to-yellow-800 drop-shadow-sm" : isSecond ? "text-base md:text-lg lg:text-xl xl:text-2xl text-transparent bg-clip-text bg-gradient-to-br from-gray-600 to-gray-800 drop-shadow-sm" : "text-sm md:text-base lg:text-lg xl:text-xl text-transparent bg-clip-text bg-gradient-to-br from-orange-600 to-orange-800 drop-shadow-sm"}`, children: formatEfficiency(item.efficiency) })
|
|
55059
|
+
] })
|
|
55060
|
+
] })
|
|
55061
|
+
}
|
|
55062
|
+
)
|
|
55063
|
+
]
|
|
55064
|
+
},
|
|
55065
|
+
item.id
|
|
55066
|
+
);
|
|
55067
|
+
}) })
|
|
55068
|
+
] }),
|
|
55069
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-none h-[30%] min-h-0 flex flex-col", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden h-full flex flex-col", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-auto flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse", children: [
|
|
55070
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-gray-50 border-b border-gray-200 sticky top-0 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
55071
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider w-16", children: "Rank" }),
|
|
55072
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider", children: "Assigned To" }),
|
|
55073
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider", children: "Line" }),
|
|
55074
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-right text-xs font-semibold text-gray-500 uppercase tracking-wider", children: "Efficiency" })
|
|
55075
|
+
] }) }),
|
|
55076
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-gray-100", children: leaderboardData.map((item) => {
|
|
55077
|
+
const isTopThree = item.rank <= 3;
|
|
55078
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
55079
|
+
"tr",
|
|
55080
|
+
{
|
|
55081
|
+
onClick: () => handleLeaderboardLineClick(item, isTopThree ? "podium" : "table"),
|
|
55082
|
+
className: `hover:bg-gray-50 transition-colors cursor-pointer group ${isTopThree ? "sm:hidden" : ""}`,
|
|
55083
|
+
children: [
|
|
55084
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center w-8 h-8 rounded-full bg-gray-100 text-gray-600 font-bold text-sm", children: item.rank }) }),
|
|
55085
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
55086
|
+
item.supervisors && item.supervisors.length > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex -space-x-2", children: [
|
|
55087
|
+
item.supervisors.slice(0, 3).map((supervisor) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
55088
|
+
"div",
|
|
55089
|
+
{
|
|
55090
|
+
className: "relative inline-block w-7 h-7 rounded-full ring-2 ring-white bg-white shadow-sm overflow-hidden",
|
|
55091
|
+
children: supervisor.profilePhotoUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
55092
|
+
"img",
|
|
55093
|
+
{
|
|
55094
|
+
src: supervisor.profilePhotoUrl,
|
|
55095
|
+
alt: supervisor.displayName,
|
|
55096
|
+
className: "w-full h-full object-cover rounded-full"
|
|
55097
|
+
}
|
|
55098
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gray-100 text-[10px] font-bold text-gray-600 uppercase rounded-full", children: getInitials(supervisor.displayName) })
|
|
55099
|
+
},
|
|
55100
|
+
supervisor.userId
|
|
55101
|
+
)),
|
|
55102
|
+
item.supervisors.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-7 h-7 rounded-full ring-2 ring-white bg-gray-100 items-center justify-center text-[10px] font-medium text-gray-600", children: [
|
|
55103
|
+
"+",
|
|
55104
|
+
item.supervisors.length - 3
|
|
55105
|
+
] })
|
|
55106
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center text-gray-500 overflow-hidden border border-gray-200 flex-shrink-0", children: item.supervisorImage ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: item.supervisorImage, alt: item.supervisorName, className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-bold", children: getInitials(item.supervisorName) }) }),
|
|
55107
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-900", children: item.supervisorName })
|
|
55108
|
+
] }) }),
|
|
55109
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 whitespace-nowrap text-sm text-gray-500", children: item.line.line_name }),
|
|
55110
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 whitespace-nowrap text-right", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-end", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-bold text-gray-900", children: formatEfficiency(item.efficiency) }) }) })
|
|
55111
|
+
]
|
|
55112
|
+
},
|
|
55113
|
+
item.id
|
|
55114
|
+
);
|
|
55115
|
+
}) })
|
|
55116
|
+
] }) }) }) })
|
|
55117
|
+
] });
|
|
55118
|
+
};
|
|
54575
55119
|
var LineCard = ({
|
|
54576
55120
|
line,
|
|
54577
55121
|
kpis,
|
|
@@ -54730,6 +55274,8 @@ var KPIsOverviewView = ({
|
|
|
54730
55274
|
lineIds
|
|
54731
55275
|
}) => {
|
|
54732
55276
|
const [lines, setLines] = React25.useState([]);
|
|
55277
|
+
const [activeTab, setActiveTab] = React25.useState("today");
|
|
55278
|
+
const [timeRange, setTimeRange] = React25.useState("today");
|
|
54733
55279
|
const [loading, setLoading] = React25.useState(true);
|
|
54734
55280
|
const [error, setError] = React25.useState(null);
|
|
54735
55281
|
const [topPerformer, setTopPerformer] = React25.useState({
|
|
@@ -54743,6 +55289,10 @@ var KPIsOverviewView = ({
|
|
|
54743
55289
|
});
|
|
54744
55290
|
const [topPerformerLoading, setTopPerformerLoading] = React25.useState(true);
|
|
54745
55291
|
const [topPerformerImageError, setTopPerformerImageError] = React25.useState(false);
|
|
55292
|
+
const [monthlyEfficiencyByLineId, setMonthlyEfficiencyByLineId] = React25.useState(/* @__PURE__ */ new Map());
|
|
55293
|
+
const [monthlyLoading, setMonthlyLoading] = React25.useState(false);
|
|
55294
|
+
const [monthlyError, setMonthlyError] = React25.useState(null);
|
|
55295
|
+
const monthlyRequestKeyRef = React25.useRef(null);
|
|
54746
55296
|
const supabase = useSupabase();
|
|
54747
55297
|
const dashboardConfig = useDashboardConfig();
|
|
54748
55298
|
const entityConfig = useEntityConfig();
|
|
@@ -54757,6 +55307,7 @@ var KPIsOverviewView = ({
|
|
|
54757
55307
|
const supervisorEnabled = dashboardConfig?.supervisorConfig?.enabled || false;
|
|
54758
55308
|
const dbTimezone = useAppTimezone();
|
|
54759
55309
|
const configuredTimezone = dbTimezone || dateTimeConfig.defaultTimezone || "UTC";
|
|
55310
|
+
const { startDate: monthStartDate, endDate: monthEndDateKey, monthEndDate } = getMonthDateInfo(configuredTimezone);
|
|
54760
55311
|
const factoryViewId = entityConfig.factoryViewId || "factory";
|
|
54761
55312
|
const {
|
|
54762
55313
|
lineMetrics,
|
|
@@ -54774,6 +55325,16 @@ var KPIsOverviewView = ({
|
|
|
54774
55325
|
});
|
|
54775
55326
|
return map;
|
|
54776
55327
|
}, [lineMetrics]);
|
|
55328
|
+
const todayEfficiencyByLineId = React25__namespace.default.useMemo(() => {
|
|
55329
|
+
const map = /* @__PURE__ */ new Map();
|
|
55330
|
+
kpisByLineId.forEach((kpis, lineId) => {
|
|
55331
|
+
const value = kpis?.efficiency?.value;
|
|
55332
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
55333
|
+
map.set(lineId, value);
|
|
55334
|
+
}
|
|
55335
|
+
});
|
|
55336
|
+
return map;
|
|
55337
|
+
}, [kpisByLineId]);
|
|
54777
55338
|
const visibleLineIds = React25__namespace.default.useMemo(() => lines.map((l) => l.id), [lines]);
|
|
54778
55339
|
const { supervisorNamesByLineId, supervisorsByLineId, allSupervisorsMap } = useSupervisorsByLineIds(visibleLineIds, {
|
|
54779
55340
|
enabled: supervisorEnabled && visibleLineIds.length > 0
|
|
@@ -54837,6 +55398,61 @@ var KPIsOverviewView = ({
|
|
|
54837
55398
|
};
|
|
54838
55399
|
fetchLines();
|
|
54839
55400
|
}, [supabase, dashboardConfig, lineIds]);
|
|
55401
|
+
const fetchMonthlyLeaderboard = React25.useCallback(async () => {
|
|
55402
|
+
if (!supabase || !resolvedCompanyId || lines.length === 0) return;
|
|
55403
|
+
const targetLineIds = lines.map((line) => line.id);
|
|
55404
|
+
const lineIdsKey = targetLineIds.slice().sort().join(",");
|
|
55405
|
+
const requestKey = `${resolvedCompanyId}|${monthStartDate}|${monthEndDateKey}|${lineIdsKey}`;
|
|
55406
|
+
if (monthlyRequestKeyRef.current === requestKey) return;
|
|
55407
|
+
monthlyRequestKeyRef.current = requestKey;
|
|
55408
|
+
setMonthlyLoading(true);
|
|
55409
|
+
setMonthlyError(null);
|
|
55410
|
+
const fetchStartTime = Date.now();
|
|
55411
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
55412
|
+
const currentMonth = (/* @__PURE__ */ new Date()).getMonth() + 1;
|
|
55413
|
+
try {
|
|
55414
|
+
const entries = await lineLeaderboardService.getLineLeaderboard(supabase, {
|
|
55415
|
+
companyId: resolvedCompanyId,
|
|
55416
|
+
startDate: monthStartDate,
|
|
55417
|
+
endDate: monthEndDateKey,
|
|
55418
|
+
lineIds: targetLineIds
|
|
55419
|
+
});
|
|
55420
|
+
const nextMap = /* @__PURE__ */ new Map();
|
|
55421
|
+
targetLineIds.forEach((lineId) => nextMap.set(lineId, 0));
|
|
55422
|
+
entries.forEach((entry) => {
|
|
55423
|
+
const value = Number(entry.avg_efficiency);
|
|
55424
|
+
nextMap.set(entry.line_id, Number.isFinite(value) ? value : 0);
|
|
55425
|
+
});
|
|
55426
|
+
setMonthlyEfficiencyByLineId(nextMap);
|
|
55427
|
+
trackCoreEvent("Leaderboard Monthly Data Fetched", {
|
|
55428
|
+
success: true,
|
|
55429
|
+
lines_count: entries.length,
|
|
55430
|
+
fetch_duration_ms: Date.now() - fetchStartTime,
|
|
55431
|
+
year: currentYear,
|
|
55432
|
+
month: currentMonth,
|
|
55433
|
+
has_data: entries.length > 0,
|
|
55434
|
+
from_page: "leaderboard"
|
|
55435
|
+
});
|
|
55436
|
+
} catch (err) {
|
|
55437
|
+
console.error("[KPIsOverviewView] Failed to load monthly leaderboard:", err);
|
|
55438
|
+
setMonthlyError("Failed to load monthly leaderboard");
|
|
55439
|
+
monthlyRequestKeyRef.current = null;
|
|
55440
|
+
trackCoreEvent("Leaderboard Monthly Data Fetched", {
|
|
55441
|
+
success: false,
|
|
55442
|
+
error_message: err instanceof Error ? err.message : "Unknown error",
|
|
55443
|
+
fetch_duration_ms: Date.now() - fetchStartTime,
|
|
55444
|
+
year: currentYear,
|
|
55445
|
+
month: currentMonth,
|
|
55446
|
+
from_page: "leaderboard"
|
|
55447
|
+
});
|
|
55448
|
+
} finally {
|
|
55449
|
+
setMonthlyLoading(false);
|
|
55450
|
+
}
|
|
55451
|
+
}, [supabase, resolvedCompanyId, lines, monthStartDate, monthEndDateKey]);
|
|
55452
|
+
React25.useEffect(() => {
|
|
55453
|
+
if (activeTab !== "leaderboard") return;
|
|
55454
|
+
fetchMonthlyLeaderboard();
|
|
55455
|
+
}, [activeTab, timeRange, fetchMonthlyLeaderboard]);
|
|
54840
55456
|
const formatTopPerformerWeek = (periodStart, periodEnd) => {
|
|
54841
55457
|
if (!periodStart || !periodEnd) return "Last Week";
|
|
54842
55458
|
const startDate = /* @__PURE__ */ new Date(`${periodStart}T00:00:00`);
|
|
@@ -54847,6 +55463,21 @@ var KPIsOverviewView = ({
|
|
|
54847
55463
|
return `${startLabel} - ${endLabel}`;
|
|
54848
55464
|
};
|
|
54849
55465
|
const buildTopPerformerDisplay = (record) => {
|
|
55466
|
+
const supervisorAvatars = [];
|
|
55467
|
+
if (record.supervisors && record.supervisors.length > 0) {
|
|
55468
|
+
for (const s of record.supervisors) {
|
|
55469
|
+
let supervisorName = "Supervisor";
|
|
55470
|
+
if (s.first_name) {
|
|
55471
|
+
supervisorName = s.last_name ? `${s.first_name} ${s.last_name}` : s.first_name;
|
|
55472
|
+
}
|
|
55473
|
+
supervisorAvatars.push({
|
|
55474
|
+
userId: s.user_id,
|
|
55475
|
+
name: supervisorName,
|
|
55476
|
+
imageUrl: s.profile_photo_url || null,
|
|
55477
|
+
initials: getInitials(supervisorName)
|
|
55478
|
+
});
|
|
55479
|
+
}
|
|
55480
|
+
}
|
|
54850
55481
|
let displayName = record.recipient_name || "Supervisor";
|
|
54851
55482
|
if (record.first_name) {
|
|
54852
55483
|
displayName = record.last_name ? `${record.first_name} ${record.last_name}` : record.first_name;
|
|
@@ -54865,16 +55496,26 @@ var KPIsOverviewView = ({
|
|
|
54865
55496
|
displayName = parts[0].charAt(0).toUpperCase() + parts[0].slice(1);
|
|
54866
55497
|
}
|
|
54867
55498
|
}
|
|
55499
|
+
if (supervisorAvatars.length === 0 && record.recipient_user_id) {
|
|
55500
|
+
supervisorAvatars.push({
|
|
55501
|
+
userId: record.recipient_user_id,
|
|
55502
|
+
name: displayName,
|
|
55503
|
+
imageUrl: record.profile_photo_url || null,
|
|
55504
|
+
initials: getInitials(displayName)
|
|
55505
|
+
});
|
|
55506
|
+
}
|
|
54868
55507
|
const efficiencyValue = typeof record.avg_efficiency === "number" ? record.avg_efficiency : Number.parseFloat(String(record.avg_efficiency));
|
|
54869
55508
|
const efficiency = Number.isFinite(efficiencyValue) ? efficiencyValue : null;
|
|
55509
|
+
const unitLabel = record.winning_line_name || record.unit || "Line";
|
|
54870
55510
|
return {
|
|
54871
55511
|
name: displayName,
|
|
54872
55512
|
role: "Sup.",
|
|
54873
|
-
unit:
|
|
55513
|
+
unit: unitLabel,
|
|
54874
55514
|
periodLabel: formatTopPerformerWeek(record.period_start, record.period_end),
|
|
54875
55515
|
efficiency,
|
|
54876
55516
|
imageUrl: record.profile_photo_url || null,
|
|
54877
|
-
initials: getInitials(displayName)
|
|
55517
|
+
initials: getInitials(displayName),
|
|
55518
|
+
supervisors: supervisorAvatars.length > 0 ? supervisorAvatars : void 0
|
|
54878
55519
|
};
|
|
54879
55520
|
};
|
|
54880
55521
|
const handleLineClick = (line, kpis) => {
|
|
@@ -54905,6 +55546,16 @@ var KPIsOverviewView = ({
|
|
|
54905
55546
|
navigation.navigate("/");
|
|
54906
55547
|
}
|
|
54907
55548
|
}, [onBackClick, backLinkUrl, navigation]);
|
|
55549
|
+
const handleTabChange = React25.useCallback((newTab) => {
|
|
55550
|
+
if (newTab === activeTab) return;
|
|
55551
|
+
trackCoreEvent("Leaderboard Tab Switched", {
|
|
55552
|
+
from_tab: activeTab,
|
|
55553
|
+
to_tab: newTab,
|
|
55554
|
+
from_page: "kpis_overview",
|
|
55555
|
+
lines_count: lines.length
|
|
55556
|
+
});
|
|
55557
|
+
setActiveTab(newTab);
|
|
55558
|
+
}, [activeTab, lines.length]);
|
|
54908
55559
|
const formatLocalDate2 = (date) => {
|
|
54909
55560
|
const options = {
|
|
54910
55561
|
year: "numeric",
|
|
@@ -54913,7 +55564,20 @@ var KPIsOverviewView = ({
|
|
|
54913
55564
|
};
|
|
54914
55565
|
return date.toLocaleDateString("en-US", options);
|
|
54915
55566
|
};
|
|
55567
|
+
const getMonthRange = () => {
|
|
55568
|
+
const now4 = /* @__PURE__ */ new Date();
|
|
55569
|
+
const startOfMonth2 = new Date(now4.getFullYear(), now4.getMonth(), 1);
|
|
55570
|
+
const endOfMonth2 = new Date(now4.getFullYear(), now4.getMonth() + 1, 0);
|
|
55571
|
+
const startLabel = startOfMonth2.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
55572
|
+
const endLabel = endOfMonth2.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
55573
|
+
return `${startLabel} - ${endLabel}, ${now4.getFullYear()}`;
|
|
55574
|
+
};
|
|
55575
|
+
const isMonthlyMode = activeTab === "leaderboard" && timeRange === "monthly";
|
|
54916
55576
|
const currentShiftDetails = getCurrentShift(configuredTimezone, shiftConfig);
|
|
55577
|
+
const shiftEndDate = React25__namespace.default.useMemo(
|
|
55578
|
+
() => getShiftEndDate(currentShiftDetails, configuredTimezone),
|
|
55579
|
+
[currentShiftDetails, configuredTimezone]
|
|
55580
|
+
);
|
|
54917
55581
|
const shiftName = (currentShiftDetails.shiftName || "Day").replace(/ Shift$/i, "");
|
|
54918
55582
|
const showTopPerformerImage = Boolean(topPerformer.imageUrl) && !topPerformerImageError;
|
|
54919
55583
|
typeof topPerformer.efficiency === "number" && Number.isFinite(topPerformer.efficiency);
|
|
@@ -55021,29 +55685,61 @@ var KPIsOverviewView = ({
|
|
|
55021
55685
|
}
|
|
55022
55686
|
),
|
|
55023
55687
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
55024
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900", children: "Overview" }),
|
|
55688
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-gray-900", children: activeTab === "leaderboard" ? "Leaderboard" : "Overview" }),
|
|
55025
55689
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-emerald-500 animate-pulse ring-2 ring-emerald-500/20" })
|
|
55026
55690
|
] }) }),
|
|
55027
55691
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-12" })
|
|
55028
55692
|
] }),
|
|
55029
55693
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-center gap-2", children: [
|
|
55030
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className:
|
|
55031
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
55032
|
-
/* @__PURE__ */ jsxRuntime.
|
|
55033
|
-
|
|
55034
|
-
|
|
55035
|
-
|
|
55694
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `inline-flex items-center bg-gray-100 rounded-full ${isMonthlyMode ? "px-4 py-1.5 ring-1 ring-gray-200 shadow-sm" : "px-2.5 py-1"}`, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `font-medium text-gray-700 ${isMonthlyMode ? "text-sm" : "text-xs"}`, children: isMonthlyMode ? getMonthRange() : formatLocalDate2(/* @__PURE__ */ new Date()) }) }),
|
|
55695
|
+
!isMonthlyMode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
55696
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-gray-100 rounded-full", children: [
|
|
55697
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-700 scale-90", children: getShiftIcon(currentShiftDetails.shiftId) }),
|
|
55698
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-gray-700", children: shiftName })
|
|
55699
|
+
] }),
|
|
55700
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center px-2.5 py-1 bg-green-100 rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-green-700", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) }) })
|
|
55701
|
+
] })
|
|
55036
55702
|
] }),
|
|
55037
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 bg-white shadow-md hover:shadow-lg transition-all duration-300 ease-out hover:scale-[1.01] relative rounded-2xl border border-amber-100 pl-2 pr-4 py-1.5 flex items-center justify-between group", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 min-w-0", children: [
|
|
55038
|
-
/* @__PURE__ */ jsxRuntime.
|
|
55039
|
-
"
|
|
55040
|
-
|
|
55041
|
-
|
|
55042
|
-
|
|
55043
|
-
|
|
55044
|
-
|
|
55045
|
-
|
|
55046
|
-
|
|
55703
|
+
activeTab !== "leaderboard" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 bg-white shadow-md hover:shadow-lg transition-all duration-300 ease-out hover:scale-[1.01] relative rounded-2xl border border-amber-100 pl-2 pr-4 py-1.5 flex items-center justify-between group", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 min-w-0", children: [
|
|
55704
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-shrink-0", children: [
|
|
55705
|
+
(!topPerformer.supervisors || topPerformer.supervisors.length <= 1) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-full border-2 border-amber-100 overflow-hidden bg-amber-50 shadow-sm transition-transform group-hover:scale-105", children: showTopPerformerImage ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
55706
|
+
"img",
|
|
55707
|
+
{
|
|
55708
|
+
src: topPerformer.imageUrl || "",
|
|
55709
|
+
alt: "Top Performer",
|
|
55710
|
+
className: "w-full h-full object-cover",
|
|
55711
|
+
onError: () => setTopPerformerImageError(true)
|
|
55712
|
+
}
|
|
55713
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-amber-50 text-sm font-bold text-amber-600", children: topPerformer.initials }) }),
|
|
55714
|
+
topPerformer.supervisors && topPerformer.supervisors.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex -space-x-2", children: [
|
|
55715
|
+
topPerformer.supervisors.slice(0, 3).map((supervisor, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
55716
|
+
"div",
|
|
55717
|
+
{
|
|
55718
|
+
className: "relative inline-block w-9 h-9 rounded-full ring-2 ring-white bg-amber-50 shadow-sm z-0 hover:z-10 transition-all hover:scale-110 group/avatar",
|
|
55719
|
+
style: { zIndex: 3 - idx },
|
|
55720
|
+
children: [
|
|
55721
|
+
supervisor.imageUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
55722
|
+
"img",
|
|
55723
|
+
{
|
|
55724
|
+
src: supervisor.imageUrl,
|
|
55725
|
+
alt: supervisor.name,
|
|
55726
|
+
className: "w-full h-full object-cover rounded-full"
|
|
55727
|
+
}
|
|
55728
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-xs font-bold text-amber-600 uppercase rounded-full", children: supervisor.initials }),
|
|
55729
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-gray-900 text-white text-[10px] font-medium rounded shadow-lg opacity-0 group-hover/avatar:opacity-100 transition-opacity whitespace-nowrap pointer-events-none z-20", children: [
|
|
55730
|
+
supervisor.name,
|
|
55731
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 -mt-[1px] border-4 border-transparent border-t-gray-900" })
|
|
55732
|
+
] })
|
|
55733
|
+
]
|
|
55734
|
+
},
|
|
55735
|
+
supervisor.userId
|
|
55736
|
+
)),
|
|
55737
|
+
topPerformer.supervisors.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-9 h-9 rounded-full ring-2 ring-white bg-amber-100 items-center justify-center text-xs font-medium text-amber-700 z-0", children: [
|
|
55738
|
+
"+",
|
|
55739
|
+
topPerformer.supervisors.length - 3
|
|
55740
|
+
] })
|
|
55741
|
+
] })
|
|
55742
|
+
] }),
|
|
55047
55743
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
55048
55744
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 leading-none mb-1", children: [
|
|
55049
55745
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-amber-600 uppercase tracking-widest", children: "Performer of the week" }),
|
|
@@ -55069,6 +55765,24 @@ var KPIsOverviewView = ({
|
|
|
55069
55765
|
) })
|
|
55070
55766
|
] })
|
|
55071
55767
|
] })
|
|
55768
|
+
] }) }),
|
|
55769
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex bg-gray-100/80 p-1 rounded-xl w-full", children: [
|
|
55770
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
55771
|
+
"button",
|
|
55772
|
+
{
|
|
55773
|
+
onClick: () => handleTabChange("today"),
|
|
55774
|
+
className: `flex-1 py-2 text-xs font-medium rounded-lg transition-all duration-200 ${activeTab === "today" ? "bg-white text-blue-600 shadow-sm ring-1 ring-black/5" : "text-gray-600 hover:text-gray-900"}`,
|
|
55775
|
+
children: "Overview"
|
|
55776
|
+
}
|
|
55777
|
+
),
|
|
55778
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
55779
|
+
"button",
|
|
55780
|
+
{
|
|
55781
|
+
onClick: () => handleTabChange("leaderboard"),
|
|
55782
|
+
className: `flex-1 py-2 text-xs font-medium rounded-lg transition-all duration-200 ${activeTab === "leaderboard" ? "bg-white text-blue-600 shadow-sm ring-1 ring-black/5" : "text-gray-600 hover:text-gray-900"}`,
|
|
55783
|
+
children: "Leaderboard"
|
|
55784
|
+
}
|
|
55785
|
+
)
|
|
55072
55786
|
] }) })
|
|
55073
55787
|
] }),
|
|
55074
55788
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden sm:block", children: [
|
|
@@ -55083,19 +55797,49 @@ var KPIsOverviewView = ({
|
|
|
55083
55797
|
}
|
|
55084
55798
|
) }),
|
|
55085
55799
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
55086
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight", children: "Overview" }),
|
|
55800
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl md:text-3xl lg:text-4xl font-semibold text-gray-900 tracking-tight", children: activeTab === "leaderboard" ? "Leaderboard" : "Overview" }),
|
|
55087
55801
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2.5 w-2.5 rounded-full bg-emerald-500 animate-pulse ring-4 ring-emerald-500/10 flex-shrink-0" })
|
|
55088
55802
|
] }),
|
|
55089
|
-
!topPerformerLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-2xl border border-amber-200 shadow-md pl-1.5 pr-4 py-1.5 flex items-center gap-4 transition-all hover:shadow-lg hover:border-amber-300 group", children: [
|
|
55090
|
-
/* @__PURE__ */ jsxRuntime.
|
|
55091
|
-
"
|
|
55092
|
-
|
|
55093
|
-
|
|
55094
|
-
|
|
55095
|
-
|
|
55096
|
-
|
|
55097
|
-
|
|
55098
|
-
|
|
55803
|
+
!topPerformerLoading && activeTab !== "leaderboard" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-2xl border border-amber-200 shadow-md pl-1.5 pr-4 py-1.5 flex items-center gap-4 transition-all hover:shadow-lg hover:border-amber-300 group", children: [
|
|
55804
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
55805
|
+
(!topPerformer.supervisors || topPerformer.supervisors.length <= 1) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-full ring-2 ring-amber-100 overflow-hidden bg-amber-50 shadow-inner flex-shrink-0 transition-transform group-hover:scale-105", children: showTopPerformerImage ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
55806
|
+
"img",
|
|
55807
|
+
{
|
|
55808
|
+
src: topPerformer.imageUrl || "",
|
|
55809
|
+
alt: topPerformer.name,
|
|
55810
|
+
className: "w-full h-full object-cover",
|
|
55811
|
+
onError: () => setTopPerformerImageError(true)
|
|
55812
|
+
}
|
|
55813
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-sm font-bold text-amber-600 uppercase", children: topPerformer.initials }) }),
|
|
55814
|
+
topPerformer.supervisors && topPerformer.supervisors.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex -space-x-2", children: [
|
|
55815
|
+
topPerformer.supervisors.slice(0, 3).map((supervisor, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
55816
|
+
"div",
|
|
55817
|
+
{
|
|
55818
|
+
className: "relative inline-block w-10 h-10 rounded-full ring-2 ring-white bg-amber-50 shadow-sm z-0 hover:z-10 transition-all hover:scale-110 group/avatar",
|
|
55819
|
+
style: { zIndex: 3 - idx },
|
|
55820
|
+
children: [
|
|
55821
|
+
supervisor.imageUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
55822
|
+
"img",
|
|
55823
|
+
{
|
|
55824
|
+
src: supervisor.imageUrl,
|
|
55825
|
+
alt: supervisor.name,
|
|
55826
|
+
className: "w-full h-full object-cover rounded-full"
|
|
55827
|
+
}
|
|
55828
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-sm font-bold text-amber-600 uppercase rounded-full", children: supervisor.initials }),
|
|
55829
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-gray-900 text-white text-[10px] font-medium rounded shadow-lg opacity-0 group-hover/avatar:opacity-100 transition-opacity whitespace-nowrap pointer-events-none z-20", children: [
|
|
55830
|
+
supervisor.name,
|
|
55831
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 -mt-[1px] border-4 border-transparent border-t-gray-900" })
|
|
55832
|
+
] })
|
|
55833
|
+
]
|
|
55834
|
+
},
|
|
55835
|
+
supervisor.userId
|
|
55836
|
+
)),
|
|
55837
|
+
topPerformer.supervisors.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex w-10 h-10 rounded-full ring-2 ring-white bg-amber-100 items-center justify-center text-sm font-medium text-amber-700 z-0", children: [
|
|
55838
|
+
"+",
|
|
55839
|
+
topPerformer.supervisors.length - 3
|
|
55840
|
+
] })
|
|
55841
|
+
] })
|
|
55842
|
+
] }),
|
|
55099
55843
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0", children: [
|
|
55100
55844
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-[10px] leading-tight mb-1", children: [
|
|
55101
55845
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-bold text-amber-600 uppercase tracking-widest", children: "Performer of the week" }),
|
|
@@ -55124,40 +55868,84 @@ var KPIsOverviewView = ({
|
|
|
55124
55868
|
] }) })
|
|
55125
55869
|
] }),
|
|
55126
55870
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-blue-50/50 px-4 py-2 rounded-xl border border-blue-100/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-6", children: [
|
|
55127
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
55128
|
-
/* @__PURE__ */ jsxRuntime.
|
|
55129
|
-
|
|
55871
|
+
!isMonthlyMode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
55872
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-700", children: [
|
|
55873
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4 opacity-70", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
|
|
55874
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-semibold tabular-nums", children: /* @__PURE__ */ jsxRuntime.jsx(ISTTimer_default, {}) })
|
|
55875
|
+
] }),
|
|
55876
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" })
|
|
55130
55877
|
] }),
|
|
55131
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
|
|
55132
55878
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
55133
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className:
|
|
55134
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium"
|
|
55879
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: `w-4 h-4 opacity-70 ${isMonthlyMode ? "scale-110" : ""}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
|
|
55880
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `${isMonthlyMode ? "text-base font-medium" : "text-sm font-medium"}`, children: isMonthlyMode ? getMonthRange() : formatLocalDate2(/* @__PURE__ */ new Date()) })
|
|
55135
55881
|
] }),
|
|
55136
|
-
/* @__PURE__ */ jsxRuntime.
|
|
55137
|
-
|
|
55138
|
-
/* @__PURE__ */ jsxRuntime.
|
|
55139
|
-
|
|
55140
|
-
|
|
55141
|
-
|
|
55882
|
+
!isMonthlyMode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
55883
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-blue-200" }),
|
|
55884
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-blue-600", children: [
|
|
55885
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "opacity-70", children: getShiftIcon(currentShiftDetails.shiftId) }),
|
|
55886
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-semibold uppercase tracking-wider", children: [
|
|
55887
|
+
shiftName,
|
|
55888
|
+
" Shift"
|
|
55889
|
+
] })
|
|
55142
55890
|
] })
|
|
55143
55891
|
] })
|
|
55892
|
+
] }) }),
|
|
55893
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 flex justify-start", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1.5 lg:gap-2", children: [
|
|
55894
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
55895
|
+
"button",
|
|
55896
|
+
{
|
|
55897
|
+
onClick: () => handleTabChange("today"),
|
|
55898
|
+
className: `px-3 lg:px-4 py-1.5 lg:py-2 text-sm lg:text-base font-medium rounded-lg transition-colors whitespace-nowrap ${activeTab === "today" ? "bg-blue-50 text-blue-600" : "text-gray-600 hover:bg-gray-50"}`,
|
|
55899
|
+
children: "Overview"
|
|
55900
|
+
}
|
|
55901
|
+
),
|
|
55902
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
55903
|
+
"button",
|
|
55904
|
+
{
|
|
55905
|
+
onClick: () => handleTabChange("leaderboard"),
|
|
55906
|
+
className: `px-3 lg:px-4 py-1.5 lg:py-2 text-sm lg:text-base font-medium rounded-lg transition-colors whitespace-nowrap ${activeTab === "leaderboard" ? "bg-blue-50 text-blue-600" : "text-gray-600 hover:bg-gray-50"}`,
|
|
55907
|
+
children: "Leaderboard"
|
|
55908
|
+
}
|
|
55909
|
+
)
|
|
55144
55910
|
] }) })
|
|
55145
55911
|
] })
|
|
55146
55912
|
] }) }),
|
|
55147
|
-
/* @__PURE__ */ jsxRuntime.jsx("main", { className:
|
|
55148
|
-
|
|
55149
|
-
{
|
|
55150
|
-
|
|
55151
|
-
|
|
55152
|
-
|
|
55153
|
-
|
|
55154
|
-
|
|
55155
|
-
|
|
55156
|
-
|
|
55157
|
-
|
|
55158
|
-
|
|
55159
|
-
|
|
55160
|
-
|
|
55913
|
+
/* @__PURE__ */ jsxRuntime.jsx("main", { className: `flex-1 p-3 sm:p-4 md:p-6 bg-slate-50 ${activeTab === "leaderboard" ? "overflow-hidden flex flex-col" : "overflow-y-auto"}`, children: activeTab === "today" ? (
|
|
55914
|
+
/* Line Cards Grid */
|
|
55915
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3 sm:gap-4 md:gap-6", children: lines.map((line) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
55916
|
+
LineCard,
|
|
55917
|
+
{
|
|
55918
|
+
line,
|
|
55919
|
+
kpis: metricsError ? null : kpisByLineId.get(line.id) ?? (metricsLoading ? null : defaultKPIs),
|
|
55920
|
+
isLoading: metricsLoading,
|
|
55921
|
+
error: metricsError,
|
|
55922
|
+
onClick: (kpis) => handleLineClick(line, kpis),
|
|
55923
|
+
supervisorEnabled,
|
|
55924
|
+
supervisorName: supervisorNamesByLineId.get(line.id) || null,
|
|
55925
|
+
supervisors: supervisorsByLineId?.get(line.id)
|
|
55926
|
+
},
|
|
55927
|
+
line.id
|
|
55928
|
+
)) })
|
|
55929
|
+
) : (
|
|
55930
|
+
/* Leaderboard View */
|
|
55931
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
55932
|
+
LinesLeaderboard,
|
|
55933
|
+
{
|
|
55934
|
+
lines,
|
|
55935
|
+
onLineClick: (line) => handleLineClick(line),
|
|
55936
|
+
timeRange,
|
|
55937
|
+
setTimeRange,
|
|
55938
|
+
todayEfficiencyByLineId,
|
|
55939
|
+
monthlyEfficiencyByLineId,
|
|
55940
|
+
supervisorsByLineId,
|
|
55941
|
+
supervisorNamesByLineId,
|
|
55942
|
+
isLoadingToday: metricsLoading,
|
|
55943
|
+
isLoadingMonthly: monthlyLoading,
|
|
55944
|
+
shiftEndDate,
|
|
55945
|
+
monthEndDate
|
|
55946
|
+
}
|
|
55947
|
+
) })
|
|
55948
|
+
) })
|
|
55161
55949
|
] });
|
|
55162
55950
|
};
|
|
55163
55951
|
var KPIsOverviewView_default = KPIsOverviewView;
|
|
@@ -55303,6 +56091,12 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
55303
56091
|
const [activeTab, setActiveTab] = React25.useState("today");
|
|
55304
56092
|
const timezone = useAppTimezone();
|
|
55305
56093
|
const staticShiftConfig = useShiftConfig();
|
|
56094
|
+
const representativeLineId = lineId || lines[0]?.id;
|
|
56095
|
+
const {
|
|
56096
|
+
shiftConfig: dynamicShiftConfig,
|
|
56097
|
+
isLoading: isDynamicShiftConfigLoading
|
|
56098
|
+
} = useDynamicShiftConfig(representativeLineId);
|
|
56099
|
+
const activeShiftConfig = dynamicShiftConfig ?? staticShiftConfig;
|
|
55306
56100
|
const shiftId = React25.useMemo(
|
|
55307
56101
|
() => typeof shift === "number" ? shift : typeof shift === "string" ? parseInt(shift) : void 0,
|
|
55308
56102
|
[shift]
|
|
@@ -55336,7 +56130,7 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
55336
56130
|
return shiftId.toString();
|
|
55337
56131
|
}
|
|
55338
56132
|
try {
|
|
55339
|
-
const current = getCurrentShift(timezone || "Asia/Kolkata",
|
|
56133
|
+
const current = getCurrentShift(timezone || "Asia/Kolkata", activeShiftConfig);
|
|
55340
56134
|
return current.shiftId.toString();
|
|
55341
56135
|
} catch (e) {
|
|
55342
56136
|
return "0";
|
|
@@ -55348,13 +56142,13 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
55348
56142
|
}
|
|
55349
56143
|
}, [shiftId]);
|
|
55350
56144
|
React25.useEffect(() => {
|
|
55351
|
-
if (shiftId !== void 0 || !
|
|
56145
|
+
if (shiftId !== void 0 || isDynamicShiftConfigLoading || !activeShiftConfig) return;
|
|
55352
56146
|
try {
|
|
55353
|
-
const current = getCurrentShift(timezone || "Asia/Kolkata",
|
|
56147
|
+
const current = getCurrentShift(timezone || "Asia/Kolkata", activeShiftConfig);
|
|
55354
56148
|
setSelectedShiftFilter((prev) => prev === "0" ? current.shiftId.toString() : prev);
|
|
55355
56149
|
} catch (e) {
|
|
55356
56150
|
}
|
|
55357
|
-
}, [shiftId,
|
|
56151
|
+
}, [shiftId, activeShiftConfig, isDynamicShiftConfigLoading, timezone]);
|
|
55358
56152
|
const [todayEntries, setTodayEntries] = React25.useState([]);
|
|
55359
56153
|
const [monthlyEntries, setMonthlyEntries] = React25.useState([]);
|
|
55360
56154
|
const [todayLoading, setTodayLoading] = React25.useState(false);
|
|
@@ -55451,8 +56245,8 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
55451
56245
|
return Array.from(uniqueLines.entries()).map(([id3, name]) => ({ id: id3, label: name }));
|
|
55452
56246
|
}, [configuredLineIds, lines, getLineName]);
|
|
55453
56247
|
const shiftOptions = React25.useMemo(() => {
|
|
55454
|
-
if (
|
|
55455
|
-
return
|
|
56248
|
+
if (activeShiftConfig?.shifts && activeShiftConfig.shifts.length > 0) {
|
|
56249
|
+
return activeShiftConfig.shifts.map((shift2) => ({
|
|
55456
56250
|
id: shift2.shiftId.toString(),
|
|
55457
56251
|
label: shift2.shiftName
|
|
55458
56252
|
}));
|
|
@@ -55461,14 +56255,14 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
55461
56255
|
{ id: "0", label: "Day Shift" },
|
|
55462
56256
|
{ id: "1", label: "Night Shift" }
|
|
55463
56257
|
];
|
|
55464
|
-
}, [
|
|
56258
|
+
}, [activeShiftConfig]);
|
|
55465
56259
|
const currentShiftInfo = React25.useMemo(() => {
|
|
55466
56260
|
try {
|
|
55467
|
-
return getCurrentShift(timezone || "Asia/Kolkata",
|
|
56261
|
+
return getCurrentShift(timezone || "Asia/Kolkata", activeShiftConfig);
|
|
55468
56262
|
} catch (e) {
|
|
55469
56263
|
return { shiftId: 0, date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0], shiftName: "Day" };
|
|
55470
56264
|
}
|
|
55471
|
-
}, [timezone,
|
|
56265
|
+
}, [timezone, activeShiftConfig]);
|
|
55472
56266
|
const selectedShiftId = React25.useMemo(() => {
|
|
55473
56267
|
const parsed = Number(selectedShiftFilter);
|
|
55474
56268
|
return Number.isFinite(parsed) ? parsed : void 0;
|
|
@@ -55709,7 +56503,7 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
55709
56503
|
]);
|
|
55710
56504
|
const getShiftName = React25.useCallback((shiftId2) => {
|
|
55711
56505
|
if (shiftId2 !== void 0) {
|
|
55712
|
-
return getShiftNameById(shiftId2, timezone || "Asia/Kolkata",
|
|
56506
|
+
return getShiftNameById(shiftId2, timezone || "Asia/Kolkata", activeShiftConfig);
|
|
55713
56507
|
}
|
|
55714
56508
|
if (shiftGroups.length > 1) {
|
|
55715
56509
|
const shiftNames = shiftGroups.map((g) => g.shiftName).join(" & ");
|
|
@@ -55717,14 +56511,14 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
55717
56511
|
} else if (shiftGroups.length === 1) {
|
|
55718
56512
|
return shiftGroups[0].shiftName;
|
|
55719
56513
|
}
|
|
55720
|
-
const currentShift = getCurrentShift(timezone || "Asia/Kolkata",
|
|
55721
|
-
return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata",
|
|
55722
|
-
}, [timezone,
|
|
56514
|
+
const currentShift = getCurrentShift(timezone || "Asia/Kolkata", activeShiftConfig);
|
|
56515
|
+
return currentShift.shiftName || getShiftNameById(currentShift.shiftId, timezone || "Asia/Kolkata", activeShiftConfig);
|
|
56516
|
+
}, [timezone, activeShiftConfig, shiftGroups]);
|
|
55723
56517
|
const getShiftIcon = React25.useCallback((shiftId2) => {
|
|
55724
56518
|
if (shiftId2 === void 0 && shiftGroups.length > 1) {
|
|
55725
56519
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
55726
56520
|
}
|
|
55727
|
-
const effectiveShiftId = shiftId2 !== void 0 ? shiftId2 : shiftGroups.length === 1 ? shiftGroups[0].shiftId : getCurrentShift(timezone || "Asia/Kolkata",
|
|
56521
|
+
const effectiveShiftId = shiftId2 !== void 0 ? shiftId2 : shiftGroups.length === 1 ? shiftGroups[0].shiftId : getCurrentShift(timezone || "Asia/Kolkata", activeShiftConfig).shiftId;
|
|
55728
56522
|
const shiftNameLower = getShiftName(effectiveShiftId).toLowerCase();
|
|
55729
56523
|
if (shiftNameLower.includes("day") || shiftNameLower.includes("morning")) {
|
|
55730
56524
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) });
|
|
@@ -55736,7 +56530,7 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
55736
56530
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) });
|
|
55737
56531
|
}
|
|
55738
56532
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) });
|
|
55739
|
-
}, [getShiftName, shiftGroups, timezone,
|
|
56533
|
+
}, [getShiftName, shiftGroups, timezone, activeShiftConfig]);
|
|
55740
56534
|
const formatDate2 = React25.useCallback((date2) => {
|
|
55741
56535
|
return new Intl.DateTimeFormat("en-US", {
|
|
55742
56536
|
weekday: "long",
|
|
@@ -55970,7 +56764,7 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
55970
56764
|
{
|
|
55971
56765
|
onClick: () => setActiveTab("today"),
|
|
55972
56766
|
className: `flex-1 px-2 py-1.5 text-xs font-medium rounded-md transition-all duration-200 ${activeTab === "today" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600"}`,
|
|
55973
|
-
children: "
|
|
56767
|
+
children: "Daily"
|
|
55974
56768
|
}
|
|
55975
56769
|
),
|
|
55976
56770
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -55978,7 +56772,7 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
55978
56772
|
{
|
|
55979
56773
|
onClick: () => setActiveTab("monthly"),
|
|
55980
56774
|
className: `flex-1 px-2 py-1.5 text-xs font-medium rounded-md transition-all duration-200 ${activeTab === "monthly" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600"}`,
|
|
55981
|
-
children: "Monthly
|
|
56775
|
+
children: "Monthly"
|
|
55982
56776
|
}
|
|
55983
56777
|
)
|
|
55984
56778
|
] }),
|
|
@@ -56017,7 +56811,7 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
56017
56811
|
{
|
|
56018
56812
|
onClick: () => setActiveTab("today"),
|
|
56019
56813
|
className: `px-2 lg:px-3 py-1 lg:py-1.5 text-sm lg:text-base font-medium rounded-lg transition-colors whitespace-nowrap ${activeTab === "today" ? "bg-blue-50 text-blue-600" : "text-gray-600 hover:bg-gray-50"}`,
|
|
56020
|
-
children: "
|
|
56814
|
+
children: "Daily"
|
|
56021
56815
|
}
|
|
56022
56816
|
),
|
|
56023
56817
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -56025,7 +56819,7 @@ var LeaderboardDetailView = React25.memo(({
|
|
|
56025
56819
|
{
|
|
56026
56820
|
onClick: () => setActiveTab("monthly"),
|
|
56027
56821
|
className: `px-2 lg:px-3 py-1 lg:py-1.5 text-sm lg:text-base font-medium rounded-lg transition-colors whitespace-nowrap ${activeTab === "monthly" ? "bg-blue-50 text-blue-600" : "text-gray-600 hover:bg-gray-50"}`,
|
|
56028
|
-
children: "Monthly
|
|
56822
|
+
children: "Monthly"
|
|
56029
56823
|
}
|
|
56030
56824
|
)
|
|
56031
56825
|
] }),
|
|
@@ -59098,6 +59892,7 @@ var getInitialTab = (sourceType, defaultTab, fromMonthly, urlDate) => {
|
|
|
59098
59892
|
}
|
|
59099
59893
|
return "overview";
|
|
59100
59894
|
};
|
|
59895
|
+
var DEBUG_DASHBOARD2 = process.env.NEXT_PUBLIC_DEBUG_DASHBOARD === "true";
|
|
59101
59896
|
var chartCardVariants = {
|
|
59102
59897
|
initial: { opacity: 0, y: 10 },
|
|
59103
59898
|
animate: {
|
|
@@ -59534,6 +60329,34 @@ var WorkspaceDetailView = ({
|
|
|
59534
60329
|
const idleTimeReasonsEnabled = Boolean(
|
|
59535
60330
|
workspaceId && idleTimeReasonsDate && idleTimeReasonsShiftId !== void 0
|
|
59536
60331
|
);
|
|
60332
|
+
React25.useEffect(() => {
|
|
60333
|
+
if (!DEBUG_DASHBOARD2) return;
|
|
60334
|
+
console.log("[WorkspaceDetailView] IdleTimeReasons gate", {
|
|
60335
|
+
workspaceId,
|
|
60336
|
+
idleTimeReasonsDate,
|
|
60337
|
+
idleTimeReasonsShiftId,
|
|
60338
|
+
idleTimeReasonsEnabled,
|
|
60339
|
+
isShiftConfigLoading,
|
|
60340
|
+
calculatedOperationalDate,
|
|
60341
|
+
calculatedShiftId,
|
|
60342
|
+
workspaceDate: workspace?.date,
|
|
60343
|
+
workspaceShiftId: workspace?.shift_id,
|
|
60344
|
+
parsedShiftId,
|
|
60345
|
+
hasWorkspaceSnapshot
|
|
60346
|
+
});
|
|
60347
|
+
}, [
|
|
60348
|
+
workspaceId,
|
|
60349
|
+
idleTimeReasonsDate,
|
|
60350
|
+
idleTimeReasonsShiftId,
|
|
60351
|
+
idleTimeReasonsEnabled,
|
|
60352
|
+
isShiftConfigLoading,
|
|
60353
|
+
calculatedOperationalDate,
|
|
60354
|
+
calculatedShiftId,
|
|
60355
|
+
workspace?.date,
|
|
60356
|
+
workspace?.shift_id,
|
|
60357
|
+
parsedShiftId,
|
|
60358
|
+
hasWorkspaceSnapshot
|
|
60359
|
+
]);
|
|
59537
60360
|
const {
|
|
59538
60361
|
chartData: idleTimeChartData,
|
|
59539
60362
|
isLoading: idleTimeLoading,
|
|
@@ -66883,6 +67706,7 @@ exports.isValidWorkspaceDetailedMetricsPayload = isValidWorkspaceDetailedMetrics
|
|
|
66883
67706
|
exports.isValidWorkspaceMetricsPayload = isValidWorkspaceMetricsPayload;
|
|
66884
67707
|
exports.isWorkspaceDisplayNamesLoaded = isWorkspaceDisplayNamesLoaded;
|
|
66885
67708
|
exports.isWorkspaceDisplayNamesLoading = isWorkspaceDisplayNamesLoading;
|
|
67709
|
+
exports.lineLeaderboardService = lineLeaderboardService;
|
|
66886
67710
|
exports.linesService = linesService;
|
|
66887
67711
|
exports.mergeWithDefaultConfig = mergeWithDefaultConfig;
|
|
66888
67712
|
exports.migrateLegacyConfiguration = migrateLegacyConfiguration;
|