2305c3dc9d
- Add backend/locale/ar_SA/LC_MESSAGES/django.po with Arabic (ar-sa) translations
for all 62 user-facing error/validation strings across accounts, bookings,
payments, and notifications apps; compile to django.mo
- Add common.loading and salon.unknownStaff keys to both ar-sa.json and en.json
- ProtectedRoute: replace hardcoded "Loading..." with t("common.loading")
- BookPage, SalonDetailPage: replace `Staff ${s.id}` fallback with
t("salon.unknownStaff", { id: s.id })
- BookingsPage: pass getActiveLocale() to toLocaleString so date/time
format matches the active app language
All 35 backend tests and 7 frontend tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
56 lines
1.6 KiB
React
56 lines
1.6 KiB
React
import { useEffect, useState } from "react";
|
||
import { useParams, Link } from "react-router-dom";
|
||
import { useTranslation } from "react-i18next";
|
||
import { apiGet } from "../api/client";
|
||
|
||
export default function SalonDetailPage() {
|
||
const { t } = useTranslation();
|
||
const { id } = useParams();
|
||
const [salon, setSalon] = useState(null);
|
||
const [loading, setLoading] = useState(true);
|
||
const [error, setError] = useState("");
|
||
|
||
useEffect(() => {
|
||
if (!id) return;
|
||
apiGet(`/salons/${id}/`)
|
||
.then(setSalon)
|
||
.catch((err) => setError(err.message))
|
||
.finally(() => setLoading(false));
|
||
}, [id]);
|
||
|
||
if (loading) return <p>{t("results.loading")}</p>;
|
||
if (error) return <p className="error">{error}</p>;
|
||
if (!salon) return null;
|
||
|
||
return (
|
||
<section className="salon-detail">
|
||
<h1>{salon.name}</h1>
|
||
<p>{salon.description || t("card.noDescription")}</p>
|
||
<div className="meta">
|
||
<span>{salon.city}</span>
|
||
<span>{salon.phone_number || t("card.phoneUnavailable")}</span>
|
||
</div>
|
||
|
||
<h2>{t("salon.services")}</h2>
|
||
<ul className="service-list">
|
||
{salon.services?.map((s) => (
|
||
<li key={s.id}>
|
||
{s.name} – {s.duration_minutes} min, {s.price_amount} {s.currency}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
|
||
<h2>{t("salon.staff")}</h2>
|
||
<ul className="staff-list">
|
||
{salon.staff?.map((s) => (
|
||
<li key={s.id}>{s.name || s.title || t("salon.unknownStaff", { id: s.id })}</li>
|
||
))}
|
||
</ul>
|
||
|
||
<Link to={`/book?salon=${salon.id}`} className="book-cta">
|
||
{t("book.cta")}
|
||
</Link>
|
||
</section>
|
||
);
|
||
}
|