Skip to content

Commit

Permalink
refactor: view store
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnyjoygh committed Mar 6, 2025
1 parent 2e0467e commit 56ad8ab
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 80 deletions.
36 changes: 23 additions & 13 deletions web/src/components/MemoDisplaySettingMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Option, Select, Switch } from "@mui/joy";
import { Option, Select } from "@mui/joy";
import { Settings2Icon } from "lucide-react";
import { observer } from "mobx-react-lite";
import { useMemoFilterStore } from "@/store/v1";
import { viewStore } from "@/store/v2";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover";
Expand All @@ -12,34 +12,44 @@ interface Props {

const MemoDisplaySettingMenu = observer(({ className }: Props) => {
const t = useTranslate();
const memoFilterStore = useMemoFilterStore();
const isApplying = Boolean(memoFilterStore.orderByTimeAsc) !== false || memoFilterStore.masonry;
const isApplying = viewStore.state.orderByTimeAsc !== false || viewStore.state.layout !== "LIST";

return (
<Popover>
<PopoverTrigger
className={cn(className, isApplying ? "text-teal-600 bg-teal-50 dark:text-teal-500 dark:bg-teal-900 rounded-sm" : "opacity-40")}
className={cn(className, isApplying ? "text-teal-600 bg-teal-100 dark:text-teal-500 dark:bg-teal-900 rounded" : "opacity-40")}
>
<Settings2Icon className="w-4 h-auto shrink-0" />
</PopoverTrigger>
<PopoverContent align="end" alignOffset={-12} sideOffset={14}>
<div className="flex flex-col gap-2">
<div className="w-full flex flex-row justify-between items-center">
<span className="text-sm shrink-0 mr-3">{t("memo.order-by")}</span>
<Select value="displayTime">
<Option value={"displayTime"}>{t("memo.display-time")}</Option>
</Select>
</div>
<div className="w-full flex flex-row justify-between items-center">
<span className="text-sm shrink-0 mr-3">{t("memo.direction")}</span>
<Select value={memoFilterStore.orderByTimeAsc} onChange={(_, value) => memoFilterStore.setOrderByTimeAsc(Boolean(value))}>
<Select
value={viewStore.state.orderByTimeAsc}
onChange={(_, value) =>
viewStore.state.setPartial({
orderByTimeAsc: Boolean(value),
})
}
>
<Option value={false}>{t("memo.direction-desc")}</Option>
<Option value={true}>{t("memo.direction-asc")}</Option>
</Select>
</div>
<div className="w-full flex flex-row justify-between items-center">
<span className="text-sm shrink-0 mr-3">{t("memo.masonry-view")}</span>
<Switch checked={memoFilterStore.masonry} onChange={(event) => memoFilterStore.setMasonry(event.target.checked)} />
<Select
value={viewStore.state.layout}
onChange={(_, value) =>
viewStore.state.setPartial({
layout: value as "LIST" | "MASONRY",
})
}
>
<Option value={"LIST"}>{"List"}</Option>
<Option value={"MASONRY"}>{"Masonry"}</Option>
</Select>
</div>
</div>
</PopoverContent>
Expand Down
53 changes: 12 additions & 41 deletions web/src/components/MemoFilters.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,33 @@
import { isEqual } from "lodash-es";
import { CalendarIcon, CheckCircleIcon, CodeIcon, EyeIcon, HashIcon, LinkIcon, SearchIcon, XIcon } from "lucide-react";
import { useEffect, useRef } from "react";
import { useEffect } from "react";
import { useSearchParams } from "react-router-dom";
import { FilterFactor, getMemoFilterKey, MemoFilter, parseFilterQuery, stringifyFilters, useMemoFilterStore } from "@/store/v1";
import { FilterFactor, getMemoFilterKey, MemoFilter, stringifyFilters, useMemoFilterStore } from "@/store/v1";

const MemoFilters = () => {
const [searchParams, setSearchParams] = useSearchParams();
const memoFilterStore = useMemoFilterStore();
const filters = memoFilterStore.filters;
const orderByTimeAsc = memoFilterStore.orderByTimeAsc;
const lastUpdateRef = useRef<"url" | "store">("url");

// set lastUpdateRef to store when filters or orderByTimeAsc changes
useEffect(() => {
lastUpdateRef.current = "store";
}, [filters, orderByTimeAsc]);

// set lastUpdateRef to url when searchParams changes
useEffect(() => {
lastUpdateRef.current = "url";
}, [searchParams]);

const checkAndSync = () => {
const filtersInURL = searchParams.get("filter") || "";
const orderByTimeAscInURL = searchParams.get("orderBy") === "asc";
const storeMatchesURL = filtersInURL === stringifyFilters(filters) && orderByTimeAscInURL === orderByTimeAsc;
const storeMatchesURL = filtersInURL === stringifyFilters(filters);

if (!storeMatchesURL) {
if (lastUpdateRef.current === "url") {
// Sync URL -> Store
memoFilterStore.setState({
filters: parseFilterQuery(filtersInURL),
orderByTimeAsc: orderByTimeAscInURL,
masonry: memoFilterStore.masonry,
});
} else if (lastUpdateRef.current === "store") {
// Sync Store -> URL
const newSearchParams = new URLSearchParams(searchParams);

if (orderByTimeAsc) {
newSearchParams.set("orderBy", "asc");
} else {
newSearchParams.delete("orderBy");
}
// Sync Store -> URL
const newSearchParams = new URLSearchParams(searchParams);

if (filters.length > 0) {
newSearchParams.set("filter", stringifyFilters(filters));
} else {
newSearchParams.delete("filter");
}

setSearchParams(newSearchParams);
if (filters.length > 0) {
newSearchParams.set("filter", stringifyFilters(filters));
} else {
newSearchParams.delete("filter");
}

setSearchParams(newSearchParams);
}
};

// Watch both URL and store changes
useEffect(checkAndSync, [searchParams, filters, orderByTimeAsc]);
useEffect(checkAndSync, [searchParams, filters]);

const getFilterDisplayText = (filter: MemoFilter) => {
if (filter.value) {
Expand Down
8 changes: 4 additions & 4 deletions web/src/components/PagedMemoList/PagedMemoList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import PullToRefresh from "react-simple-pull-to-refresh";
import { DEFAULT_LIST_MEMOS_PAGE_SIZE } from "@/helpers/consts";
import useResponsiveWidth from "@/hooks/useResponsiveWidth";
import { Routes } from "@/router";
import { useMemoFilterStore, useMemoList, useMemoStore } from "@/store/v1";
import { useMemoList, useMemoStore } from "@/store/v1";
import { viewStore } from "@/store/v2";
import { Direction, State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service";
import { useTranslate } from "@/utils/i18n";
Expand Down Expand Up @@ -36,7 +37,6 @@ const PagedMemoList = observer((props: Props) => {
const { md } = useResponsiveWidth();
const memoStore = useMemoStore();
const memoList = useMemoList();
const memoFilterStore = useMemoFilterStore();
const [state, setState] = useState<LocalState>({
isRequesting: true, // Initial request
nextPageToken: "",
Expand Down Expand Up @@ -77,7 +77,7 @@ const PagedMemoList = observer((props: Props) => {
memoList={sortedMemoList}
renderer={props.renderer}
prefixElement={showMemoEditor ? <MemoEditor className="mb-2" cacheKey="home-memo-editor" /> : undefined}
listMode={!memoFilterStore.masonry}
listMode={viewStore.state.layout === "LIST"}
/>
{state.isRequesting && (
<div className="w-full flex flex-row justify-center items-center my-4">
Expand All @@ -92,7 +92,7 @@ const PagedMemoList = observer((props: Props) => {
<p className="mt-2 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>
</div>
) : (
<div className="w-full flex flex-row justify-center items-center my-4">
<div className="w-full opacity-70 flex flex-row justify-center items-center my-4">
{state.nextPageToken && (
<Button variant="plain" onClick={() => fetchMoreMemos(state.nextPageToken)}>
{t("memo.load-more")}
Expand Down
5 changes: 3 additions & 2 deletions web/src/pages/Archived.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import MemoView from "@/components/MemoView";
import PagedMemoList from "@/components/PagedMemoList";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useMemoFilterStore } from "@/store/v1";
import { viewStore } from "@/store/v2";
import { Direction, State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service";

Expand Down Expand Up @@ -38,14 +39,14 @@ const Archived = () => {
memos
.filter((memo) => memo.state === State.ARCHIVED)
.sort((a, b) =>
memoFilterStore.orderByTimeAsc
viewStore.state.orderByTimeAsc
? dayjs(a.displayTime).unix() - dayjs(b.displayTime).unix()
: dayjs(b.displayTime).unix() - dayjs(a.displayTime).unix(),
)
}
owner={user.name}
state={State.ARCHIVED}
direction={memoFilterStore.orderByTimeAsc ? Direction.ASC : Direction.DESC}
direction={viewStore.state.orderByTimeAsc ? Direction.ASC : Direction.DESC}
oldFilter={memoListFilter}
/>
);
Expand Down
7 changes: 4 additions & 3 deletions web/src/pages/Explore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import MemoView from "@/components/MemoView";
import PagedMemoList from "@/components/PagedMemoList";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useMemoFilterStore } from "@/store/v1";
import { viewStore } from "@/store/v2";
import { Direction, State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service";

Expand Down Expand Up @@ -41,7 +42,7 @@ const Explore = () => {
conditions.push(`tag_search == [${tagSearch.join(", ")}]`);
}
return conditions.join(" && ");
}, [user, memoFilterStore.filters, memoFilterStore.orderByTimeAsc]);
}, [user, memoFilterStore.filters, viewStore.state.orderByTimeAsc]);

return (
<PagedMemoList
Expand All @@ -50,12 +51,12 @@ const Explore = () => {
memos
.filter((memo) => memo.state === State.NORMAL)
.sort((a, b) =>
memoFilterStore.orderByTimeAsc
viewStore.state.orderByTimeAsc
? dayjs(a.displayTime).unix() - dayjs(b.displayTime).unix()
: dayjs(b.displayTime).unix() - dayjs(a.displayTime).unix(),
)
}
direction={memoFilterStore.orderByTimeAsc ? Direction.ASC : Direction.DESC}
direction={viewStore.state.orderByTimeAsc ? Direction.ASC : Direction.DESC}
oldFilter={memoListFilter}
/>
);
Expand Down
8 changes: 4 additions & 4 deletions web/src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import MemoView from "@/components/MemoView";
import PagedMemoList from "@/components/PagedMemoList";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useMemoFilterStore } from "@/store/v1";
import { userStore } from "@/store/v2";
import { viewStore, userStore } from "@/store/v2";
import { Direction, State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service";

Expand Down Expand Up @@ -44,7 +44,7 @@ const Home = observer(() => {
conditions.push(`tag_search == [${tagSearch.join(", ")}]`);
}
return conditions.join(" && ");
}, [user, memoFilterStore.filters, memoFilterStore.orderByTimeAsc]);
}, [user, memoFilterStore.filters, viewStore.state.orderByTimeAsc]);

return (
<PagedMemoList
Expand All @@ -53,14 +53,14 @@ const Home = observer(() => {
memos
.filter((memo) => memo.state === State.NORMAL)
.sort((a, b) =>
memoFilterStore.orderByTimeAsc
viewStore.state.orderByTimeAsc
? dayjs(a.displayTime).unix() - dayjs(b.displayTime).unix()
: dayjs(b.displayTime).unix() - dayjs(a.displayTime).unix(),
)
.sort((a, b) => Number(b.pinned) - Number(a.pinned))
}
owner={user.name}
direction={memoFilterStore.orderByTimeAsc ? Direction.ASC : Direction.DESC}
direction={viewStore.state.orderByTimeAsc ? Direction.ASC : Direction.DESC}
filter={selectedShortcut?.filter || ""}
oldFilter={memoListFilter}
/>
Expand Down
11 changes: 6 additions & 5 deletions web/src/pages/UserProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Button } from "@usememos/mui";
import copy from "copy-to-clipboard";
import dayjs from "dayjs";
import { ExternalLinkIcon } from "lucide-react";
import { observer } from "mobx-react-lite";
import { useEffect, useMemo, useState } from "react";
import { toast } from "react-hot-toast";
import { useParams } from "react-router-dom";
Expand All @@ -11,13 +12,13 @@ import PagedMemoList from "@/components/PagedMemoList";
import UserAvatar from "@/components/UserAvatar";
import useLoading from "@/hooks/useLoading";
import { useMemoFilterStore } from "@/store/v1";
import { userStore } from "@/store/v2";
import { viewStore, userStore } from "@/store/v2";
import { Direction, State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service";
import { User } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n";

const UserProfile = () => {
const UserProfile = observer(() => {
const t = useTranslate();
const params = useParams();
const loadingState = useLoading();
Expand Down Expand Up @@ -107,14 +108,14 @@ const UserProfile = () => {
memos
.filter((memo) => memo.state === State.NORMAL)
.sort((a, b) =>
memoFilterStore.orderByTimeAsc
viewStore.state.orderByTimeAsc
? dayjs(a.displayTime).unix() - dayjs(b.displayTime).unix()
: dayjs(b.displayTime).unix() - dayjs(a.displayTime).unix(),
)
.sort((a, b) => Number(b.pinned) - Number(a.pinned))
}
owner={user.name}
direction={memoFilterStore.orderByTimeAsc ? Direction.ASC : Direction.DESC}
direction={viewStore.state.orderByTimeAsc ? Direction.ASC : Direction.DESC}
oldFilter={memoListFilter}
/>
</>
Expand All @@ -124,6 +125,6 @@ const UserProfile = () => {
</div>
</section>
);
};
});

export default UserProfile;
7 changes: 0 additions & 7 deletions web/src/store/v1/memoFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,14 @@ export const stringifyFilters = (filters: MemoFilter[]): string => {

interface State {
filters: MemoFilter[];
orderByTimeAsc: boolean;
// The id of selected shortcut.
shortcut?: string;
// TODO: Remove this when the masonry view is implemented.
masonry: boolean;
}

const getInitialState = (): State => {
const searchParams = new URLSearchParams(window.location.search);
return {
filters: parseFilterQuery(searchParams.get("filter")),
orderByTimeAsc: searchParams.get("orderBy") === "asc",
masonry: false,
};
};

Expand All @@ -63,8 +58,6 @@ export const useMemoFilterStore = create(
getFiltersByFactor: (factor: FilterFactor) => get().filters.filter((f) => f.factor === factor),
addFilter: (filter: MemoFilter) => set((state) => ({ filters: uniqBy([...state.filters, filter], getMemoFilterKey) })),
removeFilter: (filterFn: (f: MemoFilter) => boolean) => set((state) => ({ filters: state.filters.filter((f) => !filterFn(f)) })),
setOrderByTimeAsc: (orderByTimeAsc: boolean) => set({ orderByTimeAsc }),
setShortcut: (shortcut?: string) => set({ shortcut }),
setMasonry: (masonry: boolean) => set({ masonry }),
})),
);
3 changes: 2 additions & 1 deletion web/src/store/v2/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import userStore from "./user";
import viewStore from "./view";
import workspaceStore from "./workspace";

export { workspaceStore, userStore };
export { workspaceStore, userStore, viewStore };
Loading

0 comments on commit 56ad8ab

Please sign in to comment.