287 lines
9.1 KiB
JavaScript
287 lines
9.1 KiB
JavaScript
import React from "react";
|
||
import { assignDriverToOrderGroup, fetchOrderGroupById, fetchOrderGroups, saveShipmentData, updateDeliveryStatus, updateOrderGroupDeliveryChoice } from "../services/supabase/orderGroupRepository";
|
||
import {
|
||
buildOrderGroupBuckets,
|
||
filterOrderGroups,
|
||
groupOrderGroupsByDate,
|
||
ORDER_GROUP_DISPLAY_STATUS_OPTIONS,
|
||
getOrderGroupDisplayStatusValue,
|
||
} from "../services/orderGroupViews";
|
||
import { getErrorMessage } from "../utils/deliveryUtils";
|
||
|
||
export const useOrderGroups = ({ enabled = true, details = false, groupId = null } = {}) => {
|
||
const [orderGroups, setOrderGroups] = React.useState(() => []);
|
||
const FILTERS_STORAGE_KEY = "supersam_order_filters";
|
||
const [filters, setFilters] = React.useState(() => {
|
||
try {
|
||
const saved = localStorage.getItem(FILTERS_STORAGE_KEY);
|
||
if (saved) return JSON.parse(saved);
|
||
} catch (e) {}
|
||
return { query: "", displayStatus: "all", deliveryType: "" };
|
||
});
|
||
|
||
// Persist filters to localStorage on every change
|
||
React.useEffect(() => {
|
||
try {
|
||
localStorage.setItem(FILTERS_STORAGE_KEY, JSON.stringify(filters));
|
||
} catch (e) {}
|
||
}, [filters]);
|
||
const [selectedOrderGroupId, setSelectedOrderGroupId] = React.useState(null);
|
||
const [isLoading, setIsLoading] = React.useState(enabled);
|
||
const [loadError, setLoadError] = React.useState("");
|
||
const [isSavingDeliveryChoice, setIsSavingDeliveryChoice] = React.useState(false);
|
||
const [isSavingDriverAssignment, setIsSavingDriverAssignment] = React.useState(false);
|
||
const [isSavingStatusChange, setIsSavingStatusChange] = React.useState(false);
|
||
|
||
const loadLiveData = React.useCallback(async (showLoading = true) => {
|
||
if (showLoading) {
|
||
setIsLoading(true);
|
||
}
|
||
setLoadError("");
|
||
|
||
if (!enabled) { setOrderGroups([]); setIsLoading(false); return; }
|
||
|
||
// Single-group mode: load only the requested group (avoids pulling all
|
||
// 430 groups with their full source_orders JSON — 2.6MB — for a detail view).
|
||
if (groupId) {
|
||
const singleResult = await fetchOrderGroupById(groupId);
|
||
if (!singleResult) {
|
||
return;
|
||
}
|
||
if (singleResult.error) {
|
||
setLoadError(singleResult.error?.message || "Не удалось загрузить группу доставки");
|
||
setOrderGroups([]);
|
||
setIsLoading(false);
|
||
return;
|
||
}
|
||
setOrderGroups(singleResult.data ? [singleResult.data] : []);
|
||
setIsLoading(false);
|
||
return;
|
||
}
|
||
|
||
const groupsResult = await fetchOrderGroups({ details });
|
||
|
||
if (!groupsResult) {
|
||
return;
|
||
}
|
||
|
||
if (groupsResult.error) {
|
||
setLoadError(groupsResult.error?.message || "Не удалось загрузить группы доставки");
|
||
setOrderGroups([]);
|
||
setIsLoading(false);
|
||
return;
|
||
}
|
||
|
||
setOrderGroups(groupsResult.data || []);
|
||
setIsLoading(false);
|
||
}, [enabled, details, groupId]);
|
||
|
||
// Initial load
|
||
React.useEffect(() => {
|
||
let cancelled = false;
|
||
const doLoad = async () => {
|
||
setIsLoading(true);
|
||
await loadLiveData(true);
|
||
if (cancelled) return;
|
||
};
|
||
if (enabled) doLoad(); else { setOrderGroups([]); setIsLoading(false); }
|
||
return () => { cancelled = true; };
|
||
}, [loadLiveData, enabled]);
|
||
|
||
// Refetch on window focus to keep data fresh across tabs/pages
|
||
React.useEffect(() => {
|
||
if (!enabled) return undefined;
|
||
const handleFocus = () => {
|
||
loadLiveData(false); // silent refetch, no loading spinner
|
||
};
|
||
window.addEventListener("focus", handleFocus);
|
||
return () => window.removeEventListener("focus", handleFocus);
|
||
}, [loadLiveData, enabled]);
|
||
|
||
React.useEffect(() => {
|
||
if (!orderGroups.length) {
|
||
setSelectedOrderGroupId(null);
|
||
return;
|
||
}
|
||
|
||
if (!selectedOrderGroupId || !orderGroups.some((group) => group.id === selectedOrderGroupId)) {
|
||
setSelectedOrderGroupId(orderGroups[0].id);
|
||
}
|
||
}, [orderGroups, selectedOrderGroupId]);
|
||
|
||
const statusCounts = React.useMemo(() => {
|
||
const counts = {};
|
||
orderGroups.forEach((group) => {
|
||
const status = getOrderGroupDisplayStatusValue(group);
|
||
counts[status] = (counts[status] || 0) + 1;
|
||
});
|
||
return counts;
|
||
}, [orderGroups]);
|
||
|
||
const statusOptions = React.useMemo(() =>
|
||
ORDER_GROUP_DISPLAY_STATUS_OPTIONS.map((opt) => ({
|
||
...opt,
|
||
count: opt.value === "all" ? orderGroups.length : (statusCounts[opt.value] || 0),
|
||
})),
|
||
[statusCounts, orderGroups]
|
||
);
|
||
|
||
const filteredOrderGroups = React.useMemo(
|
||
() => filterOrderGroups(orderGroups, filters),
|
||
[filters, orderGroups],
|
||
);
|
||
|
||
const visibleOrderGroups = filteredOrderGroups;
|
||
const selectedOrderGroup =
|
||
visibleOrderGroups.find((group) => group.id === selectedOrderGroupId) ||
|
||
orderGroups.find((group) => group.id === selectedOrderGroupId) ||
|
||
visibleOrderGroups[0] ||
|
||
null;
|
||
|
||
const orderGroupsByDate = React.useMemo(() => groupOrderGroupsByDate(orderGroups), [orderGroups]);
|
||
const deliveryGroupBuckets = React.useMemo(() => buildOrderGroupBuckets(orderGroups), [orderGroups]);
|
||
|
||
const saveManualDeliveryChoice = React.useCallback(async ({
|
||
orderGroupId,
|
||
deliveryDate,
|
||
deliveryTime,
|
||
deliveryType,
|
||
deliveryAddress,
|
||
pickupDate,
|
||
pickupTimeSlot,
|
||
}) => {
|
||
setIsSavingDeliveryChoice(true);
|
||
|
||
try {
|
||
/* Demo mode removed */
|
||
|
||
const result = await updateOrderGroupDeliveryChoice({
|
||
orderGroupId,
|
||
deliveryDate,
|
||
deliveryTime,
|
||
deliveryType,
|
||
deliveryAddress,
|
||
pickupDate,
|
||
pickupTimeSlot,
|
||
});
|
||
|
||
if (result.error) {
|
||
return {
|
||
success: false,
|
||
error: getErrorMessage(result.error, "Не удалось сохранить согласование доставки"),
|
||
};
|
||
}
|
||
|
||
setOrderGroups((currentGroups) =>
|
||
currentGroups.map((group) => (group.id === orderGroupId ? result.data : group)),
|
||
);
|
||
return { success: true, data: result.data };
|
||
} catch (error) {
|
||
return {
|
||
success: false,
|
||
error: getErrorMessage(error, "Не удалось сохранить согласование доставки"),
|
||
};
|
||
} finally {
|
||
setIsSavingDeliveryChoice(false);
|
||
}
|
||
}, []);
|
||
|
||
const assignDriver = React.useCallback(async ({ orderGroupId, driverId }) => {
|
||
setIsSavingDriverAssignment(true);
|
||
|
||
try {
|
||
const result = await assignDriverToOrderGroup({ orderGroupId, driverId });
|
||
|
||
|
||
if (result.error) {
|
||
return {
|
||
success: false,
|
||
error: getErrorMessage(result.error, "Не удалось назначить водителя"),
|
||
};
|
||
}
|
||
|
||
setOrderGroups((currentGroups) =>
|
||
currentGroups.map((group) => (group.id === orderGroupId ? result.data : group)),
|
||
);
|
||
return { success: true, data: result.data };
|
||
} catch (error) {
|
||
return {
|
||
success: false,
|
||
error: getErrorMessage(error, "Не удалось назначить водителя"),
|
||
};
|
||
} finally {
|
||
setIsSavingDriverAssignment(false);
|
||
}
|
||
}, []);
|
||
|
||
const changeDeliveryStatus = React.useCallback(async ({ orderGroupId, status, details, shipmentData }) => {
|
||
setIsSavingStatusChange(true);
|
||
try {
|
||
const result = await updateDeliveryStatus({ orderGroupId, status, details, shipmentData });
|
||
if (result.error) {
|
||
return {
|
||
success: false,
|
||
error: getErrorMessage(result.error, "Не удалось обновить статус"),
|
||
};
|
||
}
|
||
setOrderGroups((currentGroups) =>
|
||
currentGroups.map((group) => (group.id === orderGroupId ? result.data : group)),
|
||
);
|
||
return { success: true, data: result.data };
|
||
} catch (error) {
|
||
return {
|
||
success: false,
|
||
error: getErrorMessage(error, "Не удалось обновить статус"),
|
||
};
|
||
} finally {
|
||
setIsSavingStatusChange(false);
|
||
}
|
||
}, []);
|
||
|
||
const onSaveShipmentData = React.useCallback(async ({ orderGroupId, shipmentData }) => {
|
||
try {
|
||
const result = await saveShipmentData({ orderGroupId, shipmentData });
|
||
if (result.error) {
|
||
return {
|
||
success: false,
|
||
error: getErrorMessage(result.error, "Не удалось сохранить данные отгрузки"),
|
||
};
|
||
}
|
||
setOrderGroups((currentGroups) =>
|
||
currentGroups.map((group) => (group.id === orderGroupId ? result.data : group)),
|
||
);
|
||
return { success: true, data: result.data };
|
||
} catch (error) {
|
||
return {
|
||
success: false,
|
||
error: getErrorMessage(error, "Не удалось сохранить данные отгрузки"),
|
||
};
|
||
}
|
||
}, []);
|
||
|
||
return {
|
||
orderGroups,
|
||
allOrderGroups: orderGroups,
|
||
filteredOrderGroups,
|
||
visibleOrderGroups,
|
||
selectedOrderGroup,
|
||
selectedOrderGroupId,
|
||
setSelectedOrderGroupId,
|
||
filters,
|
||
setFilters,
|
||
statusOptions,
|
||
orderGroupsByDate,
|
||
deliveryGroupBuckets,
|
||
saveManualDeliveryChoice,
|
||
assignDriver,
|
||
changeDeliveryStatus,
|
||
saveShipmentData: onSaveShipmentData,
|
||
isSavingDeliveryChoice,
|
||
isSavingDriverAssignment,
|
||
isSavingStatusChange,
|
||
isLoading,
|
||
loadError,
|
||
refetch: loadLiveData,
|
||
};
|
||
};
|