feat: improve login/logout flow in customer SPA

1. Logout flow:
   - Added confirmation dialog (window.confirm)
   - Changed to API-based logout (/auth/logout)
   - Full page reload after logout to clear cookies
   - Added loading state during logout

2. Login flow (already correct):
   - Uses window.location.href for full page redirect
   - Redirects to /store/#/my-account after login
This commit is contained in:
Dwindi Ramadhana
2026-01-01 17:00:11 +07:00
parent 58681e272e
commit c83ea78911

View File

@@ -1,4 +1,4 @@
import React, { ReactNode } from 'react';
import React, { ReactNode, useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { LayoutDashboard, ShoppingBag, Download, MapPin, Heart, User, LogOut } from 'lucide-react';
import { useModules } from '@/hooks/useModules';
@@ -12,6 +12,7 @@ export function AccountLayout({ children }: AccountLayoutProps) {
const user = (window as any).woonoowCustomer?.user;
const { isEnabled } = useModules();
const wishlistEnabled = (window as any).woonoowCustomer?.settings?.wishlist_enabled !== false;
const [isLoggingOut, setIsLoggingOut] = useState(false);
const allMenuItems = [
{ id: 'dashboard', label: 'Dashboard', path: '/my-account', icon: LayoutDashboard },
@@ -27,8 +28,27 @@ export function AccountLayout({ children }: AccountLayoutProps) {
item.id !== 'wishlist' || (isEnabled('wishlist') && wishlistEnabled)
);
const handleLogout = () => {
window.location.href = '/wp-login.php?action=logout';
const handleLogout = async () => {
setIsLoggingOut(true);
try {
const apiRoot = (window as any).woonoowCustomer?.apiRoot || '/wp-json/woonoow/v1';
const nonce = (window as any).woonoowCustomer?.nonce || '';
await fetch(`${apiRoot}/auth/logout`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': nonce,
},
credentials: 'include',
});
// Full page reload to clear cookies and refresh state
window.location.href = window.location.origin + '/store/';
} catch (error) {
// Even on error, try to redirect and let server handle session
window.location.href = window.location.origin + '/store/';
}
};
const isActive = (path: string) => {
@@ -60,8 +80,7 @@ export function AccountLayout({ children }: AccountLayoutProps) {
<Link
key={item.id}
to={item.path}
className={`flex items-center gap-3 px-4 py-2.5 rounded-lg transition-colors ${
isActive(item.path)
className={`flex items-center gap-3 px-4 py-2.5 rounded-lg transition-colors ${isActive(item.path)
? 'bg-primary text-primary-foreground'
: 'text-gray-700 hover:bg-gray-100'
}`}
@@ -73,11 +92,16 @@ export function AccountLayout({ children }: AccountLayoutProps) {
})}
<button
onClick={handleLogout}
className="w-full font-[inherit] flex items-center gap-3 px-4 py-2.5 rounded-lg text-gray-700 hover:bg-gray-100 transition-colors"
onClick={() => {
if (window.confirm('Are you sure you want to log out?')) {
handleLogout();
}
}}
disabled={isLoggingOut}
className="w-full font-[inherit] flex items-center gap-3 px-4 py-2.5 rounded-lg text-gray-700 hover:bg-gray-100 transition-colors disabled:opacity-50"
>
<LogOut className="w-5 h-5" />
<span className="font-medium">Logout</span>
<span className="font-medium">{isLoggingOut ? 'Logging out...' : 'Logout'}</span>
</button>
</nav>
</aside>
@@ -93,8 +117,7 @@ export function AccountLayout({ children }: AccountLayoutProps) {
<Link
key={item.id}
to={item.path}
className={`flex items-center gap-2 px-6 py-4 border-b-2 transition-colors whitespace-nowrap text-sm ${
isActive(item.path)
className={`flex items-center gap-2 px-6 py-4 border-b-2 transition-colors whitespace-nowrap text-sm ${isActive(item.path)
? 'border-primary text-primary font-medium'
: 'border-transparent text-gray-600 hover:text-gray-900'
}`}