|
| 1 | +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; |
1 | 2 | import { trySafe, type Optional } from '@silverhand/essentials'; |
2 | 3 | import { useEffect, useMemo, useState } from 'react'; |
3 | 4 |
|
4 | 5 | import { defaultApiBaseProdUrl, defaultApiBaseDevUrl } from './constants'; |
5 | | -import { createDebugLogger, type DebugLogger } from './debug-logger'; |
6 | 6 | import { type GoogleOneTapConfig, googleOneTapConfigSchema } from './google-one-tap'; |
7 | | -import type { SiteConfig } from './types'; |
| 7 | +import { type SiteConfig, siteConfigSchema } from './types'; |
8 | 8 |
|
9 | | -export function useDebugLogger(siteConfig: SiteConfig): DebugLogger { |
10 | | - const isDebugMode = Boolean(siteConfig.customFields?.isDebuggingEnabled); |
| 9 | +type DebugLogger = { |
| 10 | + log: (...args: unknown[]) => void; |
| 11 | + warn: (...args: unknown[]) => void; |
| 12 | + error: (...args: unknown[]) => void; |
| 13 | +}; |
11 | 14 |
|
12 | | - return useMemo(() => createDebugLogger(isDebugMode), [isDebugMode]); |
| 15 | +const createDebugLogger = (isDebugMode: boolean): DebugLogger => { |
| 16 | + return { |
| 17 | + log: (...args: unknown[]) => { |
| 18 | + if (isDebugMode) { |
| 19 | + console.log(...args); |
| 20 | + } |
| 21 | + }, |
| 22 | + warn: (...args: unknown[]) => { |
| 23 | + if (isDebugMode) { |
| 24 | + console.warn(...args); |
| 25 | + } |
| 26 | + }, |
| 27 | + error: (...args: unknown[]) => { |
| 28 | + if (isDebugMode) { |
| 29 | + console.error(...args); |
| 30 | + } |
| 31 | + }, |
| 32 | + }; |
| 33 | +}; |
| 34 | + |
| 35 | +const useSiteConfig = (): { siteConfig: SiteConfig } => { |
| 36 | + const { siteConfig } = useDocusaurusContext(); |
| 37 | + const parsedConfig = siteConfigSchema.safeParse(siteConfig); |
| 38 | + if (!parsedConfig.success) { |
| 39 | + throw new Error('Invalid site config'); |
| 40 | + } |
| 41 | + return { siteConfig: parsedConfig.data }; |
| 42 | +}; |
| 43 | + |
| 44 | +export function useDebugLogger(): { debugLogger: DebugLogger } { |
| 45 | + const { |
| 46 | + siteConfig: { customFields }, |
| 47 | + } = useSiteConfig(); |
| 48 | + const isDebugMode = Boolean(customFields?.isDebuggingEnabled); |
| 49 | + |
| 50 | + return { debugLogger: useMemo(() => createDebugLogger(isDebugMode), [isDebugMode]) }; |
13 | 51 | } |
14 | 52 |
|
15 | | -export function useApiBaseUrl(siteConfig: SiteConfig): { |
| 53 | +export function useApiBaseUrl(): { |
16 | 54 | baseUrl: string; |
17 | 55 | logtoAdminConsoleUrl?: string; |
18 | 56 | } { |
19 | | - return useMemo(() => { |
20 | | - const logtoApiBaseUrl = siteConfig.customFields?.logtoApiBaseUrl; |
| 57 | + const { |
| 58 | + siteConfig: { customFields }, |
| 59 | + } = useSiteConfig(); |
| 60 | + const { logtoApiBaseUrl, isDevFeatureEnabled, logtoAdminConsoleUrl } = customFields ?? {}; |
21 | 61 |
|
| 62 | + return useMemo(() => { |
22 | 63 | const baseUrl = |
23 | 64 | typeof logtoApiBaseUrl === 'string' |
24 | 65 | ? logtoApiBaseUrl |
25 | | - : siteConfig.customFields?.isDevFeatureEnabled |
| 66 | + : isDevFeatureEnabled |
26 | 67 | ? defaultApiBaseDevUrl |
27 | 68 | : defaultApiBaseProdUrl; |
28 | 69 |
|
29 | | - const logtoAdminConsoleUrl = siteConfig.customFields?.logtoAdminConsoleUrl; |
30 | | - |
31 | 70 | return { |
32 | 71 | baseUrl, |
33 | 72 | logtoAdminConsoleUrl, |
34 | 73 | }; |
35 | | - }, [ |
36 | | - siteConfig.customFields?.logtoApiBaseUrl, |
37 | | - siteConfig.customFields?.isDevFeatureEnabled, |
38 | | - siteConfig.customFields?.logtoAdminConsoleUrl, |
39 | | - ]); |
| 74 | + }, [logtoApiBaseUrl, isDevFeatureEnabled, logtoAdminConsoleUrl]); |
40 | 75 | } |
41 | 76 |
|
42 | | -export function useGoogleOneTapConfig( |
43 | | - siteConfig: SiteConfig, |
44 | | - debugLogger: DebugLogger |
45 | | -): { config: Optional<GoogleOneTapConfig> } { |
| 77 | +export function useGoogleOneTapConfig(): { |
| 78 | + config: Optional<GoogleOneTapConfig>; |
| 79 | +} { |
46 | 80 | const [config, setConfig] = useState<GoogleOneTapConfig>(); |
| 81 | + const { debugLogger } = useDebugLogger(); |
| 82 | + const { |
| 83 | + siteConfig: { customFields }, |
| 84 | + } = useSiteConfig(); |
47 | 85 |
|
48 | 86 | useEffect(() => { |
49 | 87 | const loadConfig = async () => { |
50 | | - try { |
51 | | - const rawConfig = siteConfig.customFields?.googleOneTapConfig; |
52 | | - if (typeof rawConfig !== 'string') { |
53 | | - throw new TypeError('Google One Tap config is not a string'); |
54 | | - } |
55 | | - const parsedConfig = googleOneTapConfigSchema.safeParse( |
56 | | - // eslint-disable-next-line no-restricted-syntax |
57 | | - trySafe(() => JSON.parse(rawConfig) as unknown) |
58 | | - ); |
| 88 | + const rawConfig = customFields?.googleOneTapConfig; |
| 89 | + if (typeof rawConfig !== 'string') { |
| 90 | + throw new TypeError('Google One Tap config is not a string'); |
| 91 | + } |
| 92 | + const parsedConfig = googleOneTapConfigSchema.safeParse( |
| 93 | + // eslint-disable-next-line no-restricted-syntax |
| 94 | + trySafe(() => JSON.parse(rawConfig) as unknown) |
| 95 | + ); |
59 | 96 |
|
60 | | - if (parsedConfig.success) { |
61 | | - setConfig(parsedConfig.data); |
62 | | - } else { |
63 | | - debugLogger.error('Failed to parse Google One Tap config:', parsedConfig.error); |
64 | | - setConfig(undefined); |
65 | | - } |
66 | | - } catch (error) { |
67 | | - debugLogger.error('Failed to load Google One Tap config:', error); |
68 | | - // Don't throw, just set config to undefined to prevent render blocking |
| 97 | + if (parsedConfig.success) { |
| 98 | + setConfig(parsedConfig.data); |
| 99 | + } else { |
| 100 | + debugLogger.error('Failed to parse Google One Tap config:', parsedConfig.error); |
69 | 101 | setConfig(undefined); |
70 | 102 | } |
71 | 103 | }; |
72 | 104 |
|
73 | 105 | void loadConfig(); |
74 | | - }, [siteConfig.customFields?.googleOneTapConfig, debugLogger]); |
| 106 | + }, [customFields?.googleOneTapConfig, debugLogger]); |
75 | 107 |
|
76 | 108 | return { config }; |
77 | 109 | } |
0 commit comments