|
import React, { createContext, useState, useEffect, useCallback } from 'react'; |
|
import type { UserProfile } from '../types'; |
|
import { KOFI_LOGIN_NAME, KOFI_SECRET_PASSWORD } from '../config'; |
|
|
|
|
|
const CUSTOM_NAME_KEY = 'yuki-app-login-name'; |
|
const CUSTOM_SECRET_KEY = 'yuki-app-login-secret'; |
|
const SESSION_KEY = 'yuki-user-session'; |
|
|
|
interface IAuthContext { |
|
user: UserProfile | null; |
|
isLoading: boolean; |
|
login: (name: string, secret: string) => boolean; |
|
logout: () => void; |
|
updateCredentials: (currentSecret: string, newName: string, newSecret: string) => { success: boolean; message: string }; |
|
} |
|
|
|
export const AuthContext = createContext<IAuthContext>({ |
|
user: null, |
|
isLoading: true, |
|
login: () => false, |
|
logout: () => {}, |
|
updateCredentials: () => ({ success: false, message: 'Not implemented' }), |
|
}); |
|
|
|
const createAuthenticatedUser = (name: string): UserProfile => ({ |
|
id: `user-${name}`, |
|
name: "Bonsai Master", |
|
email: '', |
|
picture: '', |
|
}); |
|
|
|
|
|
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { |
|
const [user, setUser] = useState<UserProfile | null>(null); |
|
const [isLoading, setIsLoading] = useState(true); |
|
const storageKey = 'yuki-user-session'; |
|
|
|
useEffect(() => { |
|
try { |
|
const session = window.localStorage.getItem(storageKey); |
|
if (session) { |
|
const sessionUser = JSON.parse(session); |
|
setUser(sessionUser); |
|
} |
|
} catch (error) { |
|
console.error("Failed to parse user session:", error); |
|
window.localStorage.removeItem(storageKey); |
|
} finally { |
|
setIsLoading(false); |
|
} |
|
}, [storageKey]); |
|
|
|
const login = useCallback((name: string, secret: string): boolean => { |
|
const customName = window.localStorage.getItem(CUSTOM_NAME_KEY); |
|
const customSecret = window.localStorage.getItem(CUSTOM_SECRET_KEY); |
|
|
|
const effectiveName = customName || KOFI_LOGIN_NAME; |
|
const effectiveSecret = customSecret || KOFI_SECRET_PASSWORD; |
|
|
|
if (name === effectiveName && secret === effectiveSecret) { |
|
const authenticatedUser = createAuthenticatedUser(name); |
|
try { |
|
window.localStorage.setItem(storageKey, JSON.stringify(authenticatedUser)); |
|
setUser(authenticatedUser); |
|
return true; |
|
} catch (error) { |
|
console.error("Failed to save user session:", error); |
|
return false; |
|
} |
|
} |
|
return false; |
|
}, [storageKey]); |
|
|
|
const logout = useCallback(() => { |
|
try { |
|
window.localStorage.removeItem(storageKey); |
|
setUser(null); |
|
} catch (error) { |
|
console.error("Failed to clear user session:", error); |
|
} |
|
}, [storageKey]); |
|
|
|
const updateCredentials = useCallback((currentSecret: string, newName: string, newSecret: string): { success: boolean; message: string } => { |
|
const customSecret = window.localStorage.getItem(CUSTOM_SECRET_KEY); |
|
const effectiveSecret = customSecret || KOFI_SECRET_PASSWORD; |
|
|
|
if (currentSecret !== effectiveSecret) { |
|
return { success: false, message: "Current secret password is incorrect." }; |
|
} |
|
|
|
if (!newName.trim() || !newSecret.trim()) { |
|
return { success: false, message: "New login name and secret cannot be empty." }; |
|
} |
|
|
|
try { |
|
window.localStorage.setItem(CUSTOM_NAME_KEY, newName); |
|
window.localStorage.setItem(CUSTOM_SECRET_KEY, newSecret); |
|
return { success: true, message: "Credentials updated successfully! You will need to use these next time you log in." }; |
|
} catch (error) { |
|
console.error("Failed to update credentials:", error); |
|
return { success: false, message: "Failed to save new credentials due to a storage error." }; |
|
} |
|
}, []); |
|
|
|
return ( |
|
<AuthContext.Provider value={{ user, isLoading, login, logout, updateCredentials }}> |
|
{children} |
|
</AuthContext.Provider> |
|
); |
|
}; |
|
|