import axios from "axios"; import { playSound } from "@/utils/sound"; import { toast } from "react-toastify"; import { Generating } from "@/stores/examEditor/types"; import useExamEditorStore from "@/stores/examEditor"; import { Module } from "@/interfaces"; interface GeneratorConfig { method: 'GET' | 'POST'; queryParams?: Record; files?: Record; body?: Record; } export function generate( sectionId: number, module: Module, type: Generating, config: GeneratorConfig, mapData: (data: any) => Record[], levelSectionId?: number, level: boolean = false ) { const setGenerating = (sectionId: number, generating: Generating, level: boolean, remove?: boolean) => { const state = useExamEditorStore.getState(); const dispatch = state.dispatch; let generatingUpdate; if (level) { if (remove) { generatingUpdate = state.modules["level"].sections.find((s) => s.sectionId === levelSectionId)!.levelGenerating.filter(g => g === generating) } else { generatingUpdate = [...state.modules["level"].sections.find((s) => s.sectionId === levelSectionId)!.levelGenerating, generating]; } } else { generatingUpdate = generating; } dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId, module: level ? "level" : module, field: level ? "levelGenerating" : "generating", value: generatingUpdate } }); }; const setGeneratedResult = (sectionId: number, generating: Generating, result: Record[] | undefined, level: boolean) => { const state = useExamEditorStore.getState(); const dispatch = state.dispatch; let genResults; if (level) { genResults = [...state.modules["level"].sections.find((s) => s.sectionId === levelSectionId)!.levelGenResults, { generating, result, module }]; } else { genResults = { generating, result, module }; } dispatch({ type: "UPDATE_SECTION_SINGLE_FIELD", payload: { sectionId: level ? levelSectionId! : sectionId, module: level ? "level" : module, field: level ? "levelGenResults" : "genResult", value: genResults } }); }; setGenerating(level ? levelSectionId! : sectionId, type, level); function buildQueryString(params: Record): string { const searchParams = new URLSearchParams(); Object.entries(params).forEach(([key, value]) => { if (Array.isArray(value)) { value.forEach(v => searchParams.append(key, v)); } else { searchParams.append(key, value); } }); return searchParams.toString(); } const queryString = config.queryParams ? buildQueryString(config.queryParams) : ''; const url = `/api/exam/generate/${module}/${sectionId}${queryString ? `?${queryString}` : ''}`; let body = null; if (config.files && Object.keys(config.files).length > 0 && config.method === 'POST') { const formData = new FormData(); const buildForm = async () => { await Promise.all( Object.entries(config.files ?? {}).map(async ([key, blobUrl]) => { const response = await fetch(blobUrl); const blob = await response.blob(); const file = new File([blob], key, { type: blob.type }); formData.append(key, file); }) ); if (config.body) { Object.entries(config.body).forEach(([key, value]) => { formData.append(key, value as string); }); } return formData; }; buildForm().then(form => { body = form; const request = axios.post(url, body, { headers: { 'Content-Type': 'multipart/form-data' } }); request .then((result) => { playSound("check"); setGeneratedResult(level ? levelSectionId! : sectionId, type, mapData(result.data), level); }) .catch((error) => { setGenerating(sectionId, undefined, level, true); playSound("error"); toast.error("Something went wrong! Try to generate again."); }); }); } else { body = config.body; const request = config.method === 'POST' ? axios.post(url, body, { headers: { 'Content-Type': 'application/json' } }) : axios.get(url); request .then((result) => { playSound("check"); setGeneratedResult(level ? levelSectionId! : sectionId, type, mapData(result.data), level); }) .catch((error) => { setGenerating(sectionId, undefined, level, true); playSound("error"); toast.error("Something went wrong! Try to generate again."); }); } }