feat: Go-to-Account button + wishlist merge on login

1. ThankYou page - Go to Account button:
   - Added for logged-in users (next to Continue Shopping)
   - Shows in both receipt and basic templates
   - Uses outline variant with User icon

2. Wishlist merge on login:
   - Reads guest wishlist from localStorage (woonoow_guest_wishlist)
   - POSTs each product to /account/wishlist API
   - Handles duplicates gracefully (skips on error)
   - Clears localStorage after successful merge
This commit is contained in:
Dwindi Ramadhana
2026-01-01 17:17:12 +07:00
parent 508ec682a7
commit 10b3c0e47f
2 changed files with 66 additions and 14 deletions

View File

@@ -54,6 +54,39 @@ export default function Login() {
};
}
// Merge guest wishlist to account
const GUEST_WISHLIST_KEY = 'woonoow_guest_wishlist';
try {
const stored = localStorage.getItem(GUEST_WISHLIST_KEY);
if (stored) {
const guestProductIds = JSON.parse(stored) as number[];
if (guestProductIds.length > 0) {
// Merge each product to account wishlist
const newNonce = data.nonce;
for (const productId of guestProductIds) {
try {
await fetch(`${apiRoot}/account/wishlist`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': newNonce,
},
credentials: 'include',
body: JSON.stringify({ product_id: productId }),
});
} catch (e) {
// Skip if product already in wishlist or other error
console.debug('Wishlist merge skipped for product:', productId);
}
}
// Clear guest wishlist after merge
localStorage.removeItem(GUEST_WISHLIST_KEY);
}
}
} catch (e) {
console.error('Failed to merge guest wishlist:', e);
}
toast.success('Login successful!');
// Set the target URL with hash route, then force reload

View File

@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { useParams, Link, useSearchParams } from 'react-router-dom';
import { useThankYouSettings } from '@/hooks/useAppearanceSettings';
import Container from '@/components/Layout/Container';
import { CheckCircle, ShoppingBag, Package, Truck } from 'lucide-react';
import { CheckCircle, ShoppingBag, Package, Truck, User } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { formatPrice } from '@/lib/currency';
import { apiClient } from '@/lib/api/client';
@@ -16,6 +16,7 @@ export default function ThankYou() {
const [relatedProducts, setRelatedProducts] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const isLoggedIn = (window as any).woonoowCustomer?.user?.isLoggedIn;
useEffect(() => {
const fetchOrderData = async () => {
@@ -186,14 +187,24 @@ export default function ThankYou() {
: 'Thank you for your business!'}
</p>
{elements.continue_shopping_button && (
<Link to="/shop">
<Button size="lg" className="gap-2">
<ShoppingBag className="w-5 h-5" />
Continue Shopping
</Button>
</Link>
)}
<div className="flex flex-col sm:flex-row gap-3 justify-center">
{elements.continue_shopping_button && (
<Link to="/shop">
<Button size="lg" className="gap-2">
<ShoppingBag className="w-5 h-5" />
Continue Shopping
</Button>
</Link>
)}
{isLoggedIn && (
<Link to="/my-account">
<Button size="lg" variant="outline" className="gap-2">
<User className="w-5 h-5" />
Go to Account
</Button>
</Link>
)}
</div>
</div>
</div>
@@ -430,17 +441,25 @@ export default function ThankYou() {
</div>
)}
{/* Continue Shopping Button */}
{elements.continue_shopping_button && (
<div className="text-center">
{/* Action Buttons */}
<div className="text-center flex flex-col sm:flex-row gap-3 justify-center">
{elements.continue_shopping_button && (
<Link to="/shop">
<Button size="lg" className="gap-2">
<ShoppingBag className="w-5 h-5" />
Continue Shopping
</Button>
</Link>
</div>
)}
)}
{isLoggedIn && (
<Link to="/my-account">
<Button size="lg" variant="outline" className="gap-2">
<User className="w-5 h-5" />
Go to Account
</Button>
</Link>
)}
</div>
{/* Related Products */}
{elements.related_products && relatedProducts.length > 0 && (