fix: Critical payment toggle sync and 3rd party gateway settings

 Issue 1: Toggle Not Saving (CRITICAL FIX)
Problem: Toggle appeared to work but didn't persist
Root Cause: Missing query invalidation after toggle
Solution:
- Added queryClient.invalidateQueries after successful toggle
- Now fetches real server state after optimistic update
- Ensures SPA and WooCommerce stay in sync

 Issue 2: SearchableSelect Default Value
Problem: Showing 'Select country...' when Indonesia selected
Root Cause: WooCommerce stores country as 'ID:DKI_JAKARTA'
Solution:
- Split country:state format in backend
- Extract country code only for select
- Added timezone fallback to 'UTC' if empty

 Issue 3: 3rd Party Gateway Settings
Problem: TriPay showing 'Configure in WooCommerce' link
Solution:
- Replaced external link with Settings button
- Now opens GenericGatewayForm modal
- All WC form_fields render automatically
- TriPay fields (enable_icon, expired, checkout_method) work!

📋 Files Modified:
- Payments.tsx: Added invalidation + settings button
- StoreSettingsProvider.php: Split country format
- All 3rd party gateways now configurable in SPA

🎯 Result:
 Toggle saves correctly to WooCommerce
 Country/timezone show selected values
 All gateways with form_fields are editable
 No more 'Configure in WooCommerce' for compliant gateways
This commit is contained in:
dwindown
2025-11-05 22:41:02 +07:00
parent 79d3b449c3
commit 42eb8eb441
3 changed files with 18 additions and 16 deletions

View File

@@ -57,7 +57,7 @@ function useFullscreen() {
.wnw-fullscreen .woonoow-fullscreen-root { .wnw-fullscreen .woonoow-fullscreen-root {
position: fixed; position: fixed;
inset: 0; inset: 0;
z-index: 999999; z-index: 9999;
background: var(--background, #fff); background: var(--background, #fff);
height: 100dvh; /* ensure full viewport height on mobile/desktop */ height: 100dvh; /* ensure full viewport height on mobile/desktop */
overflow: hidden; /* prevent double scrollbars; inner <main> handles scrolling */ overflow: hidden; /* prevent double scrollbars; inner <main> handles scrolling */

View File

@@ -82,6 +82,8 @@ export default function PaymentsPage() {
toast.error('Failed to update gateway'); toast.error('Failed to update gateway');
}, },
onSuccess: () => { onSuccess: () => {
// Invalidate to fetch real state from server
queryClient.invalidateQueries({ queryKey: ['payment-gateways'] });
toast.success('Gateway updated successfully'); toast.success('Gateway updated successfully');
}, },
}); });
@@ -303,20 +305,15 @@ export default function PaymentsPage() {
</div> </div>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button {gateway.enabled && (
variant="outline" <Button
size="sm" variant="ghost"
asChild size="sm"
> onClick={() => handleManageGateway(gateway)}
<a
href={gateway.wc_settings_url}
target="_blank"
rel="noopener noreferrer"
> >
<ExternalLink className="h-4 w-4 mr-2" /> <Settings className="h-4 w-4" />
Configure in WooCommerce </Button>
</a> )}
</Button>
<ToggleField <ToggleField
id={gateway.id} id={gateway.id}
label="" label=""

View File

@@ -110,12 +110,17 @@ class StoreSettingsProvider {
* @return array Store settings * @return array Store settings
*/ */
public static function get_settings(): array { public static function get_settings(): array {
// WooCommerce stores country as "COUNTRY:STATE" format
$default_country = get_option('woocommerce_default_country', '');
$country_parts = explode(':', $default_country);
$country_code = $country_parts[0] ?? '';
return [ return [
'store_name' => get_option('blogname', ''), 'store_name' => get_option('blogname', ''),
'contact_email' => get_option('admin_email', ''), 'contact_email' => get_option('admin_email', ''),
'support_email' => get_option('woocommerce_email_from_address', ''), 'support_email' => get_option('woocommerce_email_from_address', ''),
'phone' => get_option('woocommerce_store_phone', ''), 'phone' => get_option('woocommerce_store_phone', ''),
'country' => get_option('woocommerce_default_country', ''), 'country' => $country_code,
'address' => get_option('woocommerce_store_address', ''), 'address' => get_option('woocommerce_store_address', ''),
'address_2' => get_option('woocommerce_store_address_2', ''), 'address_2' => get_option('woocommerce_store_address_2', ''),
'city' => get_option('woocommerce_store_city', ''), 'city' => get_option('woocommerce_store_city', ''),
@@ -125,7 +130,7 @@ class StoreSettingsProvider {
'thousand_separator' => get_option('woocommerce_price_thousand_sep', ','), 'thousand_separator' => get_option('woocommerce_price_thousand_sep', ','),
'decimal_separator' => get_option('woocommerce_price_decimal_sep', '.'), 'decimal_separator' => get_option('woocommerce_price_decimal_sep', '.'),
'number_of_decimals' => (int) get_option('woocommerce_price_num_decimals', 2), 'number_of_decimals' => (int) get_option('woocommerce_price_num_decimals', 2),
'timezone' => get_option('timezone_string', 'UTC'), 'timezone' => get_option('timezone_string', 'UTC') ?: 'UTC',
'weight_unit' => get_option('woocommerce_weight_unit', 'kg'), 'weight_unit' => get_option('woocommerce_weight_unit', 'kg'),
'dimension_unit' => get_option('woocommerce_dimension_unit', 'cm'), 'dimension_unit' => get_option('woocommerce_dimension_unit', 'cm'),
]; ];