Jake Vanderwerf
2026-06-29 4089ba01e0881c89a72332e13bc3a80b6bddec2a
inc/ui/Checkout.php
@@ -1,7 +1,10 @@
<?php
namespace JVBase\ui;
use JVBase\base\Site;
use JVBase\integrations\Integrations;
use JVBase\meta\Form;
use JVBase\meta\Meta;
if (!defined('ABSPATH')) {
   exit;
@@ -26,6 +29,15 @@
 */
class Checkout
{
    public static function getProvider():Integrations|false
    {
        foreach (Site::getIntegrations() as $integration => $active) {
            if (in_array($integration, ['square', 'helcim']) && $active) {
                return JVB()->connect($integration);
            }
        }
        return false;
    }
   /**
    * Render the checkout aside and append to actions.
    *
@@ -37,55 +49,58 @@
         return $actions;
      }
      $provider = jvbGetPaymentProvider();
      $provider = self::getProvider();
      if (!$provider || !$provider->isSetUp()) {
         return $actions;
      }
      $providerName = strtolower($provider->getServiceName());
      $form = '<aside id="cart" class="right main">
         <form id="checkout" data-form-id="checkout" data-save="checkout" data-provider="' . esc_attr($providerName) . '">';
      $aside = '<aside id="cart" class="right main"><div class="wrap">';
      $tabs = new Tabs();
      $tabs->addTab('cartItems')
         ->title('Your Cart')
         ->icon('shopping-cart-simple')
         ->description('Here\'s your order. You can change quantities, remove items, or clear your cart. To checkout, click the checkout tab.')
         ->content(self::cartContent($providerName));
      $tabs = [
         'cartItems' => [
            'title'       => 'Your Order',
            'icon'        => 'cart',
            'description' => 'Here\'s your order. You can change quantities, remove items, or clear your cart.',
            'content'     => self::cartContent(),
         ],
         'checkout' => [
            'title'       => 'Checkout',
            'icon'        => 'checkout',
            'description' => apply_filters('jvb_checkout_description',
               'Securely checkout with your name, email, and payment.',
               $providerName
            ),
            'content' => self::checkoutContent($providerName),
         ],
         'order' => [
            'title'       => 'Your Order',
            'icon'        => 'truck',
            'hidden'      => true,
            'description' => '',
            'content'     => self::orderStatus(),
         ],
      ];
      if (!is_user_logged_in()) {
         $tabs->addTab('thelogin')
            ->title('Login')
            ->description('Login to see past orders and access your saved cards')
            ->content(JVB()->magicLink()->renderForm());
      } else {
         $tabs->addTab('account')
            ->title('Account')
            ->description('Manage your contact information, saved cards, and see past orders')
            ->content(self::renderAccount());
      }
      $form .= jvbRenderTabs($tabs, true);
      $tabs->addTab('checkout')
         ->title('Checkout')
         ->icon('hand-coins')
         ->description(apply_filters('jvb_checkout_description',
            'Securely checkout with your name, email, and payment.', $providerName))
         ->content(self::checkoutContent($providerName));
      $form .= '<div class="cart-total row right">
            <p class="tax">Tax: <span></span></p>
            <p class="total">GRAND TOTAL: <span></span></p>
         </div>
      </form>
      $tabs->addTab('order')
         ->title('Your Order')
         ->icon('truck')
         ->hidden()
         ->content(self::orderStatus());
      $aside .= $tabs->render();
      $aside .= '</div>
      </aside>';
      $form .= self::templates($providerName);
      $aside .= self::templates($providerName);
      $actions[] = [
         'button'  => self::toggleButton(),
         'content' => $form,
         'content' => $aside,
      ];
      return $actions;
@@ -100,94 +115,93 @@
    */
   private static function checkoutContent(string $provider): string
   {
      $fields = '<div class="checkout-section">
         <h3>Customer Information</h3>'
         . Form::render('cart_name', null, [
      $name = $email = $phone = '';
      if (is_user_logged_in()) {
         $meta = Meta::forUser(get_current_user_id());
         if ($meta) {
            $name = $meta->get('display_name');
            $email = $meta->get('user_email');
            $phone = $meta->get('phone');
         }
      }
      $form = sprintf(
         '<form id="checkout" data-handled>
            <h3>Your Information</h3>
            %s%s%s',
         Form::render('cart_name', $name, [
            'type'         => 'text',
            'label'        => 'Your Name',
            'required'     => true,
            'autocomplete' => 'name',
         ])
         . Form::render('cart_email', null, [
         ]),
         Form::render('cart_email', $email, [
            'type'         => 'email',
            'label'        => 'Your Email',
            'required'     => true,
            'autocomplete' => 'email',
         ])
         . Form::render('cart_phone', null, [
         ]),
         Form::render('cart_phone', $phone, [
            'type'         => 'tel',
            'label'        => 'Your Phone',
            'required'     => true,
            'autocomplete' => 'phone',
         ]);
         ])
      );
      // Optional sections — integrations can add pickup, scheduling, etc.
      $fields .= apply_filters('jvb_checkout_fields', '', $provider);
      $form .= apply_filters('jvb_checkout_fields', '', $provider);
      $fields .= '</div>';
      // Payment section — provider JS mounts its own UI inside #payment-container
      $fields .= '<div class="checkout-section">
      $form .= '<div class="checkout-section">
         <h3>Payment Information</h3>
         <div id="saved-cards"></div>
         <div id="payment-container" data-provider="' . esc_attr($provider) . '"></div>
      </div>';
      </div>
      </form>';
      return $fields;
      return $form;
   }
   /**
    * Cart items tab: table + account details
    */
   private static function cartContent(): string
   private static function cartContent(string $provider): string
   {
      ob_start();
      ?>
      <div class="cart-items">
      $content = sprintf('<form id="checkout" data-form-id="checkout" data-save="checkout" data-provider="%s">',
            esc_attr($provider)
      );
      $content.= '<div class="cart-items">
         <table>
            <thead>
            <tr>
               <th scope="col">Item</th>
               <th scope="col">Price</th>
               <th scope="col">Total</th>
                    <th scope="col"></th>
            </tr>
            </thead>
            <tbody></tbody>
                <tfoot>
                    <tr>
                        <th scope="col"></th>
                        <th scope="col">TAX</th>
                        <td class="tax"></td>
                        <th scope="col"></th>
                    </tr>
                    <tr>
                        <th scope="col"></th>
                        <th scope="col">Net:</th>
                        <td class="total"></td>
                        <th scope="col"></th>
                    </tr>
                </tfoot>
         </table>
      </div>
      <details class="account">
         <summary>
            <?php
            if (is_user_logged_in()) {
               echo 'Your Favourites and Order History';
            } else {
               echo '<a href="' . wp_login_url(get_the_permalink()) . '">Log in</a> to save your favourites and view order history.';
            }
            ?>
         </summary>
         <?php
         if (is_user_logged_in()) {
            $tabs = [
               'history' => [
                  'title'       => 'Order History',
                  'icon'        => 'checkout',
                  'description' => 'View your past orders and quickly reorder',
                  'content'     => apply_filters('jvb_checkout_order_history', ''),
               ],
               'favourites' => [
                  'title'       => 'Favourites',
                  'icon'        => 'heart',
                  'description' => 'View your favourites',
                  'content'     => apply_filters('jvb_checkout_favourites', ''),
               ],
            ];
            jvbRenderTabs($tabs);
         }
         ?>
      </details>
      <?php
      return ob_get_clean();
      </form>';
      return $content;
   }
   /**
@@ -224,6 +238,11 @@
      return ob_get_clean();
   }
   private static function renderAccount():string
   {
      return '';
   }
   /*****************************************************************
    * TEMPLATES — cloned by JS at runtime
    *****************************************************************/
@@ -235,7 +254,7 @@
      $browseText = apply_filters('jvb_checkout_browse_text', 'browse our products');
      return '<template class="restoredCart">
         <div class="restored">
         <div class="fstatus restored">
            <h3>Looks like we left things hanging</h3>
            <p>We\'ve restored your cart from your last session below.</p>
            <p>If you\'d rather start over, click the button below.</p>
@@ -245,7 +264,12 @@
            </div>
         </div>
      </template>
      <template class="cartItem">
      <template class="mainCartItem">
            <tbody>
                <tr class="header"><th></th></tr>
            </tbody>
        </template>
      <template class="childCartItem">
         <tr class="item">
            <td class="item">
               <label for="quantity"></label>
@@ -275,11 +299,11 @@
    */
   private static function toggleButton(): string
   {
      return '<button type="button" class="toggle-cart row" title="Your Cart"
      return '<button type="button" class="toggle-cart row empty" title="Your Cart"
            data-action="toggle-cart" aria-label="Open Cart"
            aria-controls="checkout" aria-expanded="false">'
         . jvbIcon('shopping-cart')
         . '<span class="abs"></span><span class="abs count"></span>
         . '<span class="abs close"></span><span class="abs count"></span>
      </button>';
   }
}