From 6ad415217135deabbc53d14a69a9e515b76eebd6 Mon Sep 17 00:00:00 2001 From: Vula Builder Date: Mon, 3 Aug 2026 11:42:08 +0000 Subject: [PATCH] Deploy --- src/hooks/useCustomerAuth.ts | 102 +++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/hooks/useCustomerAuth.ts diff --git a/src/hooks/useCustomerAuth.ts b/src/hooks/useCustomerAuth.ts new file mode 100644 index 0000000..03f8fe4 --- /dev/null +++ b/src/hooks/useCustomerAuth.ts @@ -0,0 +1,102 @@ +'use client' +import { useState, useEffect, useCallback } from 'react' + +const COMMERCE_URL = process.env.NEXT_PUBLIC_VULA_COMMERCE_URL || 'https://ide.vulai.co.za' +const PROJECT_ID = process.env.NEXT_PUBLIC_VULA_PROJECT_ID || '' +const TOKEN_KEY = `vula_customer_${PROJECT_ID}` + +export interface Customer { + id: string + email: string + first_name: string | null + last_name: string | null + phone: string | null + address_line1: string | null + address_line2: string | null + city: string | null + province: string | null + postal_code: string | null + created_at: string +} + +export function useCustomerAuth() { + const [customer, setCustomer] = useState(null) + const [token, setToken] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + + useEffect(() => { + const sync = () => { + const saved = typeof window !== 'undefined' ? localStorage.getItem(TOKEN_KEY) : null + if (!saved) { setCustomer(null); setToken(null); setLoading(false); return } + fetch(`${COMMERCE_URL}/api/commerce/${PROJECT_ID}/customers/me`, { + headers: { Authorization: `Bearer ${saved}` } + }) + .then(r => r.json()) + .then(d => { + if (d.success) { setCustomer(d.customer); setToken(saved) } + else { localStorage.removeItem(TOKEN_KEY); setCustomer(null); setToken(null) } + }) + .catch(() => { localStorage.removeItem(TOKEN_KEY); setCustomer(null); setToken(null) }) + .finally(() => setLoading(false)) + } + sync() + window.addEventListener('vula-auth-updated', sync) + return () => window.removeEventListener('vula-auth-updated', sync) + }, []) + + const register = useCallback(async (data: { + email: string; password: string; first_name?: string; last_name?: string; phone?: string + }) => { + setError(null); setLoading(true) + try { + const r = await fetch(`${COMMERCE_URL}/api/commerce/${PROJECT_ID}/customers/register`, { + method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) + }) + const d = await r.json() + if (!d.success) throw new Error(d.error || 'Registration failed') + localStorage.setItem(TOKEN_KEY, d.token) + setCustomer(d.customer); setToken(d.token) + window.dispatchEvent(new CustomEvent('vula-auth-updated')) + return d.customer as Customer + } catch (e: any) { setError(e.message); throw e } + finally { setLoading(false) } + }, []) + + const login = useCallback(async (email: string, password: string) => { + setError(null); setLoading(true) + try { + const r = await fetch(`${COMMERCE_URL}/api/commerce/${PROJECT_ID}/customers/login`, { + method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) + }) + const d = await r.json() + if (!d.success) throw new Error(d.error || 'Login failed') + localStorage.setItem(TOKEN_KEY, d.token) + setCustomer(d.customer); setToken(d.token) + window.dispatchEvent(new CustomEvent('vula-auth-updated')) + return d.customer as Customer + } catch (e: any) { setError(e.message); throw e } + finally { setLoading(false) } + }, []) + + const logout = useCallback(() => { + localStorage.removeItem(TOKEN_KEY) + setCustomer(null); setToken(null) + window.dispatchEvent(new CustomEvent('vula-auth-updated')) + }, []) + + const updateProfile = useCallback(async (data: Partial> & { password?: string; new_password?: string }) => { + const t = typeof window !== 'undefined' ? localStorage.getItem(TOKEN_KEY) : null + if (!t) throw new Error('Not authenticated') + const r = await fetch(`${COMMERCE_URL}/api/commerce/${PROJECT_ID}/customers/me`, { + method: 'PUT', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${t}` }, + body: JSON.stringify(data) + }) + const d = await r.json() + if (!d.success) throw new Error(d.error || 'Update failed') + setCustomer(d.customer) + return d.customer as Customer + }, []) + + return { customer, token, loading, error, isAuthenticated: !!customer, register, login, logout, updateProfile } +}