diff --git a/src/app/api/streetcode/text-content/facts.api.ts b/src/app/api/streetcode/text-content/facts.api.ts index b167a83..31fdee6 100644 --- a/src/app/api/streetcode/text-content/facts.api.ts +++ b/src/app/api/streetcode/text-content/facts.api.ts @@ -1,6 +1,6 @@ import Agent from '@api/agent.api'; import { API_ROUTES } from '@constants/api-routes.constants'; -import { Fact } from '@models/streetcode/text-contents.model'; +import { Fact, FactCreate } from '@models/streetcode/text-contents.model'; const FactsApi = { getById: (id: number) => Agent.get(`${API_ROUTES.FACTS.GET}/${id}`), @@ -11,7 +11,7 @@ const FactsApi = { `${API_ROUTES.FACTS.GET_BY_STREETCODE_ID}/${streetcodeId}`, ), - create: (fact: Fact) => Agent.post(`${API_ROUTES.FACTS.CREATE}`, fact), + create: (fact: FactCreate) => Agent.post(`${API_ROUTES.FACTS.CREATE}`, fact), update: (fact: Fact) => Agent.put(`${API_ROUTES.FACTS.UPDATE}`, fact), diff --git a/src/app/common/components/modals/InterestingFacts/FactsAdminModal/InterestingFactsAdminModal.component.tsx b/src/app/common/components/modals/InterestingFacts/FactsAdminModal/InterestingFactsAdminModal.component.tsx index 6ddcb8f..8a13157 100644 --- a/src/app/common/components/modals/InterestingFacts/FactsAdminModal/InterestingFactsAdminModal.component.tsx +++ b/src/app/common/components/modals/InterestingFacts/FactsAdminModal/InterestingFactsAdminModal.component.tsx @@ -1,87 +1,235 @@ -import './InterestingFactsAdminModal.style.scss'; +import './InterestingFactsAdminModal.styles.scss'; import { observer } from 'mobx-react-lite'; -import { useState } from 'react'; +import { useEffect } from 'react'; import { InboxOutlined } from '@ant-design/icons'; import CancelBtn from '@assets/images/utils/Cancel_btn.svg'; import useMobx from '@stores/root-store'; import { Button, Form, Modal, Upload } from 'antd'; import FormItem from 'antd/es/form/FormItem'; -import { UploadFile } from 'antd/lib/upload/interface'; -import Image, { ImageCreate } from '@/models/media/image.model'; +import { ImageCreate } from '@/models/media/image.model'; import { Fact, FactCreate } from '@/models/streetcode/text-contents.model'; -const InterestingFactsModal = () => { - const { modalStore, factsStore, imagesStore: { getImageArray } } = useMobx(); +interface InterestingFactsModalProps { + streetcodeId: number; + factToEdit?: Fact | null; +} + +const InterestingFactsModal = ({ streetcodeId = 1, factToEdit = null }: InterestingFactsModalProps) => { + const { modalStore, factsStore, imagesStore: { createImage } } = useMobx(); const { setModal, modalsState: { adminFacts } } = modalStore; - const [factContent, setFactContent] = useState(''); + const [form] = Form.useForm(); + + const titleValue = Form.useWatch('title', form) || ''; + const mainTextValue = Form.useWatch('mainText', form) || ''; + const imageDescriptionValue = Form.useWatch('imageDescription', form) || ''; + + const titleCount = titleValue.length; + const mainTextCount = mainTextValue.length; + const imageDescCount = imageDescriptionValue.length; + + useEffect(() => { + if (adminFacts.isOpen && factToEdit) { + form.setFieldsValue({ + title: factToEdit.title, + mainText: factToEdit.factContent, + imageDescription: factToEdit.imageDescription, + }); + } else if (adminFacts.isOpen && !factToEdit) { + form.resetFields(); + } + }, [adminFacts.isOpen, factToEdit, form]); - const characterCount = factContent.length | 0; + const fileToBase64 = (file: File): Promise => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => { + const result = reader.result as string; + const base64 = result.split(',')[1]; + resolve(base64); + }; + reader.onerror = (error) => reject(error); + }); + }; + + const normFile = (e: any) => { + if (Array.isArray(e)) { + return e; + } + return e?.fileList; + }; - const onFinish = (values: any) => { - const uploadedFile = values.picture.file as UploadFile; + const onFinish = async (values: any) => { + let imgId = factToEdit?.imageId; - const image: ImageCreate = { - blobName: uploadedFile.name ?? '', - mimeType: uploadedFile.type ?? '', - }; + if (values.picture && values.picture.length > 0) { + const uploadedFile = values.picture[0]; + const file = uploadedFile.originFileObj as File; + + if (!file) { + Modal.error({ title: 'Помилка', content: 'Не вдалося отримати файл' }); + return; + } + + const fileName = uploadedFile.name ?? ''; + const extension = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase(); + const base64 = await fileToBase64(file); + + const imageToCreate: ImageCreate = { + title: values.title || fileName, + baseFormat: base64, + mimeType: file.type ?? 'image/jpeg', + extension: extension, + }; + + const createdImage = await createImage(imageToCreate); + if (!createdImage) { + Modal.error({ title: 'Помилка', content: 'Не вдалося створити зображення' }); + return; + } + imgId = createdImage.id; + } - const fact: FactCreate = { - title: values.title, - factContent, - image, - }; + if (!imgId && !factToEdit) { + Modal.error({ title: 'Помилка', content: 'Зображення є обовʼязковим' }); + return; + } - factsStore.addFactToCreate(fact); + try { + if (factToEdit) { + const fact: Fact = { + id: factToEdit.id, + title: values.title, + factContent: values.mainText, + imageId: imgId!, + order: factToEdit.order, + imageDescription: values.imageDescription, + }; + await factsStore.updateFact(fact); + } else { + const fact: FactCreate = { + title: values.title, + factContent: values.mainText, + imageId: imgId!, + imageDescription: values.imageDescription, + streetcodeId: streetcodeId, + }; + await factsStore.createFact(fact); + } + + form.resetFields(); + setModal('adminFacts', undefined, false); + } catch (error) { + console.log("Error: Fact has not been saved!"); + Modal.error({ + title: 'Помилка', + content: 'Не вдалося зберегти факт' + }); + } }; return ( setModal('adminFacts')} + onCancel={() => { + form.resetFields(); + setModal('adminFacts', undefined, false); + }} footer={null} maskClosable centered closeIcon={} > -
+

Wow-Факт

-

Заголовок

+
- - - +

Заголовок

+
+ + + + {titleCount}/68 +
+
+ +

Основний текст

-