feat(shipping): searchable state fields and addon hook

1. Admin OrderForm: Changed billing & shipping state from Select to
   SearchableSelect for better UX (consistent with country field)

2. OrdersController: Replaced Rajaongkir-specific hardcoded session
   handling with generic filter hook:
   do_action('woonoow/shipping/before_calculate', $shipping, $items)

3. Added RAJAONGKIR_INTEGRATION.md with:
   - Hook documentation
   - Code snippet to bridge Rajaongkir with WooNooW
   - Frontend integration examples
   - Troubleshooting guide
This commit is contained in:
Dwindi Ramadhana
2026-01-08 11:00:55 +07:00
parent 83836298ec
commit 786e01c8f6
3 changed files with 232 additions and 21 deletions

View File

@@ -1126,16 +1126,13 @@ export default function OrderForm({
</div>
<div>
<Label>{__('State/Province')}</Label>
<Select value={bState} onValueChange={setBState}>
<SelectTrigger className="w-full"><SelectValue placeholder={__('Select state')} /></SelectTrigger>
<SelectContent className="max-h-64">
{bStateOptions.length ? bStateOptions.map(o => (
<SelectItem key={o.value} value={o.value}>{o.label}</SelectItem>
)) : (
<SelectItem value="__none__" disabled>{__('N/A')}</SelectItem>
)}
</SelectContent>
</Select>
<SearchableSelect
options={bStateOptions}
value={bState}
onChange={setBState}
placeholder={bStateOptions.length ? __('Select state') : __('N/A')}
disabled={!bStateOptions.length}
/>
</div>
</>
)}
@@ -1177,7 +1174,7 @@ export default function OrderForm({
{field.label}
{field.required && <span className="text-destructive ml-1">*</span>}
</Label>
{field.type === 'select' && field.options ? (
{field.type === 'select' && field.options && field.key !== 'shipping_state' ? (
<Select
value={shippingData[fieldKey] || ''}
onValueChange={(v) => setShippingData({ ...shippingData, [fieldKey]: v })}
@@ -1199,6 +1196,14 @@ export default function OrderForm({
placeholder={field.placeholder || __('Select country')}
disabled={oneCountryOnly}
/>
) : field.key === 'shipping_state' && field.options ? (
<SearchableSelect
options={Object.entries(field.options).map(([value, label]: [string, any]) => ({ value, label }))}
value={shippingData.state || ''}
onChange={(v) => setShippingData({ ...shippingData, state: v })}
placeholder={field.placeholder || __('Select state')}
disabled={!Object.keys(field.options).length}
/>
) : field.type === 'textarea' ? (
<Textarea
value={shippingData[fieldKey] || ''}