2025-05-28 15:36:51 -07:00

91 lines
2.5 KiB
TypeScript

import { createContext, FC, useContext, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { ApiAdapterUtils } from "@dndbeyond/character-rules-engine";
import { builderActions } from "~/tools/js/CharacterBuilder/actions";
import { apiCreatorSelectors } from "~/tools/js/Shared/selectors";
import { ClassDefinitionContract as ClassDef } from "~/types";
/**
* A context to provide data to the application without causing a re-render or
* unnecessary fetches and transforms. This context is used in places where
* character-specific data is not needed.
*/
export interface ClassContextType {
query: string;
setQuery: (query: string) => void;
filteredClasses: Array<ClassDef>;
allClasses: Array<ClassDef>;
handleSelectClass: (id: number) => void;
isLoading: boolean;
isModalShowing: boolean;
closeModal: () => void;
}
export const ClassContext = createContext<ClassContextType>(null!);
export const ClassProvider: FC = ({ children }) => {
const dispatch = useDispatch();
const [query, setQuery] = useState("");
const [allClasses, setAllClasses] = useState<Array<ClassDef>>([]);
const [isLoading, setIsLoading] = useState(true);
const [isModalShowing, setIsModalShowing] = useState(false);
const closeModal = () => setIsModalShowing(false);
const loadClasses = useSelector(apiCreatorSelectors.makeLoadAvailableClasses);
const handleSelectClass = (id: number) => {
const entity = allClasses.find((c) => c.id === id);
if (entity) {
dispatch(builderActions.confirmClassSet(entity));
setIsModalShowing(true);
window.scrollTo(0, 0);
}
};
// Handle searching through items
const filteredClasses = query
? allClasses.filter((c) =>
c.name?.toLowerCase().includes(query.toLowerCase())
)
: allClasses;
useEffect(() => {
const getAllData = async () => {
// Load all classes
const response = await loadClasses();
const classes = ApiAdapterUtils.getResponseData(response) || [];
setAllClasses(classes);
if (classes.length > 0) {
setIsLoading(false);
}
};
getAllData();
}, [loadClasses]);
return (
<ClassContext.Provider
value={{
query,
setQuery,
filteredClasses,
allClasses,
handleSelectClass,
isLoading,
isModalShowing,
closeModal,
}}
>
{children}
</ClassContext.Provider>
);
};
export const useClassContext = () => {
return useContext(ClassContext);
};