Consolidate profile and security into AccountTab, add shared dashboard components, and move awaiting-approval payment messages to translations. Co-authored-by: Cursor <cursoragent@cursor.com>
55 lines
1.2 KiB
TypeScript
55 lines
1.2 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
|
|
/**
|
|
* Live, human countdown to a target time. Renders a short message such as
|
|
* "Pay within 23h or your spot is released". Once the target passes it shows a
|
|
* calm "expired" message instead of a negative timer.
|
|
*/
|
|
export function HoldCountdown({
|
|
target,
|
|
locale,
|
|
}: {
|
|
target: Date;
|
|
locale: string;
|
|
}) {
|
|
const [now, setNow] = useState(() => Date.now());
|
|
|
|
useEffect(() => {
|
|
const id = setInterval(() => setNow(Date.now()), 60 * 1000);
|
|
return () => clearInterval(id);
|
|
}, []);
|
|
|
|
const msLeft = target.getTime() - now;
|
|
|
|
if (msLeft <= 0) {
|
|
return (
|
|
<span>
|
|
{locale === 'es'
|
|
? 'Paga pronto para mantener tu lugar'
|
|
: 'Pay soon to keep your spot'}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
const totalMinutes = Math.floor(msLeft / (60 * 1000));
|
|
const hours = Math.floor(totalMinutes / 60);
|
|
const minutes = totalMinutes % 60;
|
|
|
|
let remaining: string;
|
|
if (hours >= 1) {
|
|
remaining = `${hours}h${minutes > 0 ? ` ${minutes}m` : ''}`;
|
|
} else {
|
|
remaining = `${minutes}m`;
|
|
}
|
|
|
|
return (
|
|
<span>
|
|
{locale === 'es'
|
|
? `Paga en ${remaining} o tu lugar se libera`
|
|
: `Pay within ${remaining} or your spot is released`}
|
|
</span>
|
|
);
|
|
}
|