Phase 6: Translate User Pages - exchange, trades, invites, profile
- Expand exchange.json with all exchange page strings (page, steps, detailsStep, bookingStep, confirmationStep, priceDisplay) - Create trades.json translation files for es, en, ca - Create invites.json translation files for es, en, ca - Create profile.json translation files for es, en, ca - Translate exchange page and all components (ExchangeDetailsStep, BookingStep, ConfirmationStep, StepIndicator, PriceDisplay) - Translate trades page (titles, sections, buttons, status labels) - Translate invites page (titles, sections, status badges, copy button) - Translate profile page (form labels, hints, placeholders, messages) - Update IntlProvider to load all new namespaces - All frontend tests passing
This commit is contained in:
parent
7dd13292a0
commit
246553c402
22 changed files with 559 additions and 115 deletions
|
|
@ -15,9 +15,12 @@ import { useMutation } from "../hooks/useMutation";
|
|||
import { formatDateTime } from "../utils/date";
|
||||
import { formatEur } from "../utils/exchange";
|
||||
import { typographyStyles, tradeCardStyles } from "../styles/shared";
|
||||
import { useTranslation } from "../hooks/useTranslation";
|
||||
|
||||
export default function TradesPage() {
|
||||
const router = useRouter();
|
||||
const t = useTranslation("trades");
|
||||
const tExchange = useTranslation("exchange");
|
||||
const { user, isLoading, isAuthorized } = useRequireAuth({
|
||||
requiredPermission: Permission.VIEW_OWN_EXCHANGES,
|
||||
fallbackRedirect: "/",
|
||||
|
|
@ -70,17 +73,17 @@ export default function TradesPage() {
|
|||
error={error}
|
||||
contentStyle={styles.content}
|
||||
>
|
||||
<h1 style={typographyStyles.pageTitle}>My Trades</h1>
|
||||
<p style={typographyStyles.pageSubtitle}>View and manage your Bitcoin trades</p>
|
||||
<h1 style={typographyStyles.pageTitle}>{t("page.title")}</h1>
|
||||
<p style={typographyStyles.pageSubtitle}>{t("page.subtitle")}</p>
|
||||
|
||||
{isLoadingTrades ? (
|
||||
<EmptyState message="Loading trades..." isLoading={true} />
|
||||
<EmptyState message={t("page.loadingTrades")} isLoading={true} />
|
||||
) : (trades?.length ?? 0) === 0 ? (
|
||||
<EmptyState
|
||||
message="You don't have any trades yet."
|
||||
message={t("page.noTrades")}
|
||||
action={
|
||||
<a href="/exchange" style={styles.emptyStateLink}>
|
||||
Start trading
|
||||
{t("page.startTrading")}
|
||||
</a>
|
||||
}
|
||||
/>
|
||||
|
|
@ -89,7 +92,9 @@ export default function TradesPage() {
|
|||
{/* Upcoming Trades */}
|
||||
{upcomingTrades.length > 0 && (
|
||||
<div style={styles.section}>
|
||||
<h2 style={styles.sectionTitle}>Upcoming ({upcomingTrades.length})</h2>
|
||||
<h2 style={styles.sectionTitle}>
|
||||
{t("page.upcoming", { count: upcomingTrades.length })}
|
||||
</h2>
|
||||
<div style={tradeCardStyles.tradeList}>
|
||||
{upcomingTrades.map((trade) => {
|
||||
const isBuy = trade.direction === "buy";
|
||||
|
|
@ -110,7 +115,7 @@ export default function TradesPage() {
|
|||
color: isBuy ? "#4ade80" : "#f87171",
|
||||
}}
|
||||
>
|
||||
{isBuy ? "BUY BTC" : "SELL BTC"}
|
||||
{isBuy ? tExchange("direction.buy") : tExchange("direction.sell")}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
|
|
@ -120,8 +125,8 @@ export default function TradesPage() {
|
|||
}}
|
||||
>
|
||||
{isBuy
|
||||
? `Receive via ${trade.bitcoin_transfer_method === "onchain" ? "Onchain" : "Lightning"}`
|
||||
: `Send via ${trade.bitcoin_transfer_method === "onchain" ? "Onchain" : "Lightning"}`}
|
||||
? `${tExchange("bookingStep.receiveVia")} ${trade.bitcoin_transfer_method === "onchain" ? tExchange("transferMethod.onchain") : tExchange("transferMethod.lightning")}`
|
||||
: `${tExchange("bookingStep.sendVia")} ${trade.bitcoin_transfer_method === "onchain" ? tExchange("transferMethod.onchain") : tExchange("transferMethod.lightning")}`}
|
||||
</span>
|
||||
<span style={tradeCardStyles.amount}>
|
||||
{formatEur(trade.eur_amount)}
|
||||
|
|
@ -132,7 +137,7 @@ export default function TradesPage() {
|
|||
</span>
|
||||
</div>
|
||||
<div style={tradeCardStyles.rateRow}>
|
||||
<span style={tradeCardStyles.rateLabel}>Rate:</span>
|
||||
<span style={tradeCardStyles.rateLabel}>{t("trade.rate")}</span>
|
||||
<span style={tradeCardStyles.rateValue}>
|
||||
€
|
||||
{trade.agreed_price_eur.toLocaleString("de-DE", {
|
||||
|
|
@ -153,7 +158,7 @@ export default function TradesPage() {
|
|||
onConfirm={() => handleCancel(trade.public_id)}
|
||||
onCancel={() => setConfirmCancelId(null)}
|
||||
onActionClick={() => setConfirmCancelId(trade.public_id)}
|
||||
actionLabel="Cancel"
|
||||
actionLabel={t("trade.cancel")}
|
||||
isLoading={cancellingId === trade.public_id}
|
||||
confirmVariant="danger"
|
||||
confirmButtonStyle={styles.confirmButton}
|
||||
|
|
@ -166,7 +171,7 @@ export default function TradesPage() {
|
|||
}}
|
||||
style={styles.viewDetailsButton}
|
||||
>
|
||||
View Details
|
||||
{t("trade.viewDetails")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -181,7 +186,7 @@ export default function TradesPage() {
|
|||
{pastOrFinalTrades.length > 0 && (
|
||||
<div style={styles.section}>
|
||||
<h2 style={typographyStyles.sectionTitleMuted}>
|
||||
History ({pastOrFinalTrades.length})
|
||||
{t("page.history", { count: pastOrFinalTrades.length })}
|
||||
</h2>
|
||||
<div style={tradeCardStyles.tradeList}>
|
||||
{pastOrFinalTrades.map((trade) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue