aaa
This commit is contained in:
140
src/sheets/save-to-collection-sheet.tsx
Normal file
140
src/sheets/save-to-collection-sheet.tsx
Normal file
@@ -0,0 +1,140 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useTransition } from "react";
|
||||
import { useCollections } from "@/lib/app-context";
|
||||
import type { Dispatch } from "@/lib/app-state";
|
||||
import { Icons } from "@/components/icons";
|
||||
import {
|
||||
addPlaceToCollection,
|
||||
removePlaceFromCollection,
|
||||
} from "@/lib/db/actions";
|
||||
|
||||
export function SaveToCollectionSheet({
|
||||
placeId,
|
||||
onClose,
|
||||
dispatch,
|
||||
}: {
|
||||
placeId: number;
|
||||
onClose: () => void;
|
||||
dispatch: Dispatch;
|
||||
}) {
|
||||
const collections = useCollections();
|
||||
// Initial membership state derived from server data.
|
||||
const [membership, setMembership] = useState<Record<string, boolean>>(() =>
|
||||
Object.fromEntries(collections.map((c) => [c.id, c.place_ids.includes(placeId)])),
|
||||
);
|
||||
const [, startTransition] = useTransition();
|
||||
const editable = collections.filter((c) => c.my_role !== "viewer");
|
||||
|
||||
const toggle = (cid: number) => {
|
||||
const wasIn = !!membership[cid];
|
||||
setMembership({ ...membership, [cid]: !wasIn });
|
||||
startTransition(() => {
|
||||
const op = wasIn
|
||||
? removePlaceFromCollection(cid, placeId)
|
||||
: addPlaceToCollection(cid, placeId);
|
||||
op.catch(() => {
|
||||
setMembership({ ...membership, [cid]: wasIn });
|
||||
dispatch({ type: "TOAST", value: "Lưu thất bại" });
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="overlay" onClick={onClose} />
|
||||
<div className="sheet" style={{ maxHeight: "70%" }}>
|
||||
<div className="sheet-handle" />
|
||||
<div
|
||||
style={{
|
||||
padding: "6px 16px 12px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<button
|
||||
onClick={onClose}
|
||||
style={{
|
||||
background: "transparent",
|
||||
border: 0,
|
||||
color: "var(--muted-foreground)",
|
||||
fontSize: 15,
|
||||
fontWeight: 500,
|
||||
padding: "8px 0",
|
||||
}}
|
||||
>
|
||||
Xong
|
||||
</button>
|
||||
<div style={{ fontSize: 16, fontWeight: 600 }}>Lưu vào bộ sưu tập</div>
|
||||
<div style={{ width: 48 }} />
|
||||
</div>
|
||||
<div style={{ overflowY: "auto", padding: "0 16px 16px" }}>
|
||||
{editable.length === 0 ? (
|
||||
<div
|
||||
style={{
|
||||
padding: "32px 16px",
|
||||
textAlign: "center",
|
||||
color: "var(--muted-foreground)",
|
||||
fontSize: 14,
|
||||
}}
|
||||
>
|
||||
Bạn chưa có bộ sưu tập nào có quyền chỉnh sửa. Tạo bộ sưu tập trước từ tab "Bộ sưu tập".
|
||||
</div>
|
||||
) : (
|
||||
editable.map((c) => {
|
||||
const inIt = !!membership[c.id];
|
||||
const Icon = c.type === "trip" ? Icons.Plane : Icons.Folder;
|
||||
return (
|
||||
<button
|
||||
key={c.id}
|
||||
onClick={() => toggle(c.id)}
|
||||
style={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 14,
|
||||
padding: "12px 4px",
|
||||
background: "transparent",
|
||||
border: 0,
|
||||
borderBottom: "0.5px solid var(--border)",
|
||||
textAlign: "left",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: 10,
|
||||
background: c.type === "trip" ? "var(--primary-soft)" : "var(--muted)",
|
||||
color: c.type === "trip" ? "var(--primary)" : "var(--muted-foreground)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<Icon size={18} stroke={1.75} />
|
||||
</div>
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
<div style={{ fontSize: 15, fontWeight: 500 }}>{c.name}</div>
|
||||
<div style={{ fontSize: 12, color: "var(--muted-foreground)" }}>
|
||||
{c.place_count} địa điểm
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="checkbox"
|
||||
data-checked={inIt}
|
||||
style={{ pointerEvents: "none" }}
|
||||
>
|
||||
<Icons.Check size={14} stroke={3} />
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user