winofy-front/src/components/customer/address-selector.tsx
2026-09-05 11:37:15 +03:30

106 lines
4 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState, useTransition } from "react";
import { useRouter } from "next/navigation";
import { updateAddress } from "@/lib/api/addresses";
import type { Address, AddressLabel } from "@/types/api";
const ADDRESS_LABEL_FA: Record<AddressLabel, string> = {
home: "خانه",
work: "محل کار",
other: "سایر",
};
/**
* Doubles as both a plain address-management screen (reached from the profile menu)
* and a picker (reached from checkout's "تغییر آدرس" with a `next` return path) —
* the radio always reflects/sets which address is the default, "تأیید" just persists
* that choice and, if there's somewhere to return to, goes back there.
*/
export function AddressSelector({ addresses, next }: { addresses: Address[]; next: string | null }) {
const router = useRouter();
const [selectedUuid, setSelectedUuid] = useState(
() => addresses.find((a) => a.is_default)?.uuid ?? addresses[0]?.uuid ?? null,
);
const [error, setError] = useState<string | null>(null);
const [isPending, startTransition] = useTransition();
function handleConfirm() {
setError(null);
const currentDefaultUuid = addresses.find((a) => a.is_default)?.uuid;
if (!selectedUuid || selectedUuid === currentDefaultUuid) {
if (next) router.push(next);
return;
}
startTransition(async () => {
const result = await updateAddress(selectedUuid, { is_default: true });
if (result.ok) {
if (next) router.push(next);
else router.refresh();
} else {
setError(result.message);
}
});
}
return (
<div className="flex flex-1 flex-col gap-6 px-4 pb-6">
<div className="flex flex-col gap-3">
{addresses.map((address) => {
const isSelected = address.uuid === selectedUuid;
return (
<button
key={address.uuid}
type="button"
onClick={() => setSelectedUuid(address.uuid)}
className={`flex flex-col gap-1 rounded-2xl border p-4 text-right ${
isSelected ? "border-primary-action" : "border-gray-300"
}`}
>
{/* DOM order intentionally mirrors the screenshot's left→right layout —
see the inherited dir="rtl" note on the /cart page. */}
<div className="flex items-center justify-between">
<span className="text-[14px] font-bold leading-none text-foreground">
{address.title || ADDRESS_LABEL_FA[address.label]}
</span>
<span
className={`flex h-5 w-5 shrink-0 items-center justify-center rounded-full border-2 ${
isSelected ? "border-primary-action" : "border-gray-300"
}`}
>
{isSelected && <span className="h-2.5 w-2.5 rounded-full bg-primary-action" />}
</span>
</div>
<p className="text-[13px] leading-normal text-gray-600">{address.full_address}</p>
</button>
);
})}
{addresses.length === 0 && (
<p className="py-4 text-center text-[13px] text-gray-600">هنوز آدرسی ثبت نکرده‌اید.</p>
)}
<button
type="button"
onClick={() => router.push(next ? `/addresses/map?next=${encodeURIComponent(next)}` : "/addresses/map")}
className="rounded-2xl border border-primary-action py-4 text-[14px] font-bold text-primary-action"
>
افزودن آدرس جدید
</button>
</div>
{error && <p className="text-[13px] text-error">{error}</p>}
{addresses.length > 0 && (
<button
type="button"
onClick={handleConfirm}
disabled={isPending}
className="mt-auto w-full rounded-2xl bg-primary-action py-4 text-[15px] font-bold text-white disabled:opacity-40"
>
{isPending ? "در حال ذخیره..." : "تأیید"}
</button>
)}
</div>
);
}