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

@@ -63,10 +63,10 @@ export default function AppearanceHeader() {
style,
sticky,
height,
mobile_menu: mobileMenu,
mobile_logo: mobileLogo,
logo_width: logoWidth,
logo_height: logoHeight,
mobileMenu,
mobileLogo,
logoWidth,
logoHeight,
elements,
});
toast.success('Header settings saved successfully');

View File

@@ -11,7 +11,11 @@ import { api } from '@/lib/api';
export default function AppearanceShop() {
const [loading, setLoading] = useState(true);
const [gridColumns, setGridColumns] = useState('3');
const [gridColumns, setGridColumns] = useState({
mobile: '2',
tablet: '3',
desktop: '4'
});
const [gridStyle, setGridStyle] = useState('standard');
const [cardStyle, setCardStyle] = useState('card');
const [aspectRatio, setAspectRatio] = useState('square');
@@ -37,7 +41,11 @@ export default function AppearanceShop() {
const shop = response.data?.pages?.shop;
if (shop) {
setGridColumns(shop.layout?.grid_columns || '3');
setGridColumns(shop.layout?.grid_columns || {
mobile: '2',
tablet: '3',
desktop: '4'
});
setGridStyle(shop.layout?.grid_style || 'standard');
setCardStyle(shop.layout?.card_style || 'card');
setAspectRatio(shop.layout?.aspect_ratio || 'square');
@@ -110,17 +118,55 @@ export default function AppearanceShop() {
title="Layout"
description="Configure shop page layout and product display"
>
<SettingsSection label="Grid Columns" htmlFor="grid-columns">
<Select value={gridColumns} onValueChange={setGridColumns}>
<SelectTrigger id="grid-columns">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="2">2 Columns</SelectItem>
<SelectItem value="3">3 Columns</SelectItem>
<SelectItem value="4">4 Columns</SelectItem>
</SelectContent>
</Select>
<SettingsSection label="Grid Columns" description="Set columns for each breakpoint">
<div className="grid grid-cols-3 gap-4">
<div>
<Label htmlFor="grid-columns-mobile" className="text-sm font-medium mb-2 block">Mobile</Label>
<Select value={gridColumns.mobile} onValueChange={(value) => setGridColumns({ ...gridColumns, mobile: value })}>
<SelectTrigger id="grid-columns-mobile">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">1</SelectItem>
<SelectItem value="2">2</SelectItem>
<SelectItem value="3">3</SelectItem>
</SelectContent>
</Select>
<p className="text-xs text-gray-500 mt-1">&lt;768px</p>
</div>
<div>
<Label htmlFor="grid-columns-tablet" className="text-sm font-medium mb-2 block">Tablet</Label>
<Select value={gridColumns.tablet} onValueChange={(value) => setGridColumns({ ...gridColumns, tablet: value })}>
<SelectTrigger id="grid-columns-tablet">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="2">2</SelectItem>
<SelectItem value="3">3</SelectItem>
<SelectItem value="4">4</SelectItem>
</SelectContent>
</Select>
<p className="text-xs text-gray-500 mt-1">768-1024px</p>
</div>
<div>
<Label htmlFor="grid-columns-desktop" className="text-sm font-medium mb-2 block">Desktop</Label>
<Select value={gridColumns.desktop} onValueChange={(value) => setGridColumns({ ...gridColumns, desktop: value })}>
<SelectTrigger id="grid-columns-desktop">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="2">2</SelectItem>
<SelectItem value="3">3</SelectItem>
<SelectItem value="4">4</SelectItem>
<SelectItem value="5">5</SelectItem>
<SelectItem value="6">6</SelectItem>
</SelectContent>
</Select>
<p className="text-xs text-gray-500 mt-1">&gt;1024px</p>
</div>
</div>
</SettingsSection>
<SettingsSection label="Grid Style" htmlFor="grid-style" description="Masonry creates a Pinterest-like layout with varying heights">