supersam/src/pages/GroupDetailPage.jsx

132 lines
4.5 KiB
JavaScript

/**
* @file GroupDetailPage.jsx
* @description Detail view for a single order group. Reads groupId from URL
* params, loads drivers, and renders the OrderDetailPanel.
*/
import React from "react";
import { Navigate, useNavigate, useParams, useLocation } from "react-router-dom";
import { OrderDetailPanel } from "../components/orders/OrderDetailPanel";
import ErrorBoundary from "../components/ErrorBoundary";
import { Button } from "../components/UI/Button";
import { Panel } from "../components/UI/Panel";
import { SkeletonPanel } from "../components/UI/Loading";
import { useAuth } from "../context/AuthContext";
import { fetchDrivers } from "../services/supabase/userRepository";
import { useOrderGroups } from "../hooks/useOrderGroups";
const ALLOWED_ROLES = ["admin", "mega_admin", "manager", "logistician", "driver"];
export const GroupDetailPage = () => {
// ── Route Params & Auth ───────────────────────────────────────────────────
const { groupId } = useParams();
const navigate = useNavigate();
const location = useLocation();
const { user, isSessionLoading } = useAuth();
const userRole = user?.role;
// ALL hooks must be called before any early return (Rules of Hooks)
const {
allOrderGroups,
selectedOrderGroupId,
setSelectedOrderGroupId,
saveManualDeliveryChoice,
isSavingDeliveryChoice,
isSavingDriverAssignment,
isSavingStatusChange,
assignDriver,
changeDeliveryStatus,
saveShipmentData,
isLoading,
refetch,
} = useOrderGroups({ details: true, groupId });
// ── Drivers ────────────────────────────────────────────────────────────────
const [drivers, setDrivers] = React.useState([]);
React.useEffect(() => {
if (groupId) {
setSelectedOrderGroupId(groupId);
}
}, [groupId, setSelectedOrderGroupId]);
// Refetch data when navigating to this page to ensure fresh status
React.useEffect(() => {
refetch(false); // silent refetch, no loading spinner
}, [refetch]);
React.useEffect(() => {
let cancelled = false;
const load = async () => {
const result = await fetchDrivers();
if (cancelled) return;
if (result.data) {
setDrivers(result.data.filter((u) => u.role === "driver"));
}
};
load();
return () => { cancelled = true; };
}, []);
// ALL hooks must be called before any early return (Rules of Hooks)
const order = isLoading ? null : (allOrderGroups.find((g) => g.id === groupId) ||
allOrderGroups.find((g) => g.id === selectedOrderGroupId) ||
null);
// Preserve the tab the user came from when going back
const handleGoBack = React.useCallback(() => {
if (window.history.length > 1) {
navigate(-1);
} else {
navigate("/dashboard");
}
}, [navigate]);
// Wait for session restore before deciding redirect
if (isSessionLoading) {
return null;
}
// Auth guard: redirect to login if not authenticated
if (!user) {
return <Navigate to={`/login?redirect=${encodeURIComponent(location.pathname + location.search)}`} replace />;
}
// Role guard: only allowed roles can access group details
if (!ALLOWED_ROLES.includes(userRole)) {
return <Navigate to="/forbidden" replace />;
}
return (
<div className="mx-auto w-full max-w-3xl space-y-5">
<div className="flex items-center justify-between">
<Button variant="ghost" onClick={handleGoBack} className="text-sm">
← Назад к списку
</Button>
</div>
{isLoading ? (
<SkeletonPanel lines={6} />
) : order ? (
<ErrorBoundary compact>
<OrderDetailPanel
order={order}
canManageDelivery={["manager", "logistician", "admin", "mega_admin"].includes(userRole)}
onSaveManualDeliveryChoice={saveManualDeliveryChoice}
isSavingDeliveryChoice={isSavingDeliveryChoice}
isSavingDriverAssignment={isSavingDriverAssignment}
isSavingStatusChange={isSavingStatusChange}
drivers={drivers}
onAssignDriver={assignDriver}
onChangeDeliveryStatus={changeDeliveryStatus}
onSaveShipmentData={saveShipmentData}
userRole={userRole}
/>
</ErrorBoundary>
) : (
<Panel className="p-6 text-sm text-[var(--color-text-muted)]">
Группа не найдена.
</Panel>
)}
</div>
);
};