110 lines
2.9 KiB
TypeScript
Executable File
110 lines
2.9 KiB
TypeScript
Executable File
import { PostType, Prisma } from "@nice/common";
|
|
import React, {
|
|
createContext,
|
|
ReactNode,
|
|
useContext,
|
|
useMemo,
|
|
useState,
|
|
} from "react";
|
|
import { useDebounce } from "use-debounce";
|
|
interface SelectedTerms {
|
|
[key: string]: string[]; // 每个 slug 对应一个 string 数组
|
|
}
|
|
|
|
interface MainContextType {
|
|
searchValue?: string;
|
|
selectedTerms?: SelectedTerms;
|
|
setSearchValue?: React.Dispatch<React.SetStateAction<string>>;
|
|
setSelectedTerms?: React.Dispatch<React.SetStateAction<SelectedTerms>>;
|
|
searchCondition?: Prisma.PostWhereInput;
|
|
termsCondition?: Prisma.PostWhereInput;
|
|
searchMode?: PostType.COURSE | PostType.PATH | "both";
|
|
setSearchMode?: React.Dispatch<
|
|
React.SetStateAction<PostType.COURSE | PostType.PATH | "both">
|
|
>;
|
|
showSearchMode?: boolean;
|
|
setShowSearchMode?: React.Dispatch<React.SetStateAction<boolean>>;
|
|
}
|
|
|
|
const MainContext = createContext<MainContextType | null>(null);
|
|
interface MainProviderProps {
|
|
children: ReactNode;
|
|
}
|
|
|
|
export function MainProvider({ children }: MainProviderProps) {
|
|
const [searchMode, setSearchMode] = useState<
|
|
PostType.COURSE | PostType.PATH | "both"
|
|
>("both");
|
|
const [showSearchMode, setShowSearchMode] = useState<boolean>(false);
|
|
const [searchValue, setSearchValue] = useState<string>("");
|
|
const [debouncedValue] = useDebounce<string>(searchValue, 500);
|
|
const [selectedTerms, setSelectedTerms] = useState<SelectedTerms>({}); // 初始化状态
|
|
const termFilters = useMemo(() => {
|
|
return Object.entries(selectedTerms)
|
|
.filter(([, terms]) => terms.length > 0)
|
|
?.map(([, terms]) => terms);
|
|
}, [selectedTerms]);
|
|
|
|
const termsCondition: Prisma.PostWhereInput = useMemo(() => {
|
|
return termFilters && termFilters?.length > 0
|
|
? {
|
|
AND: termFilters.map((termFilter) => ({
|
|
terms: {
|
|
some: {
|
|
id: {
|
|
in: termFilter, // 确保至少有一个 term.id 在当前 termFilter 中
|
|
},
|
|
},
|
|
},
|
|
})),
|
|
}
|
|
: {};
|
|
}, [termFilters]);
|
|
const searchCondition: Prisma.PostWhereInput = useMemo(() => {
|
|
const containTextCondition: Prisma.StringNullableFilter = {
|
|
contains: debouncedValue,
|
|
mode: "insensitive" as Prisma.QueryMode, // 使用类型断言
|
|
};
|
|
return debouncedValue
|
|
? {
|
|
OR: [
|
|
{ title: containTextCondition },
|
|
{ subTitle: containTextCondition },
|
|
{ content: containTextCondition },
|
|
{
|
|
terms: {
|
|
some: {
|
|
name: containTextCondition,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
}
|
|
: {};
|
|
}, [debouncedValue]);
|
|
return (
|
|
<MainContext.Provider
|
|
value={{
|
|
searchValue,
|
|
setSearchValue,
|
|
selectedTerms,
|
|
setSelectedTerms,
|
|
searchCondition,
|
|
termsCondition,
|
|
searchMode,
|
|
setSearchMode,
|
|
showSearchMode,
|
|
setShowSearchMode,
|
|
}}>
|
|
{children}
|
|
</MainContext.Provider>
|
|
);
|
|
}
|
|
export const useMainContext = () => {
|
|
const context = useContext(MainContext);
|
|
if (!context) {
|
|
throw new Error("useMainContext must be used within MainProvider");
|
|
}
|
|
return context;
|
|
};
|