- /settings/published : l'utilisateur voit ses notes publiées - Copier le lien, ouvrir, dépublier - API /api/user/published - Onglet 'Mes pages' (Globe) dans la nav settings - Fix: import Shield dupliqué dans admin-sidebar.tsx - i18n FR/EN
104 lines
4.5 KiB
TypeScript
104 lines
4.5 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useEffect, useCallback } from 'react'
|
|
import { Globe, ExternalLink, Trash2, Loader2, Copy, Check } from 'lucide-react'
|
|
import { toast } from 'sonner'
|
|
import { useLanguage } from '@/lib/i18n'
|
|
|
|
interface PublishedNote {
|
|
id: string
|
|
title: string | null
|
|
publicSlug: string | null
|
|
publishedAt: string | null
|
|
}
|
|
|
|
export default function UserPublishedPage() {
|
|
const { t } = useLanguage()
|
|
const [notes, setNotes] = useState<PublishedNote[]>([])
|
|
const [loading, setLoading] = useState(true)
|
|
const [copiedId, setCopiedId] = useState<string | null>(null)
|
|
|
|
const load = useCallback(async () => {
|
|
setLoading(true)
|
|
try {
|
|
const res = await fetch('/api/user/published')
|
|
const data = await res.json()
|
|
setNotes(data.notes || [])
|
|
} catch { toast.error('Erreur') }
|
|
finally { setLoading(false) }
|
|
}, [])
|
|
|
|
useEffect(() => { load() }, [load])
|
|
|
|
const unpublish = async (noteId: string) => {
|
|
try {
|
|
const res = await fetch('/api/notes/publish', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ noteId, action: 'unpublish' }),
|
|
})
|
|
if (res.ok) { toast.success(t('richTextEditor.unpublishSuccess') || 'Note dépubliée'); load() }
|
|
else { toast.error('Erreur') }
|
|
} catch { toast.error('Erreur') }
|
|
}
|
|
|
|
const copyLink = (slug: string, noteId: string) => {
|
|
const url = `${window.location.origin}/p/${slug}`
|
|
navigator.clipboard?.writeText(url).then(() => {
|
|
setCopiedId(noteId); setTimeout(() => setCopiedId(null), 2000); toast.success('Lien copié !')
|
|
}).catch(() => {
|
|
const el = document.createElement('textarea'); el.value = url; document.body.appendChild(el); el.select()
|
|
document.execCommand('copy'); document.body.removeChild(el)
|
|
setCopiedId(noteId); setTimeout(() => setCopiedId(null), 2000); toast.success('Lien copié !')
|
|
})
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6" dir="auto">
|
|
<div>
|
|
<h2 className="text-xl font-semibold mb-1">{t('settings.publishedTitle') || 'Mes pages publiées'}</h2>
|
|
<p className="text-sm text-muted-foreground">{t('settings.publishedDesc') || 'Gérez les notes que vous avez publiées publiquement.'}</p>
|
|
</div>
|
|
|
|
{loading ? (
|
|
<div className="flex justify-center py-8"><Loader2 className="h-5 w-5 animate-spin text-muted-foreground" /></div>
|
|
) : notes.length === 0 ? (
|
|
<div className="text-center py-12 rounded-xl border border-dashed border-border">
|
|
<Globe size={32} className="mx-auto text-muted-foreground/40 mb-3" />
|
|
<p className="text-sm text-muted-foreground">{t('settings.publishedEmpty') || 'Aucune note publiée pour le moment.'}</p>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-2">
|
|
{notes.map(note => (
|
|
<div key={note.id} className="flex items-center gap-3 p-3.5 rounded-xl border border-border bg-card">
|
|
<div className="w-9 h-9 rounded-lg bg-green-50 dark:bg-green-950/20 flex items-center justify-center shrink-0">
|
|
<Globe size={15} className="text-green-600 dark:text-green-400" />
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="text-sm font-medium truncate">{note.title || 'Sans titre'}</div>
|
|
<div className="text-[11px] text-muted-foreground">
|
|
{note.publishedAt ? new Date(note.publishedAt).toLocaleDateString() : ''}
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-1 shrink-0">
|
|
<button onClick={() => copyLink(note.publicSlug!, note.id)}
|
|
className="p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title="Copier le lien">
|
|
{copiedId === note.id ? <Check size={15} className="text-green-500" /> : <Copy size={15} />}
|
|
</button>
|
|
<a href={`/p/${note.publicSlug}`} target="_blank" rel="noopener noreferrer"
|
|
className="p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title="Ouvrir">
|
|
<ExternalLink size={15} />
|
|
</a>
|
|
<button onClick={() => unpublish(note.id)}
|
|
className="p-2 rounded-lg hover:bg-red-50 dark:hover:bg-red-950/20 text-muted-foreground hover:text-red-500 transition-colors" title="Dépublier">
|
|
<Trash2 size={15} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|