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