aaa
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useReducer } from "react";
|
||||
import { COLLECTIONS } from "@/lib/mock-data";
|
||||
import { useEffect, useReducer, useTransition } from "react";
|
||||
import {
|
||||
INITIAL_STATE,
|
||||
makeInitialState,
|
||||
reducer,
|
||||
type Screen,
|
||||
type Tab,
|
||||
} from "@/lib/app-state";
|
||||
import { AppDataProvider, type AppData } from "@/lib/app-context";
|
||||
import type { Place } from "@/lib/types";
|
||||
import { deleteCollection, deletePlace } from "@/lib/db/actions";
|
||||
import { TabBar } from "@/components/ui-primitives";
|
||||
import { Icons } from "@/components/icons";
|
||||
import { PlacesListScreen } from "@/screens/places-list-screen";
|
||||
@@ -16,11 +18,21 @@ import { CollectionsListScreen } from "@/screens/collections-list-screen";
|
||||
import { CollectionDetailScreen } from "@/screens/collection-detail-screen";
|
||||
import { ProfileScreen } from "@/screens/profile-screen";
|
||||
import { AddPlaceSheet } from "@/sheets/add-place-sheet";
|
||||
import { EditPlaceSheet } from "@/sheets/edit-place-sheet";
|
||||
import { SaveToCollectionSheet } from "@/sheets/save-to-collection-sheet";
|
||||
import { CollectionFormSheet } from "@/sheets/collection-form-sheet";
|
||||
import { InviteDialog } from "@/sheets/invite-dialog";
|
||||
import { MembersSheet, ConfirmDialog } from "@/sheets/members-sheet";
|
||||
|
||||
export function PlacesApp() {
|
||||
const [state, dispatch] = useReducer(reducer, INITIAL_STATE);
|
||||
export function PlacesApp({
|
||||
initialPlaces,
|
||||
data,
|
||||
}: {
|
||||
initialPlaces: Place[];
|
||||
data: AppData;
|
||||
}) {
|
||||
const [state, dispatch] = useReducer(reducer, initialPlaces, makeInitialState);
|
||||
const [, startTransition] = useTransition();
|
||||
|
||||
useEffect(() => {
|
||||
if (!state.toast) return;
|
||||
@@ -32,7 +44,6 @@ export function PlacesApp() {
|
||||
return () => clearTimeout(id);
|
||||
}, [state.toast, state.toastKey]);
|
||||
|
||||
// Online/offline detection
|
||||
useEffect(() => {
|
||||
const sync = () =>
|
||||
dispatch({ type: "SET_OFFLINE", value: !navigator.onLine });
|
||||
@@ -88,70 +99,118 @@ export function PlacesApp() {
|
||||
: null;
|
||||
const collectionForDelete =
|
||||
m?.type === "confirmDeleteCollection"
|
||||
? COLLECTIONS.find((c) => c.id === m.collectionId)
|
||||
? data.collections.find((c) => c.id === m.collectionId)
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="app-frame">
|
||||
{renderScreen(top.screen)}
|
||||
<TabBar
|
||||
active={activeTab}
|
||||
onTab={onTab}
|
||||
onFab={() => dispatch({ type: "OPEN_ADD" })}
|
||||
showFab={top.screen !== "profile"}
|
||||
/>
|
||||
<AppDataProvider value={data}>
|
||||
<div className="app-frame">
|
||||
{renderScreen(top.screen)}
|
||||
<TabBar
|
||||
active={activeTab}
|
||||
onTab={onTab}
|
||||
onFab={() => dispatch({ type: "OPEN_ADD" })}
|
||||
showFab={top.screen !== "profile"}
|
||||
/>
|
||||
|
||||
{m?.type === "add" && (
|
||||
<AddPlaceSheet
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
)}
|
||||
{m?.type === "invite" && (
|
||||
<InviteDialog
|
||||
collectionId={m.collectionId}
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
)}
|
||||
{m?.type === "members" && (
|
||||
<MembersSheet
|
||||
collectionId={m.collectionId}
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
)}
|
||||
{m?.type === "confirmDeletePlace" && placeForDelete && (
|
||||
<ConfirmDialog
|
||||
title="Xóa địa điểm?"
|
||||
body={`"${placeForDelete.name}" sẽ bị xóa khỏi tất cả bộ sưu tập. Không thể hoàn tác.`}
|
||||
confirmLabel="Xóa"
|
||||
onConfirm={() =>
|
||||
dispatch({ type: "DELETE_PLACE", placeId: m.placeId })
|
||||
}
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
/>
|
||||
)}
|
||||
{m?.type === "confirmDeleteCollection" && collectionForDelete && (
|
||||
<ConfirmDialog
|
||||
title="Xóa bộ sưu tập?"
|
||||
body={`"${collectionForDelete.name}" sẽ bị xóa. Các địa điểm bên trong vẫn còn ở "Địa điểm".`}
|
||||
confirmLabel="Xóa"
|
||||
onConfirm={() => {
|
||||
dispatch({ type: "CLOSE_MODAL" });
|
||||
dispatch({ type: "BACK" });
|
||||
dispatch({ type: "TOAST", value: "Đã xóa" });
|
||||
}}
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
/>
|
||||
)}
|
||||
{m?.type === "add" && (
|
||||
<AddPlaceSheet
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
)}
|
||||
{m?.type === "editPlace" && (() => {
|
||||
const p = state.places.find((x) => x.id === m.placeId);
|
||||
return p ? (
|
||||
<EditPlaceSheet
|
||||
place={p}
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
) : null;
|
||||
})()}
|
||||
{m?.type === "saveToCollection" && (
|
||||
<SaveToCollectionSheet
|
||||
placeId={m.placeId}
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
)}
|
||||
{m?.type === "createCollection" && (
|
||||
<CollectionFormSheet
|
||||
mode="create"
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
)}
|
||||
{m?.type === "editCollection" && (() => {
|
||||
const c = data.collections.find((x) => x.id === m.collectionId);
|
||||
return c ? (
|
||||
<CollectionFormSheet
|
||||
mode="edit"
|
||||
collection={c}
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
) : null;
|
||||
})()}
|
||||
{m?.type === "invite" && (
|
||||
<InviteDialog
|
||||
collectionId={m.collectionId}
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
)}
|
||||
{m?.type === "members" && (
|
||||
<MembersSheet
|
||||
collectionId={m.collectionId}
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
)}
|
||||
{m?.type === "confirmDeletePlace" && placeForDelete && (
|
||||
<ConfirmDialog
|
||||
title="Xóa địa điểm?"
|
||||
body={`"${placeForDelete.name}" sẽ bị xóa khỏi tất cả bộ sưu tập. Không thể hoàn tác.`}
|
||||
confirmLabel="Xóa"
|
||||
onConfirm={() => {
|
||||
const id = m.placeId;
|
||||
dispatch({ type: "DELETE_PLACE", placeId: id });
|
||||
startTransition(() => {
|
||||
deletePlace(id).catch(() =>
|
||||
dispatch({ type: "TOAST", value: "Xóa thất bại" }),
|
||||
);
|
||||
});
|
||||
}}
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
/>
|
||||
)}
|
||||
{m?.type === "confirmDeleteCollection" && collectionForDelete && (
|
||||
<ConfirmDialog
|
||||
title="Xóa bộ sưu tập?"
|
||||
body={`"${collectionForDelete.name}" sẽ bị xóa. Các địa điểm bên trong vẫn còn ở "Địa điểm".`}
|
||||
confirmLabel="Xóa"
|
||||
onConfirm={() => {
|
||||
const id = m.collectionId;
|
||||
dispatch({ type: "CLOSE_MODAL" });
|
||||
dispatch({ type: "BACK" });
|
||||
startTransition(() => {
|
||||
deleteCollection(id)
|
||||
.then(() => dispatch({ type: "TOAST", value: "Đã xóa" }))
|
||||
.catch(() => dispatch({ type: "TOAST", value: "Xóa thất bại" }));
|
||||
});
|
||||
}}
|
||||
onClose={() => dispatch({ type: "CLOSE_MODAL" })}
|
||||
/>
|
||||
)}
|
||||
|
||||
{state.toast && (
|
||||
<div className="toast" key={state.toastKey}>
|
||||
<Icons.Check size={14} stroke={2.5} />
|
||||
{state.toast}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{state.toast && (
|
||||
<div className="toast" key={state.toastKey}>
|
||||
<Icons.Check size={14} stroke={2.5} />
|
||||
{state.toast}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</AppDataProvider>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user