fix(checkout): fix disabled country/state and add public countries API
Issues fixed:
1. Country field was disabled when API failed (length 0)
- Changed: disabled={countries.length <= 1} → disabled={countries.length === 1}
- Only disables in single-country mode now
2. State field was disabled when no preloaded states
- Changed: Falls back to text input instead of disabled SearchableSelect
- Allows manual state entry for countries without state list
3. /countries API required admin permission
- Added public /countries endpoint to CheckoutController
- Uses permission_callback __return_true for customer checkout access
- Returns countries, states, and default_country
This commit is contained in:
@@ -628,18 +628,27 @@ export default function Checkout() {
|
||||
value={billingData.country}
|
||||
onChange={(v) => setBillingData({ ...billingData, country: v })}
|
||||
placeholder="Select country"
|
||||
disabled={countries.length <= 1}
|
||||
disabled={countries.length === 1}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2">State / Province *</label>
|
||||
<SearchableSelect
|
||||
options={billingStateOptions}
|
||||
value={billingData.state}
|
||||
onChange={(v) => setBillingData({ ...billingData, state: v })}
|
||||
placeholder={billingStateOptions.length ? "Select state" : "N/A"}
|
||||
disabled={!billingStateOptions.length}
|
||||
/>
|
||||
{billingStateOptions.length > 0 ? (
|
||||
<SearchableSelect
|
||||
options={billingStateOptions}
|
||||
value={billingData.state}
|
||||
onChange={(v) => setBillingData({ ...billingData, state: v })}
|
||||
placeholder="Select state"
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
type="text"
|
||||
value={billingData.state}
|
||||
onChange={(e) => setBillingData({ ...billingData, state: e.target.value })}
|
||||
placeholder="Enter state/province"
|
||||
className="w-full border rounded-lg px-4 py-2"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2">Postcode / ZIP *</label>
|
||||
@@ -801,18 +810,27 @@ export default function Checkout() {
|
||||
value={shippingData.country}
|
||||
onChange={(v) => setShippingData({ ...shippingData, country: v })}
|
||||
placeholder="Select country"
|
||||
disabled={countries.length <= 1}
|
||||
disabled={countries.length === 1}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2">State / Province *</label>
|
||||
<SearchableSelect
|
||||
options={shippingStateOptions}
|
||||
value={shippingData.state}
|
||||
onChange={(v) => setShippingData({ ...shippingData, state: v })}
|
||||
placeholder={shippingStateOptions.length ? "Select state" : "N/A"}
|
||||
disabled={!shippingStateOptions.length}
|
||||
/>
|
||||
{shippingStateOptions.length > 0 ? (
|
||||
<SearchableSelect
|
||||
options={shippingStateOptions}
|
||||
value={shippingData.state}
|
||||
onChange={(v) => setShippingData({ ...shippingData, state: v })}
|
||||
placeholder="Select state"
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
type="text"
|
||||
value={shippingData.state}
|
||||
onChange={(e) => setShippingData({ ...shippingData, state: e.target.value })}
|
||||
placeholder="Enter state/province"
|
||||
className="w-full border rounded-lg px-4 py-2"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2">Postcode / ZIP *</label>
|
||||
|
||||
Reference in New Issue
Block a user