feat: визуальный результат отгрузки — восстановление состояния + блок с результатом

- Восстановление shippedItems и comments из order.driverShipmentData при загрузке
- Визуальный блок 'Отгрузка сохранена' с галочками/крестиками и комментариями
- Зачёркнутый текст для отгруженных позиций, причина для неотгруженных
This commit is contained in:
root 2026-06-15 15:24:13 +00:00
parent ae1e0a2e0e
commit a687d0b8a8
1 changed files with 67 additions and 2 deletions

View File

@ -92,6 +92,7 @@ const parseOrderItems = (order) => {
export const DriverShipmentPanel = ({ order, onShipmentChange, onSaveShipment, isSavingShipment }) => {
const [stopWords, setStopWords] = React.useState([]);
const [scopeActive, setScopeActive] = React.useState(true);
const [savedShipment, setSavedShipment] = React.useState(null); // last saved snapshot
React.useEffect(() => {
if (!supabase) return;
@ -109,10 +110,46 @@ export const DriverShipmentPanel = ({ order, onShipmentChange, onSaveShipment, i
if (!stopWords.length || !scopeActive) return allItems;
return allItems.filter((item) => !matchesStopWord(item.name, stopWords));
}, [allItems, stopWords, scopeActive]);
const [shippedItems, setShippedItems] = React.useState(new Set());
const [comments, setComments] = React.useState({});
// Restore previously saved shipment data from order
const initialShippedIds = React.useMemo(() => {
const saved = order?.driverShipmentData;
if (!Array.isArray(saved) || saved.length === 0) return new Set();
const ids = new Set();
for (const item of saved) {
if (item.shipped && item.id) ids.add(item.id);
}
return ids;
}, [order?.driverShipmentData]);
const initialComments = React.useMemo(() => {
const saved = order?.driverShipmentData;
if (!Array.isArray(saved) || saved.length === 0) return {};
const map = {};
for (const item of saved) {
if (!item.shipped && item.id && item.comment) map[item.id] = item.comment;
}
return map;
}, [order?.driverShipmentData]);
const [shippedItems, setShippedItems] = React.useState(initialShippedIds);
const [comments, setComments] = React.useState(initialComments);
const [commentInput, setCommentInput] = React.useState("");
// Sync state when order data changes (e.g. after save)
React.useEffect(() => {
setShippedItems(initialShippedIds);
setComments(initialComments);
}, [initialShippedIds, initialComments]);
// Track last saved shipment data for visual display
React.useEffect(() => {
const saved = order?.driverShipmentData;
if (Array.isArray(saved) && saved.length > 0) {
setSavedShipment(saved);
}
}, [order?.driverShipmentData]);
const toggleItem = (itemId) => {
setShippedItems((prev) => {
const next = new Set(prev);
@ -284,6 +321,34 @@ export const DriverShipmentPanel = ({ order, onShipmentChange, onSaveShipment, i
)}
</div>
)}
{savedShipment && savedShipment.length > 0 && (
<div className="rounded-xl border border-[var(--color-accent)] bg-[var(--color-accent-soft)] p-4 text-sm">
<div className="flex items-center gap-2 mb-2">
<span className="text-lg"></span>
<strong className="text-[var(--color-accent)]">
Отгрузка сохранена: {savedShipment.filter((i) => i.shipped).length} из {savedShipment.length} позиций
</strong>
</div>
<div className="space-y-1">
{savedShipment.map((item) => (
<div key={item.id} className="flex items-start gap-2">
<span className={item.shipped ? "text-[var(--color-accent)]" : "text-[var(--color-warning)]"}>
{item.shipped ? "✓" : "✗"}
</span>
<span className={item.shipped ? "text-[var(--color-text-muted)] line-through" : "text-[var(--color-text)]"}>
{item.name}{item.quantity ? `${item.quantity}${item.unit ? ` ${item.unit}` : ""}` : ""}
</span>
{!item.shipped && item.comment && (
<span className="text-xs text-[var(--color-warning)] ml-1">
({item.comment})
</span>
)}
</div>
))}
</div>
</div>
)}
</Panel>
);
};