chore: update redux store and service

pull/65/head
boojack 3 years ago
parent c3c2882dc5
commit a580df5c9f

@ -55,7 +55,9 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
}
try {
await userService.updatePassword(newPassword);
await userService.patchUser({
password: newPassword,
});
toastHelper.info("Password changed.");
handleCloseBtnClick();
} catch (error: any) {

@ -25,7 +25,9 @@ const ConfirmResetOpenIdDialog: React.FC<Props> = ({ destroy }: Props) => {
resetBtnClickLoadingState.setLoading();
try {
await userService.resetOpenId();
await userService.patchUser({
resetOpenId: true,
});
} catch (error) {
toastHelper.error("Request reset open API failed.");
return;

@ -48,9 +48,16 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
try {
if (shortcutId) {
await shortcutService.updateShortcut(shortcutId, title, JSON.stringify(filters));
await shortcutService.patchShortcut({
id: shortcutId,
title,
payload: JSON.stringify(filters),
});
} else {
await shortcutService.createShortcut(title, JSON.stringify(filters));
await shortcutService.createShortcut({
title,
payload: JSON.stringify(filters),
});
}
} catch (error: any) {
toastHelper.error(error.message);

@ -38,7 +38,10 @@ const DeletedMemo: React.FC<Props> = (props: Props) => {
const handleRestoreMemoClick = async () => {
try {
await memoService.restoreMemoById(memo.id);
await memoService.patchMemo({
id: memo.id,
rowStatus: "NORMAL",
});
handleDeletedMemoAction(memo.id);
toastHelper.info("Restored successfully");
} catch (error: any) {

@ -33,16 +33,8 @@ const Memo: React.FC<Props> = (props: Props) => {
try {
if (memo.pinned) {
await memoService.unpinMemo(memo.id);
memoService.editMemo({
...memo,
pinned: false,
});
} else {
await memoService.pinMemo(memo.id);
memoService.editMemo({
...memo,
pinned: true,
});
}
} catch (error) {
// do nth
@ -50,23 +42,26 @@ const Memo: React.FC<Props> = (props: Props) => {
};
const handleMarkMemoClick = () => {
editorStateService.setMarkMemo(memo.id);
editorStateService.setMarkMemoWithId(memo.id);
};
const handleEditMemoClick = () => {
editorStateService.setEditMemo(memo.id);
editorStateService.setEditMemoWithId(memo.id);
};
const handleDeleteMemoClick = async () => {
if (showConfirmDeleteBtn) {
try {
await memoService.archiveMemoById(memo.id);
await memoService.patchMemo({
id: memo.id,
rowStatus: "ARCHIVED",
});
} catch (error: any) {
toastHelper.error(error.message);
}
if (editorStateService.getState().editMemoId === memo.id) {
editorStateService.setEditMemo(UNKNOWN_ID);
editorStateService.clearEditMemo();
}
} else {
toggleConfirmDeleteBtn();

@ -96,7 +96,7 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
const handleEditMemoBtnClick = useCallback(() => {
props.destroy();
editorStateService.setEditMemo(memo.id);
editorStateService.setEditMemoWithId(memo.id);
}, [memo.id]);
return (

@ -57,7 +57,7 @@ const MemoEditor: React.FC<Props> = () => {
const editorCurrentValue = editorRef.current?.getContent();
const memoLinkText = `${editorCurrentValue ? "\n" : ""}Mark: [@MEMO](${editorState.markMemoId})`;
editorRef.current?.insertText(memoLinkText);
editorStateService.setMarkMemo(UNKNOWN_ID);
editorStateService.clearMarkMemo();
}
if (
@ -155,14 +155,16 @@ const MemoEditor: React.FC<Props> = () => {
const prevMemo = memoService.getMemoById(editMemoId ?? UNKNOWN_ID);
if (prevMemo && prevMemo.content !== content) {
const editedMemo = await memoService.updateMemo(prevMemo.id, content);
editedMemo.createdTs = Date.now();
memoService.editMemo(editedMemo);
await memoService.patchMemo({
id: prevMemo.id,
content,
});
}
editorStateService.setEditMemo(UNKNOWN_ID);
editorStateService.clearEditMemo();
} else {
const newMemo = await memoService.createMemo(content);
memoService.pushMemo(newMemo);
await memoService.createMemo({
content,
});
locationService.clearQuery();
}
} catch (error: any) {
@ -173,7 +175,7 @@ const MemoEditor: React.FC<Props> = () => {
}, []);
const handleCancelBtnClick = useCallback(() => {
editorStateService.setEditMemo(UNKNOWN_ID);
editorStateService.clearEditMemo();
editorRef.current?.setContent("");
setEditorContentCache("");
}, []);

@ -28,7 +28,7 @@ const MemoFilter: React.FC<FilterProps> = () => {
<div
className={"filter-item-container " + (tagQuery ? "" : "hidden")}
onClick={() => {
locationService.setTagQuery("");
locationService.setTagQuery(undefined);
}}
>
<span className="icon-text">🏷</span> {tagQuery}
@ -45,7 +45,7 @@ const MemoFilter: React.FC<FilterProps> = () => {
<div
className="filter-item-container"
onClick={() => {
locationService.setFromAndToQuery(0, 0);
locationService.setFromAndToQuery();
}}
>
<span className="icon-text">🗓</span> {utils.getDateString(duration.from)} to {utils.getDateString(duration.to)}

@ -18,9 +18,7 @@ const MemoTrashDialog: React.FC<Props> = (props: Props) => {
memoService
.fetchDeletedMemos()
.then((result) => {
if (result !== false) {
setDeletedMemos(result);
}
setDeletedMemos(result);
})
.catch((error) => {
toastHelper.error("Failed to fetch deleted memos: ", error);

@ -32,7 +32,9 @@ const MenuBtnsPopup: React.FC<Props> = (props: Props) => {
};
const handleSignOutBtnClick = async () => {
await userService.doSignOut();
userService.doSignOut().catch(() => {
// do nth
});
locationService.replaceHistory("/signin");
window.location.reload();
};

@ -39,8 +39,9 @@ const MyAccountSection: React.FC<Props> = () => {
}
try {
await userService.updateUsername(username);
await userService.doSignIn();
await userService.patchUser({
name: username,
});
toastHelper.info("Username changed");
} catch (error: any) {
toastHelper.error(error.message);

@ -45,7 +45,11 @@ const PreferencesSection: React.FC<Props> = () => {
const createdTs = (memo as any).createdAt || memo.createdTs || Date.now();
try {
await memoService.importMemo(content, createdTs);
const memoCreate = {
content,
createdTs: Math.floor(utils.getTimeStampByDate(createdTs) / 1000),
};
await memoService.createMemo(memoCreate);
succeedAmount++;
} catch (error) {
// do nth

@ -96,19 +96,11 @@ const ShortcutContainer: React.FC<ShortcutContainerProps> = (props: ShortcutCont
event.stopPropagation();
try {
if (shortcut.rowStatus === "ARCHIVED") {
await shortcutService.unpinShortcut(shortcut.id);
shortcutService.editShortcut({
...shortcut,
rowStatus: "NORMAL",
});
} else {
await shortcutService.pinShortcut(shortcut.id);
shortcutService.editShortcut({
...shortcut,
rowStatus: "ARCHIVED",
});
}
const shortcutPatch: ShortcutPatch = {
id: shortcut.id,
rowStatus: shortcut.rowStatus === "ARCHIVED" ? "NORMAL" : "ARCHIVED",
};
await shortcutService.patchShortcut(shortcutPatch);
} catch (error) {
// do nth
}

@ -72,7 +72,7 @@ const UsageHeatMap: React.FC<Props> = () => {
const handleUsageStatItemClick = useCallback((item: DailyUsageStat) => {
if (locationService.getState().query?.duration?.from === item.timestamp) {
locationService.setFromAndToQuery(0, 0);
locationService.setFromAndToQuery();
setCurrentStat(null);
} else if (item.count > 0) {
if (!["/"].includes(locationService.getState().pathname)) {

@ -159,26 +159,6 @@ namespace api {
});
}
export function archiveMemo(memoId: MemoId) {
return request({
method: "PATCH",
url: `/api/memo/${memoId}`,
data: {
rowStatus: "ARCHIVED",
},
});
}
export function restoreMemo(memoId: MemoId) {
return request({
method: "PATCH",
url: `/api/memo/${memoId}`,
data: {
rowStatus: "NORMAL",
},
});
}
export function deleteMemo(memoId: MemoId) {
return request({
method: "DELETE",
@ -193,25 +173,19 @@ namespace api {
});
}
export function createShortcut(title: string, payload: string) {
export function createShortcut(shortcutCreate: ShortcutCreate) {
return request<Shortcut>({
method: "POST",
url: "/api/shortcut",
data: {
title,
payload,
},
data: shortcutCreate,
});
}
export function updateShortcut(shortcutId: ShortcutId, title: string, payload: string) {
export function patchShortcut(shortcutPatch: ShortcutPatch) {
return request<Shortcut>({
method: "PATCH",
url: `/api/shortcut/${shortcutId}`,
data: {
title,
payload,
},
url: `/api/shortcut/${shortcutPatch.id}`,
data: shortcutPatch,
});
}
@ -222,26 +196,6 @@ namespace api {
});
}
export function pinShortcut(shortcutId: ShortcutId) {
return request({
method: "PATCH",
url: `/api/shortcut/${shortcutId}`,
data: {
rowStatus: "ARCHIVED",
},
});
}
export function unpinShortcut(shortcutId: ShortcutId) {
return request({
method: "PATCH",
url: `/api/shortcut/${shortcutId}`,
data: {
rowStatus: "NORMAL",
},
});
}
export function uploadFile(formData: FormData) {
return request<Resource>({
method: "POST",

@ -5,7 +5,7 @@
> .search-bar-inputer {
.flex(row, flex-start, center);
@apply w-full py-2 px-4 rounded-lg flex flex-row justify-start items-center bg-gray-200;
@apply w-full py-2 px-4 rounded-lg flex flex-row justify-start items-center bg-zinc-200;
> .icon-img {
@apply mr-2 w-4 h-auto opacity-80;

@ -6,13 +6,21 @@ const editorStateService = {
return store.getState().editor;
},
setEditMemo: (editMemoId: MemoId) => {
setEditMemoWithId: (editMemoId: MemoId) => {
store.dispatch(setEditMemoId(editMemoId));
},
setMarkMemo: (markMemoId: MemoId) => {
clearEditMemo: () => {
store.dispatch(setEditMemoId());
},
setMarkMemoWithId: (markMemoId: MemoId) => {
store.dispatch(setMarkMemoId(markMemoId));
},
clearMarkMemo: () => {
store.dispatch(setMarkMemoId());
},
};
export default editorStateService;

@ -1,6 +1,6 @@
import utils from "../helpers/utils";
import store from "../store";
import { setQuery, setPathname } from "../store/modules/location";
import { setQuery, setPathname, Query } from "../store/modules/location";
const updateLocationUrl = (method: "replace" | "push" = "replace") => {
const { query, pathname, hash } = store.getState().location;
@ -23,36 +23,34 @@ const locationService = {
return store.getState().location;
},
clearQuery: () => {
store.dispatch(setQuery({}));
updateLocationUrl();
},
setQuery: (query: Query) => {
store.dispatch(setQuery(query));
updateLocationUrl();
},
setPathname: (pathname: AppRouter) => {
setPathname: (pathname: string) => {
store.dispatch(setPathname(pathname));
updateLocationUrl();
},
pushHistory: (pathname: AppRouter) => {
pushHistory: (pathname: string) => {
store.dispatch(setPathname(pathname));
updateLocationUrl("push");
},
replaceHistory: (pathname: AppRouter) => {
replaceHistory: (pathname: string) => {
store.dispatch(setPathname(pathname));
updateLocationUrl("replace");
},
setQuery: (query: Query) => {
store.dispatch(setQuery(query));
updateLocationUrl();
},
clearQuery: () => {
store.dispatch(setQuery({}));
updateLocationUrl();
},
setMemoTypeQuery: (type?: MemoSpecType) => {
const { query } = store.getState().location;
store.dispatch(
setQuery({
...query,
type: type,
})
);
@ -60,10 +58,8 @@ const locationService = {
},
setMemoShortcut: (shortcutId?: ShortcutId) => {
const { query } = store.getState().location;
store.dispatch(
setQuery({
...query,
shortcutId: shortcutId,
})
);
@ -71,10 +67,8 @@ const locationService = {
},
setTextQuery: (text?: string) => {
const { query } = store.getState().location;
store.dispatch(
setQuery({
...query,
text: text,
})
);
@ -82,34 +76,30 @@ const locationService = {
},
setTagQuery: (tag?: string) => {
const { query } = store.getState().location;
store.dispatch(
setQuery({
...query,
tag: tag,
})
);
updateLocationUrl();
},
setFromAndToQuery: (from: number, to: number) => {
const { query } = store.getState().location;
setFromAndToQuery: (from?: number, to?: number) => {
let duration = undefined;
if (from && to && from < to) {
duration = {
from,
to,
};
}
store.dispatch(
setQuery({
...query,
duration: { from, to },
duration,
})
);
updateLocationUrl();
},
getValidPathname: (pathname: string): AppRouter => {
if (["/", "/signin"].includes(pathname)) {
return pathname as AppRouter;
} else {
return "/";
}
},
};
export default locationService;

@ -1,9 +1,7 @@
import api from "../helpers/api";
import { TAG_REG } from "../helpers/consts";
import utils from "../helpers/utils";
import { patchMemo, setMemos, setTags } from "../store/modules/memo";
import { createMemo, patchMemo, setMemos, setTags } from "../store/modules/memo";
import store from "../store";
import userService from "./userService";
const convertResponseModelMemo = (memo: Memo): Memo => {
return {
@ -19,36 +17,24 @@ const memoService = {
},
fetchAllMemos: async () => {
if (!userService.getState().user) {
return false;
}
const data = await api.getMyMemos();
const memos: Memo[] = data.filter((m) => m.rowStatus !== "ARCHIVED").map((m) => convertResponseModelMemo(m));
const memos = data.filter((m) => m.rowStatus !== "ARCHIVED").map((m) => convertResponseModelMemo(m));
store.dispatch(setMemos(memos));
return memos;
},
fetchDeletedMemos: async () => {
if (!userService.getState().user) {
return false;
}
const data = await api.getMyArchivedMemos();
const deletedMemos: Memo[] = data.map((m) => {
const deletedMemos = data.map((m) => {
return convertResponseModelMemo(m);
});
return deletedMemos;
},
pushMemo: (memo: Memo) => {
store.dispatch(setMemos(memoService.getState().memos.concat(memo)));
},
getMemoById: (id: MemoId) => {
getMemoById: (memoId: MemoId) => {
for (const m of memoService.getState().memos) {
if (m.id === id) {
if (m.id === memoId) {
return m;
}
}
@ -56,35 +42,6 @@ const memoService = {
return null;
},
archiveMemoById: async (id: MemoId) => {
const memo = memoService.getMemoById(id);
if (!memo) {
return;
}
await api.archiveMemo(id);
store.dispatch(
patchMemo({
...memo,
rowStatus: "ARCHIVED",
})
);
},
restoreMemoById: async (id: MemoId) => {
await api.restoreMemo(id);
memoService.clearMemos();
memoService.fetchAllMemos();
},
deleteMemoById: async (id: MemoId) => {
await api.deleteMemo(id);
},
editMemo: (memo: Memo) => {
store.dispatch(patchMemo(memo));
},
updateTagsState: () => {
const { memos } = memoService.getState();
const tagsSet = new Set<string>();
@ -97,43 +54,46 @@ const memoService = {
store.dispatch(setTags(Array.from(tagsSet).filter((t) => Boolean(t))));
},
clearMemos: () => {
store.dispatch(setMemos([]));
},
getLinkedMemos: async (memoId: MemoId): Promise<Memo[]> => {
const { memos } = memoService.getState();
return memos.filter((m) => m.content.includes(`${memoId}`));
},
createMemo: async (content: string): Promise<Memo> => {
const memo = await api.createMemo({
content,
});
return convertResponseModelMemo(memo);
createMemo: async (memoCreate: MemoCreate) => {
const data = await api.createMemo(memoCreate);
const memo = convertResponseModelMemo(data);
store.dispatch(createMemo(memo));
},
updateMemo: async (memoId: MemoId, content: string): Promise<Memo> => {
const memo = await api.patchMemo({
id: memoId,
content,
});
return convertResponseModelMemo(memo);
patchMemo: async (memoPatch: MemoPatch): Promise<Memo> => {
const data = await api.patchMemo(memoPatch);
const memo = convertResponseModelMemo(data);
store.dispatch(patchMemo(memo));
return memo;
},
pinMemo: async (memoId: MemoId) => {
await api.pinMemo(memoId);
store.dispatch(
patchMemo({
id: memoId,
pinned: true,
})
);
},
unpinMemo: async (memoId: MemoId) => {
await api.unpinMemo(memoId);
store.dispatch(
patchMemo({
id: memoId,
pinned: false,
})
);
},
importMemo: async (content: string, createdTs: TimeStamp) => {
await api.createMemo({
content,
createdTs: Math.floor(utils.getTimeStampByDate(createdTs) / 1000),
});
deleteMemoById: async (memoId: MemoId) => {
await api.deleteMemo(memoId);
},
};

@ -1,8 +1,6 @@
import userService from "./userService";
import api from "../helpers/api";
import { UNKNOWN_ID } from "../helpers/consts";
import store from "../store/";
import { deleteShortcut, patchShortcut, setShortcuts } from "../store/modules/shortcut";
import { createShortcut, deleteShortcut, patchShortcut, setShortcuts } from "../store/modules/shortcut";
const convertResponseModelShortcut = (shortcut: Shortcut): Shortcut => {
return {
@ -18,21 +16,12 @@ const shortcutService = {
},
getMyAllShortcuts: async () => {
if (!userService.getState().user) {
return false;
}
const data = await api.getMyShortcuts();
const shortcuts = data.map((s) => convertResponseModelShortcut(s));
const rawData = await api.getMyShortcuts();
const shortcuts = rawData.map((s) => convertResponseModelShortcut(s));
store.dispatch(setShortcuts(shortcuts));
return shortcuts;
},
getShortcutById: (id: ShortcutId) => {
if (id === UNKNOWN_ID) {
return null;
}
for (const s of shortcutService.getState().shortcuts) {
if (s.id === id) {
return s;
@ -42,11 +31,15 @@ const shortcutService = {
return null;
},
pushShortcut: (shortcut: Shortcut) => {
store.dispatch(setShortcuts(shortcutService.getState().shortcuts.concat(shortcut)));
createShortcut: async (shortcutCreate: ShortcutCreate) => {
const data = await api.createShortcut(shortcutCreate);
const shortcut = convertResponseModelShortcut(data);
store.dispatch(createShortcut(shortcut));
},
editShortcut: (shortcut: Shortcut) => {
patchShortcut: async (shortcutPatch: ShortcutPatch) => {
const data = await api.patchShortcut(shortcutPatch);
const shortcut = convertResponseModelShortcut(data);
store.dispatch(patchShortcut(shortcut));
},
@ -54,24 +47,6 @@ const shortcutService = {
await api.deleteShortcutById(shortcutId);
store.dispatch(deleteShortcut(shortcutId));
},
createShortcut: async (title: string, payload: string) => {
const data = await api.createShortcut(title, payload);
shortcutService.pushShortcut(convertResponseModelShortcut(data));
},
updateShortcut: async (shortcutId: ShortcutId, title: string, payload: string) => {
const data = await api.updateShortcut(shortcutId, title, payload);
store.dispatch(patchShortcut(convertResponseModelShortcut(data)));
},
pinShortcut: async (shortcutId: ShortcutId) => {
await api.pinShortcut(shortcutId);
},
unpinShortcut: async (shortcutId: ShortcutId) => {
await api.unpinShortcut(shortcutId);
},
};
export default shortcutService;

@ -1,6 +1,6 @@
import api from "../helpers/api";
import { signin, signout } from "../store/modules/user";
import store from "../store";
import { setUser, patchUser } from "../store/modules/user";
const convertResponseModelUser = (user: User): User => {
return {
@ -18,7 +18,7 @@ const userService = {
doSignIn: async () => {
const user = await api.getUser();
if (user) {
store.dispatch(signin(convertResponseModelUser(user)));
store.dispatch(setUser(convertResponseModelUser(user)));
} else {
userService.doSignOut();
}
@ -26,29 +26,14 @@ const userService = {
},
doSignOut: async () => {
store.dispatch(signout);
api.signout().catch(() => {
// do nth
});
store.dispatch(setUser());
await api.signout();
},
updateUsername: async (name: string): Promise<void> => {
await api.patchUser({
name,
});
},
updatePassword: async (password: string): Promise<void> => {
await api.patchUser({
password,
});
},
resetOpenId: async (): Promise<string> => {
const user = await api.patchUser({
resetOpenId: true,
});
return user.openId;
patchUser: async (userPatch: UserPatch): Promise<void> => {
const data = await api.patchUser(userPatch);
const user = convertResponseModelUser(data);
store.dispatch(patchUser(user));
},
};

@ -10,10 +10,16 @@ const editorSlice = createSlice({
initialState: {} as State,
reducers: {
setMarkMemoId: (state, action: PayloadAction<Option<MemoId>>) => {
state.markMemoId = action.payload;
return {
...state,
markMemoId: action.payload,
};
},
setEditMemoId: (state, action: PayloadAction<Option<MemoId>>) => {
state.editMemoId = action.payload;
return {
...state,
editMemoId: action.payload,
};
},
},
});

@ -1,14 +1,27 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
interface Duration {
from: number;
to: number;
}
export interface Query {
tag?: string;
duration?: Duration;
type?: MemoSpecType;
text?: string;
shortcutId?: ShortcutId;
}
interface State {
pathname: AppRouter;
pathname: string;
hash: string;
query?: Query;
query: Query;
}
const getValidPathname = (pathname: string): AppRouter => {
const getValidPathname = (pathname: string): string => {
if (["/", "/signin"].includes(pathname)) {
return pathname as AppRouter;
return pathname;
} else {
return "/";
}
@ -20,6 +33,7 @@ const getStateFromLocation = () => {
const state: State = {
pathname: getValidPathname(pathname),
hash: hash,
query: {},
};
if (search !== "") {
@ -48,11 +62,20 @@ const locationSlice = createSlice({
updateStateWithLocation: () => {
return getStateFromLocation();
},
setPathname: (state, action: PayloadAction<AppRouter>) => {
state.pathname = action.payload;
setPathname: (state, action: PayloadAction<string>) => {
return {
...state,
pathname: action.payload,
};
},
setQuery: (state, action: PayloadAction<Partial<Query>>) => {
state.query = action.payload;
return {
...state,
query: {
...state.query,
...action.payload,
},
};
},
},
});

@ -33,12 +33,9 @@ const memoSlice = createSlice({
}
});
},
deleteMemo: (state, action: PayloadAction<MemoId>) => {
state.memos = [...state.memos].filter((memo) => memo.id !== action.payload);
},
},
});
export const { setMemos, setTags, createMemo, patchMemo, deleteMemo } = memoSlice.actions;
export const { setMemos, setTags, createMemo, patchMemo } = memoSlice.actions;
export default memoSlice.reducer;

@ -8,18 +8,12 @@ const userSlice = createSlice({
name: "user",
initialState: {} as State,
reducers: {
signin: (state, action: PayloadAction<User>) => {
setUser: (state, action: PayloadAction<User | undefined>) => {
return {
...state,
user: action.payload,
};
},
signout: (state) => {
return {
...state,
user: undefined,
};
},
patchUser: (state, action: PayloadAction<Partial<User>>) => {
state.user = {
...state.user,
@ -29,6 +23,6 @@ const userSlice = createSlice({
},
});
export const { signin, signout, patchUser } = userSlice.actions;
export const { setUser, patchUser } = userSlice.actions;
export default userSlice.reducer;

@ -1,20 +0,0 @@
interface Duration {
from: number;
to: number;
}
interface Query {
tag?: string;
duration?: Duration;
type?: MemoSpecType;
text?: string;
shortcutId?: ShortcutId;
}
type AppRouter = "/" | "/signin";
interface AppLocation {
pathname: AppRouter;
hash: string;
query: Query;
}

@ -10,3 +10,15 @@ interface Shortcut {
title: string;
payload: string;
}
interface ShortcutCreate {
title: string;
payload: string;
}
interface ShortcutPatch {
id: ShortcutId;
title?: string;
payload?: string;
rowStatus?: RowStatus;
}

Loading…
Cancel
Save