Skip to content

Commit 7f94de8

Browse files
committed
fix: Admin UI clickable labels and granular settings save logic
1 parent 5447524 commit 7f94de8

File tree

2 files changed

+74
-37
lines changed

2 files changed

+74
-37
lines changed

app/admin/settings/page.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ export default async function AdminSettings() {
6969
Maintenance Mode Kill Switch
7070
</p>
7171
</div>
72-
<div className="relative inline-flex items-center cursor-pointer">
72+
<label className="relative inline-flex items-center cursor-pointer">
7373
<input
7474
type="checkbox"
7575
name="storeEnabled"
7676
defaultChecked={isEnabled}
7777
className="sr-only peer"
7878
/>
7979
<div className="w-14 h-7 bg-[#121214] peer-focus:outline-none rounded-full border border-white/10 peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[4px] after:bg-white after:border-charcoal/30 after:border after:rounded-full after:h-6 after:w-6 after:transition-all peer-checked:bg-emerald-500 shadow-inner group transition-all"></div>
80-
</div>
80+
</label>
8181
</div>
8282
</SettingsForm>
8383
</section>
@@ -96,21 +96,21 @@ export default async function AdminSettings() {
9696
<p className="text-[11px] uppercase tracking-luxury font-bold text-white">Show Bestsellers in Hero</p>
9797
<p className="text-[9px] text-luxury-subtext leading-relaxed">Replace the top sale slider with bestsellers.</p>
9898
</div>
99-
<div className="relative inline-flex items-center cursor-pointer">
99+
<label className="relative inline-flex items-center cursor-pointer">
100100
<input type="checkbox" name="show_bestsellers_hero" defaultChecked={homeConfig.show_bestsellers_hero === true} className="sr-only peer" />
101101
<div className="w-11 h-6 bg-[#121214] peer-focus:outline-none rounded-full border border-white/10 peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-charcoal/30 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-gold shadow-inner group transition-all"></div>
102-
</div>
102+
</label>
103103
</div>
104104

105105
<div className="flex items-center justify-between border-t border-white/5 pt-6">
106106
<div className="space-y-1">
107107
<p className="text-[11px] uppercase tracking-luxury font-bold text-white">Obsidian Bestsellers</p>
108108
<p className="text-[9px] text-luxury-subtext leading-relaxed">Show the horizontal scrolling carousel of best-selling items.</p>
109109
</div>
110-
<div className="relative inline-flex items-center cursor-pointer">
110+
<label className="relative inline-flex items-center cursor-pointer">
111111
<input type="checkbox" name="show_bestsellers" defaultChecked={homeConfig.show_bestsellers !== false} className="sr-only peer" />
112112
<div className="w-11 h-6 bg-[#121214] peer-focus:outline-none rounded-full border border-white/10 peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-charcoal/30 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-gold shadow-inner group transition-all"></div>
113-
</div>
113+
</label>
114114
</div>
115115

116116
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">

lib/actions/admin.ts

Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -494,19 +494,39 @@ export async function updateOrderStatus(orderId: string, status: string) {
494494
export async function updateStoreSettings(formData: FormData) {
495495
const supabase = await ensureAdmin();
496496

497-
const name = formData.get('name') as string;
498-
const tagline = formData.get('tagline') as string;
499-
const currency = formData.get('currency') as string;
500-
const logo_url = formData.get('logo_url') as string;
501-
const storeEnabled = formData.get('storeEnabled') === 'on' || formData.get('storeEnabled') === 'true';
502-
503-
const warehouseJson = formData.get('warehouse_info') as string;
504-
505-
const { error: infoError } = await supabase
506-
.from('site_settings')
507-
.upsert({ setting_key: 'store_info', setting_value: { name, tagline, currency, logo_url } }, { onConflict: 'setting_key' });
508-
509-
if (infoError) throw infoError;
497+
const name = formData.get('name') as string | null;
498+
const tagline = formData.get('tagline') as string | null;
499+
const currency = formData.get('currency') as string | null;
500+
const logo_url = formData.get('logo_url') as string | null;
501+
502+
// Check if storeEnabled was even in the form before using its value
503+
const hasStoreEnabled = formData.has('storeEnabled');
504+
const storeEnabledRaw = formData.get('storeEnabled');
505+
const storeEnabled = storeEnabledRaw === 'on' || storeEnabledRaw === 'true';
506+
507+
const warehouseJson = formData.get('warehouse_info') as string | null;
508+
509+
// Handle store_info (merge if only some fields are present)
510+
if (name !== null || tagline !== null || currency !== null || logo_url !== null) {
511+
const { data: existingInfo } = await supabase
512+
.from('site_settings')
513+
.select('setting_value')
514+
.eq('setting_key', 'store_info')
515+
.maybeSingle();
516+
517+
const newInfo = {
518+
...(existingInfo?.setting_value || {}),
519+
...(name !== null ? { name } : {}),
520+
...(tagline !== null ? { tagline } : {}),
521+
...(currency !== null ? { currency } : {}),
522+
...(logo_url !== null ? { logo_url } : {}),
523+
};
524+
525+
const { error } = await supabase
526+
.from('site_settings')
527+
.upsert({ setting_key: 'store_info', setting_value: newInfo }, { onConflict: 'setting_key' });
528+
if (error) throw error;
529+
}
510530

511531
if (warehouseJson) {
512532
const { error: whError } = await supabase
@@ -515,14 +535,14 @@ export async function updateStoreSettings(formData: FormData) {
515535
if (whError) throw whError;
516536
}
517537

518-
const { error: enabledError } = await supabase
519-
.from('site_settings')
520-
.upsert({ setting_key: 'store_enabled', setting_value: storeEnabled }, { onConflict: 'setting_key' });
521-
522-
if (enabledError) throw enabledError;
538+
if (hasStoreEnabled) {
539+
const { error: enabledError } = await supabase
540+
.from('site_settings')
541+
.upsert({ setting_key: 'store_enabled', setting_value: storeEnabled }, { onConflict: 'setting_key' });
542+
if (enabledError) throw enabledError;
543+
}
523544

524545
revalidatePath('/admin/settings');
525-
revalidatePath('/collections');
526546
revalidatePath('/', 'layout');
527547
return { success: true };
528548
}
@@ -649,23 +669,40 @@ export async function updateShippingSettings(formData: FormData) {
649669
export async function updateHomeSections(formData: FormData) {
650670
const supabase = await ensureAdmin();
651671

652-
const show_bestsellers = formData.get('show_bestsellers') === 'on';
653-
const bestseller_heading = (formData.get('bestseller_heading') as string)?.trim() || 'Obsidian Bestsellers';
654-
const bestseller_subheading = (formData.get('bestseller_subheading') as string)?.trim() || 'Most-loved by our community';
655-
const show_featured = formData.get('show_featured') !== 'off';
656-
const show_collections = formData.get('show_collections') !== 'off';
672+
// Fetch existing to avoid wiping out fields not present in this form/v4 schema
673+
const { data: existing } = await supabase
674+
.from('site_settings')
675+
.select('setting_value')
676+
.eq('setting_key', 'home_sections')
677+
.maybeSingle();
678+
679+
const newValue = { ...(existing?.setting_value || {}) };
680+
681+
// Only update keys that are actually in the form data
682+
if (formData.has('show_bestsellers')) {
683+
newValue.show_bestsellers = formData.get('show_bestsellers') === 'on' || formData.get('show_bestsellers') === 'true';
684+
}
685+
if (formData.has('show_bestsellers_hero')) {
686+
newValue.show_bestsellers_hero = formData.get('show_bestsellers_hero') === 'on' || formData.get('show_bestsellers_hero') === 'true';
687+
}
688+
if (formData.has('bestseller_heading')) {
689+
newValue.bestseller_heading = (formData.get('bestseller_heading') as string)?.trim();
690+
}
691+
if (formData.has('bestseller_subheading')) {
692+
newValue.bestseller_subheading = (formData.get('bestseller_subheading') as string)?.trim();
693+
}
694+
if (formData.has('show_featured')) {
695+
newValue.show_featured = formData.get('show_featured') === 'on' || formData.get('show_featured') === 'true';
696+
}
697+
if (formData.has('show_collections')) {
698+
newValue.show_collections = formData.get('show_collections') === 'on' || formData.get('show_collections') === 'true';
699+
}
657700

658701
const { error } = await supabase
659702
.from('site_settings')
660703
.upsert({
661704
setting_key: 'home_sections',
662-
setting_value: {
663-
show_bestsellers,
664-
bestseller_heading,
665-
bestseller_subheading,
666-
show_featured,
667-
show_collections,
668-
},
705+
setting_value: newValue,
669706
}, { onConflict: 'setting_key' });
670707

671708
if (error) throw error;

0 commit comments

Comments
 (0)