feat(pwa/repairs): show price per row + total sum header
В каждой карточке ленты ремонтов справа от строки работ выводим сумму работ (works_total из бэка, без запчастей). Шапка над лентой переехала: слева «Итого: NNN ₽ (X ремонтов)», справа кнопка «Обновить» (раньше была одна сверху-справа).
This commit is contained in:
@@ -14,6 +14,7 @@ export interface FeedItem {
|
||||
mechanic_name: string;
|
||||
works_preview: FeedWorkBrief[];
|
||||
works_extra: number;
|
||||
works_total: number; // сумма работ без запчастей
|
||||
photo_url: string | null;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,8 +83,19 @@ export default function RepairsFeedPage() {
|
||||
</header>
|
||||
|
||||
<main className="flex-1 container max-w-2xl py-3 space-y-2">
|
||||
{/* Refresh tap-area для не-touch юзкейса; жест pull-to-refresh — в PR-8. */}
|
||||
<div className="flex items-center justify-end">
|
||||
{/* Итого слева — сумма работ загруженных ремонтов; Обновить справа. */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-sm">
|
||||
<span className="text-muted-foreground">Итого:</span>{" "}
|
||||
<span className="font-semibold tabular-nums">
|
||||
{fmtMoney(items.reduce((s, it) => s + (it.works_total || 0), 0))} ₽
|
||||
</span>
|
||||
{items.length > 0 && (
|
||||
<span className="text-xs text-muted-foreground ml-2">
|
||||
({items.length} {pluralRepairs(items.length)})
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleRefresh}
|
||||
@@ -176,13 +187,32 @@ function RepairRow({ item, onOpen }: { item: FeedItem; onOpen: () => void }) {
|
||||
<div className="text-xs text-muted-foreground truncate">
|
||||
Механик: {item.mechanic_name}
|
||||
</div>
|
||||
<div className="flex items-baseline justify-between gap-2">
|
||||
<WorksLine works={item.works_preview.map((w) => w.name)} extra={item.works_extra} />
|
||||
<div className="text-sm font-semibold tabular-nums flex-shrink-0">
|
||||
{fmtMoney(item.works_total || 0)} ₽
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function fmtMoney(n: number): string {
|
||||
return new Intl.NumberFormat("ru-RU", { maximumFractionDigits: 0 }).format(Math.round(n));
|
||||
}
|
||||
|
||||
function pluralRepairs(n: number): string {
|
||||
const mod10 = n % 10;
|
||||
const mod100 = n % 100;
|
||||
if (mod100 >= 11 && mod100 <= 14) return "ремонтов";
|
||||
if (mod10 === 1) return "ремонт";
|
||||
if (mod10 >= 2 && mod10 <= 4) return "ремонта";
|
||||
return "ремонтов";
|
||||
}
|
||||
|
||||
|
||||
function WorksLine({ works, extra }: { works: string[]; extra: number }) {
|
||||
// У40: ellipsis в одну строку. Соединяем имена работ через «·».
|
||||
if (works.length === 0) return null;
|
||||
|
||||
Reference in New Issue
Block a user