mirror of https://github.com/usememos/memos
refactor: filter store (#1331)
parent
f3f0efba1e
commit
a9218ed5f0
@ -0,0 +1,77 @@
|
|||||||
|
import store, { useAppSelector } from "..";
|
||||||
|
import { setFilter, Filter } from "../reducer/filter";
|
||||||
|
|
||||||
|
export const useFilterStore = () => {
|
||||||
|
const state = useAppSelector((state) => state.filter);
|
||||||
|
|
||||||
|
return {
|
||||||
|
state,
|
||||||
|
getState: () => {
|
||||||
|
return store.getState().filter;
|
||||||
|
},
|
||||||
|
setFilter: (filter: Filter) => {
|
||||||
|
store.dispatch(setFilter(filter));
|
||||||
|
},
|
||||||
|
clearFilter: () => {
|
||||||
|
store.dispatch(
|
||||||
|
setFilter({
|
||||||
|
tag: undefined,
|
||||||
|
type: undefined,
|
||||||
|
duration: undefined,
|
||||||
|
text: undefined,
|
||||||
|
shortcutId: undefined,
|
||||||
|
visibility: undefined,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
setMemoTypeFilter: (type?: MemoSpecType) => {
|
||||||
|
store.dispatch(
|
||||||
|
setFilter({
|
||||||
|
type: type,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
setMemoShortcut: (shortcutId?: ShortcutId) => {
|
||||||
|
store.dispatch(
|
||||||
|
setFilter({
|
||||||
|
shortcutId: shortcutId,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
setTextFilter: (text?: string) => {
|
||||||
|
store.dispatch(
|
||||||
|
setFilter({
|
||||||
|
text: text,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
setTagFilter: (tag?: string) => {
|
||||||
|
store.dispatch(
|
||||||
|
setFilter({
|
||||||
|
tag: tag,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
setFromAndToFilter: (from?: number, to?: number) => {
|
||||||
|
let duration = undefined;
|
||||||
|
if (from && to && from < to) {
|
||||||
|
duration = {
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
store.dispatch(
|
||||||
|
setFilter({
|
||||||
|
duration,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
setMemoVisibilityFilter: (visibility?: Visibility) => {
|
||||||
|
store.dispatch(
|
||||||
|
setFilter({
|
||||||
|
visibility: visibility,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -1,122 +0,0 @@
|
|||||||
import { stringify } from "qs";
|
|
||||||
import store, { useAppSelector } from "../";
|
|
||||||
import { setQuery, setPathname, Query, updateStateWithLocation, updatePathnameStateWithLocation } from "../reducer/location";
|
|
||||||
|
|
||||||
const updateLocationUrl = (method: "replace" | "push" = "replace") => {
|
|
||||||
// avoid pathname confusion when entering from non-home page
|
|
||||||
store.dispatch(updatePathnameStateWithLocation());
|
|
||||||
|
|
||||||
const { query, pathname, hash } = store.getState().location;
|
|
||||||
let queryString = stringify(query);
|
|
||||||
if (queryString) {
|
|
||||||
queryString = "?" + queryString;
|
|
||||||
} else {
|
|
||||||
queryString = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (method === "replace") {
|
|
||||||
window.history.replaceState(null, "", pathname + hash + queryString);
|
|
||||||
} else {
|
|
||||||
window.history.pushState(null, "", pathname + hash + queryString);
|
|
||||||
}
|
|
||||||
store.dispatch(updateStateWithLocation());
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useLocationStore = () => {
|
|
||||||
const state = useAppSelector((state) => state.location);
|
|
||||||
|
|
||||||
return {
|
|
||||||
state,
|
|
||||||
getState: () => {
|
|
||||||
return store.getState().location;
|
|
||||||
},
|
|
||||||
updateStateWithLocation: () => {
|
|
||||||
store.dispatch(updateStateWithLocation());
|
|
||||||
},
|
|
||||||
setPathname: (pathname: string) => {
|
|
||||||
store.dispatch(setPathname(pathname));
|
|
||||||
updateLocationUrl();
|
|
||||||
},
|
|
||||||
pushHistory: (pathname: string) => {
|
|
||||||
store.dispatch(setPathname(pathname));
|
|
||||||
updateLocationUrl("push");
|
|
||||||
},
|
|
||||||
replaceHistory: (pathname: string) => {
|
|
||||||
store.dispatch(setPathname(pathname));
|
|
||||||
updateLocationUrl("replace");
|
|
||||||
},
|
|
||||||
setQuery: (query: Query) => {
|
|
||||||
store.dispatch(setQuery(query));
|
|
||||||
updateLocationUrl();
|
|
||||||
},
|
|
||||||
clearQuery: () => {
|
|
||||||
store.dispatch(
|
|
||||||
setQuery({
|
|
||||||
tag: undefined,
|
|
||||||
type: undefined,
|
|
||||||
duration: undefined,
|
|
||||||
text: undefined,
|
|
||||||
shortcutId: undefined,
|
|
||||||
visibility: undefined,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
updateLocationUrl();
|
|
||||||
},
|
|
||||||
setMemoTypeQuery: (type?: MemoSpecType) => {
|
|
||||||
store.dispatch(
|
|
||||||
setQuery({
|
|
||||||
type: type,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
updateLocationUrl();
|
|
||||||
},
|
|
||||||
setMemoShortcut: (shortcutId?: ShortcutId) => {
|
|
||||||
store.dispatch(
|
|
||||||
setQuery({
|
|
||||||
shortcutId: shortcutId,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
updateLocationUrl();
|
|
||||||
},
|
|
||||||
setTextQuery: (text?: string) => {
|
|
||||||
store.dispatch(
|
|
||||||
setQuery({
|
|
||||||
text: text,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
updateLocationUrl();
|
|
||||||
},
|
|
||||||
setTagQuery: (tag?: string) => {
|
|
||||||
store.dispatch(
|
|
||||||
setQuery({
|
|
||||||
tag: tag,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
updateLocationUrl();
|
|
||||||
},
|
|
||||||
setFromAndToQuery: (from?: number, to?: number) => {
|
|
||||||
let duration = undefined;
|
|
||||||
if (from && to && from < to) {
|
|
||||||
duration = {
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
store.dispatch(
|
|
||||||
setQuery({
|
|
||||||
duration,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
updateLocationUrl();
|
|
||||||
},
|
|
||||||
setMemoVisibilityQuery: (visibility?: Visibility) => {
|
|
||||||
store.dispatch(
|
|
||||||
setQuery({
|
|
||||||
visibility: visibility,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
updateLocationUrl();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@ -0,0 +1,38 @@
|
|||||||
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||||
|
|
||||||
|
interface Duration {
|
||||||
|
from: number;
|
||||||
|
to: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
tag?: string;
|
||||||
|
duration?: Duration;
|
||||||
|
type?: MemoSpecType;
|
||||||
|
text?: string;
|
||||||
|
shortcutId?: ShortcutId;
|
||||||
|
visibility?: Visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Filter = State;
|
||||||
|
|
||||||
|
const filterSlice = createSlice({
|
||||||
|
name: "filter",
|
||||||
|
initialState: {} as State,
|
||||||
|
reducers: {
|
||||||
|
setFilter: (state, action: PayloadAction<Partial<State>>) => {
|
||||||
|
if (JSON.stringify(action.payload) === state) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...action.payload,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { setFilter } = filterSlice.actions;
|
||||||
|
|
||||||
|
export default filterSlice.reducer;
|
@ -1,107 +0,0 @@
|
|||||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
|
||||||
import { parse, ParsedQs } from "qs";
|
|
||||||
|
|
||||||
interface Duration {
|
|
||||||
from: number;
|
|
||||||
to: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Query {
|
|
||||||
tag?: string;
|
|
||||||
duration?: Duration;
|
|
||||||
type?: MemoSpecType;
|
|
||||||
text?: string;
|
|
||||||
shortcutId?: ShortcutId;
|
|
||||||
visibility?: Visibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface State {
|
|
||||||
pathname: string;
|
|
||||||
hash: string;
|
|
||||||
query: Query;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getValidPathname = (pathname: string): string => {
|
|
||||||
const userPageUrlRegex = /^\/u\/\d+.*/;
|
|
||||||
if (["/", "/auth", "/explore"].includes(pathname) || userPageUrlRegex.test(pathname)) {
|
|
||||||
return pathname;
|
|
||||||
} else {
|
|
||||||
return "/";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStateFromLocation = () => {
|
|
||||||
const { pathname, search, hash } = window.location;
|
|
||||||
const urlParams = parse(search.slice(1));
|
|
||||||
const state: State = {
|
|
||||||
pathname: getValidPathname(pathname),
|
|
||||||
hash: hash,
|
|
||||||
query: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (search !== "") {
|
|
||||||
state.query = {};
|
|
||||||
state.query.tag = urlParams["tag"] as string;
|
|
||||||
state.query.type = urlParams["type"] as MemoSpecType;
|
|
||||||
state.query.text = urlParams["text"] as string;
|
|
||||||
const shortcutIdStr = urlParams["shortcutId"] as string;
|
|
||||||
state.query.shortcutId = shortcutIdStr ? Number(shortcutIdStr) : undefined;
|
|
||||||
const durationObj = urlParams["duration"] as ParsedQs;
|
|
||||||
if (durationObj) {
|
|
||||||
const duration: Duration = {
|
|
||||||
from: Number(durationObj["from"]),
|
|
||||||
to: Number(durationObj["to"]),
|
|
||||||
};
|
|
||||||
if (duration.to > duration.from && duration.to !== 0) {
|
|
||||||
state.query.duration = duration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state.query.visibility = urlParams["visibility"] as Visibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
};
|
|
||||||
|
|
||||||
const locationSlice = createSlice({
|
|
||||||
name: "location",
|
|
||||||
initialState: getStateFromLocation(),
|
|
||||||
reducers: {
|
|
||||||
updateStateWithLocation: () => {
|
|
||||||
return getStateFromLocation();
|
|
||||||
},
|
|
||||||
updatePathnameStateWithLocation: (state) => {
|
|
||||||
const { pathname } = window.location;
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
pathname: getValidPathname(pathname),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
setPathname: (state, action: PayloadAction<string>) => {
|
|
||||||
if (state.pathname === action.payload) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
pathname: action.payload,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
setQuery: (state, action: PayloadAction<Partial<Query>>) => {
|
|
||||||
if (JSON.stringify(action.payload) === state.query) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
query: {
|
|
||||||
...state.query,
|
|
||||||
...action.payload,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const { setPathname, setQuery, updateStateWithLocation, updatePathnameStateWithLocation } = locationSlice.actions;
|
|
||||||
|
|
||||||
export default locationSlice.reducer;
|
|
Loading…
Reference in New Issue