72 lines
2.4 KiB
TypeScript
72 lines
2.4 KiB
TypeScript
import { create } from 'zustand'
|
|
import { supabase } from '@/lib/supabase'
|
|
import type { User } from '@/types'
|
|
|
|
interface AuthState {
|
|
user: User | null
|
|
isLoading: boolean
|
|
login: (email: string, password: string) => Promise<void>
|
|
register: (name: string, email: string, password: string) => Promise<void>
|
|
logout: () => Promise<void>
|
|
initialize: () => Promise<void>
|
|
}
|
|
|
|
function sessionToUser(session: { user: { id: string; email?: string; user_metadata?: { name?: string } } } | null): User | null {
|
|
if (!session) return null
|
|
const { id, email, user_metadata } = session.user
|
|
const name = user_metadata?.name ?? email?.split('@')[0] ?? 'Người dùng'
|
|
return { id, email: email ?? '', name }
|
|
}
|
|
|
|
export const useAuthStore = create<AuthState>((set) => ({
|
|
user: null,
|
|
isLoading: true,
|
|
|
|
initialize: async () => {
|
|
set({ isLoading: true })
|
|
|
|
// Restore existing session (JWT in localStorage via Supabase SDK)
|
|
const { data: { session } } = await supabase.auth.getSession()
|
|
set({ user: sessionToUser(session), isLoading: false })
|
|
|
|
// Keep state in sync across tabs and token refresh
|
|
supabase.auth.onAuthStateChange((_event, newSession) => {
|
|
set({ user: sessionToUser(newSession), isLoading: false })
|
|
})
|
|
},
|
|
|
|
login: async (email, password) => {
|
|
const { error } = await supabase.auth.signInWithPassword({ email, password })
|
|
if (error) throw new Error(mapAuthError(error.message))
|
|
// onAuthStateChange fires and updates user state
|
|
},
|
|
|
|
register: async (name, email, password) => {
|
|
const { error } = await supabase.auth.signUp({
|
|
email,
|
|
password,
|
|
options: { data: { name } },
|
|
})
|
|
if (error) throw new Error(mapAuthError(error.message))
|
|
// onAuthStateChange fires and updates user state
|
|
},
|
|
|
|
logout: async () => {
|
|
await supabase.auth.signOut()
|
|
// onAuthStateChange fires → user set to null
|
|
},
|
|
}))
|
|
|
|
function mapAuthError(msg: string): string {
|
|
if (msg.includes('already registered') || msg.includes('already exists')) {
|
|
return 'Email này đã được sử dụng. Vui lòng đăng nhập.'
|
|
}
|
|
if (msg.includes('Invalid login credentials') || msg.includes('invalid_credentials')) {
|
|
return 'Sai email hoặc mật khẩu. Vui lòng kiểm tra lại.'
|
|
}
|
|
if (msg.includes('Email not confirmed')) {
|
|
return 'Email chưa được xác nhận.'
|
|
}
|
|
return 'Đã có lỗi xảy ra. Vui lòng thử lại.'
|
|
}
|