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 = ``;
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 = ``;
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 (
You are being automatically redirected to the topic page...
{formData.title}
{statusMessage.success === true && ✓} {statusMessage.success === false && ❌} {statusMessage.message}