feat(admin): merge Site Settings and Wishlist into single Configurações panel
Single-wishlist apps no longer need two separate edit sections. Both siteTitle/homepageSubtext and wishlist fields now save together in one action from a unified Configurações card. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,6 @@ import {
|
||||
} from '@/lib/api';
|
||||
import Header from '@/components/header';
|
||||
import Link from 'next/link';
|
||||
import SettingsSection from '@/components/admin/SettingsSection';
|
||||
import ItemCard from '@/components/admin/ItemCard';
|
||||
import ItemForm from '@/components/admin/ItemForm';
|
||||
import ImageUpload from '@/components/image-upload';
|
||||
@@ -42,7 +41,7 @@ function AdminPageContent() {
|
||||
homepageSubtext: '',
|
||||
});
|
||||
|
||||
// Wishlist edit state
|
||||
// Unified config edit state
|
||||
const [isEditingWishlist, setIsEditingWishlist] = useState(false);
|
||||
const [editForm, setEditForm] = useState({
|
||||
name: '',
|
||||
@@ -51,6 +50,8 @@ function AdminPageContent() {
|
||||
preferences: '',
|
||||
imageUrl: '',
|
||||
isPublic: true,
|
||||
siteTitle: '',
|
||||
homepageSubtext: '',
|
||||
});
|
||||
const [editError, setEditError] = useState('');
|
||||
const [isWishlistImageUploading, setIsWishlistImageUploading] = useState(false);
|
||||
@@ -105,6 +106,8 @@ function AdminPageContent() {
|
||||
preferences: wishlist.preferences || '',
|
||||
imageUrl: wishlist.imageUrl || '',
|
||||
isPublic: wishlist.isPublic,
|
||||
siteTitle: settings.siteTitle,
|
||||
homepageSubtext: settings.homepageSubtext,
|
||||
});
|
||||
setEditError('');
|
||||
setIsEditingWishlist(true);
|
||||
@@ -115,11 +118,16 @@ function AdminPageContent() {
|
||||
if (!wishlist) return;
|
||||
setEditError('');
|
||||
try {
|
||||
const updated = await wishlistsApi.update(wishlist.id, editForm);
|
||||
const { siteTitle, homepageSubtext, ...wishlistFields } = editForm;
|
||||
const [updated] = await Promise.all([
|
||||
wishlistsApi.update(wishlist.id, wishlistFields),
|
||||
settingsApi.updateSettings({ siteTitle, homepageSubtext }),
|
||||
]);
|
||||
setWishlist(updated);
|
||||
setSettings({ siteTitle, homepageSubtext });
|
||||
setIsEditingWishlist(false);
|
||||
} catch (error: any) {
|
||||
setEditError(error.message || 'Failed to update wishlist');
|
||||
setEditError(error.message || 'Failed to update settings');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -181,10 +189,6 @@ function AdminPageContent() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdateSettings = async (updatedSettings: Settings) => {
|
||||
await settingsApi.updateSettings(updatedSettings);
|
||||
setSettings(updatedSettings);
|
||||
};
|
||||
|
||||
const editingItem = items.find((item) => item.id === editingItemId);
|
||||
|
||||
@@ -229,55 +233,72 @@ function AdminPageContent() {
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{/* Settings Section */}
|
||||
<SettingsSection settings={settings} onUpdate={handleUpdateSettings} />
|
||||
|
||||
{/* Wishlist Info Section */}
|
||||
{/* Unified Settings & Wishlist Config */}
|
||||
{wishlist && (
|
||||
<div className="mb-6 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
|
||||
<div className="p-5 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
||||
<h2 className="text-xl font-bold text-gray-900 dark:text-white">Configurações</h2>
|
||||
{!isEditingWishlist && (
|
||||
<button
|
||||
onClick={startEditingWishlist}
|
||||
className="px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 text-sm cursor-pointer"
|
||||
>
|
||||
Editar
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-5">
|
||||
{isEditingWishlist ? (
|
||||
<form onSubmit={handleUpdateWishlist} className="space-y-4">
|
||||
<h2 className="text-xl font-bold text-gray-900 dark:text-white mb-4">
|
||||
Editar Lista
|
||||
</h2>
|
||||
{editError && (
|
||||
<div className="p-3 bg-red-50 dark:bg-red-900/20 text-red-800 dark:text-red-400 rounded-lg text-base">
|
||||
{editError}
|
||||
</div>
|
||||
)}
|
||||
<ImageUpload
|
||||
currentImageUrl={editForm.imageUrl}
|
||||
onImageChange={(url) =>
|
||||
setEditForm((prev) => ({ ...prev, imageUrl: url }))
|
||||
}
|
||||
onUploadStateChange={setIsWishlistImageUploading}
|
||||
type="wishlist"
|
||||
label="Imagem da Lista"
|
||||
/>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Título do site *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
value={editForm.siteTitle}
|
||||
onChange={(e) => setEditForm((prev) => ({ ...prev, siteTitle: e.target.value }))}
|
||||
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:text-white"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Nome da lista *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
value={editForm.name}
|
||||
onChange={(e) => setEditForm((prev) => ({ ...prev, name: e.target.value }))}
|
||||
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:text-white"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Nome *
|
||||
Mensagem de boas-vindas
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
value={editForm.name}
|
||||
onChange={(e) =>
|
||||
setEditForm((prev) => ({ ...prev, name: e.target.value }))
|
||||
}
|
||||
<textarea
|
||||
value={editForm.homepageSubtext}
|
||||
onChange={(e) => setEditForm((prev) => ({ ...prev, homepageSubtext: e.target.value }))}
|
||||
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:text-white"
|
||||
rows={2}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Descrição
|
||||
Descrição da lista
|
||||
</label>
|
||||
<textarea
|
||||
value={editForm.description}
|
||||
onChange={(e) =>
|
||||
setEditForm((prev) => ({ ...prev, description: e.target.value }))
|
||||
}
|
||||
onChange={(e) => setEditForm((prev) => ({ ...prev, description: e.target.value }))}
|
||||
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:text-white"
|
||||
rows={2}
|
||||
/>
|
||||
@@ -288,12 +309,17 @@ function AdminPageContent() {
|
||||
</label>
|
||||
<RichTextEditor
|
||||
value={editForm.preferences}
|
||||
onChange={(html) =>
|
||||
setEditForm((prev) => ({ ...prev, preferences: html }))
|
||||
}
|
||||
onChange={(html) => setEditForm((prev) => ({ ...prev, preferences: html }))}
|
||||
placeholder="Interesses e preferências gerais..."
|
||||
/>
|
||||
</div>
|
||||
<ImageUpload
|
||||
currentImageUrl={editForm.imageUrl}
|
||||
onImageChange={(url) => setEditForm((prev) => ({ ...prev, imageUrl: url }))}
|
||||
onUploadStateChange={setIsWishlistImageUploading}
|
||||
type="wishlist"
|
||||
label="Imagem da Lista"
|
||||
/>
|
||||
<div className="flex gap-3 justify-end">
|
||||
<button
|
||||
type="button"
|
||||
@@ -312,33 +338,38 @@ function AdminPageContent() {
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
<div className="flex items-start gap-4">
|
||||
{wishlist.imageUrl && (
|
||||
<img
|
||||
src={wishlist.imageUrl}
|
||||
alt={wishlist.name}
|
||||
className="w-20 h-20 object-cover rounded border border-gray-200 dark:border-gray-600 flex-shrink-0"
|
||||
/>
|
||||
)}
|
||||
<div className="flex-1">
|
||||
<h2 className="text-xl font-bold text-gray-900 dark:text-white">
|
||||
{wishlist.name}
|
||||
</h2>
|
||||
{wishlist.description && (
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
||||
{wishlist.description}
|
||||
</p>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-start gap-4">
|
||||
{wishlist.imageUrl && (
|
||||
<img
|
||||
src={wishlist.imageUrl}
|
||||
alt={wishlist.name}
|
||||
className="w-16 h-16 object-cover rounded border border-gray-200 dark:border-gray-600 flex-shrink-0"
|
||||
/>
|
||||
)}
|
||||
<p className="text-sm text-gray-500 dark:text-gray-500 mt-1">
|
||||
/{wishlist.slug}
|
||||
</p>
|
||||
<div className="flex-1 grid grid-cols-1 md:grid-cols-2 gap-x-6 gap-y-2">
|
||||
<div>
|
||||
<p className="text-xs font-medium text-gray-500 dark:text-gray-400">Título do site</p>
|
||||
<p className="text-sm text-gray-900 dark:text-white">{settings.siteTitle}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs font-medium text-gray-500 dark:text-gray-400">Nome da lista</p>
|
||||
<p className="text-sm text-gray-900 dark:text-white">{wishlist.name}</p>
|
||||
</div>
|
||||
{settings.homepageSubtext && (
|
||||
<div className="md:col-span-2">
|
||||
<p className="text-xs font-medium text-gray-500 dark:text-gray-400">Mensagem de boas-vindas</p>
|
||||
<p className="text-sm text-gray-900 dark:text-white">{settings.homepageSubtext}</p>
|
||||
</div>
|
||||
)}
|
||||
{wishlist.description && (
|
||||
<div className="md:col-span-2">
|
||||
<p className="text-xs font-medium text-gray-500 dark:text-gray-400">Descrição</p>
|
||||
<p className="text-sm text-gray-900 dark:text-white">{wishlist.description}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={startEditingWishlist}
|
||||
className="flex-shrink-0 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 text-sm cursor-pointer"
|
||||
>
|
||||
Editar
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user