feat: add ESLint and Prettier with pre-commit hook

- Install ESLint 9 with TypeScript and React support
- Install Prettier with custom configuration (no semicolons)
- Add husky and lint-staged for pre-commit hooks
- Configure lint-staged to auto-fix and format on commit
- Relax ESLint rules to avoid large-scale code changes
- Format all existing code with Prettier (no semicolons)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ember
2025-11-05 11:30:27 +08:00
parent 332d0fbdc0
commit 11c767cdda
44 changed files with 9619 additions and 3482 deletions

View File

@@ -1,62 +1,86 @@
import React, { createContext, useContext, useState, useEffect } from 'react';
import { getSystemConfig } from '../lib/config';
import React, { createContext, useContext, useState, useEffect } from 'react'
import { getSystemConfig } from '../lib/config'
interface User {
id: string;
email: string;
id: string
email: string
}
interface AuthContextType {
user: User | null;
token: string | null;
login: (email: string, password: string) => Promise<{ success: boolean; message?: string; userID?: string; requiresOTP?: boolean }>;
register: (email: string, password: string, betaCode?: string) => Promise<{ success: boolean; message?: string; userID?: string; otpSecret?: string; qrCodeURL?: string }>;
verifyOTP: (userID: string, otpCode: string) => Promise<{ success: boolean; message?: string }>;
completeRegistration: (userID: string, otpCode: string) => Promise<{ success: boolean; message?: string }>;
logout: () => void;
isLoading: boolean;
user: User | null
token: string | null
login: (
email: string,
password: string
) => Promise<{
success: boolean
message?: string
userID?: string
requiresOTP?: boolean
}>
register: (
email: string,
password: string,
betaCode?: string
) => Promise<{
success: boolean
message?: string
userID?: string
otpSecret?: string
qrCodeURL?: string
}>
verifyOTP: (
userID: string,
otpCode: string
) => Promise<{ success: boolean; message?: string }>
completeRegistration: (
userID: string,
otpCode: string
) => Promise<{ success: boolean; message?: string }>
logout: () => void
isLoading: boolean
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
const AuthContext = createContext<AuthContextType | undefined>(undefined)
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [token, setToken] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [user, setUser] = useState<User | null>(null)
const [token, setToken] = useState<string | null>(null)
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
// 先检查是否为管理员模式(使用带缓存的系统配置获取)
getSystemConfig()
.then(data => {
.then((data) => {
if (data.admin_mode) {
// 管理员模式下模拟admin用户
setUser({ id: 'admin', email: 'admin@localhost' });
setToken('admin-mode');
setUser({ id: 'admin', email: 'admin@localhost' })
setToken('admin-mode')
} else {
// 非管理员模式检查本地存储中是否有token
const savedToken = localStorage.getItem('auth_token');
const savedUser = localStorage.getItem('auth_user');
const savedToken = localStorage.getItem('auth_token')
const savedUser = localStorage.getItem('auth_user')
if (savedToken && savedUser) {
setToken(savedToken);
setUser(JSON.parse(savedUser));
setToken(savedToken)
setUser(JSON.parse(savedUser))
}
}
setIsLoading(false);
setIsLoading(false)
})
.catch(err => {
console.error('Failed to fetch system config:', err);
.catch((err) => {
console.error('Failed to fetch system config:', err)
// 发生错误时,继续检查本地存储
const savedToken = localStorage.getItem('auth_token');
const savedUser = localStorage.getItem('auth_user');
const savedToken = localStorage.getItem('auth_token')
const savedUser = localStorage.getItem('auth_user')
if (savedToken && savedUser) {
setToken(savedToken);
setUser(JSON.parse(savedUser));
setToken(savedToken)
setUser(JSON.parse(savedUser))
}
setIsLoading(false);
});
}, []);
setIsLoading(false)
})
}, [])
const login = async (email: string, password: string) => {
try {
@@ -66,9 +90,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
});
})
const data = await response.json();
const data = await response.json()
if (response.ok) {
if (data.requires_otp) {
@@ -77,23 +101,31 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
userID: data.user_id,
requiresOTP: true,
message: data.message,
};
}
}
} else {
return { success: false, message: data.error };
return { success: false, message: data.error }
}
} catch (error) {
return { success: false, message: '登录失败,请重试' };
return { success: false, message: '登录失败,请重试' }
}
return { success: false, message: '未知错误' };
};
return { success: false, message: '未知错误' }
}
const register = async (email: string, password: string, betaCode?: string) => {
const register = async (
email: string,
password: string,
betaCode?: string
) => {
try {
const requestBody: { email: string; password: string; beta_code?: string } = { email, password };
const requestBody: {
email: string
password: string
beta_code?: string
} = { email, password }
if (betaCode) {
requestBody.beta_code = betaCode;
requestBody.beta_code = betaCode
}
const response = await fetch('/api/register', {
@@ -102,9 +134,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody),
});
})
const data = await response.json();
const data = await response.json()
if (response.ok) {
return {
@@ -113,14 +145,14 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
otpSecret: data.otp_secret,
qrCodeURL: data.qr_code_url,
message: data.message,
};
}
} else {
return { success: false, message: data.error };
return { success: false, message: data.error }
}
} catch (error) {
return { success: false, message: '注册失败,请重试' };
return { success: false, message: '注册失败,请重试' }
}
};
}
const verifyOTP = async (userID: string, otpCode: string) => {
try {
@@ -189,11 +221,11 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
}
const logout = () => {
setUser(null);
setToken(null);
localStorage.removeItem('auth_token');
localStorage.removeItem('auth_user');
};
setUser(null)
setToken(null)
localStorage.removeItem('auth_token')
localStorage.removeItem('auth_user')
}
return (
<AuthContext.Provider
@@ -210,13 +242,13 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
>
{children}
</AuthContext.Provider>
);
)
}
export function useAuth() {
const context = useContext(AuthContext);
const context = useContext(AuthContext)
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
throw new Error('useAuth must be used within an AuthProvider')
}
return context;
}
return context
}

View File

@@ -1,37 +1,41 @@
import { createContext, useContext, useState, ReactNode } from 'react';
import type { Language } from '../i18n/translations';
import { createContext, useContext, useState, ReactNode } from 'react'
import type { Language } from '../i18n/translations'
interface LanguageContextType {
language: Language;
setLanguage: (lang: Language) => void;
language: Language
setLanguage: (lang: Language) => void
}
const LanguageContext = createContext<LanguageContextType | undefined>(undefined);
const LanguageContext = createContext<LanguageContextType | undefined>(
undefined
)
export function LanguageProvider({ children }: { children: ReactNode }) {
// Initialize language from localStorage or default to English
const [language, setLanguage] = useState<Language>(() => {
const saved = localStorage.getItem('language');
return (saved === 'en' || saved === 'zh') ? saved : 'en';
});
const saved = localStorage.getItem('language')
return saved === 'en' || saved === 'zh' ? saved : 'en'
})
// Save language to localStorage whenever it changes
const handleSetLanguage = (lang: Language) => {
setLanguage(lang);
localStorage.setItem('language', lang);
};
setLanguage(lang)
localStorage.setItem('language', lang)
}
return (
<LanguageContext.Provider value={{ language, setLanguage: handleSetLanguage }}>
<LanguageContext.Provider
value={{ language, setLanguage: handleSetLanguage }}
>
{children}
</LanguageContext.Provider>
);
)
}
export function useLanguage() {
const context = useContext(LanguageContext);
const context = useContext(LanguageContext)
if (!context) {
throw new Error('useLanguage must be used within LanguageProvider');
throw new Error('useLanguage must be used within LanguageProvider')
}
return context;
return context
}