Skip to content

Commit d6e6467

Browse files
fix(payments): categorize binance_enabled under Payment settings, not general (#479) (#490)
getAllSettingsByCategory()'s categoryMap had no entry for binance_enabled, so it fell through to 'general' instead of 'payment'. The admin Settings > Payment page reads settings.payment.binance_enabled to set the Binance Pay switch's initial state, so the toggle always rendered unchecked on reload regardless of the saved value — an admin who enabled it would see it off on next visit, and re-saving from that state would silently disable it in the DB. getEnabledPaymentProviders() (used by checkout/product forms) queries the key directly and was unaffected. Claude-Session: https://claude.ai/code/session_01UYWqTKnHDLQC1hbithnsb3 Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 0bcdec3 commit d6e6467

2 files changed

Lines changed: 64 additions & 2 deletions

File tree

app/actions/admin/settings.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export async function getSettings(category?: string): Promise<SettingsResponse>
3535
const categoryPrefixes: Record<string, string[]> = {
3636
general: ['site_name', 'site_description', 'contact_email', 'support_email', 'timezone', 'maintenance_mode'],
3737
email: ['smtp_', 'email_'],
38-
payment: ['stripe_', 'paypal_', 'lemonsqueezy_', 'solana_', 'currency', 'tax_rate', 'invoice_prefix', 'require_payment_approval', 'manual_payment_instructions'],
38+
payment: ['stripe_', 'paypal_', 'lemonsqueezy_', 'solana_', 'binance_', 'currency', 'tax_rate', 'invoice_prefix', 'require_payment_approval', 'manual_payment_instructions'],
3939
enrollment: ['auto_enrollment', 'require_enrollment_approval', 'max_enrollments_per_user', 'allow_self_enrollment', 'enrollment_expiration_days', 'course_capacity_enabled'],
4040
}
4141
const keys = categoryPrefixes[category]
@@ -440,7 +440,7 @@ export async function getAllSettingsByCategory(): Promise<SettingsResponse> {
440440
smtp_host: 'email', smtp_port: 'email', smtp_username: 'email', smtp_password: 'email',
441441
smtp_from_email: 'email', smtp_from_name: 'email', email_notifications: 'email',
442442
stripe_enabled: 'payment', paypal_enabled: 'payment',
443-
lemonsqueezy_enabled: 'payment', solana_enabled: 'payment', solana_accept_sol: 'payment', currency: 'payment',
443+
lemonsqueezy_enabled: 'payment', solana_enabled: 'payment', solana_accept_sol: 'payment', binance_enabled: 'payment', currency: 'payment',
444444
tax_rate: 'payment', invoice_prefix: 'payment', require_payment_approval: 'payment',
445445
manual_payment_instructions: 'payment',
446446
auto_enrollment: 'enrollment', require_enrollment_approval: 'enrollment',
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { describe, it, expect, beforeEach, vi } from 'vitest'
2+
3+
/**
4+
* Regression for issue #479: getAllSettingsByCategory()'s categoryMap
5+
* previously had no entry for `binance_enabled`, so it fell through to the
6+
* `'general'` bucket instead of `'payment'`. The admin Settings > Payment
7+
* page reads `settings.payment.binance_enabled` — a missing map entry made
8+
* the Binance Pay toggle always render unchecked on reload regardless of the
9+
* saved value, even though getEnabledPaymentProviders() (which queries the
10+
* key directly) still gated checkout/product forms correctly.
11+
*/
12+
13+
const state: {
14+
role: string
15+
rows: { setting_key: string; setting_value: unknown }[]
16+
} = { role: 'admin', rows: [] }
17+
18+
function makeFakeAdmin() {
19+
const b: Record<string, unknown> = {
20+
from() { return b },
21+
select() { return b },
22+
eq() { return b },
23+
order() { return Promise.resolve({ data: state.rows, error: null }) },
24+
}
25+
return b
26+
}
27+
28+
vi.mock('next/cache', () => ({ revalidatePath: vi.fn() }))
29+
vi.mock('@/lib/supabase/tenant', () => ({ getCurrentTenantId: () => Promise.resolve('t1') }))
30+
vi.mock('@/lib/supabase/get-user-role', () => ({ getUserRole: () => Promise.resolve(state.role) }))
31+
vi.mock('@/lib/supabase/admin', () => ({
32+
createAdminClient: () => makeFakeAdmin(),
33+
}))
34+
35+
import { getAllSettingsByCategory } from '@/app/actions/admin/settings'
36+
37+
beforeEach(() => { state.role = 'admin'; state.rows = [] })
38+
39+
describe('getAllSettingsByCategory', () => {
40+
it('groups binance_enabled under payment, not general', async () => {
41+
state.rows = [{ setting_key: 'binance_enabled', setting_value: { enabled: true } }]
42+
const r = await getAllSettingsByCategory()
43+
expect(r.success).toBe(true)
44+
expect(r.data?.payment?.binance_enabled?.value?.enabled).toBe(true)
45+
expect(r.data?.general?.binance_enabled).toBeUndefined()
46+
})
47+
48+
it('keeps every other payment toggle categorized alongside it', async () => {
49+
state.rows = [
50+
{ setting_key: 'stripe_enabled', setting_value: { enabled: true } },
51+
{ setting_key: 'paypal_enabled', setting_value: { enabled: false } },
52+
{ setting_key: 'lemonsqueezy_enabled', setting_value: { enabled: false } },
53+
{ setting_key: 'solana_enabled', setting_value: { enabled: false } },
54+
{ setting_key: 'binance_enabled', setting_value: { enabled: true } },
55+
]
56+
const r = await getAllSettingsByCategory()
57+
const paymentKeys = Object.keys(r.data?.payment ?? {})
58+
expect(paymentKeys.sort()).toEqual(
59+
['binance_enabled', 'lemonsqueezy_enabled', 'paypal_enabled', 'solana_enabled', 'stripe_enabled'].sort()
60+
)
61+
})
62+
})

0 commit comments

Comments
 (0)