feat: templates

This commit is contained in:
IlyaDoronin 2024-05-17 17:13:05 +03:00
parent bcb8b6a988
commit c3d39cde78
46 changed files with 459 additions and 177 deletions

@ -38,12 +38,12 @@ import { isAxiosError } from "axios";
import RecoverPassword from "./pages/auth/RecoverPassword";
import { InfoPrivilege } from "./pages/InfoPrivilege";
import OutdatedLink from "./pages/auth/OutdatedLink";
import QuizGallery from "./pages/createQuize/QuizGallery";
import { useAfterpay } from "@utils/hooks/useAfterpay";
import { useUserAccountFetcher } from "@utils/hooks/useUserAccountFetcher";
const MyQuizzesFull = lazy(() => import("./pages/createQuize/MyQuizzesFull"));
const QuizGallery = lazy(() => import("./pages/createQuize/QuizGallery"));
const ViewPage = lazy(() => import("./pages/ViewPublicationPage"));
const Analytics = lazy(() => import("./pages/Analytics/Analytics"));
const EditPage = lazy(() => import("./pages/startPage/EditPage"));
@ -202,7 +202,10 @@ export default function App() {
/>
}
/>
<Route path="/gallery" element={<QuizGallery />} />
<Route
path="/gallery"
element={<LazyLoading children={<QuizGallery />} />}
/>
<Route
path="/list"
element={<LazyLoading children={<MyQuizzesFull />} />}

@ -164,6 +164,24 @@ export const addQuizImages = async (
}
};
export const copyQuizTemplate = async (
qid: string,
): Promise<[string | null, string?]> => {
try {
const copyQuizTemplateResult = await makeRequest<{ Qid: string }, string>({
method: "POST",
url: `${API_URL}/quiz/template`,
body: { Qid: qid },
});
return [copyQuizTemplateResult];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Не удалось скопировать шаблон квиза. ${error}`];
}
};
export const quizApi = {
create: createQuiz,
getList: getQuizList,
@ -172,6 +190,7 @@ export const quizApi = {
copy: copyQuiz,
delete: deleteQuiz,
addImages: addQuizImages,
copyTemplate: copyQuizTemplate,
};
const defaultCreateQuizBody: CreateQuizRequest = {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 881 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

@ -5,25 +5,30 @@ import { enqueueSnackbar } from "notistack";
import { quizApi } from "@/api/quiz";
import { setEditQuizId } from "@root/quizes/actions";
interface Props {
image: string;
quizId: number;
import type { Template } from "./Template";
interface QuizTemplateCardProps {
category: string;
template: Template;
}
export default function QuizTemplateCard({ image, quizId }: Props) {
export const QuizTemplateCard = ({
category,
template: { quizId, title, picture, categoryDescription },
}: QuizTemplateCardProps) => {
const navigate = useNavigate();
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down("md"));
const copyTemplate = async () => {
try {
const { updated } = await quizApi.copy(quizId);
const [copiedQuizId, copyError] = await quizApi.copyTemplate(quizId);
setEditQuizId(updated);
navigate("/edit");
} catch {
enqueueSnackbar("Ошибка создания квиза");
if (copyError || !copiedQuizId) {
return enqueueSnackbar(copyError);
}
setEditQuizId(0);
navigate("/edit");
};
return (
@ -49,10 +54,8 @@ export default function QuizTemplateCard({ image, quizId }: Props) {
<Box
sx={{
width: "100%",
height: "219px",
backgroundImage: `url(${image})`,
backgroundRepeat: "no-repeat",
backgroundPosition: "center",
height: "220px",
background: `url(${picture}) center / 100% auto no-repeat`,
display: "flex",
alignItems: "end",
p: "20px",
@ -78,28 +81,38 @@ export default function QuizTemplateCard({ image, quizId }: Props) {
px: 0,
},
}}
label="Услуги"
/>
<Chip
sx={{
backgroundColor: theme.palette.brightPurple.main,
color: "white",
height: "auto",
px: "10px",
py: "2px",
borderRadius: "8px",
...theme.typography.button,
"& .MuiChip-label": {
px: 0,
},
}}
label="Медицина"
label={category}
/>
{categoryDescription && (
<Chip
sx={{
backgroundColor: theme.palette.brightPurple.main,
color: "white",
height: "auto",
px: "10px",
py: "2px",
borderRadius: "8px",
...theme.typography.button,
"& .MuiChip-label": {
px: 0,
},
}}
label={categoryDescription}
/>
)}
</Box>
</Box>
<Box sx={{ p: "20px" }}>
<Typography sx={{ color: "#4D4D4D" }}>Название шаблона</Typography>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: "0 20px",
height: "60px",
}}
>
<Typography sx={{ color: "#4D4D4D" }}>{title}</Typography>
</Box>
</Box>
);
}
};

@ -0,0 +1,21 @@
import { FormControl } from "@mui/material";
import CustomTextField from "@ui_kit/CustomTextField";
type SearchTemplateProps = {
searchValue: string;
setSearchValue: (value: string) => void;
};
export const SearchTemplate = ({
searchValue,
setSearchValue,
}: SearchTemplateProps) => (
<FormControl fullWidth variant="standard" sx={{ width: "71%" }}>
<CustomTextField
placeholder="Поиск шаблонов"
value={searchValue}
onChange={({ target }) => setSearchValue(target.value)}
/>
</FormControl>
);

@ -0,0 +1,71 @@
import { FormControl, InputLabel, MenuItem, Select } from "@mui/material";
import ArrowDown from "@icons/ArrowDownIcon";
import type { CategoryType } from "./Template";
const CATEGORIES = [
{ categoryType: "All", category: "Все" },
{ categoryType: "Tourism", category: "Туризм" },
{ categoryType: "Services", category: "Услуги" },
{ categoryType: "RealEstate", category: "Недвижимость" },
{ categoryType: "Auto", category: "Авто" },
{ categoryType: "Health", category: "Здоровье и уход" },
{ categoryType: "Research", category: "Исследовательские" },
{ categoryType: "Production", category: "Производство" },
{ categoryType: "Repair", category: "Ремонт" },
{ categoryType: "Education", category: "Образование" },
] as const;
type SelectCategoryProps = {
categoryType: CategoryType | "All";
setCategoryType: (categoryType: CategoryType) => void;
};
export const SelectCategory = ({
categoryType,
setCategoryType,
}: SelectCategoryProps) => (
<FormControl
fullWidth
size="small"
sx={{
width: "27%",
minWidth: "200px",
height: "45px",
"& .MuiInputLabel-outlined": { mt: "4px", ml: "-3px" },
"& .MuiInputLabel-outlined.MuiInputLabel-shrink": {
ml: "3px",
mt: "0px",
},
}}
>
<InputLabel
sx={{ color: "black", fontSize: "16px", lineHeight: "19px" }}
id="demo-simple-select-label"
>
Категории
</InputLabel>
<Select
labelId="demo-simple-select-label"
id="category-select"
label="Категории"
defaultValue="re"
variant="outlined"
value={categoryType}
onChange={({ target }) => setCategoryType(target.value as CategoryType)}
sx={{ height: "45px", borderRadius: "10px" }}
inputProps={{ sx: { pt: "12px" } }}
IconComponent={(props) => <ArrowDown {...props} />}
>
{CATEGORIES.map((currentCategory) => (
<MenuItem
key={currentCategory.categoryType}
value={currentCategory.categoryType}
>
{currentCategory.category}
</MenuItem>
))}
</Select>
</FormControl>
);

@ -1,17 +1,37 @@
import { Box, Typography, useTheme, useMediaQuery } from "@mui/material";
import QuizTemplateCard from "./QuizTemplateCard";
import { QuizTemplateCard } from "./QuizTemplateCard";
export type CategoryType =
| "Tourism"
| "Services"
| "RealEstate"
| "Auto"
| "Health"
| "Research"
| "Production"
| "Repair"
| "Education";
export type Template = {
quizId: string;
picture: string;
quizId: number;
title: string;
categoryDescription?: string;
};
export type Category = {
category: string;
categoryType: CategoryType;
templates: Template[];
};
type TemplateProps = {
title: string;
items: Template[];
template: Category;
};
export const Template = ({ title, items }: TemplateProps) => {
export const Template = ({
template: { category, templates },
}: TemplateProps) => {
const theme = useTheme();
const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1100));
const isTablet = useMediaQuery(theme.breakpoints.down("md"));
@ -21,7 +41,7 @@ export const Template = ({ title, items }: TemplateProps) => {
<Box
sx={{ display: "flex", alignItems: "baseline", mt: "28px", mb: "40px" }}
>
<Typography variant="h5">{title}</Typography>
<Typography variant="h5">{category}</Typography>
<Box
sx={{
flexGrow: 1,
@ -32,7 +52,7 @@ export const Template = ({ title, items }: TemplateProps) => {
mb: "0px",
}}
/>
<Typography sx={{ color: "#4D4D4D" }}>({items.length})</Typography>
<Typography sx={{ color: "#4D4D4D" }}>({templates.length})</Typography>
</Box>
<Box
sx={{
@ -42,8 +62,12 @@ export const Template = ({ title, items }: TemplateProps) => {
justifyContent: isTablet ? "center" : "normal",
}}
>
{items.map(({ picture, quizId }) => (
<QuizTemplateCard key={picture} image={picture} quizId={quizId} />
{templates.map((template) => (
<QuizTemplateCard
key={template.quizId}
category={category}
template={template}
/>
))}
</Box>
</>

@ -1,36 +1,41 @@
import { useState } from "react";
import {
Box,
Button,
FormControl,
InputAdornment,
InputLabel,
MenuItem,
Select,
TextField,
Typography,
useTheme,
} from "@mui/material";
import { useState, useMemo } from "react";
import { Box, Button, Typography, useTheme } from "@mui/material";
import ComplexNavText from "../ComplexNavText";
import { TourismTemplate } from "./templates/Tourism";
import { PoolsTemplate } from "./templates/Polls";
import { SearchTemplate } from "./SearchTemplate";
import { SelectCategory } from "./SelectCategory";
import { TEMPLATES } from "./templates";
import { Template } from "./Template";
import SearchIcon from "@icons/SearchIcon";
import SectionWrapper from "@ui_kit/SectionWrapper";
import ArrowDown from "@icons/ArrowDownIcon";
const categories = [
"Категория 1",
"Категория 2",
"Категория 3",
"Категория 4",
] as const;
type Category = (typeof categories)[number];
import type { Category, CategoryType } from "./Template";
export default function QuizGallery() {
const theme = useTheme();
const [category, setCategory] = useState<Category | "">("");
const [searchValue, setSearchValue] = useState<string>("");
const [categoryType, setCategoryType] = useState<CategoryType | "All">("All");
const filteredTemplates = useMemo(
() =>
categoryType === "All"
? TEMPLATES
: TEMPLATES.filter((item) => item.categoryType === categoryType),
[categoryType],
);
const foundTemplates = useMemo(
() =>
filteredTemplates.reduce((total, category) => {
const templates = category.templates.filter(({ title }) =>
title.toLowerCase().includes(searchValue.toLowerCase()),
);
if (!templates.length) {
return total;
}
return [...total, { ...category, templates }];
}, [] as Category[]),
[searchValue, categoryType],
);
return (
<SectionWrapper
@ -44,78 +49,19 @@ export default function QuizGallery() {
</Typography>
<Box sx={{ width: "100%" }}>
<Box sx={{ display: "flex", gap: "2%" }}>
<FormControl fullWidth variant="standard" sx={{ width: "71%" }}>
<TextField
fullWidth
id="search"
placeholder="Поиск шаблонов"
sx={{
backgroundColor: theme.palette.background.default,
"& .MuiInputBase-root": {
height: "45px",
borderRadius: "10px",
pl: "10px",
},
}}
InputProps={{
sx: {
borderRadius: "10px",
fontSize: "16px",
lineHeight: "19px",
},
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
/>
</FormControl>
<FormControl
fullWidth
size="small"
sx={{
width: "27%",
minWidth: "200px",
height: "45px",
"& .MuiInputLabel-outlined": { mt: "4px", ml: "-3px" },
"& .MuiInputLabel-outlined.MuiInputLabel-shrink": {
ml: "3px",
mt: "0px",
},
}}
>
<InputLabel
sx={{ color: "black", fontSize: "16px", lineHeight: "19px" }}
id="demo-simple-select-label"
>
Категории
</InputLabel>
<Select
labelId="demo-simple-select-label"
id="category-select"
label="Категории"
variant="outlined"
value={category}
onChange={(e) => setCategory(e.target.value as Category)}
sx={{
height: "45px",
borderRadius: "10px",
}}
inputProps={{ sx: { pt: "12px" } }}
IconComponent={(props) => <ArrowDown {...props} />}
>
{categories.map((cat) => (
<MenuItem key={cat} value={cat}>
{cat}
</MenuItem>
))}
</Select>
</FormControl>
<SearchTemplate
searchValue={searchValue}
setSearchValue={setSearchValue}
/>
<SelectCategory
categoryType={categoryType}
setCategoryType={setCategoryType}
/>
</Box>
</Box>
<TourismTemplate />
<PoolsTemplate />
{foundTemplates.map((template) => (
<Template key={template.category} template={template} />
))}
<Box
sx={{ width: "100%", borderBottom: "1px solid #9A9AAF", mt: "50px" }}
/>

@ -0,0 +1,7 @@
import type { Category } from "../Template";
export const AUTO_TEMPLATES: Category = {
categoryType: "Auto",
category: "Авто",
templates: [],
};

@ -0,0 +1,7 @@
import type { Category } from "../Template";
export const EDUCATION_TEMPLATES: Category = {
categoryType: "Education",
category: "Образование",
templates: [],
};

@ -0,0 +1,7 @@
import type { Category } from "../Template";
export const HEALTH_TEMPLATES: Category = {
categoryType: "Health",
category: "Здоровье и уход",
templates: [],
};

@ -1,18 +0,0 @@
import { Template } from "../Template";
import quizTemplateImage4 from "@/assets/quiz-templates/quiz-template-4.png";
import quizTemplateImage5 from "@/assets/quiz-templates/quiz-template-5.png";
import quizTemplateImage6 from "@/assets/quiz-templates/quiz-template-6.png";
export const PoolsTemplate = () => {
return (
<Template
title="Исследования и опросы"
items={[
{ quizId: 0, picture: quizTemplateImage4 },
{ quizId: 0, picture: quizTemplateImage5 },
{ quizId: 0, picture: quizTemplateImage6 },
]}
/>
);
};

@ -0,0 +1,7 @@
import type { Category } from "../Template";
export const PRODUCTION_TEMPLATES: Category = {
categoryType: "Production",
category: "Производство",
templates: [],
};

@ -0,0 +1,7 @@
import type { Category } from "../Template";
export const REAL_ESTATE_TEMPLATES: Category = {
categoryType: "RealEstate",
category: "Недвижимость",
templates: [],
};

@ -0,0 +1,7 @@
import type { Category } from "../Template";
export const REPAIR_TEMPLATES: Category = {
categoryType: "Repair",
category: "Ремонт",
templates: [],
};

@ -0,0 +1,7 @@
import type { Category } from "../Template";
export const RESEARCH_TEMPLATES: Category = {
categoryType: "Research",
category: "Исследовательские",
templates: [],
};

@ -0,0 +1,80 @@
import ServiceIcon1 from "@/assets/quiz-templates/services/service-1.jpg";
import ServiceIcon2 from "@/assets/quiz-templates/services/service-2.jpg";
import ServiceIcon3 from "@/assets/quiz-templates/services/service-3.jpg";
import ServiceIcon4 from "@/assets/quiz-templates/services/service-4.jpg";
import ServiceIcon5 from "@/assets/quiz-templates/services/service-5.jpg";
import ServiceIcon6 from "@/assets/quiz-templates/services/service-6.jpg";
import ServiceIcon7 from "@/assets/quiz-templates/services/service-7.jpg";
import ServiceIcon8 from "@/assets/quiz-templates/services/service-8.jpg";
import ServiceIcon9 from "@/assets/quiz-templates/services/service-9.jpg";
import ServiceIcon10 from "@/assets/quiz-templates/services/service-10.jpg";
import ServiceIcon11 from "@/assets/quiz-templates/services/service-11.jpg";
import type { Category } from "../Template";
export const SERVICE_TEMPLATES: Category = {
categoryType: "Services",
category: "Услуги",
templates: [
{
quizId: "a3490800-1ad3-4944-bb9c-32189d36b75c",
title:
"Ответьте на 3 вопроса и узнайте, паспорт какой европейской страны вам подойдёт",
picture: ServiceIcon1,
},
{
quizId: "785fed83-6608-4029-ae22-6a26ce621e5f",
title:
"Ответьте на 7 вопросов, чтобы получить коммерческое предложение от маркетолога",
picture: ServiceIcon2,
},
{
quizId: "dfa3733f-66ce-4335-b83a-2c6511cbd1ce",
title:
"Ответьте на пару вопросов, чтобы найти свой индивидуальный стиль одежды",
picture: ServiceIcon3,
},
{
quizId: "8bf582a9-0a66-4f7b-bc0f-3c2f656c7449",
title: "Обменяйте рубли на валюту с комиссией 0%",
picture: ServiceIcon4,
},
{
quizId: "206ba071-afe9-4ee0-a722-a24a4f592679",
title: "Рассчитайте стоимость уборки вашей квартиры",
picture: ServiceIcon5,
},
{
quizId: "6938ff93-52eb-4296-86bf-fe5aa3fddabf",
title: "Забронируйте номер в зоогостинице для своего любимого питомца",
picture: ServiceIcon6,
},
{
quizId: "5262bc69-1ea0-446c-a16f-e929b6190e6d",
title: "Организуем перевозку под ключ",
picture: ServiceIcon7,
},
{
quizId: "9f8015f7-07fc-4acb-92dd-6e00505884cc",
title: "Рассчитайте стоимость ремонта пластиковых окон за 3 минуты",
picture: ServiceIcon8,
},
{
quizId: "259749bf-a54f-4a8e-ab5a-4cd0862d7504",
title: "Поможем подобрать эскиз для татуировки",
picture: ServiceIcon9,
},
{
quizId: "e107c0cd-4fa1-4a8f-938a-10a329b6528d",
title: "Подбери себе лучшего юриста за 30 секунд",
categoryDescription: "Юр услуги",
picture: ServiceIcon10,
},
{
quizId: "ce7903b1-3dfb-4a28-a2a4-0b41af447ae1",
title: "Рассчитайте размер ипотечного кредитования, ответив на 4 вопроса",
categoryDescription: "Юр услуги",
picture: ServiceIcon11,
},
],
};

@ -0,0 +1,69 @@
import TourismIcon1 from "@/assets/quiz-templates/tourism/tourism-1.jpg";
import TourismIcon2 from "@/assets/quiz-templates/tourism/tourism-2.jpg";
import TourismIcon3 from "@/assets/quiz-templates/tourism/tourism-3.jpg";
import TourismIcon4 from "@/assets/quiz-templates/tourism/tourism-4.jpg";
import TourismIcon5 from "@/assets/quiz-templates/tourism/tourism-5.jpg";
import TourismIcon6 from "@/assets/quiz-templates/tourism/tourism-6.jpg";
import TourismIcon7 from "@/assets/quiz-templates/tourism/tourism-7.jpg";
import TourismIcon8 from "@/assets/quiz-templates/tourism/tourism-8.jpg";
import TourismIcon9 from "@/assets/quiz-templates/tourism/tourism-9.jpg";
import TourismIcon10 from "@/assets/quiz-templates/tourism/tourism-10.jpg";
import type { Category } from "../Template";
export const TOURISM_TEMPLATES: Category = {
categoryType: "Tourism",
category: "Туризм",
templates: [
{
quizId: "f7a2b3b8-2548-47d8-afb3-f2c69a3a0a81",
title: "Подбор туристической страховки",
picture: TourismIcon1,
},
{
quizId: "e0927ded-5c4c-4d45-a5ba-c2e938362ffa",
title: "Оцените свои шансы на получение визы в США",
picture: TourismIcon2,
},
{
quizId: "23af97f4-0b8f-4d8b-8099-66ebef409ce1",
title: "Персональный тур с лучшими местами в Германии",
picture: TourismIcon3,
},
{
quizId: "ca3bd705-7d41-4ff1-ae4c-0b2d4a8faa30",
title: "Подберём лучший вариант тура под ваши критерии",
picture: TourismIcon4,
},
{
quizId: "5c2effd9-fe6a-40e6-9752-3f61dc20d6fa",
title: "Выберем самый подходящий для вас тур в Грузию",
picture: TourismIcon5,
},
{
quizId: "b559a764-6f55-4dc2-a9c4-aecd8b96003c",
title: "Бонжур, Сена! Подберём для вас тур по Франции",
picture: TourismIcon6,
},
{
quizId: "e33bf54b-9ad5-4cb9-b552-77148264d6af",
title: "Персональный тур в Египет с лучшими местами страны",
picture: TourismIcon7,
},
{
quizId: "c5815b1d-4991-4df2-ae14-8713d7f313b9",
title: "Тур по местам России",
picture: TourismIcon8,
},
{
quizId: "a0a4dce8-43bb-4978-a802-96d384465df4",
title: "Подберём для вас тур с самыми красивыми местами мира",
picture: TourismIcon9,
},
{
quizId: "0749abc5-a352-41b9-85c3-db7541326f23",
title: "Выберем лучшие туристические места для вас",
picture: TourismIcon10,
},
],
};

@ -1,18 +0,0 @@
import { Template } from "../Template";
import quizTemplateImage1 from "@/assets/quiz-templates/quiz-template-1.png";
import quizTemplateImage2 from "@/assets/quiz-templates/quiz-template-2.png";
import quizTemplateImage3 from "@/assets/quiz-templates/quiz-template-3.png";
export const TourismTemplate = () => {
return (
<Template
title="Квизы"
items={[
{ quizId: 0, picture: quizTemplateImage1 },
{ quizId: 0, picture: quizTemplateImage2 },
{ quizId: 0, picture: quizTemplateImage3 },
]}
/>
);
};

@ -0,0 +1,23 @@
import { TOURISM_TEMPLATES } from "./Tourism";
import { SERVICE_TEMPLATES } from "./Services";
import { REAL_ESTATE_TEMPLATES } from "./RealEstate";
import { AUTO_TEMPLATES } from "./Auto";
import { HEALTH_TEMPLATES } from "./Health";
import { RESEARCH_TEMPLATES } from "./Research";
import { PRODUCTION_TEMPLATES } from "./Production";
import { REPAIR_TEMPLATES } from "./Repair";
import { EDUCATION_TEMPLATES } from "./Education";
import type { Category } from "../Template";
export const TEMPLATES: Category[] = [
TOURISM_TEMPLATES,
SERVICE_TEMPLATES,
REAL_ESTATE_TEMPLATES,
AUTO_TEMPLATES,
HEALTH_TEMPLATES,
RESEARCH_TEMPLATES,
PRODUCTION_TEMPLATES,
REPAIR_TEMPLATES,
EDUCATION_TEMPLATES,
];