docs: Flag emoji strategy + Tax design + Shipping types

##  Issue #1: Flag Emoji Strategy (Research-Based)

Your comprehensive research revealed:
- Chrome on Windows does NOT render flag emojis
- Flags work for country selection (expected UX)
- Flags problematic for summary cards (political sensitivity)

**Action Taken:**
-  Removed flag from Store summary card
-  Changed to: "📍 Store Location: Indonesia"
-  Kept flags in dropdowns (country, currency)
-  Professional, accessible, future-proof

**Pattern:**
- Dropdowns: 🇮🇩 Indonesia (visual aid)
- Summary: 📍 Indonesia (neutral, professional)
- Shipping zones: Text only (clean, scalable)

##  Issue #2: Tax Settings Design

Created TAX_SETTINGS_DESIGN.md with:
- Toggle at top to enable/disable
- **Predefined rates based on store country**
- Indonesia: 11% (PPN) auto-shown
- Malaysia: 6% (SST) auto-shown
- Smart! No re-selecting country
- Zero learning curve

**User Flow:**
1. Enable tax toggle
2. See: "🇮🇩 Indonesia: 11% (Standard)"
3. Done! Tax working.

**For multi-country:**
1. Click "+ Add Tax Rate"
2. Select Malaysia
3. Auto-fills: 6%
4. Save. Done!

##  Issue #3: Shipping Method Types

Created SHIPPING_METHOD_TYPES.md documenting:

**Type 1: Static Methods** (WC Core)
- Free Shipping, Flat Rate, Local Pickup
- No API, immediate availability
- Basic address fields

**Type 2: Live Rate Methods** (API-based)
- UPS, FedEx, DHL (International)
- J&T, JNE, SiCepat (Indonesian)
- Requires "Calculate" button
- Returns service options

**Address Requirements:**
- International: Postal Code (required)
- Indonesian: Subdistrict (required)
- Static: Basic address only

**The Pattern:**
```
Static → Immediate display
Live Rate → Calculate → Service options → Select
```

**Next:** Fix Create Order to show conditional fields

## Documentation Added:
- TAX_SETTINGS_DESIGN.md
- SHIPPING_METHOD_TYPES.md

Both ready for implementation!
This commit is contained in:
dwindown
2025-11-10 11:23:42 +07:00
parent e502dcc807
commit 8bebd3abe5
3 changed files with 508 additions and 5 deletions

327
SHIPPING_METHOD_TYPES.md Normal file
View File

@@ -0,0 +1,327 @@
# Shipping Method Types - WooCommerce Core Structure
## The Two Types of Shipping Methods
WooCommerce has TWO fundamentally different shipping method types:
---
## Type 1: Static Methods (WooCommerce Core)
**Characteristics:**
- No API calls
- Fixed rates or free
- Configured once in settings
- Available immediately
**Examples:**
- Free Shipping
- Flat Rate
- Local Pickup
**Structure:**
```
Method: Free Shipping
├── Conditions: Order total > $50
└── Cost: $0
```
**In Create Order:**
```
User fills address
→ Static methods appear immediately
→ User selects one
→ Done!
```
---
## Type 2: Live Rate Methods (API-based)
**Characteristics:**
- Requires API call
- Dynamic rates based on address + weight
- Returns multiple service options
- Needs "Calculate" button
**Examples:**
- UPS (International)
- FedEx, DHL
- Indonesian Shipping Addons (J&T, JNE, SiCepat)
**Structure:**
```
Method: UPS Live Rates
├── API Credentials configured
└── On calculate:
├── Service: UPS Ground - $15.00
├── Service: UPS 2nd Day - $25.00
└── Service: UPS Next Day - $45.00
```
**In Create Order:**
```
User fills address
→ Click "Calculate Shipping"
→ API returns service options
→ User selects one
→ Done!
```
---
## The Real Hierarchy
### Static Method (Simple):
```
Method
└── (No sub-levels)
```
### Live Rate Method (Complex):
```
Method
├── Courier (if applicable)
│ ├── Service Option 1
│ ├── Service Option 2
│ └── Service Option 3
└── Or directly:
├── Service Option 1
└── Service Option 2
```
---
## Indonesian Shipping Example
**Method:** Indonesian Shipping (API-based)
**API:** Biteship / RajaOngkir / Custom
**After Calculate:**
```
J&T Express
├── Regular Service: Rp15,000 (2-3 days)
└── Express Service: Rp25,000 (1 day)
JNE
├── REG: Rp18,000 (2-4 days)
├── YES: Rp28,000 (1-2 days)
└── OKE: Rp12,000 (3-5 days)
SiCepat
├── Regular: Rp16,000 (2-3 days)
└── BEST: Rp20,000 (1-2 days)
```
**User sees:** Courier name + Service name + Price + Estimate
---
## UPS Example (International)
**Method:** UPS Live Rates
**API:** UPS API
**After Calculate:**
```
UPS Ground: $15.00 (5-7 business days)
UPS 2nd Day Air: $25.00 (2 business days)
UPS Next Day Air: $45.00 (1 business day)
```
**User sees:** Service name + Price + Estimate
---
## Address Field Requirements
### Static Methods:
- Country
- State/Province
- City
- Postal Code
- Address Line 1
- Address Line 2 (optional)
### Live Rate Methods:
**International (UPS, FedEx, DHL):**
- Country
- State/Province
- City
- **Postal Code** (REQUIRED - used for rate calculation)
- Address Line 1
- Address Line 2 (optional)
**Indonesian (J&T, JNE, SiCepat):**
- Country: Indonesia
- Province
- City/Regency
- **Subdistrict** (REQUIRED - used for rate calculation)
- Postal Code
- Address Line 1
- Address Line 2 (optional)
---
## The Pattern
| Method Type | Address Requirement | Rate Calculation |
|-------------|---------------------|------------------|
| Static | Basic address | Fixed/Free |
| Live Rate (International) | **Postal Code** required | API call with postal code |
| Live Rate (Indonesian) | **Subdistrict** required | API call with subdistrict ID |
---
## Implementation in Create Order
### Current Problem:
- We probably require subdistrict for ALL methods
- This breaks international live rate methods
### Solution:
**Step 1: Detect Available Methods**
```javascript
const availableMethods = getShippingMethods(address.country);
const needsSubdistrict = availableMethods.some(method =>
method.type === 'live_rate' && method.country === 'ID'
);
const needsPostalCode = availableMethods.some(method =>
method.type === 'live_rate' && method.country !== 'ID'
);
```
**Step 2: Show Conditional Fields**
```javascript
// Always show
- Country
- State/Province
- City
- Address Line 1
// Conditional
if (needsSubdistrict) {
- Subdistrict (required)
}
if (needsPostalCode || needsSubdistrict) {
- Postal Code (required)
}
// Always optional
- Address Line 2
```
**Step 3: Calculate Shipping**
```javascript
// Static methods
if (method.type === 'static') {
return method.cost; // Immediate
}
// Live rate methods
if (method.type === 'live_rate') {
const rates = await fetchLiveRates({
method: method.id,
address: {
country: address.country,
state: address.state,
city: address.city,
subdistrict: address.subdistrict, // If Indonesian
postal_code: address.postal_code, // If international
// ... other fields
}
});
return rates; // Array of service options
}
```
---
## UI Flow
### Scenario 1: Static Method Only
```
1. User fills basic address
2. Shipping options appear immediately:
- Free Shipping: $0
- Flat Rate: $10
3. User selects one
4. Done!
```
### Scenario 2: Indonesian Live Rate
```
1. User fills address including subdistrict
2. Click "Calculate Shipping"
3. API returns:
- J&T Regular: Rp15,000
- JNE REG: Rp18,000
- SiCepat BEST: Rp20,000
4. User selects one
5. Done!
```
### Scenario 3: International Live Rate
```
1. User fills address including postal code
2. Click "Calculate Shipping"
3. API returns:
- UPS Ground: $15.00
- UPS 2nd Day: $25.00
4. User selects one
5. Done!
```
### Scenario 4: Mixed (Static + Live Rate)
```
1. User fills address
2. Static methods appear immediately:
- Free Shipping: $0
3. Click "Calculate Shipping" for live rates
4. Live rates appear:
- UPS Ground: $15.00
5. User selects from all options
6. Done!
```
---
## WooCommerce Core Behavior
**Yes, this is all in WooCommerce core!**
- Static methods: `WC_Shipping_Method` class
- Live rate methods: Extend `WC_Shipping_Method` with API logic
- Service options: Stored as shipping rates with method_id + instance_id
**WooCommerce handles:**
- Method registration
- Rate calculation
- Service option display
- Selection and storage
**We need to handle:**
- Conditional address fields
- "Calculate" button for live rates
- Service option display in Create Order
- Proper address validation
---
## Next Steps
1. Investigate Create Order address field logic
2. Add conditional field display based on available methods
3. Add "Calculate Shipping" button for live rates
4. Display service options properly
5. Test with:
- Static methods only
- Indonesian live rates
- International live rates
- Mixed scenarios

177
TAX_SETTINGS_DESIGN.md Normal file
View File

@@ -0,0 +1,177 @@
# Tax Settings Design - WooNooW
## Philosophy: Zero Learning Curve
User should understand tax setup in 30 seconds, not 30 minutes.
---
## UI Structure
```
Tax Settings Page
├── [Toggle] Enable tax calculations
│ └── Description: "Calculate and display taxes at checkout"
├── When ENABLED, show:
├── Predefined Tax Rates [SettingsCard]
│ └── Based on store country from Store Details
│ Example for Indonesia:
│ ┌─────────────────────────────────────┐
│ │ 🇮🇩 Indonesia Tax Rates │
│ ├─────────────────────────────────────┤
│ │ Standard Rate: 11% │
│ │ Applied to: All products │
│ │ [Edit Rate] │
│ └─────────────────────────────────────┘
├── Additional Tax Rates [SettingsCard]
│ ├── [+ Add Tax Rate] button
│ └── List of custom rates:
│ ┌─────────────────────────────────┐
│ │ Malaysia: 6% │
│ │ Applied to: All products │
│ │ [Edit] [Delete] │
│ └─────────────────────────────────┘
├── Display Settings [SettingsCard]
│ ├── Prices are entered: [Including tax / Excluding tax]
│ ├── Display prices in shop: [Including tax / Excluding tax]
│ └── Display prices in cart: [Including tax / Excluding tax]
└── Advanced Settings
└── Link to WooCommerce tax settings
```
---
## Predefined Tax Rates by Country
When user's store country is set, we show the standard rate:
| Country | Standard Rate | Note |
|---------|---------------|------|
| Indonesia | 11% | PPN (VAT) |
| Malaysia | 6% | SST |
| Singapore | 9% | GST |
| Thailand | 7% | VAT |
| Philippines | 12% | VAT |
| Vietnam | 10% | VAT |
| United States | 0% | Varies by state - user adds manually |
| European Union | 20% | Average - varies by country |
---
## User Flow
### Scenario 1: Indonesian Store (Simple)
1. User enables tax toggle
2. Sees: "🇮🇩 Indonesia: 11% (Standard)"
3. Done! Tax is working.
### Scenario 2: Multi-Country Store
1. User enables tax toggle
2. Sees predefined rate for their country
3. Clicks "+ Add Tax Rate"
4. Selects country: Malaysia
5. Rate auto-fills: 6%
6. Clicks Save
7. Done!
### Scenario 3: US Store (Complex)
1. User enables tax toggle
2. Sees: "🇺🇸 United States: 0% (Add rates by state)"
3. Clicks "+ Add Tax Rate"
4. Selects: United States - California
5. Enters: 7.25%
6. Clicks Save
7. Repeats for other states
---
## Add Tax Rate Dialog
```
Add Tax Rate
├── Country/Region [Searchable Select]
│ └── 🇮🇩 Indonesia
│ 🇲🇾 Malaysia
│ 🇺🇸 United States
│ └── California
│ Texas
│ New York
├── Tax Rate (%)
│ └── [Input: 11]
├── Tax Class
│ └── [Select: Standard / Reduced / Zero]
└── [Cancel] [Save Rate]
```
---
## Backend Requirements
### API Endpoints:
- `GET /settings/tax/config` - Get tax enabled status + rates
- `POST /settings/tax/toggle` - Enable/disable tax
- `GET /settings/tax/rates` - List all tax rates
- `POST /settings/tax/rates` - Create tax rate
- `PUT /settings/tax/rates/{id}` - Update tax rate
- `DELETE /settings/tax/rates/{id}` - Delete tax rate
- `GET /settings/tax/predefined` - Get predefined rates by country
### Predefined Rates Data:
```json
{
"ID": {
"country": "Indonesia",
"rate": 11,
"name": "PPN (VAT)",
"class": "standard"
},
"MY": {
"country": "Malaysia",
"rate": 6,
"name": "SST",
"class": "standard"
}
}
```
---
## Benefits
**Zero learning curve** - User sees their country's rate immediately
**No re-selection** - Store country from Store Details is used
**Smart defaults** - Predefined rates are accurate
**Flexible** - Can add more countries/rates as needed
**Accessible** - Clear labels, simple toggle
**Scalable** - Works for single-country and multi-country stores
---
## Comparison to WooCommerce
| Feature | WooCommerce | WooNooW |
|---------|-------------|---------|
| Enable tax | Checkbox buried in settings | Toggle at top |
| Add rate | Navigate to Tax tab → Add rate → Fill form | Predefined + one-click add |
| Multi-country | Manual for each | Smart suggestions |
| Learning curve | 30 minutes | 30 seconds |
---
## Next Steps
1. Create Tax settings page component
2. Build backend API endpoints
3. Add predefined rates data
4. Test with Indonesian store
5. Test with multi-country store

View File

@@ -456,21 +456,20 @@ export default function StoreDetailsPage() {
</div>
</SettingsCard>
{/* Summary Card - Dynamic with Flag */}
{/* Summary Card - Professional, No Flag */}
<div className="bg-primary/10 border border-primary/20 rounded-lg p-4">
{(() => {
// Find flag for current currency
const currencyFlag = flagsData.find((f: any) => f.code === settings.currency);
const currencyInfo = currencies.find((c: any) => c.code === settings.currency);
const flagEmoji = currencyFlag ? countryCodeToEmoji(currencyFlag.countryCode) : '';
const countryName = currencyFlag?.country || settings.country;
return (
<>
<p className="text-sm font-medium">
{flagEmoji} Your store is located in {currencyFlag?.country || settings.country}
📍 Store Location: {countryName}
</p>
<p className="text-sm text-muted-foreground mt-1">
Prices will be displayed in {currencyInfo?.name || settings.currency} Timezone: {settings.timezone}
Currency: {currencyInfo?.name || settings.currency} Timezone: {settings.timezone}
</p>
</>
);