Changes: - Add FAL_KEY and GEMINI_API_KEY to .env.example - Update picture-it to use ~/.config/opencode/.env (unified creds) - Remove shodh-memory skill (no longer used) - Remove alphaear-* skills (deprecated) - Remove thai-frontend-dev skill (replaced by website-creator) - Remove theme-factory skill - Add mql-developer skill (MQL5 trading) - Add ecommerce-astro skill (Astro e-commerce) - Add website-creator skill (Next.js + Payload CMS) - Update install script for new skills
114 lines
3.0 KiB
TypeScript
114 lines
3.0 KiB
TypeScript
import { create } from 'zustand';
|
|
import { persist } from 'zustand/middleware';
|
|
|
|
interface User {
|
|
id: string;
|
|
email: string;
|
|
name?: string;
|
|
role: 'customer' | 'vendor' | 'admin';
|
|
avatar_url?: string;
|
|
}
|
|
|
|
interface AuthStore {
|
|
user: User | null;
|
|
token: string | null;
|
|
isLoading: boolean;
|
|
error: string | null;
|
|
|
|
login: (email: string, password: string) => Promise<boolean>;
|
|
register: (data: { email: string; password: string; name: string }) => Promise<boolean>;
|
|
logout: () => Promise<void>;
|
|
fetchUser: () => Promise<void>;
|
|
clearError: () => void;
|
|
}
|
|
|
|
export const useAuthStore = create<AuthStore>()(
|
|
persist(
|
|
(set, get) => ({
|
|
user: null,
|
|
token: null,
|
|
isLoading: false,
|
|
error: null,
|
|
|
|
login: async (email, password) => {
|
|
set({ isLoading: true, error: null });
|
|
try {
|
|
const res = await fetch('/api/auth/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ email, password })
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const data = await res.json();
|
|
set({ error: data.error || 'Login failed' });
|
|
return false;
|
|
}
|
|
|
|
const { user, token } = await res.json();
|
|
set({ user, token, isLoading: false });
|
|
return true;
|
|
} catch (error) {
|
|
set({ error: 'Network error', isLoading: false });
|
|
return false;
|
|
}
|
|
},
|
|
|
|
register: async (data) => {
|
|
set({ isLoading: true, error: null });
|
|
try {
|
|
const res = await fetch('/api/auth/register', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const error = await res.json();
|
|
set({ error: error.error || 'Registration failed' });
|
|
return false;
|
|
}
|
|
|
|
const { user, token } = await res.json();
|
|
set({ user, token, isLoading: false });
|
|
return true;
|
|
} catch (error) {
|
|
set({ error: 'Network error', isLoading: false });
|
|
return false;
|
|
}
|
|
},
|
|
|
|
logout: async () => {
|
|
await fetch('/api/auth/logout', { method: 'POST' });
|
|
set({ user: null, token: null });
|
|
},
|
|
|
|
fetchUser: async () => {
|
|
const token = get().token;
|
|
if (!token) return;
|
|
|
|
try {
|
|
const res = await fetch('/api/auth/me', {
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
|
|
if (res.ok) {
|
|
const { user } = await res.json();
|
|
set({ user });
|
|
} else {
|
|
set({ user: null, token: null });
|
|
}
|
|
} catch {
|
|
set({ user: null, token: null });
|
|
}
|
|
},
|
|
|
|
clearError: () => set({ error: null })
|
|
}),
|
|
{
|
|
name: 'auth-storage',
|
|
partialize: (state) => ({ user: state.user, token: state.token })
|
|
}
|
|
)
|
|
);
|