import React, { useState, useEffect, useRef } from "react"; import MDEditor, { commands } from '@uiw/react-md-editor'; import { Input } from './ui/input'; import { Label } from './ui/label'; import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from './ui/select'; import { Button } from './ui/button'; import { Separator } from './ui/separator'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from './ui/dialog'; import { CustomTabs } from './ui/tabs'; import Loader from "./ui/loader"; import Cookies from 'js-cookie'; const PUBLIC_TOPIC_API_URL = import.meta.env.PUBLIC_TOPIC_API_URL; const PUBLIC_MINIO_UPLOAD_URL = 'https://file-vault-prod-pdgctwgsnkiy.siliconpin.com/upload'; // const PUBLIC_MINIO_UPLOAD_URL = import.meta.env.PUBLIC_MINIO_UPLOAD_URL; const urlParams = new URLSearchParams(window.location.search); const slug = urlParams.get('slug'); // console.log('find slug from url', slug); export default function EditTopic (){ // const { slug } = useParams(); // const navigate = useNavigate(); // Form state const [formData, setFormData] = useState({ status: 'draft', category: '', slug: '', title: '', content: '', imageUrl: '' }); // UI state const [isSubmitting, setIsSubmitting] = useState(false); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [success, setSuccess] = useState(false); const [imageFile, setImageFile] = useState(null); const [uploadProgress, setUploadProgress] = useState(0); const [imageDialogOpen, setImageDialogOpen] = useState(false); const [imageUrlInput, setImageUrlInput] = useState(''); const [imageUploadFile, setImageUploadFile] = useState(null); const [imageUploadPreview, setImageUploadPreview] = useState(''); const [editorMode, setEditorMode] = useState('edit'); const [galleryImgDesc, setGalleryImgDesc] = useState(''); const [galleryImg, setGalleryImg] = useState(''); const [statusMessage, setStatusMessage] = useState({success : "", message: ""}); const [allGalleryImages, setAllGalleryImages] = useState([]); const fileInputRef = useRef(null); const fetchGalleryImage = async () => { try{ const response = await fetch(`https://gallery-image-pocndhvgmcnbacgb.siliconpin.com/gallery-image-delevery?slug=${slug}`) const data = await response.json(); setAllGalleryImages(data.images); // console.log('data.images', data.images) }catch(error){ console.error(error) } } // Fetch topic data on component mount useEffect(() => { const fetchTopic = async () => { try { const response = await fetch(`${PUBLIC_TOPIC_API_URL}?query=get-single-topic&slug=${slug}`, { credentials: 'include' }); if (!response.ok) { throw new Error('Failed to fetch topic'); } const data = await response.json(); const topic = data.data[0] // console.log('Single topic data', data) setFormData({ status: topic.status || 'draft', category: topic.category || '', title: topic.title || '', slug: topic.slug || '', content: topic.content || '', imageUrl: topic.img || '' }); } catch (err) { setError(err.message); } finally { setIsLoading(false); } }; fetchTopic(); fetchGalleryImage(); }, [slug]); // Upload Gallery Images const uploadGalleryImages = async (file, slug) => { setIsSubmitting(true); const formData = new FormData(); formData.append('file', file); formData.append('description', galleryImgDesc); formData.append('slug', slug); try { const response = await fetch(`https://gallery-image-pocndhvgmcnbacgb.siliconpin.com/upload`, { method: 'POST', body: formData }); const data = await response.json(); if (data.success === true) { setGalleryImgDesc(''); setStatusMessage({ success: true, message: "Image Uploaded! you can upload more images" }); setGalleryImg(null); fetchGalleryImage(); if (fileInputRef.current) fileInputRef.current.value = null; } else { setStatusMessage({ success: false, message: "Failed to upload image" }); } } catch (error) { console.error(error); setStatusMessage({ success: false, message: "Failed to upload image" }); } setIsSubmitting(false); }; // Upload file to MinIO (same as NewTopic) const uploadToMinIO = async (file, onProgress) => { const siliconId = Cookies.get('siliconId'); // Get from cookie or anywhere const token = Cookies.get('token'); // Get from cookie or storage const formData = new FormData(); formData.append('file', file); try { const response = await fetch(PUBLIC_MINIO_UPLOAD_URL, { method: 'POST', headers: { 'x-user-data': siliconId, 'Authorization': token, }, body: formData }); if (!response.ok) { throw new Error(`Upload failed: ${response.statusText}`); } const data = await response.json(); // console.log('Upload successful:', data); return data; } catch (error) { console.error('Upload error:', error); throw error; } }; // Generate slug from title (same as NewTopic) // useEffect(() => { // if (formData.title) { // const newSlug = formData.title // .toLowerCase() // .replace(/[^\w\s]/g, '') // .replace(/\s+/g, '-'); // setFormData(prev => ({ ...prev, slug: newSlug })); // } // }, [formData.title]); // Custom image command for MDEditor (same as NewTopic) const customImageCommand = { name: 'image', keyCommand: 'image', buttonProps: { 'aria-label': 'Insert image' }, icon: ( ), execute: () => { setImageDialogOpen(true); }, }; // Custom
insert command const lineBreakCommand = { name: 'linebreak', keyCommand: 'linebreak', buttonProps: { 'aria-label': 'Insert line break' }, icon: ( ), execute: () => { const textarea = document.querySelector('.w-md-editor-text-input'); if (!textarea) return; const start = textarea.selectionStart; const end = textarea.selectionEnd; const value = formData.content || ""; const breakTag = '
'; const newValue = value.slice(0, start) + breakTag + value.slice(end); setFormData(prev => ({ ...prev, content: newValue })); setTimeout(() => { textarea.selectionStart = textarea.selectionEnd = start + breakTag.length; textarea.focus(); }, 0); } }; // Get all commands (same as NewTopic) const allCommands = [ ...commands.getCommands().map(cmd => { if (cmd.name === 'image') { return customImageCommand; } return cmd; }), lineBreakCommand, ]; // Handle image URL insertion (same as NewTopic) const handleInsertImageUrl = () => { if (imageUrlInput) { const imgMarkdown = `![Image](${imageUrlInput})`; const textarea = document.querySelector('.w-md-editor-text-input'); if (textarea) { const startPos = textarea.selectionStart; const endPos = textarea.selectionEnd; const currentValue = formData.content; const newValue = currentValue.substring(0, startPos) + imgMarkdown + currentValue.substring(endPos); setFormData(prev => ({ ...prev, content: newValue })); } setImageDialogOpen(false); setImageUrlInput(''); } }; // Handle image file selection (same as NewTopic) const handleImageFileSelect = (e) => { const file = e.target.files[0]; if (file) { setImageUploadFile(file); const reader = new FileReader(); reader.onload = () => { setImageUploadPreview(reader.result); }; reader.readAsDataURL(file); } }; // Upload image file (same as NewTopic) const handleImageUpload = async () => { if (!imageUploadFile) return; try { setIsSubmitting(true); setUploadProgress(0); const uploadedUrl = await uploadToMinIO(imageUploadFile, (progress) => { setUploadProgress(progress); }); const imgMarkdown = `![Image](${uploadedUrl.url})`; const textarea = document.querySelector('.w-md-editor-text-input'); if (textarea) { const startPos = textarea.selectionStart; const endPos = textarea.selectionEnd; const currentValue = formData.content; const newValue = currentValue.substring(0, startPos) + imgMarkdown + currentValue.substring(endPos); setFormData(prev => ({ ...prev, content: newValue })); } setImageDialogOpen(false); setImageUploadFile(null); setImageUploadPreview(''); } catch (error) { setError('Failed to upload image: ' + error.message); } finally { setIsSubmitting(false); } }; // Form submission for EDIT const handleSubmit = async (e) => { e.preventDefault(); setIsSubmitting(true); setError(null); setUploadProgress(0); try { // Upload new featured image if selected let imageUrl = formData.imageUrl; if (imageFile) { imageUrl = await uploadToMinIO(imageFile, (progress) => { setUploadProgress(progress); }); } imageUrl = imageUrl.url; // Prepare payload const payload = { ...formData, imageUrl }; // Submit to API (PUT request for update) const response = await fetch(`${PUBLIC_TOPIC_API_URL}?query=update-topic&slug=${formData.slug}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, credentials: 'include', body: JSON.stringify(payload) }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || 'Failed to update topic'); } setSuccess(true); setTimeout(() => { navigate(`/topic/${formData.slug}`); }, 1500); } catch (err) { setError(err.message); } finally { setIsSubmitting(false); setUploadProgress(0); } }; // Handle form field changes (same as NewTopic) const handleChange = (e) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); }; // Handle featured image file selection (same as NewTopic) const handleFileChange = (e) => { const file = e.target.files[0]; if (file) { setImageFile(file); const reader = new FileReader(); reader.onload = () => { setFormData(prev => ({ ...prev, imageUrl: reader.result })); }; reader.readAsDataURL(file); } }; // Loading state if (isLoading) { return ( ); } // Success state if (success) { return (

Topic has been successfully updated!

You are being automatically redirected to the topic page...

); } return (

Edit Topic

{formData.title}

{/* Title and Slug */}
{/* */} {/*

This will be used in the topic URL

*/}
{/* Featured Image Upload */}
{formData.imageUrl && (
Preview
)}
{/* Content Editor */}
setFormData(prev => ({ ...prev, content: value || '' }))} height={400} preview={editorMode} commands={allCommands} />
{/* Image Upload Dialog (same as NewTopic) */} Add Image setImageUrlInput(e.target.value)} />
) }, { label: "Upload", value: "upload", content: (
{imageUploadPreview && (
Preview
)} {uploadProgress > 0 && uploadProgress < 100 && (
)}
) } ]} /> { allGalleryImages && (
{allGalleryImages.map((img, index) => ( {`gallery-${index}`} ))}
) }
setGalleryImgDesc(e.target.value)} value={galleryImgDesc} type="text" placeholder="Write description to proceed image upload!" /> setGalleryImg(e.target.files[0])} type="file" className={`${galleryImgDesc.trim().length > 9 ? 'border-[#6d9e37] file:bg-[#6d9e37] file:text-white file:border-0 file:rounded-md' : ''}`} disabled={galleryImgDesc.trim().length < 10} />

{statusMessage.success === true && } {statusMessage.success === false && } {statusMessage.message}

{/* Form Actions */}
{error && (
Error: {error}
)}
); };