feat: multi-platform generation + custom confirm modal + per-platform tabs
Backend: - /generate now returns array of posts (one per platform selected) - Each post generated with platform-specific LLM prompt and char limits - Monthly counter incremented by number of platforms Frontend: - ConfirmModal: reusable Editorial Fresh modal replaces ugly browser confirm() - ContentPage: platform tabs when multiple posts, switch between variants - ContentPage: generatedPosts array state replaces single generated - ContentArchive: uses ConfirmModal for delete confirmation - Platform chips filtered by plan (Freemium: IG/FB only) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { api } from '../api'
|
||||
import ConfirmModal from './ConfirmModal'
|
||||
|
||||
const statusLabels = { draft: 'Bozza', approved: 'Approvato', scheduled: 'Schedulato', published: 'Pubblicato' }
|
||||
const statusColors = {
|
||||
@@ -19,6 +20,7 @@ export default function ContentArchive() {
|
||||
const [editText, setEditText] = useState('')
|
||||
const [filterCharacter, setFilterCharacter] = useState('')
|
||||
const [filterStatus, setFilterStatus] = useState('')
|
||||
const [deleteTarget, setDeleteTarget] = useState(null)
|
||||
|
||||
useEffect(() => { loadData() }, [])
|
||||
|
||||
@@ -40,8 +42,7 @@ export default function ContentArchive() {
|
||||
try { await api.post(`/content/posts/${postId}/approve`); loadData() } catch {}
|
||||
}
|
||||
const handleDelete = async (postId) => {
|
||||
if (!confirm('Eliminare questo contenuto?')) return
|
||||
try { await api.delete(`/content/posts/${postId}`); loadData() } catch {}
|
||||
try { await api.delete(`/content/posts/${postId}`); setDeleteTarget(null); loadData() } catch {}
|
||||
}
|
||||
const handleSaveEdit = async (postId) => {
|
||||
try {
|
||||
@@ -171,7 +172,7 @@ export default function ContentArchive() {
|
||||
)}
|
||||
<button onClick={() => { setEditingId(post.id); setEditText(post.text_content || ''); setExpandedId(post.id) }}
|
||||
style={{ ...btnSmall, backgroundColor: 'var(--cream-dark)', color: 'var(--ink-light)' }}>Modifica</button>
|
||||
<button onClick={() => handleDelete(post.id)}
|
||||
<button onClick={() => setDeleteTarget(post.id)}
|
||||
style={{ ...btnSmall, color: 'var(--error)', backgroundColor: 'transparent', marginLeft: 'auto' }}>Elimina</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,6 +181,16 @@ export default function ContentArchive() {
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<ConfirmModal
|
||||
open={deleteTarget !== null}
|
||||
title="Elimina contenuto"
|
||||
message="Sei sicuro di voler eliminare questo contenuto? L'operazione non è reversibile."
|
||||
confirmLabel="Elimina"
|
||||
cancelLabel="Annulla"
|
||||
confirmStyle="danger"
|
||||
onConfirm={() => handleDelete(deleteTarget)}
|
||||
onCancel={() => setDeleteTarget(null)}
|
||||
/>
|
||||
<style>{`@keyframes spin { to { transform: rotate(360deg) } }`}</style>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user