import { useEffect, useState } from 'react' import { Link, useParams, useNavigate } from 'react-router-dom' import { SearchableSelect } from '../components/SearchableSelect' import { ImageCropper } from '../components/ImageCropper' import { TagInput } from '../components/TagInput' import { RichTextEditor } from '../components/RichTextEditor' import { SeoMetaFields } from '../components/SeoMetaFields' import { Breadcrumbs } from '../components/Breadcrumbs' import { useToast } from '../context/ToastContext' import { useT } from '../i18n/useT' import { ApiError } from '../lib/api' import { listVideoCategories, mapVideoCategoryToUi, } from '../services/videoCategoryService' import { resolveDataUrlToMediaId, resolveHtmlEmbeddedDataUrls, } from '../services/mediaService' import { createVideo, getVideo, mapVideoApiToFormState, updateVideo, } from '../services/videoService' import type { Category } from '../types/category' import type { VideoProvider } from '../types/video' import { VIDEO_PROVIDER_OPTIONS } from '../types/video' import { flattenCategories } from '../utils/categories' import { seoMetaPayload } from '../utils/seoMeta' import pageStyles from '../components/PageContent.module.css' import styles from './AddNewProductPage.module.css' export function AddNewVideoPage() { const { id } = useParams() const navigate = useNavigate() const { showToast } = useToast() const t = useT() const isEdit = Boolean(id) const [categories, setCategories] = useState([]) const [categoryId, setCategoryId] = useState('') const [titleFa, setTitleFa] = useState('') const [titleEn, setTitleEn] = useState('') const [abstract, setAbstract] = useState('') const [descriptionHtml, setDescriptionHtml] = useState('') const [videoProvider, setVideoProvider] = useState('youtube') const [embedCode, setEmbedCode] = useState('') const [coverImage, setCoverImage] = useState(null) const [tags, setTags] = useState([]) const [seoMetaTitle, setSeoMetaTitle] = useState('') const [seoMetaDescription, setSeoMetaDescription] = useState('') const [featuredMediaId, setFeaturedMediaId] = useState(null) const [loaded, setLoaded] = useState(!isEdit) const [isSubmitting, setIsSubmitting] = useState(false) const [error, setError] = useState('') const categoryOptions = flattenCategories(categories) useEffect(() => { const controller = new AbortController() async function loadCategories() { try { const items = await listVideoCategories(controller.signal) setCategories(items.map(mapVideoCategoryToUi)) } catch (err) { if (err instanceof DOMException && err.name === 'AbortError') return if (err instanceof ApiError) { setError(err.message) } else { setError(t('video.categories.errorLoad')) } } } void loadCategories() return () => controller.abort() }, []) useEffect(() => { if (!isEdit || !id) return const controller = new AbortController() async function loadVideo() { setError('') try { const video = await getVideo(id!, controller.signal) const form = mapVideoApiToFormState(video) setCategoryId(form.categoryId) setTitleFa(form.titleFa) setTitleEn(form.titleEn) setAbstract(form.abstract) setDescriptionHtml(form.descriptionHtml) setVideoProvider(form.videoProvider) setEmbedCode(form.embedCode) setCoverImage(form.coverImage) setTags(form.tags) setSeoMetaTitle(form.seoMetaTitle) setSeoMetaDescription(form.seoMetaDescription) setFeaturedMediaId(form.featuredMediaId) setLoaded(true) } catch (err) { if (err instanceof DOMException && err.name === 'AbortError') return navigate('/videos/list', { replace: true }) } } void loadVideo() return () => controller.abort() }, [isEdit, id, navigate]) if (!loaded) return null async function handleSubmit(e: React.FormEvent) { e.preventDefault() setIsSubmitting(true) setError('') try { const nextFeaturedMediaId = await resolveDataUrlToMediaId( coverImage, 'video-cover-image.jpg', featuredMediaId, ) const resolvedDescriptionHtml = await resolveHtmlEmbeddedDataUrls(descriptionHtml) const payload = { titleFa: titleFa.trim(), titleEn: titleEn.trim() || undefined, abstract: abstract.trim(), descriptionHtml: resolvedDescriptionHtml, videoProvider, embedCode: embedCode.trim(), categoryId: categoryId || undefined, featuredMediaId: nextFeaturedMediaId ?? undefined, tags, ...seoMetaPayload(seoMetaTitle, seoMetaDescription), status: 'published' as const, } if (isEdit && id) { await updateVideo(id, { ...payload, categoryId: categoryId || null, featuredMediaId: nextFeaturedMediaId, }) showToast(t('video.form.toast.updated'), 'success') } else { await createVideo(payload) showToast(t('video.form.toast.created'), 'success') } navigate('/videos/list') } catch (err) { if (err instanceof ApiError) { setError(err.message) } else if (err instanceof Error) { setError(err.message) } else { setError(t('video.form.errorSave')) } } finally { setIsSubmitting(false) } } return (

{isEdit ? t('title.editVideo') : t('title.addVideo')}

{isEdit ? t('video.form.edit.subtitle') : t('video.form.add.subtitle')}

{error && (
{error}
)}
setTitleFa(e.target.value)} required disabled={isSubmitting} />
setTitleEn(e.target.value)} disabled={isSubmitting} />