Deploy / deploy (push) Failing after 5s
Каркас витрины дизайнера Ники: главная (hero + сетка галереи), страница работы (детали + место под аукцион), список аукционов, подписка-заглушка. Клиент к backend /api с graceful-фолбэком на демо-работы при недоступном API. Standalone-сборка + Dockerfile. Сборка npm run build и tsc --noEmit проходят. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
44 lines
1.8 KiB
TypeScript
44 lines
1.8 KiB
TypeScript
import type { Work } from './types';
|
|
|
|
// Форматирование цены в рублях. NUMERIC из pg приходит строкой.
|
|
export function formatPrice(value: string | number | null | undefined): string {
|
|
if (value === null || value === undefined || value === '') return 'Цена по запросу';
|
|
const n = typeof value === 'string' ? Number(value) : value;
|
|
if (Number.isNaN(n)) return 'Цена по запросу';
|
|
return new Intl.NumberFormat('ru-RU', {
|
|
style: 'currency',
|
|
currency: 'RUB',
|
|
maximumFractionDigits: 0,
|
|
}).format(n);
|
|
}
|
|
|
|
// Детерминированный плейсхолдер из picsum по seed (id/slug работы),
|
|
// пока не пришли реальные изображения. Стабилен между сборками.
|
|
export function placeholderImage(seed: string, w = 800, h = 1000): string {
|
|
const s = encodeURIComponent(seed || 'nika');
|
|
return `https://picsum.photos/seed/${s}/${w}/${h}`;
|
|
}
|
|
|
|
// Выбираем обложку работы: cover_url из view → первое media → плейсхолдер.
|
|
export function coverOf(work: Work, w?: number, h?: number): string {
|
|
return (
|
|
work.cover_url ||
|
|
work.cover_thumb ||
|
|
work.media?.[0]?.url ||
|
|
placeholderImage(work.slug || work.id, w, h)
|
|
);
|
|
}
|
|
|
|
// Оставшееся время аукциона в человекочитаемом виде.
|
|
export function timeLeft(endAt: string): string {
|
|
const ms = new Date(endAt).getTime() - Date.now();
|
|
if (Number.isNaN(ms)) return '';
|
|
if (ms <= 0) return 'Завершён';
|
|
const d = Math.floor(ms / 86_400_000);
|
|
const h = Math.floor((ms % 86_400_000) / 3_600_000);
|
|
const m = Math.floor((ms % 3_600_000) / 60_000);
|
|
if (d > 0) return `${d} д ${h} ч`;
|
|
if (h > 0) return `${h} ч ${m} мин`;
|
|
return `${m} мин`;
|
|
}
|