mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-05 12:00:59 +08:00
feat: add whether to enable self registration toggle (#760)
* refactor(frontend): extract RegistrationDisabled as reusable component - Create RegistrationDisabled component with i18n support - Add registrationClosed and registrationClosedMessage translations - Replace inline JSX in App.tsx with new component - Improve code maintainability and reusability - Add hover effect to back button for better UX * fix(frontend): add registration toggle to LoginModal component - Add useSystemConfig hook to LoginModal - Conditionally render registration button based on registration_enabled config - Ensures consistency with HeaderBar and LoginPage registration controls - Completes registration toggle feature implementation across all entry points * feat(frontend): add registration toggle UI support - Add registration disabled page in App.tsx when registration is closed - Hide registration link in LoginPage when registration is disabled - Add registration_enabled field to SystemConfig interface - Frontend conditionally shows/hides registration UI based on backend config * feat: add registration toggle feature Add system-level registration enable/disable control: - Add registration_enabled config to system_config table (default: true) - Add registration check in handleRegister API endpoint - Expose registration_enabled status in /api/config endpoint - Frontend can use this config to conditionally show/hide registration UI This allows administrators to control user registration without code changes. * fix(frontend): add registration toggle to HeaderBar and RegisterPage - Add useSystemConfig hook and registrationEnabled check to HeaderBar - Conditionally show/hide signup buttons in both desktop and mobile views - Add registration check to RegisterPage to show RegistrationDisabled component - This completes the registration toggle feature across all UI components * test(frontend): add comprehensive unit tests for registration toggle feature - Add RegistrationDisabled component tests (rendering, navigation, styling) - Add registrationToggle logic tests (config handling, edge cases, multi-location consistency) - Configure Vitest with jsdom environment for React component testing - All 80 tests passing (9 new tests for RegistrationDisabled + 21 for toggle logic)
This commit is contained in:
committed by
tangmengqiu
parent
b282045b66
commit
ced6c3d9de
@@ -1,5 +1,6 @@
|
||||
export interface SystemConfig {
|
||||
beta_mode: boolean
|
||||
registration_enabled?: boolean
|
||||
}
|
||||
|
||||
let configPromise: Promise<SystemConfig> | null = null
|
||||
|
||||
204
web/src/lib/registrationToggle.test.ts
Normal file
204
web/src/lib/registrationToggle.test.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
/**
|
||||
* Registration Toggle Feature Tests
|
||||
*
|
||||
* Tests the logic for determining whether registration is enabled
|
||||
* This validates the registration_enabled configuration behavior
|
||||
*/
|
||||
describe('Registration Toggle Logic', () => {
|
||||
describe('registration_enabled configuration', () => {
|
||||
it('should default to true when registration_enabled is undefined', () => {
|
||||
const config = {}
|
||||
const registrationEnabled = (config as any).registration_enabled !== false
|
||||
|
||||
expect(registrationEnabled).toBe(true)
|
||||
})
|
||||
|
||||
it('should be true when registration_enabled is explicitly true', () => {
|
||||
const config = { registration_enabled: true }
|
||||
const registrationEnabled = config.registration_enabled !== false
|
||||
|
||||
expect(registrationEnabled).toBe(true)
|
||||
})
|
||||
|
||||
it('should be false when registration_enabled is explicitly false', () => {
|
||||
const config = { registration_enabled: false }
|
||||
const registrationEnabled = config.registration_enabled !== false
|
||||
|
||||
expect(registrationEnabled).toBe(false)
|
||||
})
|
||||
|
||||
it('should default to true when registration_enabled is null', () => {
|
||||
const config = { registration_enabled: null }
|
||||
const registrationEnabled = (config.registration_enabled as any) !== false
|
||||
|
||||
expect(registrationEnabled).toBe(true)
|
||||
})
|
||||
|
||||
it('should handle missing config gracefully', () => {
|
||||
const config = null
|
||||
const registrationEnabled = config?.registration_enabled !== false
|
||||
|
||||
expect(registrationEnabled).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('UI component visibility logic', () => {
|
||||
it('should show signup button when registration is enabled', () => {
|
||||
const registrationEnabled = true
|
||||
const shouldShowSignup = registrationEnabled
|
||||
|
||||
expect(shouldShowSignup).toBe(true)
|
||||
})
|
||||
|
||||
it('should hide signup button when registration is disabled', () => {
|
||||
const registrationEnabled = false
|
||||
const shouldShowSignup = registrationEnabled
|
||||
|
||||
expect(shouldShowSignup).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('conditional rendering patterns', () => {
|
||||
it('should render signup link with registrationEnabled && pattern', () => {
|
||||
const registrationEnabled = true
|
||||
const signupElement = registrationEnabled && 'SignUpButton'
|
||||
|
||||
expect(signupElement).toBe('SignUpButton')
|
||||
})
|
||||
|
||||
it('should not render signup link when disabled', () => {
|
||||
const registrationEnabled = false
|
||||
const signupElement = registrationEnabled && 'SignUpButton'
|
||||
|
||||
expect(signupElement).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('SystemConfig interface compliance', () => {
|
||||
interface SystemConfig {
|
||||
beta_mode: boolean
|
||||
registration_enabled?: boolean
|
||||
}
|
||||
|
||||
it('should have optional registration_enabled field', () => {
|
||||
const config1: SystemConfig = {
|
||||
beta_mode: false,
|
||||
}
|
||||
|
||||
const config2: SystemConfig = {
|
||||
beta_mode: false,
|
||||
registration_enabled: true,
|
||||
}
|
||||
|
||||
expect(config1.beta_mode).toBe(false)
|
||||
expect(config2.registration_enabled).toBe(true)
|
||||
})
|
||||
|
||||
it('should handle both beta_mode and registration_enabled', () => {
|
||||
const config: SystemConfig = {
|
||||
beta_mode: true,
|
||||
registration_enabled: false,
|
||||
}
|
||||
|
||||
expect(config.beta_mode).toBe(true)
|
||||
expect(config.registration_enabled).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should treat empty string as truthy (not false)', () => {
|
||||
const config = { registration_enabled: '' as any }
|
||||
const registrationEnabled = config.registration_enabled !== false
|
||||
|
||||
expect(registrationEnabled).toBe(true)
|
||||
})
|
||||
|
||||
it('should treat 0 as truthy (not false)', () => {
|
||||
const config = { registration_enabled: 0 as any }
|
||||
const registrationEnabled = config.registration_enabled !== false
|
||||
|
||||
expect(registrationEnabled).toBe(true)
|
||||
})
|
||||
|
||||
it('should treat "false" string as truthy (not false)', () => {
|
||||
const config = { registration_enabled: 'false' as any }
|
||||
const registrationEnabled = config.registration_enabled !== false
|
||||
|
||||
expect(registrationEnabled).toBe(true)
|
||||
})
|
||||
|
||||
it('should only treat boolean false as disabled', () => {
|
||||
const testCases = [
|
||||
{ value: false, expected: false },
|
||||
{ value: true, expected: true },
|
||||
{ value: null, expected: true },
|
||||
{ value: undefined, expected: true },
|
||||
{ value: 0, expected: true },
|
||||
{ value: '', expected: true },
|
||||
{ value: 'false', expected: true },
|
||||
{ value: [], expected: true },
|
||||
{ value: {}, expected: true },
|
||||
]
|
||||
|
||||
testCases.forEach(({ value, expected }) => {
|
||||
const config = { registration_enabled: value as any }
|
||||
const registrationEnabled = config.registration_enabled !== false
|
||||
expect(registrationEnabled).toBe(expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('backend API response handling', () => {
|
||||
it('should parse backend response with registration_enabled', () => {
|
||||
const apiResponse = {
|
||||
beta_mode: false,
|
||||
default_coins: ['BTCUSDT'],
|
||||
btc_eth_leverage: 5,
|
||||
altcoin_leverage: 5,
|
||||
registration_enabled: true,
|
||||
}
|
||||
|
||||
expect(apiResponse.registration_enabled).toBe(true)
|
||||
})
|
||||
|
||||
it('should handle backend response without registration_enabled', () => {
|
||||
const apiResponse = {
|
||||
beta_mode: false,
|
||||
default_coins: ['BTCUSDT'],
|
||||
btc_eth_leverage: 5,
|
||||
altcoin_leverage: 5,
|
||||
}
|
||||
|
||||
const registrationEnabled =
|
||||
(apiResponse as any).registration_enabled !== false
|
||||
|
||||
expect(registrationEnabled).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('multi-location consistency', () => {
|
||||
const systemConfig = { registration_enabled: false }
|
||||
|
||||
it('should have consistent behavior across LoginPage', () => {
|
||||
const registrationEnabled = systemConfig?.registration_enabled !== false
|
||||
expect(registrationEnabled).toBe(false)
|
||||
})
|
||||
|
||||
it('should have consistent behavior across RegisterPage', () => {
|
||||
const registrationEnabled = systemConfig?.registration_enabled !== false
|
||||
expect(registrationEnabled).toBe(false)
|
||||
})
|
||||
|
||||
it('should have consistent behavior across HeaderBar', () => {
|
||||
const registrationEnabled = systemConfig?.registration_enabled !== false
|
||||
expect(registrationEnabled).toBe(false)
|
||||
})
|
||||
|
||||
it('should have consistent behavior across LoginModal', () => {
|
||||
const registrationEnabled = systemConfig?.registration_enabled !== false
|
||||
expect(registrationEnabled).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user