73 Commits

Author SHA1 Message Date
Dwindi Ramadhana
e70aa1f554 fix: resolve email shortcode rendering and TypeScript errors
- Fix EmailRenderer.php: add missing \ namespace prefix on instanceof
  checks for WC_Order, WC_Product, WC_Customer in get_variables()
  (root cause of unrendered {order_number} etc. in all order emails)
- Fix ProductCard.tsx: remove deprecated isClassic/isModern/isBoutique
  branches, consolidate into single settings-driven render path
- Fix AccountLayout.tsx: add missing return statement
- Remove orphaned Layout.tsx (imported nothing, referenced missing Header)
2026-03-12 19:10:56 +07:00
Dwindi Ramadhana
ab10c25c28 Fix IDE errors from ESLint cleanup 2026-03-12 04:08:57 +07:00
Dwindi Ramadhana
90169b508d feat: product page layout toggle (flat/card), fix email shortcode rendering
- Add layout_style setting (flat default) to product appearance
  - AppearanceController: sanitize & persist layout_style, add to default settings
  - Admin SPA: Layout Style select in Appearance > Product
  - Customer SPA: useEffect targets <main> bg-white in flat mode (full-width),
    card mode uses per-section white floating cards on gray background
  - Accordion sections styled per mode: flat=border-t dividers, card=white cards

- Fix email shortcode gaps (EmailRenderer, EmailManager)
  - Add missing variables: return_url, contact_url, account_url (alias),
    payment_error_reason, order_items_list (alias for order_items_table)
  - Fix customer_note extra_data key mismatch (note → customer_note)
  - Pass low_stock_threshold via extra_data in low_stock email send
2026-03-04 01:14:56 +07:00
Dwindi Ramadhana
6f23ccdda4 Fix: Exclude SPA pages from Appearance Entry Page dropdown, remove hardcoded Hero paddings, fix Accordion dropdown clipping 2026-02-28 01:10:49 +07:00
Dwindi Ramadhana
a62037d993 feat/fix: checkout email tracing, UI tweaks for add-to-cart, cart page overflow fix, implement hide admin bar setting 2026-02-27 23:15:10 +07:00
Dwindi Ramadhana
7da4f0a167 feat: integrate contextual links and fix coupons navigation
- Added DocLink component and mapped routes
- Fixed Coupons nav link to /marketing/coupons
- Updated Settings pages to show inline documentation links
2026-02-05 22:51:44 +07:00
Dwindi Ramadhana
5f08c18ec7 fix: resolve container width issues, spa redirects, and appearance settings overwrite. feat: enhance order/sub details and newsletter layout 2026-02-05 00:09:40 +07:00
Dwindi Ramadhana
a0b5f8496d feat: Implement OAuth license activation flow
- Add LicenseConnect.tsx focused OAuth confirmation page in customer SPA
- Add /licenses/oauth/validate and /licenses/oauth/confirm API endpoints
- Update App.tsx to render license-connect outside BaseLayout (no header/footer)
- Add license_activation_method field to product settings in Admin SPA
- Create LICENSING_MODULE.md with comprehensive OAuth flow documentation
- Update API_ROUTES.md with license module endpoints
2026-01-31 22:22:22 +07:00
Dwindi Ramadhana
d80f34c8b9 finalizing subscription moduile, ready to test 2026-01-29 11:54:42 +07:00
Dwindi Ramadhana
6d2136d3b5 Fix button roundtrip in editor, alignment persistence, and test email rendering 2026-01-17 13:10:50 +07:00
Dwindi Ramadhana
749cfb3f92 feat: Page Editor Phase 1 - React DynamicPageRenderer
- Add DynamicPageRenderer component for structural pages and CPT content
- Add 6 section components:
  - HeroSection with multiple layout variants
  - ContentSection for rich text/HTML content
  - ImageTextSection with image-left/right layouts
  - FeatureGridSection with grid-2/3/4 layouts
  - CTABannerSection with color schemes
  - ContactFormSection with webhook POST and redirect
- Add dynamic routes to App.tsx for /:slug and /:pathBase/:slug
- Build customer-spa successfully
2026-01-11 22:35:15 +07:00
Dwindi Ramadhana
1ff9a36af3 fix: React Router basename - use ?? instead of || for empty string support
When SPA is frontpage, basePath is empty string. JavaScript || treats '' as falsy
and falls back to /store. Changed to ?? (nullish coalescing) so empty string works.
2026-01-10 01:00:46 +07:00
Dwindi Ramadhana
3357fbfcf1 feat: Dynamic SPA slug, field label storage, and SPA frontpage support (WIP) 2026-01-10 00:50:32 +07:00
Dwindi Ramadhana
d3ec580ec8 feat: cleanup and improvements for checkout fields
- Removed all debug logging (backend and frontend)
- Added filter hook 'woonoow_standard_checkout_field_keys' for extensibility
- Added form-row-wide class support to admin OrderForm
- Tax is automatically handled by WC's calculate_totals()
2026-01-09 10:06:20 +07:00
Dwindi Ramadhana
942fb48a0b fix: critical - add shipping_cost/title to sanitize_payload whitelist
ROOT CAUSE: The sanitize_payload() method was returning a whitelist of
allowed fields, but shipping_cost, shipping_title, custom_fields, and
customer_note were NOT included. This caused these values to be null
even though the frontend was sending them correctly.

Added:
- shipping_cost (float)
- shipping_title (sanitized text)
- custom_fields (array)
- customer_note (sanitized textarea)

This should fix shipping not being applied to order totals.
2026-01-09 09:45:46 +07:00
Dwindi Ramadhana
e04f1fd93f feat: add form-row-wide class support for checkout fields
- Added isFullWidthField helper to check for form-row-wide in class array
- Added getFieldWrapperClass helper to return md:col-span-2 for full width
- Applied dynamic width to billing_first_name and billing_last_name
- PHP can now control field width via class: ['form-row-wide']
- Added debug logging for shipping to help diagnose shipping not applied issue
2026-01-08 23:57:47 +07:00
Dwindi Ramadhana
c6489b6b05 fix: shipping cost applied to orders + dynamic field rendering
Shipping Fix:
- Frontend now sends shipping_cost and shipping_title in order payload
- Backend uses these values as fallback when WC zone-based rate lookup fails
- Fixes issue where Rajaongkir and other API-based shipping wasn't applied

Dynamic Field Rendering:
- Added billingFields/shippingFields filters sorted by priority
- Added getBillingField/getShippingField helpers that return undefined for hidden fields
- All standard fields now conditionally rendered based on API response
- Fields use labels and required flags from API
- Any field can be hidden via PHP snippet (type: 'hidden' or hidden: true)
- Removed unused isFieldHidden function
2026-01-08 23:41:30 +07:00
Dwindi Ramadhana
7a45b243cb fix: ThankYou page discount rows and improved hidden field detection
1. ThankYou page - Added discount row to order summary
   - All 3 template variations (receipt-inner, receipt-outer, default)
   - Shows discount with negative amount in green when > 0
   - Already had shipping/tax rows, now complete breakdown

2. Checkout - Enhanced isFieldHidden helper
   - Now checks both type='hidden' AND hidden=true flags
   - Any standard field can be hidden via PHP snippet
   - Existing city/state/postcode/country checks unchanged
2026-01-08 23:23:56 +07:00
Dwindi Ramadhana
0e561d9e8c fix: checkout issues - hidden fields, coupons, shipping in order totals
1. Hidden fields now properly hidden in SPA
   - Added billing_postcode and shipping_postcode to isFieldHidden checks
   - Fields with type='hidden' from PHP now conditionally rendered

2. Coupons now applied to order total
   - Added coupons array to order submission payload
   - CartController now calls calculate_totals() before reading discounts
   - Returns per-coupon discount amounts {code, discount, type}

3. Shipping now applied to order total
   - Already handled in submit() via find_shipping_rate_for_order
   - Frontend now sends shipping_method in payload

4. Order details now include shipping/tracking info
   - checkout/order/{id} API includes shipping_lines, tracking_number, tracking_url
   - account/orders/{id} API includes same shipping/tracking fields
   - Tracking info read from multiple plugin meta keys

5. Thank you/OrderDetails page shows shipping method and AWB
   - Shipping Method section with courier name and cost
   - AWB tracking for processing/completed orders with Track Shipment button
2026-01-08 23:04:31 +07:00
Dwindi Ramadhana
e8c60b3a09 fix: checkout improvements
1. Hidden fields now respected in SPA
   - Added isFieldHidden helper to check if PHP sets type to 'hidden'
   - Country/state/city fields conditionally rendered based on API response
   - Set default country value for hidden country fields (Indonesia-only stores)

2. Coupon discount now shows correct amount
   - Added calculate_totals() before reading discount
   - Changed coupons response to include {code, discount, type} per coupon
   - Added discount_total at root level for frontend compatibility

3. Order details page now shows shipping info and AWB tracking
   - Added shipping_lines, tracking_number, tracking_url to Order interface
   - Added Shipping Method section with courier name and cost
   - Added AWB tracking section for processing/completed orders
   - Track Shipment button with link to tracking URL
2026-01-08 20:51:26 +07:00
Dwindi Ramadhana
56b0040f7a feat(checkout): implement dynamic shipping rate fetching
Backend:
- Added /checkout/shipping-rates REST endpoint
- Returns available shipping methods from matching zone
- Triggers woonoow/shipping/before_calculate hook for Rajaongkir

Frontend:
- Added ShippingRate interface and state
- Added fetchShippingRates with 500ms debounce
- Replaced hardcoded shipping options with dynamic rates
- Added loading and empty state handling
- Added shipping_method to order submission payload

This fixes:
- Rajaongkir rates not appearing (now fetched from API)
- Free shipping showing despite disabled (now from WC zones)
2026-01-08 15:13:59 +07:00
Dwindi Ramadhana
f518d7e589 feat(checkout): fix searchable select API search and add billing destination
Fixes:
1. SearchableSelect now supports onSearch prop for API-based search
   - Added onSearch and isSearching props
   - shouldFilter disabled when onSearch provided
2. DynamicCheckoutField connects handleApiSearch to SearchableSelect
3. RAJAONGKIR_INTEGRATION.md adds both billing and shipping destination_id

This enables the destination search field to actually call the API
when user types, instead of just filtering local (empty) options.
2026-01-08 14:47:54 +07:00
Dwindi Ramadhana
274c3d35e1 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
2026-01-08 14:02:13 +07:00
Dwindi Ramadhana
6694d9e0c4 feat(checkout): dynamic checkout fields with PHP filter support
Backend (CheckoutController):
- Enhanced get_fields() API with custom_attributes, search_endpoint,
  search_param, min_chars, input_class, default
- Supports new 'searchable_select' field type for API-backed search

Customer SPA:
- Created DynamicCheckoutField component for all field types
- Checkout fetches fields from /checkout/fields API
- Renders custom fields from PHP filters (billing + shipping)
- searchable_select type with live API search
- Custom field data included in checkout submission

This enables:
- Checkout Field Editor Pro compatibility
- Rajaongkir destination_id via simple code snippet
- Any plugin using woocommerce_checkout_fields filter

Updated RAJAONGKIR_INTEGRATION.md with code snippet approach.
2026-01-08 11:48:53 +07:00
Dwindi Ramadhana
2939ebfe6b feat(checkout): searchable address fields and Rajaongkir integration
Admin SPA:
- Changed billing/shipping state from Select to SearchableSelect

Customer SPA:
- Added cmdk package for command palette
- Created popover, command, and searchable-select UI components
- Added searchable country and state fields to checkout
- Fetches countries/states from /countries API
- Auto-clears state when country changes

Backend:
- Added generic woonoow/shipping/before_calculate hook
- Removed hardcoded Rajaongkir session handling

Documentation:
- Updated RAJAONGKIR_INTEGRATION.md with:
  - Complete searchable destination selector plugin code
  - JavaScript implementation
  - React component version
  - REST API endpoint for destination search
2026-01-08 11:19:37 +07:00
Dwindi Ramadhana
5170aea882 fix: hide header wishlist for logged-in users
- Guest users see wishlist icon in header (uses /wishlist page)
- Logged-in users don't see it (they use /my-account/wishlist instead)
- Applied to all 3 layout styles: Classic, Modern, Boutique
2026-01-07 23:15:02 +07:00
Dwindi Ramadhana
a4a055a98e feat: add SEOHead to all SPA pages for dynamic page titles
Added SEOHead component to:
- ThankYou page (both template styles)
- Login page
- Account/Dashboard
- Account/Orders
- Account/Downloads
- Account/Addresses
- Account/Wishlist
- Account/Licenses
- Account/AccountDetails
- Public Wishlist page

Also created usePageTitle hook as alternative for non-Helmet usage.
2026-01-07 22:51:47 +07:00
Dwindi Ramadhana
d7b132d9d9 fix: dbDelta separate tables, add SEOHead for page titles
1. License table creation:
   - dbDelta requires separate calls per CREATE TABLE
   - Split into sql_licenses and sql_activations
   - Added 'PRIMARY KEY  (id)' with two spaces (dbDelta requirement)

2. Page titles:
   - Added SEOHead to Cart page (title: Shopping Cart)
   - Added SEOHead to Checkout page (title: Checkout)
   - Shop already had SEOHead

3. usePageTitle hook created (alternative to SEOHead for non-Helmet usage)
2026-01-07 22:40:45 +07:00
Dwindi Ramadhana
3a08e80c1f fix: category selection, checkout redirect, sidebar shipping visibility
1. Category Selection Bug:
   - Added 'id' alias to category/tag API responses
   - Frontend uses cat.id which was undefined (API returned term_id)

2. Checkout Redirect:
   - Changed from window.location.href + reload to navigate()
   - Added !isProcessing check to empty cart condition

3. Sidebar Shipping for Virtual-Only:
   - Hide Shipping Method section when isVirtualOnly
   - Hide Shipping row in totals when isVirtualOnly

4. License Table:
   - Table creation runs via ensure_tables() on plugins_loaded
2026-01-07 22:26:58 +07:00
Dwindi Ramadhana
2cc20ff760 fix: licensing table creation, consistent meta keys, checkout virtual detection
1. License table auto-creation:
   - Added ensure_tables() check on plugins_loaded
   - Tables created automatically if missing

2. Consistent licensing meta keys:
   - ProductsController now uses _woonoow_licensing_enabled
   - Matches LicensingModule and LicenseManager

3. Checkout virtual-only detection:
   - Added needs_shipping to Cart interface
   - Checkout uses cart.needs_shipping from WooCommerce API
   - Fallback to item-level virtual/downloadable check

4. Login redirect for logged-in users added previously
2026-01-07 22:15:51 +07:00
Dwindi Ramadhana
f334e018fa fix: 4 bugs - checkout virtual, login redirect, licensing, categories
1. Virtual-only checkout:
   - Added 'virtual' and 'downloadable' to CartController response
   - Checkout can now detect virtual-only carts

2. Login redirect:
   - Added useEffect to redirect logged-in users to /my-account

3. License generation:
   - Fixed meta key mismatch (_woonoow_licensing_enabled -> _licensing_enabled)

4. Product categories:
   - Added queryClient.invalidateQueries after creating new category
   - List now refreshes immediately
2026-01-07 21:08:01 +07:00
Dwindi Ramadhana
3d2bab90ec feat: Complete licensing module with admin and customer UIs
Admin SPA:
- Licenses list page with search, filter, pagination
- License detail page with activation history
- Copy license key, view details, revoke functionality

Customer SPA:
- My Account > Licenses page
- View licenses with activation info
- Copy license key
- Deactivate devices

Backend integration:
- Routes registered in App.tsx and Account/index.tsx
- License nav item in account sidebar (conditional on module enabled)
2026-01-05 16:29:37 +07:00
Dwindi Ramadhana
663e6c13e6 fix: Sync avatar to account sidebar
- Fetch avatar settings in AccountLayout on mount
- Display custom avatar or gravatar in sidebar
- Dispatch woonoow:avatar-updated event on upload/remove
- Listen for event in AccountLayout for real-time sync
2026-01-05 00:31:16 +07:00
Dwindi Ramadhana
86dca3e9c2 fix: Address issues with all 4 features
1. Admin Store Link - Add to WP admin bar (Menu.php) with proper option check
2. Activity Log - Fix Loading text to show correct state after data loads
3. Avatar Upload - Use correct option key woonoow_allow_custom_avatar
4. Downloadable Files - Connect to WooCommerce native:
   - Add downloads array to format_product_full
   - Add downloads/download_limit/download_expiry handling in update_product
   - Add downloads handling in create_product
2026-01-05 00:22:08 +07:00
Dwindi Ramadhana
51c759a4f5 feat: Add customer avatar upload and product downloadable files
Customer Avatar Upload:
- Add /account/avatar endpoint for upload/delete
- Add /account/avatar-settings endpoint for settings
- Update AccountDetails.tsx with avatar upload UI
- Support base64 image upload with validation

Product Downloadable Files:
- Create DownloadsTab component for file management
- Add downloads state to ProductFormTabbed
- Show Downloads tab when 'downloadable' is checked
- Support file name, URL, download limit, and expiry
2026-01-05 00:05:18 +07:00
Dwindi Ramadhana
0f542ad452 feat: Multiple fixes and features
1. Add allow_custom_avatar toggle to Customer Settings
2. Implement coupon apply/remove in Cart and Checkout pages
3. Update Cart interface with coupons array and discount_total
4. Implement Downloads page to fetch from /account/downloads API
2026-01-04 20:03:33 +07:00
Dwindi Ramadhana
75a82cf16c feat: add dynamic meta tags for social sharing (Phase 4-5)
Phase 4: Dynamic Meta Tags
- Added react-helmet-async dependency
- Created SEOHead component with Open Graph and Twitter Card support
- Added HelmetProvider wrapper to App.tsx
- Integrated SEOHead in Product page (title, description, image, product info)
- Integrated SEOHead in Shop page (basic meta tags)

Phase 5: Auto-Flush Permalinks
- Enhanced settings change handler to only flush when spa_mode,
  spa_page, or use_browser_router changes
- Plugin already flushes on activation (Installer.php)

This enables proper link previews when sharing product URLs
on Facebook, Twitter, Slack, etc.
2026-01-04 10:40:10 +07:00
Dwindi Ramadhana
45fcbf9d29 feat: migrate from HashRouter to BrowserRouter for SEO
Phase 1: WordPress Rewrite Rules
- Add rewrite rule for /store/* to serve SPA page
- Add use_browser_router setting toggle (default: true)
- Flush rewrite rules on settings change

Phase 2: React Router Migration
- Add BrowserRouter with basename from WordPress config
- Pass basePath and useBrowserRouter to frontend
- Conditional router based on setting

Phase 3: Hash Route Migration
- Update EmailManager.php reset password URL
- Update EmailRenderer.php login URL
- Update TemplateOverride.php WC redirects
- All routes now use path format by default

This enables proper SEO indexing as search engines
can now crawl individual product/page URLs.
2026-01-03 20:01:32 +07:00
Dwindi Ramadhana
a98217897c fix: use customer-spa for password reset page
Changed reset link URL from admin SPA to customer-spa:
- Old: /wp-admin/admin.php?page=woonoow#/reset-password?key=...
- New: /my-account#/reset-password?key=...

This fixes the login redirect issue - the customer-spa is publicly
accessible so users can reset their password without logging in first.

Added:
- customer-spa/src/pages/ResetPassword/index.tsx
- Route /reset-password in customer-spa App.tsx

EmailManager.php now:
- Uses wc_get_page_id('myaccount') to get my-account page URL
- Falls back to home_url if my-account page not found
2026-01-03 17:09:00 +07:00
Dwindi Ramadhana
78d7bc1161 fix: auto-login after checkout, ThankYou guest buttons, forgot password page
1. Auto-login after checkout:
   - Added wp_set_auth_cookie() and wp_set_current_user() in CheckoutController
   - Auto-registered users are now logged in when thank-you page loads

2. ThankYou page guest buttons:
   - Added 'Login / Create Account' button for guests
   - Shows for both receipt and basic templates
   - No more dead-end after placing order as guest

3. Forgot password flow:
   - Created ForgotPassword page component (/forgot-password route)
   - Added forgot_password API endpoint in AuthController
   - Uses WordPress retrieve_password() for reset email
   - Replaced wp-login.php link in Login page
2026-01-01 17:36:40 +07:00
Dwindi Ramadhana
62f25b624b feat: auto-login after checkout via page reload
Changed Checkout page order success handling:
- Before: SPA navigate() to thank-you page (cookies not refreshed)
- After: window.location.href + reload (cookies refreshed)

This ensures guests who are auto-registered during checkout
get their auth cookies properly set after order placement.
2026-01-01 17:25:19 +07:00
Dwindi Ramadhana
10b3c0e47f feat: Go-to-Account button + wishlist merge on login
1. ThankYou page - Go to Account button:
   - Added for logged-in users (next to Continue Shopping)
   - Shows in both receipt and basic templates
   - Uses outline variant with User icon

2. Wishlist merge on login:
   - Reads guest wishlist from localStorage (woonoow_guest_wishlist)
   - POSTs each product to /account/wishlist API
   - Handles duplicates gracefully (skips on error)
   - Clears localStorage after successful merge
2026-01-01 17:17:12 +07:00
Dwindi Ramadhana
508ec682a7 fix: login page reload + custom logout dialog
1. Login fix:
   - Added window.location.reload() after setting hash URL
   - Forces full page reload to refresh cookies from server
   - Resolves 'Cookie check failed' error after login

2. Logout UX improvement:
   - Created alert-dialog.tsx component (Radix UI AlertDialog)
   - Replaced window.confirm() with custom AlertDialog
   - Dialog shows: title, description, Cancel/Log Out buttons
   - Red 'Log Out' action button for clear intent
2026-01-01 17:08:34 +07:00
Dwindi Ramadhana
c83ea78911 feat: improve login/logout flow in customer SPA
1. Logout flow:
   - Added confirmation dialog (window.confirm)
   - Changed to API-based logout (/auth/logout)
   - Full page reload after logout to clear cookies
   - Added loading state during logout

2. Login flow (already correct):
   - Uses window.location.href for full page redirect
   - Redirects to /store/#/my-account after login
2026-01-01 17:00:11 +07:00
Dwindi Ramadhana
e9e54f52a7 fix: update all header login links to use SPA login
- BaseLayout.tsx: Updated 4 guest account links
- Wishlist.tsx: Updated guest wishlist login link
- All now use Link to /login instead of href to /wp-login.php
2025-12-31 22:50:58 +07:00
Dwindi Ramadhana
4fcc69bfcd chore: add input and label UI components for customer-spa 2025-12-31 22:44:35 +07:00
Dwindi Ramadhana
56042d4b8e feat: add customer login page in SPA
- Created Login/index.tsx with styled form
- Added /auth/customer-login API endpoint (no admin perms required)
- Registered route in Routes.php
- Added /login route in customer-spa App.tsx
- Account page now redirects to SPA login instead of wp-login.php
- Login supports redirect param for post-login navigation
2025-12-31 22:43:13 +07:00
Dwindi Ramadhana
f97cca8061 fix: properly clear cart after order placement
- Use clearCart() from store instead of iterating removeItem()
- Iteration could fail as items are removed during loop
- clearCart() resets cart to initial state atomically
2025-12-31 22:18:06 +07:00
Dwindi Ramadhana
a87357d890 fix: thank you page 401 error
- Add public /checkout/order/{id} endpoint with order_key validation
- Update checkout redirect to include order_key parameter
- Update ThankYou page to use new public endpoint with key
- Support both guest (via key) and logged-in (via customer_id) access
2025-12-31 21:42:40 +07:00
Dwindi Ramadhana
82399d4ddf fix: WP-Admin CSS conflicts and add-to-cart redirect
- Fix CSS conflicts between WP-Admin and SPA (radio buttons, chart text)
- Add Tailwind important selector scoped to #woonoow-admin-app
- Remove overly aggressive inline SVG styles from Assets.php
- Add targeted WordPress admin CSS overrides in index.css
- Fix add-to-cart redirect to use woocommerce_add_to_cart_redirect filter
- Let WooCommerce handle cart operations natively for proper session management
- Remove duplicate tailwind.config.cjs
2025-12-31 14:06:04 +07:00