import { useState, useEffect, useRef } from 'react' import { X, Trash2, Upload, FileText, Link2, ExternalLink, FolderOpen } from 'lucide-react' import { useLanguage } from '../i18n/LanguageContext' import { api, PLATFORMS, getBrandColor } from '../utils/api' import CommentsSection from './CommentsSection' import Modal from './Modal' import SlidePanel from './SlidePanel' import CollapsibleSection from './CollapsibleSection' export default function PostDetailPanel({ post, onClose, onSave, onDelete, brands, teamMembers, campaigns }) { const { t, lang } = useLanguage() const fileInputRef = useRef(null) const [form, setForm] = useState({}) const [dirty, setDirty] = useState(false) const [saving, setSaving] = useState(false) const [publishError, setPublishError] = useState('') const [showDeleteConfirm, setShowDeleteConfirm] = useState(false) // Attachments state const [attachments, setAttachments] = useState([]) const [uploading, setUploading] = useState(false) const [dragActive, setDragActive] = useState(false) const [showAssetPicker, setShowAssetPicker] = useState(false) const [availableAssets, setAvailableAssets] = useState([]) const [assetSearch, setAssetSearch] = useState('') const postId = post?._id || post?.id const isCreateMode = !postId useEffect(() => { if (post) { setForm({ title: post.title || '', description: post.description || '', brand_id: post.brandId || post.brand_id || '', platforms: post.platforms || (post.platform ? [post.platform] : []), status: post.status || 'draft', assigned_to: post.assignedTo || post.assigned_to || '', scheduled_date: post.scheduledDate ? new Date(post.scheduledDate).toISOString().slice(0, 16) : '', notes: post.notes || '', campaign_id: post.campaignId || post.campaign_id || '', publication_links: post.publication_links || post.publicationLinks || [], }) setDirty(isCreateMode) setPublishError('') if (!isCreateMode) loadAttachments() } }, [post]) if (!post) return null const statusOptions = [ { value: 'draft', label: t('posts.status.draft') }, { value: 'in_review', label: t('posts.status.in_review') }, { value: 'approved', label: t('posts.status.approved') }, { value: 'scheduled', label: t('posts.status.scheduled') }, { value: 'published', label: t('posts.status.published') }, ] const update = (field, value) => { setForm(f => ({ ...f, [field]: value })) setDirty(true) } const updatePublicationLink = (platform, url) => { setForm(f => { const links = [...(f.publication_links || [])] const idx = links.findIndex(l => l.platform === platform) if (idx >= 0) { links[idx] = { ...links[idx], url } } else { links.push({ platform, url }) } return { ...f, publication_links: links } }) setDirty(true) } const handleSave = async () => { setPublishError('') setSaving(true) try { const data = { title: form.title, description: form.description, brand_id: form.brand_id ? Number(form.brand_id) : null, assigned_to: form.assigned_to ? Number(form.assigned_to) : null, status: form.status, platforms: form.platforms || [], scheduled_date: form.scheduled_date || null, notes: form.notes, campaign_id: form.campaign_id ? Number(form.campaign_id) : null, publication_links: form.publication_links || [], } if (data.status === 'published' && data.platforms.length > 0) { const missingPlatforms = data.platforms.filter(platform => { const link = (data.publication_links || []).find(l => l.platform === platform) return !link || !link.url || !link.url.trim() }) if (missingPlatforms.length > 0) { const names = missingPlatforms.map(p => PLATFORMS[p]?.label || p).join(', ') setPublishError(`${t('posts.publishMissing')} ${names}`) setSaving(false) return } } await onSave(isCreateMode ? null : postId, data) setDirty(false) if (isCreateMode) onClose() } catch (err) { if (err.message?.includes('Cannot publish')) { setPublishError(err.message.replace(/.*: /, '')) } } finally { setSaving(false) } } const confirmDelete = async () => { setShowDeleteConfirm(false) await onDelete(postId) onClose() } // ─── Attachments ────────────────────────────── async function loadAttachments() { if (!postId) return try { const data = await api.get(`/posts/${postId}/attachments`) setAttachments(Array.isArray(data) ? data : (data.data || [])) } catch { setAttachments([]) } } const handleFileUpload = async (files) => { if (!postId || !files?.length) return setUploading(true) for (const file of files) { const fd = new FormData() fd.append('file', file) try { await api.upload(`/posts/${postId}/attachments`, fd) } catch (err) { console.error('Upload failed:', err) } } setUploading(false) loadAttachments() } const handleDeleteAttachment = async (attId) => { try { await api.delete(`/attachments/${attId}`) loadAttachments() } catch (err) { console.error('Delete attachment failed:', err) } } const openAssetPicker = async () => { try { const data = await api.get('/assets') setAvailableAssets(Array.isArray(data) ? data : (data.data || [])) } catch { setAvailableAssets([]) } setAssetSearch('') setShowAssetPicker(true) } const handleAttachAsset = async (assetId) => { if (!postId) return try { await api.post(`/posts/${postId}/attachments/from-asset`, { asset_id: assetId }) loadAttachments() setShowAssetPicker(false) } catch (err) { console.error('Attach asset failed:', err) } } const handleDrop = (e) => { e.preventDefault(); e.stopPropagation(); setDragActive(false) if (e.dataTransfer.files?.length) handleFileUpload(e.dataTransfer.files) } const brandName = (() => { if (form.brand_id) { const b = brands?.find(b => String(b._id || b.id) === String(form.brand_id)) return b ? (lang === 'ar' && b.name_ar ? b.name_ar : b.name) : null } return post.brand_name || post.brandName || null })() const header = (
{t('posts.publishRequired')}
)}{dragActive ? t('posts.dropFiles') : t('posts.uploadFiles')}
{t('posts.selectAssets')}
{t('posts.noAssetsFound')}
)}