supersam/src/hooks/useOrderGroups.js

287 lines
9.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
};
};