feat: визуальный результат отгрузки — восстановление состояния + блок с результатом
- Восстановление shippedItems и comments из order.driverShipmentData при загрузке - Визуальный блок 'Отгрузка сохранена' с галочками/крестиками и комментариями - Зачёркнутый текст для отгруженных позиций, причина для неотгруженных
This commit is contained in:
parent
ae1e0a2e0e
commit
a687d0b8a8
|
|
@ -92,6 +92,7 @@ const parseOrderItems = (order) => {
|
||||||
export const DriverShipmentPanel = ({ order, onShipmentChange, onSaveShipment, isSavingShipment }) => {
|
export const DriverShipmentPanel = ({ order, onShipmentChange, onSaveShipment, isSavingShipment }) => {
|
||||||
const [stopWords, setStopWords] = React.useState([]);
|
const [stopWords, setStopWords] = React.useState([]);
|
||||||
const [scopeActive, setScopeActive] = React.useState(true);
|
const [scopeActive, setScopeActive] = React.useState(true);
|
||||||
|
const [savedShipment, setSavedShipment] = React.useState(null); // last saved snapshot
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!supabase) return;
|
if (!supabase) return;
|
||||||
|
|
@ -109,10 +110,46 @@ export const DriverShipmentPanel = ({ order, onShipmentChange, onSaveShipment, i
|
||||||
if (!stopWords.length || !scopeActive) return allItems;
|
if (!stopWords.length || !scopeActive) return allItems;
|
||||||
return allItems.filter((item) => !matchesStopWord(item.name, stopWords));
|
return allItems.filter((item) => !matchesStopWord(item.name, stopWords));
|
||||||
}, [allItems, stopWords, scopeActive]);
|
}, [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("");
|
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) => {
|
const toggleItem = (itemId) => {
|
||||||
setShippedItems((prev) => {
|
setShippedItems((prev) => {
|
||||||
const next = new Set(prev);
|
const next = new Set(prev);
|
||||||
|
|
@ -284,6 +321,34 @@ export const DriverShipmentPanel = ({ order, onShipmentChange, onSaveShipment, i
|
||||||
)}
|
)}
|
||||||
</div>
|
</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>
|
</Panel>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue