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