feat: implement multiple saved addresses with modal selector in checkout

- Add AddressController with full CRUD API for saved addresses
- Implement address management UI in My Account > Addresses
- Add modal-based address selector in checkout (Tokopedia-style)
- Hide checkout forms when saved address is selected
- Add search functionality in address modal
- Auto-select default addresses on page load
- Fix variable products to show 'Select Options' instead of 'Add to Cart'
- Add admin toggle for multiple addresses feature
- Clean up debug logs and fix TypeScript errors
This commit is contained in:
Dwindi Ramadhana
2025-12-26 01:16:11 +07:00
parent 9ac09582d2
commit 100f9cce55
27 changed files with 2492 additions and 205 deletions

View File

@@ -112,51 +112,45 @@ function ClassicLayout({ children }: BaseLayoutProps) {
{headerSettings.elements.search && (
<button
onClick={() => setSearchOpen(true)}
className="flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg transition-colors"
className="font-[inherit] flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg transition-colors"
>
<Search className="h-5 w-5 text-gray-600" />
</button>
)}
{/* Account */}
{headerSettings.elements.account && (user?.isLoggedIn ? (
<Link to="/my-account" className="no-underline">
<button className="flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg transition-colors">
<User className="h-5 w-5 text-gray-600" />
<span className="hidden lg:block text-sm font-medium text-gray-700">Account</span>
</button>
<Link to="/my-account" className="flex items-center gap-2 text-sm font-medium text-gray-700 hover:text-gray-900 transition-colors no-underline">
<User className="h-5 w-5" />
<span className="hidden lg:block">Account</span>
</Link>
) : (
<a href="/wp-login.php" className="no-underline">
<button className="flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg transition-colors">
<User className="h-5 w-5 text-gray-600" />
<span className="hidden lg:block text-sm font-medium text-gray-700">Account</span>
</button>
<a href="/wp-login.php" className="flex items-center gap-2 text-sm font-medium text-gray-700 hover:text-gray-900 transition-colors no-underline">
<User className="h-5 w-5" />
<span className="hidden lg:block">Account</span>
</a>
))}
{/* Cart */}
{headerSettings.elements.cart && (
<Link to="/cart" className="no-underline">
<button className="flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg transition-colors relative">
<Link to="/cart" className="flex items-center gap-2 text-sm font-medium text-gray-700 hover:text-gray-900 transition-colors no-underline">
<div className="relative">
<ShoppingCart className="h-5 w-5 text-gray-600" />
<ShoppingCart className="h-5 w-5" />
{itemCount > 0 && (
<span className="absolute -top-2 -right-2 h-5 w-5 rounded-full bg-gray-900 text-white text-xs flex items-center justify-center font-medium">
{itemCount}
</span>
)}
</div>
<span className="hidden lg:block text-sm font-medium text-gray-700">
<span className="hidden lg:block">
Cart ({itemCount})
</span>
</button>
</Link>
)}
{/* Mobile Menu Toggle - Only for hamburger and slide-in */}
{(headerSettings.mobile_menu === 'hamburger' || headerSettings.mobile_menu === 'slide-in') && (
<button
className="md:hidden flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg transition-colors"
className="font-[inherit] md:hidden flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg transition-colors"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
>
{mobileMenuOpen ? <X className="h-5 w-5 text-gray-600" /> : <Menu className="h-5 w-5 text-gray-600" />}
@@ -186,7 +180,7 @@ function ClassicLayout({ children }: BaseLayoutProps) {
<div className="fixed top-0 left-0 h-full w-64 bg-white shadow-xl z-50 md:hidden transform transition-transform">
<div className="p-4 border-b flex justify-between items-center">
<span className="font-semibold">Menu</span>
<button onClick={() => setMobileMenuOpen(false)}>
<button onClick={() => setMobileMenuOpen(false)} className="font-[inherit]">
<X className="h-5 w-5 text-gray-600" />
</button>
</div>
@@ -218,7 +212,7 @@ function ClassicLayout({ children }: BaseLayoutProps) {
{headerSettings.elements.search && (
<button
onClick={() => setSearchOpen(true)}
className="flex flex-col items-center gap-1 px-4 py-2 text-xs font-medium text-gray-700 hover:text-gray-900"
className="font-[inherit] flex flex-col items-center gap-1 px-4 py-2 text-xs font-medium text-gray-700 hover:text-gray-900"
>
<Search className="h-5 w-5" />
<span>Search</span>
@@ -395,7 +389,7 @@ function ModernLayout({ children }: BaseLayoutProps) {
{headerSettings.elements.search && (
<button
onClick={() => setSearchOpen(true)}
className="flex items-center gap-1 text-sm font-medium text-gray-700 hover:text-gray-900 transition-colors"
className="font-[inherit] flex items-center gap-1 text-sm font-medium text-gray-700 hover:text-gray-900 transition-colors"
>
<Search className="h-4 w-4" />
</button>
@@ -523,7 +517,7 @@ function BoutiqueLayout({ children }: BaseLayoutProps) {
{headerSettings.elements.search && (
<button
onClick={() => setSearchOpen(true)}
className="flex items-center gap-1 text-sm uppercase tracking-wider text-gray-700 hover:text-gray-900 transition-colors"
className="font-[inherit] flex items-center gap-1 text-sm uppercase tracking-wider text-gray-700 hover:text-gray-900 transition-colors"
>
<Search className="h-4 w-4" />
</button>
@@ -547,7 +541,7 @@ function BoutiqueLayout({ children }: BaseLayoutProps) {
{/* Mobile Menu Toggle */}
<button
className="md:hidden flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg transition-colors"
className="font-[inherit] md:hidden flex items-center gap-2 px-3 py-2 hover:bg-gray-100 rounded-lg transition-colors"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
>
{mobileMenuOpen ? <X className="h-5 w-5 text-gray-600" /> : <Menu className="h-5 w-5 text-gray-600" />}