|
|
@@ -3,27 +3,147 @@
|
|
|
import { createContext, useContext } from 'react';
|
|
|
import Config from '@/types/config';
|
|
|
|
|
|
+// SSR fetchConfig 실패(API/SSR 일시 장애, DB Config 0행) 시 사용하는 안전 기본값.
|
|
|
+// 모든 하위 폼 객체를 널/기본 리프로 채워, 소비 컴포넌트의 config.account.X · config.company.X ·
|
|
|
+// config.attendance.X 같은 직접 접근이 크래시 없이 널을 반환하도록 보장한다.
|
|
|
+const DEFAULT_CONFIG: Config = {
|
|
|
+ id: 0,
|
|
|
+ basic: {
|
|
|
+ siteName: null,
|
|
|
+ siteURL: null,
|
|
|
+ rootID: null,
|
|
|
+ fromEmail: null,
|
|
|
+ fromName: null,
|
|
|
+ smtpServer: null,
|
|
|
+ smtpPort: null,
|
|
|
+ smtpEnableSSL: false,
|
|
|
+ smtpUsername: null,
|
|
|
+ smtpPassword: null,
|
|
|
+ adminWhiteIPList: null,
|
|
|
+ frontWhiteIPList: null,
|
|
|
+ blockAlertTitle: null,
|
|
|
+ blockAlertContent: null,
|
|
|
+ isMaintenance: false,
|
|
|
+ maintenanceContent: null
|
|
|
+ },
|
|
|
+ images: {
|
|
|
+ faviconPath: null,
|
|
|
+ logoSquarePath: null,
|
|
|
+ logoHorizontalPath: null,
|
|
|
+ ogDefaultPath: null,
|
|
|
+ twitterImagePath: null,
|
|
|
+ appleTouchIconPath: null,
|
|
|
+ appIcon192Path: null,
|
|
|
+ appIcon512Path: null
|
|
|
+ },
|
|
|
+ meta: {
|
|
|
+ keywords: null,
|
|
|
+ description: null,
|
|
|
+ author: null,
|
|
|
+ viewport: null,
|
|
|
+ applicationName: null,
|
|
|
+ generator: null,
|
|
|
+ robots: null,
|
|
|
+ adds: null
|
|
|
+ },
|
|
|
+ company: {
|
|
|
+ name: null,
|
|
|
+ regNo: null,
|
|
|
+ address: null,
|
|
|
+ zipCode: null,
|
|
|
+ owner: null,
|
|
|
+ tel: null,
|
|
|
+ fax: null,
|
|
|
+ retailSaleNo: null,
|
|
|
+ addedSaleNo: null,
|
|
|
+ hosting: null,
|
|
|
+ adminName: null,
|
|
|
+ adminEmail: null,
|
|
|
+ siteUrl: null,
|
|
|
+ bankCode: null,
|
|
|
+ bankOwner: null,
|
|
|
+ bankNumber: null
|
|
|
+ },
|
|
|
+ account: {
|
|
|
+ isRegisterBlock: false,
|
|
|
+ isRegisterEmailAuth: false,
|
|
|
+ passwordMinLength: null,
|
|
|
+ passwordUppercaseLength: null,
|
|
|
+ passwordNumbersLength: null,
|
|
|
+ passwordSpecialcharsLength: null,
|
|
|
+ deniedEmailList: null,
|
|
|
+ deniedNameList: null,
|
|
|
+ changeEmailDay: null,
|
|
|
+ changeNameDay: null,
|
|
|
+ changeSummaryDay: null,
|
|
|
+ changeIntroDay: null,
|
|
|
+ changeThumbDay: null,
|
|
|
+ changePasswordDay: null,
|
|
|
+ isLoginEmailVerifiedOnly: false,
|
|
|
+ maxLoginTryCount: null,
|
|
|
+ maxLoginTryLimitSecond: null
|
|
|
+ },
|
|
|
+ emailTemplate: {
|
|
|
+ registerEmailFormTitle: null,
|
|
|
+ registerEmailFormContent: null,
|
|
|
+ registrationEmailFormTitle: null,
|
|
|
+ registrationEmailFormContent: null,
|
|
|
+ resetPasswordEmailFormTitle: null,
|
|
|
+ resetPasswordEmailFormContent: null,
|
|
|
+ changedPasswordEmailFormTitle: null,
|
|
|
+ changedPasswordEmailFormContent: null,
|
|
|
+ withdrawEmailFormTitle: null,
|
|
|
+ withdrawEmailFormContent: null,
|
|
|
+ emailVerifyFormTitle: null,
|
|
|
+ emailVerifyFormContent: null,
|
|
|
+ changedEmailFormTitle: null,
|
|
|
+ changedEmailFormContent: null
|
|
|
+ },
|
|
|
+ external: {
|
|
|
+ youTubeApiKeyEnc: null,
|
|
|
+ youTubeApiName: null,
|
|
|
+ googleClientId: null,
|
|
|
+ googleClientSecretEnc: null,
|
|
|
+ googleAppId: null
|
|
|
+ },
|
|
|
+ toss: {
|
|
|
+ tossPayMode: null,
|
|
|
+ hasTestClientKey: false,
|
|
|
+ hasTestSecretKey: false,
|
|
|
+ hasLiveClientKey: false,
|
|
|
+ hasLiveSecretKey: false
|
|
|
+ },
|
|
|
+ attendance: {
|
|
|
+ isEnabled: false,
|
|
|
+ baseExp: 0,
|
|
|
+ basePoint: 0,
|
|
|
+ useStreakBonus: false,
|
|
|
+ streakBonusPerDay: 0,
|
|
|
+ streakBonusPointPerDay: 0,
|
|
|
+ streakBonusMaxDays: 0,
|
|
|
+ useRankBonus: false,
|
|
|
+ rankBonusConfig: null
|
|
|
+ },
|
|
|
+ navMenu: []
|
|
|
+};
|
|
|
+
|
|
|
const ConfigContext = createContext<Config|null>(null);
|
|
|
|
|
|
-// Context Provider
|
|
|
+// Context Provider — initialConfig 가 null(SSR 장애)이어도 DEFAULT_CONFIG 로 대체해
|
|
|
+// 하위 트리가 절대 null config 를 만나지 않도록 한다.
|
|
|
export function ConfigProvider({ children, initialConfig }: {
|
|
|
children: React.ReactNode,
|
|
|
initialConfig: Config|null
|
|
|
}) {
|
|
|
return (
|
|
|
- <ConfigContext.Provider value={initialConfig}>
|
|
|
+ <ConfigContext.Provider value={initialConfig ?? DEFAULT_CONFIG}>
|
|
|
{children}
|
|
|
</ConfigContext.Provider>
|
|
|
);
|
|
|
}
|
|
|
|
|
|
-// Context 사용을 위한 커스텀 훅
|
|
|
+// Context 사용을 위한 커스텀 훅 — 값이 없어도(프로바이더 밖 사용 포함) 기본값을 반환해
|
|
|
+// 페이지가 예외로 다운되지 않도록 한다.
|
|
|
export function useConfigContext(): Config {
|
|
|
- const context = useContext(ConfigContext);
|
|
|
-
|
|
|
- if (context === null) {
|
|
|
- throw new Error('useConfigContext는 ConfigProvider 내부에서만 사용 가능합니다.');
|
|
|
- }
|
|
|
-
|
|
|
- return context;
|
|
|
+ return useContext(ConfigContext) ?? DEFAULT_CONFIG;
|
|
|
}
|