training_data/apps/web/src/app/main/layout/MainProvider.tsx

110 lines
2.9 KiB
TypeScript
Raw Normal View History

2025-02-27 13:32:33 +08:00
import { PostType, Prisma } from "@nice/common";
2025-02-27 08:25:39 +08:00
import React, {
createContext,
ReactNode,
useContext,
useMemo,
useState,
} from "react";
2025-02-28 15:45:21 +08:00
import { useDebounce } from "use-debounce";
2025-02-25 20:40:34 +08:00
interface SelectedTerms {
[key: string]: string[]; // 每个 slug 对应一个 string 数组
}
2025-02-25 21:48:41 +08:00
2025-02-25 16:04:55 +08:00
interface MainContextType {
searchValue?: string;
2025-02-25 20:40:34 +08:00
selectedTerms?: SelectedTerms;
2025-02-25 16:04:55 +08:00
setSearchValue?: React.Dispatch<React.SetStateAction<string>>;
2025-02-25 20:40:34 +08:00
setSelectedTerms?: React.Dispatch<React.SetStateAction<SelectedTerms>>;
2025-02-27 08:25:39 +08:00
searchCondition?: Prisma.PostWhereInput;
2025-02-27 10:23:36 +08:00
termsCondition?: Prisma.PostWhereInput;
2025-02-27 12:21:38 +08:00
searchMode?: PostType.COURSE | PostType.PATH | "both";
setSearchMode?: React.Dispatch<
React.SetStateAction<PostType.COURSE | PostType.PATH | "both">
>;
showSearchMode?: boolean;
setShowSearchMode?: React.Dispatch<React.SetStateAction<boolean>>;
2025-02-25 16:04:55 +08:00
}
const MainContext = createContext<MainContextType | null>(null);
interface MainProviderProps {
children: ReactNode;
}
export function MainProvider({ children }: MainProviderProps) {
2025-02-27 12:21:38 +08:00
const [searchMode, setSearchMode] = useState<
PostType.COURSE | PostType.PATH | "both"
>("both");
const [showSearchMode, setShowSearchMode] = useState<boolean>(false);
2025-02-28 15:45:21 +08:00
const [searchValue, setSearchValue] = useState<string>("");
const [debouncedValue] = useDebounce<string>(searchValue, 500);
2025-02-25 20:40:34 +08:00
const [selectedTerms, setSelectedTerms] = useState<SelectedTerms>({}); // 初始化状态
2025-02-27 10:23:36 +08:00
const termFilters = useMemo(() => {
return Object.entries(selectedTerms)
.filter(([, terms]) => terms.length > 0)
?.map(([, terms]) => terms);
}, [selectedTerms]);
2025-02-27 08:25:39 +08:00
2025-02-27 10:23:36 +08:00
const termsCondition: Prisma.PostWhereInput = useMemo(() => {
return termFilters && termFilters?.length > 0
? {
AND: termFilters.map((termFilter) => ({
terms: {
some: {
id: {
in: termFilter, // 确保至少有一个 term.id 在当前 termFilter 中
},
},
},
})),
}
: {};
}, [termFilters]);
2025-02-27 08:25:39 +08:00
const searchCondition: Prisma.PostWhereInput = useMemo(() => {
const containTextCondition: Prisma.StringNullableFilter = {
2025-02-28 15:45:21 +08:00
contains: debouncedValue,
2025-02-27 08:25:39 +08:00
mode: "insensitive" as Prisma.QueryMode, // 使用类型断言
};
2025-02-28 15:45:21 +08:00
return debouncedValue
2025-02-27 08:25:39 +08:00
? {
OR: [
{ title: containTextCondition },
{ subTitle: containTextCondition },
{ content: containTextCondition },
{
terms: {
some: {
name: containTextCondition,
},
},
},
],
}
: {};
2025-03-02 11:49:46 +08:00
}, [debouncedValue]);
2025-02-25 16:04:55 +08:00
return (
<MainContext.Provider
value={{
searchValue,
setSearchValue,
2025-02-25 20:40:34 +08:00
selectedTerms,
setSelectedTerms,
2025-02-27 08:25:39 +08:00
searchCondition,
2025-02-27 10:23:36 +08:00
termsCondition,
2025-02-27 12:21:38 +08:00
searchMode,
setSearchMode,
showSearchMode,
setShowSearchMode,
2025-02-25 16:04:55 +08:00
}}>
{children}
</MainContext.Provider>
);
}
export const useMainContext = () => {
const context = useContext(MainContext);
if (!context) {
throw new Error("useMainContext must be used within MainProvider");
}
return context;
};