fix: date format dd.MM.yyyy in logistics board, align columns via CSS grid

- LogisticsReadinessBoard: formatDate() for delivery date (was raw yyyy-MM-dd)
- LogisticsReadinessBoard: replaced <table> with CSS grid for aligned columns
- OrdersTable: replaced <table> with CSS grid for aligned columns
- Both tables: 6-column grid with fixed proportions, all columns visible
This commit is contained in:
root 2026-06-12 19:28:10 +00:00
parent d313a3b6b9
commit 491b7705fd
2 changed files with 69 additions and 79 deletions

View File

@ -10,7 +10,7 @@ import { Badge } from "../UI/Badge";
import { Panel } from "../UI/Panel"; import { Panel } from "../UI/Panel";
import { SkeletonPage } from "../UI/Loading"; import { SkeletonPage } from "../UI/Loading";
import { OrderFilters } from "../orders/OrderFilters"; import { OrderFilters } from "../orders/OrderFilters";
import { formatDateTime } from "../../utils/formatters"; import { formatDate, formatDateTime } from "../../utils/formatters";
export const LogisticsReadinessBoard = ({ orderGroups = [], onSelectSet, statusOptions = ORDER_GROUP_DISPLAY_STATUS_OPTIONS, isLoading = false }) => { export const LogisticsReadinessBoard = ({ orderGroups = [], onSelectSet, statusOptions = ORDER_GROUP_DISPLAY_STATUS_OPTIONS, isLoading = false }) => {
const [filters, setFilters] = React.useState({ query: "", displayStatus: "all", city: "" }); const [filters, setFilters] = React.useState({ query: "", displayStatus: "all", city: "" });
@ -60,17 +60,17 @@ export const LogisticsReadinessBoard = ({ orderGroups = [], onSelectSet, statusO
const totalGroups = filteredGroups.length; const totalGroups = filteredGroups.length;
const COLS = "grid-cols-[minmax(140px,2fr)_minmax(80px,1fr)_minmax(100px,1.2fr)_minmax(80px,1fr)_minmax(100px,1fr)_minmax(120px,1fr)]";
const TableHeader = () => ( const TableHeader = () => (
<thead className="bg-[var(--color-surface-strong)] text-left text-xs uppercase tracking-[0.14em] text-[var(--color-text-muted)]"> <div className={`grid ${COLS} gap-0 border-b border-[var(--color-border)] bg-[var(--color-surface-strong)] text-xs uppercase tracking-[0.14em] text-[var(--color-text-muted)]`}>
<tr> <div className="px-4 py-3 font-medium">Клиент</div>
<th className="px-4 py-3 font-medium">Клиент</th> <div className="px-4 py-3 font-medium">Город</div>
<th className="px-4 py-3 font-medium hidden sm:table-cell">Город</th> <div className="px-4 py-3 font-medium">Дата доставки</div>
<th className="px-4 py-3 font-medium hidden md:table-cell">Дата доставки</th> <div className="px-4 py-3 font-medium">Водитель</div>
<th className="px-4 py-3 font-medium hidden lg:table-cell">Водитель</th> <div className="px-4 py-3 font-medium">Статус</div>
<th className="px-4 py-3 font-medium">Статус</th> <div className="px-4 py-3 font-medium">Обновлён</div>
<th className="px-4 py-3 font-medium hidden md:table-cell">Обновлён</th> </div>
</tr>
</thead>
); );
if (isLoading) { if (isLoading) {
@ -146,42 +146,38 @@ export const LogisticsReadinessBoard = ({ orderGroups = [], onSelectSet, statusO
{!isCollapsed && ( {!isCollapsed && (
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<table className="min-w-full border-collapse border-t border-[var(--color-border)]">
<TableHeader /> <TableHeader />
<tbody>
{groups.map((group) => ( {groups.map((group) => (
<tr <button
key={group.id} key={group.id}
className="cursor-pointer border-t border-[var(--color-border)] transition hover:bg-[var(--color-accent-soft)]" type="button"
className={`grid ${COLS} gap-0 w-full border-t border-[var(--color-border)] text-left transition hover:bg-[var(--color-accent-soft)]`}
onClick={() => { if (onSelectSet) onSelectSet(group.id); }} onClick={() => { if (onSelectSet) onSelectSet(group.id); }}
> >
<td className="px-4 py-2.5"> <div className="px-4 py-2.5">
<div className="font-medium">{group.displayTitle || group.customerName || group.groupKey}</div> <div className="font-medium">{group.displayTitle || group.customerName || group.groupKey}</div>
<div className="text-xs text-[var(--color-text-muted)] sm:hidden">{group.customerPhone || "—"}</div> <div className="text-xs text-[var(--color-text-muted)]">{group.customerPhone || "—"}</div>
<div className="text-xs text-[var(--color-text-muted)] md:hidden">{group.deliveryDate || "—"}</div> </div>
</td> <div className="px-4 py-2.5 text-sm">
<td className="px-4 py-2.5 text-sm hidden sm:table-cell">
{group.city || group.customerAddress || "—"} {group.city || group.customerAddress || "—"}
</td> </div>
<td className="px-4 py-2.5 text-sm hidden md:table-cell"> <div className="px-4 py-2.5 text-sm">
{group.deliveryDate {group.deliveryDate
? <span>{group.deliveryDate}{group.deliveryTime ? <span className="text-[var(--color-text-muted)]"> · {group.deliveryTime}</span> : ""}</span> ? <span>{formatDate(group.deliveryDate)}{group.deliveryTime ? <span className="text-[var(--color-text-muted)]"> · {group.deliveryTime}</span> : ""}</span>
: <span className="text-[var(--color-text-muted)]"></span> : <span className="text-[var(--color-text-muted)]"></span>
} }
</td> </div>
<td className="px-4 py-2.5 text-sm hidden lg:table-cell"> <div className="px-4 py-2.5 text-sm">
{group.assignedDriverName || <span className="text-[var(--color-text-muted)]"></span>} {group.assignedDriverName || <span className="text-[var(--color-text-muted)]"></span>}
</td> </div>
<td className="px-4 py-2.5"> <div className="px-4 py-2.5">
<Badge tone={getOrderGroupStatusTone(group)}>{getOrderGroupDisplayStatusLabel(group)}</Badge> <Badge tone={getOrderGroupStatusTone(group)}>{getOrderGroupDisplayStatusLabel(group)}</Badge>
</td> </div>
<td className="px-4 py-2.5 text-sm text-[var(--color-text-muted)] hidden md:table-cell"> <div className="px-4 py-2.5 text-sm text-[var(--color-text-muted)]">
{formatDateTime(group.updatedAt)} {formatDateTime(group.updatedAt)}
</td> </div>
</tr> </button>
))} ))}
</tbody>
</table>
</div> </div>
)} )}
</Panel> </Panel>

View File

@ -141,57 +141,51 @@ export const OrdersTable = ({
Группы не найдены. Попробуйте изменить поиск или статус. Группы не найдены. Попробуйте изменить поиск или статус.
</div> </div>
) : ( ) : (
<table className="min-w-full border-collapse"> <div>
<thead className="bg-[var(--color-surface-strong)] text-left text-xs uppercase tracking-[0.16em] text-[var(--color-text-muted)]"> <div className="grid grid-cols-[minmax(180px,2.5fr)_minmax(100px,1.2fr)_minmax(100px,1fr)_minmax(80px,1fr)_minmax(120px,1.2fr)_minmax(130px,1.2fr)] gap-0 border-b border-[var(--color-border)] bg-[var(--color-surface-strong)] text-xs uppercase tracking-[0.16em] text-[var(--color-text-muted)]">
<tr> <div className="px-5 py-4 font-medium">Группа / Клиент</div>
<th className="px-5 py-4 font-medium">Группа / Клиент</th> <div className="px-5 py-4 font-medium">Счёта</div>
<th className="px-5 py-4 font-medium">Счёта</th> <div className="px-5 py-4 font-medium">Статус</div>
<th className="px-5 py-4 font-medium">Статус</th> <div className="px-5 py-4 font-medium">Водитель</div>
<th className="px-5 py-4 font-medium">Водитель</th> <div className="px-5 py-4 font-medium">Дата доставки</div>
<th className="px-5 py-4 font-medium">Дата доставки</th> <div className="px-5 py-4 font-medium">Обновлён</div>
<th className="px-5 py-4 font-medium">Обновлён</th> </div>
</tr>
</thead>
<tbody>
{orderGroups.map((group) => ( {orderGroups.map((group) => (
<tr <button
key={group.id} key={group.id}
className={[ type="button"
"cursor-pointer border-t border-[var(--color-border)] transition hover:bg-[var(--color-accent-soft)]", className={`grid grid-cols-[minmax(180px,2.5fr)_minmax(100px,1.2fr)_minmax(100px,1fr)_minmax(80px,1fr)_minmax(120px,1.2fr)_minmax(130px,1.2fr)] gap-0 w-full border-t border-[var(--color-border)] text-left transition hover:bg-[var(--color-accent-soft)] ${selectedOrderGroupId === group.id ? "bg-[var(--color-accent-soft)]" : ""}`}
selectedOrderGroupId === group.id ? "bg-[var(--color-accent-soft)]" : "",
].join(" ")}
onClick={() => onOpenOrder(group.id)} onClick={() => onOpenOrder(group.id)}
> >
<td className="px-5 py-4"> <div className="px-5 py-4">
<div className="font-medium">{group.displayTitle || group.customerName || group.groupKey}</div> <div className="font-medium">{group.displayTitle || group.customerName || group.groupKey}</div>
<div className="mt-1 text-sm text-[var(--color-text-muted)]"> <div className="mt-1 text-sm text-[var(--color-text-muted)]">
{[group.customerName, group.customerPhone].filter(Boolean).join(" · ")} {[group.customerName, group.customerPhone].filter(Boolean).join(" · ")}
</div> </div>
<div className="text-xs text-[var(--color-text-muted)]">{group.groupKey}</div> <div className="text-xs text-[var(--color-text-muted)]">{group.groupKey}</div>
</td> </div>
<td className="max-w-[260px] px-5 py-4 text-sm text-[var(--color-text-muted)]"> <div className="max-w-[260px] px-5 py-4 text-sm text-[var(--color-text-muted)]">
{renderOrderNumbers(group)} {renderOrderNumbers(group)}
</td> </div>
<td className="px-5 py-4 text-center"> <div className="px-5 py-4">
<Badge tone={getOrderGroupStatusTone(group)}>{getOrderGroupDisplayStatusLabel(group)}</Badge> <Badge tone={getOrderGroupStatusTone(group)}>{getOrderGroupDisplayStatusLabel(group)}</Badge>
</td> </div>
<td className="px-5 py-4 text-sm"> <div className="px-5 py-4 text-sm">
{group.assignedDriverName || <span className="text-[var(--color-text-muted)]"></span>} {group.assignedDriverName || <span className="text-[var(--color-text-muted)]"></span>}
</td> </div>
<td className="px-5 py-4 text-sm"> <div className="px-5 py-4 text-sm">
{group.deliveryDate ? ( {group.deliveryDate ? (
<span>{fmtDate(group.deliveryDate)}{group.deliveryTime ? <span className="text-[var(--color-text-muted)]"> · {group.deliveryTime}</span> : ""}</span> <span>{fmtDate(group.deliveryDate)}{group.deliveryTime ? <span className="text-[var(--color-text-muted)]"> · {group.deliveryTime}</span> : ""}</span>
) : ( ) : (
<span className="text-[var(--color-text-muted)]"></span> <span className="text-[var(--color-text-muted)]"></span>
)} )}
</td> </div>
<td className="px-5 py-4 text-sm text-[var(--color-text-muted)]"> <div className="px-5 py-4 text-sm text-[var(--color-text-muted)]">
{formatDateTime(group.updatedAt)} {formatDateTime(group.updatedAt)}
</td> </div>
</tr> </button>
))} ))}
</tbody> </div>
</table>
)} )}
</div> </div>
</Panel> </Panel>