This commit is contained in:
2026-05-20 18:08:37 +07:00
parent dd3fd889a3
commit 290d36e8cb
21 changed files with 1359 additions and 72 deletions

View File

@@ -5,6 +5,13 @@ import { CATEGORIES } from "@/lib/ui-config";
import type { CategoryId, Place } from "@/lib/types";
import type { Dispatch } from "@/lib/app-state";
import { FieldLabel } from "@/components/ui-primitives";
import {
CoverPicker,
commitCover,
coverStateFromUrl,
disposeCover,
type CoverState,
} from "@/components/cover-picker";
import { Icons } from "@/components/icons";
import { editPlace } from "@/lib/db/actions";
@@ -22,6 +29,7 @@ export function EditPlaceSheet({
const [category, setCategory] = useState<CategoryId>(place.category);
const [tags, setTags] = useState<string[]>(place.tags);
const [tagInput, setTagInput] = useState("");
const [cover, setCover] = useState<CoverState>(() => coverStateFromUrl(place.cover_url));
const [saving, setSaving] = useState(false);
const [, startTransition] = useTransition();
@@ -37,24 +45,32 @@ export function EditPlaceSheet({
if (!isValid) return;
setSaving(true);
const trimmedAddress = address.trim();
startTransition(() => {
editPlace(place.id, {
name: name.trim(),
address: trimmedAddress,
short_address: trimmedAddress.split(",").slice(0, 2).join(" · "),
city: trimmedAddress.split(",").pop()?.trim() || "",
category,
tags,
cover_url: place.cover_url ?? null,
})
.then(() => {
onClose();
dispatch({ type: "TOAST", value: "Đã lưu thay đổi" });
})
.catch(() => {
setSaving(false);
dispatch({ type: "TOAST", value: "Lưu thất bại" });
startTransition(async () => {
try {
// Upload to R2 only now — local blob (if any) is converted to a real
// URL. An existing URL is returned unchanged.
const coverUrl = await commitCover(cover);
const patch = {
name: name.trim(),
address: trimmedAddress,
short_address: trimmedAddress.split(",").slice(0, 2).join(" · "),
city: trimmedAddress.split(",").pop()?.trim() || "",
category,
tags,
cover_url: coverUrl,
};
await editPlace(place.id, patch);
disposeCover(cover);
dispatch({ type: "PATCH_PLACE", placeId: place.id, patch });
onClose();
dispatch({ type: "TOAST", value: "Đã lưu thay đổi" });
} catch (e) {
setSaving(false);
dispatch({
type: "TOAST",
value: (e as Error).message || "Lưu thất bại",
});
}
});
};
@@ -89,6 +105,14 @@ export function EditPlaceSheet({
</div>
<div style={{ flex: 1, overflowY: "auto", padding: "4px 16px" }}>
<div style={{ marginTop: 8 }}>
<CoverPicker
value={cover}
onChange={setCover}
onError={(msg) => dispatch({ type: "TOAST", value: msg })}
/>
</div>
<FieldLabel required>Tên đa điểm</FieldLabel>
<div className="input">
<input value={name} onChange={(e) => setName(e.target.value)} />