Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Triumfator's avatar

LIVEWIRE RADIO BUTTONS not functioning properly

Guys i'm having a problem figuring out something with livewire....

Shopping cart Delivery Method radio buttons are not working properly and SHIPPING AND HANDLING cost line in Cart Totals isn't being updated properly (or sometimes it's blank) especially when changing between countries.

I'm using Laravel 8 with livewire, latest versions, with darryldecode/laravelshoppingcart shopping cart package.

Your help would be greatly appreciated.

To Reproduce

  1. Go to dev.razmerautoparts.com
  2. Browse to any item and click on BUY NOW. You will be redirected to shopping cart.
  3. Shipping rate may or may not display properly, depending on your country. Shopping cart determines your country by IP address and if you are in CANADA or UNITED STATES - CONTINENTAL, shipping rate might not show up in cart totals. If you are outside of United States and Canada, your shipping rates will be displayed and GROUND method will be selected automatically and cart totals will be updated. If you select AIR shipping method, your cart totals will update.
  4. If you are outside of UNITED STATES or CANADA. Pick another country from DELIVER TO modal. Select CANADA or UNITED STATES continental. For those 2 countries, by design, only ground service is available by default so no air quotes are given. GROUND SERVICE rates aren't available, so you'll end up with one shipping rate. It will appear next to radio button and radio button appears to be selected, but cart totals will still be carrying old shipping rate from your previous country with AIR shipping method. Notice also that $active_shipping_rate hasn't updated to GROUND on page load. It doesn't get updated when you click on radio button.

Expected behavior

Shipping and handling line must be filled with appropriate amounts on page load and must be updated when radio buttons are manipulated and countries are changed. For UNITED STATES - CONTINENTAL (COUNTRY ID 233) and CANADA (Country ID 39) $active_shipping_rate must be GROUND. All other countries must have $active_shipping_rate set to AIR. Everything should be displayed correctly on page load (without having to click on radio button) and Shipping and Handling amount in cart totals must be properly display. If user changes country on cart page, everything should still work.

This is the Cart.php Livewire page

<?php

namespace App\Http\Livewire\Pages;

use App\Mail\UserWelcomeMail;
use App\Services\PayPalClient;
use Carbon\Carbon;
use App\Models\User;
use App\Models\Order;
use App\Models\Coupon;
use App\Models\Country;
use Livewire\Component;
use App\Models\FedexRate;
use App\Models\OrderItem;
use App\Models\CountryZone;
use Illuminate\Support\Str;
use App\Models\OrderSummary;
use App\Models\PaymentMethod;
use App\Services\CartService;
use App\Http\Traits\DeliverTo;
use App\Http\Traits\Search;
use App\Models\CanadapostRate;
use App\Models\CanadapostRule;
use App\Models\CountryZoneCity;
use App\Models\Item as ItemModel;
use PayPalHttp\HttpException;

class Cart extends Component
{
    use DeliverTo;
    use Search;

    public $coupon_code;
    public $coupon_amount = 0;
    public $items_total;
    public $coupon_applied;
    public $shipping;
    public $tax;
    public $tax_amount = 0;
    public $total_before_tax;
    public $manual_checkout = false;
    public $states = [];
    public $cities = [];
    public $items_volumetric_weight = 0;
    public $items_weights = 0;
    public $items_weights_kg = 0;
    public $shipping_rate = ['ground' => null, 'air' => null];
    public $active_shipping_rate = 'ground';
    public $cart_note;
    public $verifyingPayPalPayment = false;
    public $message = null;
    /**
     * @var mixed|string
     */
    public $paypal_mode;
    public $paypal_clientId;

    public Order $order;
    public $listeners = ['refreshAll' => 'mount'];

    protected $rules = [
        'order.user_id' => 'nullable|numeric|between:0,1000000',
        'order.user_email' => 'nullable|max:191',
        'order.address_company' => 'nullable|max:127',
        'order.address_name' => 'nullable|max:128',
        'order.address_street_1' => 'nullable|max:64',
        'order.address_street_2' => 'nullable|max:64',
        'order.address_city' => 'nullable|max:40',
        'order.address_state' => 'nullable|max:40',
        'order.address_zip' => 'nullable|max:10',
        'order.address_country' => 'nullable|max:40',
        'order.contact_phone' => 'nullable|max:15',
        'order.shipping_charges' => 'required|numeri  c|between:0,100000',
        'order.tax' => 'required|numeric|between:0,100000',
        'order.order_total' => 'required|numeric|between:0,100000',
        'order.payment_method' => 'required|numeric',
        'order.payment_total' => 'required|numeric|between:0,100000',
        'order.payment_fee' => 'required|numeric|between:0,100000',
        'order.payment_net' => 'required|numeric|between:0,100000',
        'order.payment_currency' => 'required|numeric',
        'order.payment_fx_rate' => 'required|numeric',
        'order.payment_converted_total' => 'required|numeric|between:0,100000',
        'order.notes' => 'nullable',
        'order.status' => 'required|numeric',
        'order.notify_customer' => 'required|numeric',
    ];


    public function mount()
    {
        /**
         * @var PayPalClient
         */
        $payPalClient =  app()->get(PayPalClient::class);
        $this->coupon_amount = session('coupon', 0);
        $this->tax_amount = session('tax_amount', 0);
        $this->initializeOrder();
        $this->addItemToCartIfPost();
        $this->removeItemFromCartIfQuantityIsZero();
        $this->countries = Country::orderBy('name', 'asc')->get();
        $this->paypal_mode = $payPalClient->getMode();
        $this->paypal_clientId = $payPalClient->getClientId();
    }
    public function updateItemList()
    {
        session()->put('search_term', $this->search_term);
        return redirect()->route('home');
    }
    public function setup()
    {
        $this->fetchCountry();
        $this->calculateWeights();
        $this->setShippingRate();
        $this->setTaxCondition();
        $this->setShippingCondition();
        $this->refreshStates();
    }
    
    // Vladimir's note: I don't think this checkOut function is being used.
    public function checkOut()
    {
        //save order items

        //make payment
        
        $this->verifyingPayPalPayment = true;

        // This redirection doesn't happen and this route doesn't do anything.
        // This route existed in routes file, and since then have been commented out. 
        redirect()->route('paypal.checkout');

        //empty cart

        //send email

        //respond with thank you

    }

    public function removeItemFromCartIfQuantityIsZero()
    {
        foreach (CartService::getCartItems() as $item) {
            if (!$item->model->quantity) {
                CartService::removeItem($item->id);
            }
        }

        if (count(CartService::getCartItems()) === 0) {
            $this->clearCart();
        }
    }

    public function setShippingRate()
    {
        if (session()->has('shipping_country_id')) {
            $country_id = session()->get('shipping_country_id');
            if (in_array($country_id, [39, 233])) {
                if ($this->items_volumetric_weight > $this->items_weights) {
                    $rate = FedexRate::where('weight_lb', $this->items_volumetric_weight)->first();
                } else {
                    $rate = FedexRate::where('weight_lb', $this->items_weights)->first();
                }
                if ($rate) {
                    $this->shipping_rate['ground'] = ($country_id == 39) ? $rate->canada : $rate->usa;
                    $this->shipping_rate['air'] = null;
                }
            } else {
                // ALL COUNTRIES EXCEPT USA & CANADA
                $canadapostRule = CanadapostRule::where('country_id', $country_id)
                    ->select('air_zone', 'surface_zone')
                    ->first();

                if ($canadapostRule->air_zone) {
                    $air_zone = CanadapostRate::where('weight_kg', $this->items_weights_kg)
                        ->pluck($canadapostRule->air_zone)
                        ->first();
                }
                if ($canadapostRule->surface_zone) {
                    $surface_zone = CanadapostRate::where('weight_kg', $this->items_weights_kg)
                        ->pluck($canadapostRule->surface_zone)
                        ->first();
                }

                $this->shipping_rate['ground']    = $surface_zone ?? null;
                $this->shipping_rate['air']    = $air_zone ?? null;
            }
        }
    }

    public function calculateWeights()
    {
        $items = CartService::getCartItems();
        $items_volumetric_weight = 0;
        $items_weights = 0;
        $items_weights_kg = 0;
        foreach ($items as $item) {
            $items_volumetric_weight += ($item->model->volumetric_weight_pounds * $item->quantity);
            $items_weights += ($item->model->weight * $item->quantity);
            $items_weights_kg += ($item->model->weight_kg * $item->quantity);
        }

        $this->items_volumetric_weight = ceil($items_volumetric_weight);
        $this->items_weights = ceil($items_weights);
        $this->items_weights_kg = ceil($items_weights_kg);
    }
    public function addItemToCartIfPost()
    {
        if (request()->isMethod('POST') && request()->item_id) {
            $result =  CartService::addToCart(request()->item_id, 1);

            session()->flash('message', $result['message']);
            redirect()->route('cart');
            // $this->dispatchBrowserEvent('notify', ['message_type' => $result['message_type'], 'message' => $result['message']]);
        }
    }

    public function initializeOrder()
    {
        $this->order = new Order;
        $this->order->address_country = $this->country_id;
        $this->order->user_email = auth()->check() ? auth()->user()->email : null;
        $this->order->address_name = auth()->check() ? auth()->user()->name : null;

        $this->refreshStates();
        $this->refreshCities();
    }

    public function refreshStates()
    {
        if ($this->country_id)
            $this->states = CountryZone::where('country_id', $this->country_id)->get();
    }

    public function refreshCities()
    {
        if ($this->country_id && $this->order->address_state) {
            $this->cities = CountryZoneCity::where(['country_id' => $this->country_id, 'state_id' => $this->order->address_state])->get();
        }
    }

    public function setShippingCondition()
    {
        if ($this->items_weights_kg > 30 && !in_array($this->country_id, [39, 233])) {
            CartService::removeCondition('Shipping & handling');
            return;
        }
        if ($this->shipping_rate[$this->active_shipping_rate]) {
            $condition = new \Darryldecode\Cart\CartCondition(array(
                'name' => 'Shipping & handling',
                'type' => 'shipping',
                'target' => 'subtotal', // this condition will be applied to cart's subtotal when getSubTotal() is called.
                'value' => "+ {$this->shipping_rate[$this->active_shipping_rate]}",
                'attributes' => array( // attributes field is optional
                    'description' => 'Shipping & handling',
                )
            ));

            CartService::addCondition($condition);
        } else {
            CartService::removeCondition('Shipping & handling');
            return;
        }
    }
    public function setTaxCondition()
    {
        if (session()->get('shipping_country_id') == 39) {
            $this->tax_amount = round($this->computedTotalBeforeTax * 0.05, 2, PHP_ROUND_HALF_UP);
            session()->put('tax_amount', $this->tax_amount);
        } else {
            $this->tax_amount = 0;
            session()->forget('tax_amount');
        }
    }

    public function clearCart()
    {
        CartService::clear();
        $this->coupon_code = null;
        $this->coupon_applied = null;
        $this->total_before_tax = null;
        session()->forget('coupon');
        session()->forget('tax_amount');
        $this->emit('refreshAll');
    }
    public function applyCoupon()
    {
        $this->validate([
            'coupon_code' => 'required|exists:coupons,name'
        ]);
        $coupon = Coupon::where('name', $this->coupon_code)
            ->where('active', 1)
            ->where('expires_at', '>=', Carbon::now()->toDateTimeString())
            ->first();

        if ($coupon) {
            if ($coupon->discount_amount > 0) {
                $this->coupon_amount = $coupon->discount_amount;
            } else {
                $this->coupon_amount =  round(($this->computedItemsTotal + $this->computedShippingCost) * $coupon->discount_percent / 100, 2, PHP_ROUND_HALF_UP);
            }
            session()->put('coupon', $this->coupon_amount);
            $this->mount();
        }
    }
    public function removeItem($item_id)
    {
        CartService::removeItem($item_id);
        $this->removeItemFromCartIfQuantityIsZero();
        $this->emit('refreshAll');
    }

    public function updateQuantity($value, $item_id)
    {
        $item = ItemModel::find($item_id);
        if ($item->quantity >= intval($value)) {
            CartService::updateItemQuantity($value, $item_id);
        } else {
            CartService::updateItemQuantity($item->quantity, $item_id);
            session()->flash("message$item_id", "Only {$item->quantity} item(s) in stock");
            redirect()->route('cart');
        }
        $this->emit('refreshAll');
        $this->mount();
    }
    public function incrementItemInCart($item_id)
    {
        $item = ItemModel::find($item_id);
        if ($item->quantity > CartService::getCartItem($item_id)->quantity) {
            CartService::incrementItemInCart($item_id);
        } else {
            CartService::updateItemQuantity($item->quantity, $item_id);
            session()->flash("message$item_id", "There are only {$item->quantity} items in stock");
        }
        $this->emit('refreshAll');
        $this->mount();
        // $result ?? $this->dispatchBrowserEvent('notify', ['message_type' => $result['message_type'], 'message' => $result['message']]);
    }
    public function decrementItemInCart($item_id)
    {
        CartService::decrementItemInCart($item_id);
        $this->emit('refreshAll');
        $this->mount();
    }

    public function createUser($data)
    {
        $user = new User;
        $user->name = $data['name'];
        $user->email = $data['email'];
        $user->password = bcrypt(Str::random(8));
        $user->save();
        return $user;
    }

    public function getManualCheckoutUser(array $userInfo)
    {
        return User::firstOrCreate(['email'=>$userInfo['email']],$userInfo);
    }
    public function getCheckoutUser($name = null, $paypalData = null)
    {
        if (auth()->guest()) {
            $data = $paypalData
                ? [
                    'email' => $paypalData['payer']['email_address'],
                    'name' => $paypalData['payer']['name']['given_name'] . ' ' . $paypalData['payer']['name']['surname']
                ]
                : [
                    'email' => $this->order->user_email,
                    'name' => $this->order->address_name
                ];
            $userExists = User::where('email', $data['email'])->first();
            if ($userExists) {
                $user = $userExists;
            } else {
                $user = $this->createUser($data);
            }
        } else {
            $user = auth()->user();
        }
        return $user;
    }
    public function getComputedItemsTotalProperty()
    {
        $itemsTotal = 0;
        foreach (CartService::getCartItems() as $item) {
            $itemsTotal += $item->getPriceSum();
        }
        return round($itemsTotal, 2, PHP_ROUND_HALF_UP);
    }

    public function getComputedTotalBeforeTaxProperty()
    {
        return $this->computedItemsTotal + $this->computedShippingCost - $this->coupon_amount;
    }
    public function getComputedShippingCostProperty()
    {
        $shipping = CartService::getCart()->getCondition('Shipping & handling');
        if ($shipping) {
            return round(floatval($shipping->getCalculatedValue($this->computedItemsTotal)), 2, PHP_ROUND_HALF_DOWN);
        }
        return 0;
    }

    public function getComputedOrderTotalProperty()
    {
        return $this->computedTotalBeforeTax + $this->tax_amount;
    }
    public function postCheckout($orderId)
    {
        $paypalClient = app()->get(PayPalClient::class);
        try {
            $data = json_decode(json_encode($paypalClient->captureOrder($orderId)->result), true);
            if ($data['status'] == "COMPLETED") {
                $user = $this->getCheckoutUser(null, $data);

                //save order
                $order = new Order;
                $order->user_id = $user->id;
                $order->user_email = $user->email;
                $order->address_name = $data['purchase_units'][0]['shipping']['name']['full_name'];

                if (array_key_exists('address_line_1', $data['purchase_units'][0]['shipping']['address'])) {
                    $order->address_street_1 = $data['purchase_units'][0]['shipping']['address']['address_line_1'];
                }

                $order->address_city  = $data['purchase_units'][0]['shipping']['address']['admin_area_2'];
                $order->address_state  =  optional(
                    CountryZone::where('id', optional(
                        CountryZoneCity::where([
                            'state_code' => $data['purchase_units'][0]['shipping']['address']['admin_area_1'],
                            'country_code' => $data['purchase_units'][0]['shipping']['address']['country_code'],
                        ])->first()
                    )->state_id)->first()
                )->name;

                $order->address_zip  = $data['purchase_units'][0]['shipping']['address']['postal_code'];
                $order->address_country  = optional(Country::where('code', $data['purchase_units'][0]['shipping']['address']['country_code'])->first())->name;
                $order->discount_code = $this->coupon_code;
                $order->discount = $this->coupon_amount ?? 0.00;
                $order->shipping_charges = $this->computedShippingCost;
                $order->tax = $this->tax_amount ?? 0.00;
                $order->order_total = $this->computedOrderTotal;
                $order->payment_method = PaymentMethod::where('name', 'Paypal')->first()->id;
                $order->payment_total = floatval($data['purchase_units'][0]['payments']['captures'][0]['seller_receivable_breakdown']['gross_amount']['value']);
                $order->payment_fee = floatval($data['purchase_units'][0]['payments']['captures'][0]['seller_receivable_breakdown']['paypal_fee']['value']);
                $order->payment_net = floatval($data['purchase_units'][0]['payments']['captures'][0]['seller_receivable_breakdown']['net_amount']['value']);
                $order->payment_currency = ($data['purchase_units'][0]['payments']['captures'][0]['seller_receivable_breakdown']['gross_amount']['currency_code']) == "USD" ? 1 : 2;
                $order->payment_fx_rate = 1;
                $order->payment_noon_rate = 1;
                // Before order is processed and funds are withdrawn from paypal, assume currency conversion rate is 1. Multiply by noon rate when that feature will be implemented.
                $order->payment_converted_total = floatval($data['purchase_units'][0]['payments']['captures'][0]['seller_receivable_breakdown']['net_amount']['value']);
                $order->status = 1;
                $order->notify_customer = 0;
                $order->stocksubstracted = 0;
                $order->notes = $this->cart_note;
                $order->save();

                //save order items
                $orderItems = CartService::getCartItems();
                foreach ($orderItems as $item) {
                    $order_item = new OrderItem();
                    $order_item->order_id = $order->id;
                    $order_item->item_id = $item->id;
                    $order_item->price = floatval($item->price);
                    $order_item->quantity = floatval($item->quantity);
                    $order_item->save();
                }

                //store order summary
                $order_summary = new OrderSummary();
                $order_summary->order_id = $order->id;
                $order_summary->items_cost = 0;
                $order_summary->company_id = 1;
                $order_summary->shipping_charge_by_exchange_rate = $order->shipping_charges * $order->payment_fx_rate;
                $order_summary->save();
                CartService::emptyCart();
                $this->verifyingPayPalPayment = false;
                return redirect()->route('post-checkout', $order->id);
            }
        } catch (HttpException $exception) {
            $this->verifyingPayPalPayment = false;
            $message = $exception->statusCode;
            $this->message = "Unable to verify payment please due to {$message} please contact us.";
        } catch (\Exception $exception) {
            $this->verifyingPayPalPayment = false;
            $message = $exception->getMessage();
            \Log::error("{$message}, order-{$orderId}");
            $this->message = "Unable to verify payment";
        }
    }
    public function manualCheckout()
    {
        $user = $this->getManualCheckoutUser([
            'email'=>$this->order->user_email,
            'name'=>$this->order->address_name,
        ]);

        $this->order->user_id = $user->id;
        $this->order->discount_code = $this->coupon_code;
        $this->order->discount = $this->coupon_amount ?? 0.00;
        $this->order->shipping_charges = $this->computedShippingCost;
        $this->order->tax = $this->tax_amount;
        $this->order->order_total = $this->computedOrderTotal;
        $this->order->payment_total = 0;
        $this->order->payment_fee = 0;
        $this->order->payment_net = 0;
        $this->order->payment_currency = 1;
        $this->order->payment_method = 2;
        $this->order->payment_fx_rate = 1;
        $this->order->payment_noon_rate = 1;
        $this->order->payment_converted_total = 0;
        $this->order->status = 1;
        $this->order->notify_customer = 0;
        $this->order->stocksubstracted = 0;
        $this->order->notes = $this->cart_note;
        $this->order->save();

        //save order items
        $orderItems = CartService::getCartItems();
        foreach ($orderItems as $item) {
            $order_item = new OrderItem();
            $order_item->order_id = $this->order->id;
            $order_item->item_id = $item['id'];
            $order_item->price = floatval($item['price']);
            $order_item->quantity = floatval($item['quantity']);
            $order_item->save();
        }

        //store order summary
        $order_summary = new OrderSummary();
        $order_summary->order_id = $this->order->id;
        $order_summary->items_cost = $this->computedItemsTotal;
        $order_summary->company_id = 1;
        $order_summary->shipping_charge_by_exchange_rate = $this->order->shipping_charges * $this->order->payment_fx_rate;
        $order_summary->save();

        CartService::emptyCart();

        return redirect()->route('post-checkout', $this->order->id);
    }
    public function render()
    {
        $this->setup();
        $this->order->address_country = $this->country_id;
        $cartItems =  CartService::getCartItems()->sortBy('attributes.created_at');
        return view('livewire.pages.cart')
            ->with([
                'cartItems' => $cartItems
            ])
            ->layout('layouts.guest');
    }
}

This is the cart.blade.php file

<div class="mt-12 bg-gray-200">
    <div class="container mx-auto px-6 py-10 bg-white">
        <div class="flex-wrap flex mb-8 ">
            @include('components.search')
            <livewire:components.deliver :countries="$countries" :key="'tempkey'" />
        </div>
        <!-- Breadcrums navigation start -->
        <nav class="w-full m-2">
            <ol class="list-reset flex text-gray-800">
                <li><a href="/" class="text-gray-800 font-bold">Home</a></li>
                <li><span class="mx-2">></span></li>
                <li><a href="#">Cart</a></li>
            </ol>
        </nav>
        <!-- Breadcrums navigation end -->

        <!-- Shopping cart block start  -->
        <div>
            @if ($cartItems->count())
            <div class="flex justify-center">
                <div class="flex flex-wrap-reverse">
                    <div class="w-full sm:w-2/3 h-auto mt-2 px-4 sm:px-4 md:px-0 lg:px-0 xl:px-0">

                        @include('components.message')

                        <!-- Shopping cart items start -->
                        <div class="text-gray-700 bg-white shadow-lg p-8">
                            <h3 class="font-bold text-xl pb-3 text-center sm:text-left">
                                Cart Items</h3>

                            <!--This section disappears at small and medium resolution -->
                            <div class="hidden md:block">
                                <div class="flex justify-between border-b border-gray-600">
                                    <div class="w-3/5 pb-2">
                                        <p class="text-sm font-bold uppercase">Product</p>
                                    </div>
                                    <div class="w-1/5 pb-2 text-center">
                                        <p class="text-sm font-bold uppercase">Quantity</p>
                                    </div>
                                    <div class="w-1/5 pb-2 text-right">
                                        <p class="text-sm font-bold uppercase">Price</p>
                                    </div>
                                </div>
                            </div>
                            <!-- Individual cart product display for medium and larger resolutions -->
                            @foreach ($cartItems as $item)
                            <div>
                                <div class="border-b border-gray-600 flex-row justify-between items-center md:flex hidden md:visible">
                                    <button wire:click="removeItem({{ $item->id }})" class="text-gray-800 rounded-md p-2 mx-1 hover:bg-gray-200 focus:outline-none invisible md:visible">
                                        <svg class="h-4 w-4" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor">
                                            <path d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z">
                                            </path>
                                        </svg>
                                    </button>
                                    <div class="w-full md:w-3/5 flex flex-row items-center pt-0 pb-0 text-left">
                                        <div class="w-20 mx-0 pr-0">
                                            <div class="h-20 rounded flex items-center justify-center">
                                                <div class="w-16 h-12 mx-auto bg-center bg-no-repeat bg-cover" style="background-image:url({{ optional(optional($item->model->itemimages())->first())->small_url }})">
                                                </div>
                                            </div>
                                        </div>
                                        <div class="text-base my-2 mx-2">{{ $item->name }}</div>
                                    </div>
                                    <div class="w-1/5 text-center pb-4">
                                        <input type="number" id="quantity-form-desktop" value="{{ $item->quantity }}" wire:change.prevent="updateQuantity($event.target.value,{{ $item->id }})" class="form-input form-quantity rounded-r-none border w-16 py-0 px-0 text-center" x-model="productQuantity" max="{{ $item->model->quantity }}" min="1">
                                    </div>
                                    <div class="w-1/5 text-right pb-4">
                                        <span class="">${{ $item->getPriceSum() }}</span>
                                    </div>
                                </div>
                                <div class="w-full">
                                    @if (session()->has(" message$item->id"))
                                    <p class="text-right text-red-700 mt-2 mr-3">
                                        {{ session()->get("message$item->id") }}
                                    </p>
                                    @endif
                                </div>
                            </div>
                            @endforeach


                            <span>
                                @if (isset($cartItems))
                                @foreach ($cartItems as $item)
                                <!-- Individual cart product display for small resolutions -->
                                <div class="flex md:hidden mb-5 pb-5 border-b border-gray-600 items-center justify-center">
                                    <div class="w-20 mx-0 pr-0">
                                        <div class="h-20 rounded flex items-center justify-center">
                                            <div class="w-16 h-12 mx-auto bg-center bg-no-repeat bg-cover" style="background-image:url({{ optional(optional($item->model->itemimages())->first())->small_url }})">
                                            </div>
                                        </div>
                                    </div>
                                    <div class="pl-2">
                                        <span class="font-bold text-base my-2">{{ $item->name }}</span>
                                        <span class="block">${{ $item->price }}</span>
                                        <div class="w-2/3 sm:w-5/6 flex mt-2" x-data="{ productQuantity: 1 }">
                                            <input type="number" id="quantity-form-mobile" class="form-input form-quantity border border-0 border-gray-500 rounded-l w-10 py-1 px-2 text-center bg-gray-100" wire:change="updateQuantity($event.target.value,{{ $item->id }})" value="{{ $item->quantity }}" min="1" />
                                            <div class="flex flex-row">
                                                <span class="px-2 bg-white flex-1 border border-0 border-gray-500 cursor-pointer flex items-center justify-center" wire:click="decrementItemInCart({{ $item->id }})"><svg class="h-5 w-3" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor">
                                                        <path d="M16.707 10.293a1 1 0 010 1.414l-6 6a1 1 0 01-1.414 0l-6-6a1 1 0 111.414-1.414L9 14.586V3a1 1 0 012 0v11.586l4.293-4.293a1 1 0 011.414 0z">
                                                        </path>
                                                    </svg></span>
                                                <span class="px-2 bg-white flex-1 border border-0 border-gray-500 rounded-r cursor-pointer flex items-center justify-center" wire:click="incrementItemInCart({{ $item->id }})">
                                                    <svg class="h-5 w-3" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor">
                                                        <path d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L11 5.414V17a1 1 0 11-2 0V5.414L4.707 9.707a1 1 0 01-1.414 0z">
                                                        </path>
                                                    </svg></span>
                                                <span class="px-2 ml-5 bg-white border border-0 border-gray-500 flex-1 rounded cursor-pointer flex items-center justify-center" wire:click="removeItem({{ $item->id }})">
                                                    <svg class="h-5 w-4" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor">
                                                        <path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16">
                                                        </path>
                                                    </svg>
                                                </span>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                @endforeach
                                @endif
                            </span>

                            <!-- Buttons at bottom of shipping cart -->
                            <div class="flex flex-col sm:flex-row sm:justify-between sm:items-center pt-8 sm:pt-12">
                                <a href="{{ route('home') }}" class="whitespace-nowrap px-16 sm:px-20 py-2 text-base text-gray-900 bg-white border border-gray-900 hover:bg-gray-200 hover:border hover:border-gray-200 p-3 duration-300">CONTINUE
                                    SHOPPING</a>
                            </div>
                        </div>
                    </div>
                    <!-- Shopping cart items end -->

                    <!-- Shopping cart totals start -->

                    <div class="w-full sm:w-1/3 h-auto mt-2 px-8 sm:px-2">
                        <div class="mx-auto sm:mx-0 mt-0 md:mt-0 bg-gray-100 shadow-lg">
                            <div class="p-8">
                                <h3 class="font-bold text-xl pb-3 text-center sm:text-left">
                                    Cart Totals</h3>
                                <div>
                                    <p class="font-xs tracking-tightest pt-1 pb-1 text-red-500">Active_shipping_rate = {{$active_shipping_rate}} </p>
                                    <p class="font-bold tracking-tight pt-1 pb-2">Delivery Method</p>
                                    @if ($items_weights_kg > 30 && !in_array($country_id, [39, 233]))
                                    <div class="pt-6">
                                        <p class="font-bold tracking-tight pt-1 pb-4">Total Weight</p>
                                        <div class="pb-1 flex justify-between">
                                            <span class="flex-wrap">Weight:</span>
                                            <span class="">{{ $items_weights_kg ? "$items_weights_kg kg" : '-' }}</span>
                                        </div>
                                        <div>
                                            <p class="text-red-700 mt-2">ITEMS EXCEED MAXIMUM COMBINED SHIPPING
                                                WEIGHT
                                                AND/OR DIMENSIONS. REMOVE ITEMS FROM CART AND TRY AGAIN</p>

                                        </div>
                                    </div>
                                    @else
                                    <div class="flex justify-between w-auto">
                                        @if ($shipping_rate['air'])
                                        <label class="inline-flex">
                                            <input wire:click="$set('active_shipping_rate','air')" type="radio" name="delivery_method" class="form-radio h-5 w-5 text-gray-600" checked><span class="ml-2 text-gray-700">AIR:
                                                {{ "$" . $shipping_rate['air'] }}
                                                (7-12 business days)</span>
                                        </label>
                                        @endif
                                    </div>
                                    <div class="flex justify-between w-auto">
                                        @if ($shipping_rate['ground'])
                                        <label class="inline-flex">
                                            <input wire:click="$set('active_shipping_rate','ground')" type="radio" name="delivery_method" class="form-radio h-5 w-5 text-gray-600" checked><span class="ml-2 text-gray-700">GROUND:
                                                {{ "$" . $shipping_rate['ground'] }}
                                                {{ in_array($country_id, [39, 233]) ? '(2-7 days)' : '(4-8 weeks)' }}</span>
                                        </label>
                                        @endif
                                    </div>
                                    @endif
                                </div>
                                <div class="pt-4">
                                    <p class="font-bold pt-1 pb-2">Cart Note</p>
                                    <label for="cart_note" class="block relative h-0 w-0 overflow-hidden">Cart
                                        Note</label>
                                    <textarea wire:model="cart_note" rows="3" class="w-full p-2 bg-white rounded border border-gray-400" placeholder="If you have special order instructions, enter them here..."></textarea>
                                </div>
                                <div class="pt-4">
                                    <p class="font-bold tracking-tight pt-1 pb-2">Coupon Code</p>
                                    <div class="flex justify-between w-auto">
                                        <label for="discount_code" class="block relative overflow-hidden">Discount
                                            Code</label>
                                        <input wire:model="coupon_code" type="text" placeholder="Discount code" class="pr-2 w-3/5 xl:w-2/3 form-input border border-gray-400" id="discount_code">
                                        <button wire:click="applyCoupon" class="px-2 py-1 rounded bg-white hover:bg-white focus:outline-white focus:bg-white border border-gray-400" aria-label="Apply button">Apply</button>
                                    </div>
                                    <div class="w-full">
                                        @error('coupon_code')
                                        <p class="text-red-700">{{ $message }}</p>
                                        @enderror
                                    </div>
                                </div>

                                <div class="mb-10 pt-6">
                                    <p class="font-bold tracking-tight pt-1 pb-4">Cart Total</p>
                                    <div class="pb-1 flex justify-between border-b border-gray-600">
                                        <span class="flex-wrap">Items total:</span>
                                        <span class="">{{ $this->computedItemsTotal ? "$$this->computedItemsTotal" : '-' }}</span>
                                    </div>
                                    <div class="pb-1 flex justify-between border-b border-gray-600">
                                        <span class="flex-wrap">Shipping & handling:</span>
                                        <span class="">{{ $this->computedShippingCost ? "$$this->computedShippingCost" : '-' }}</span>
                                    </div>

                                    <div class="pb-1 flex justify-between border-b border-gray-600">
                                        <span class="flex-wrap">Coupon applied</span>
                                        <span class="">{{ $coupon_amount ? "-$" . abs($coupon_amount) : '-' }}</span>
                                    </div>
                                    <div class="pb-1 flex justify-between border-b border-gray-600">
                                        <span class="flex-wrap">Total before tax:</span>
                                        <span class="">{{ $this->computedTotalBeforeTax ? "$$this->computedTotalBeforeTax" : '-' }}</span>
                                    </div>
                                    <div class="pb-1 flex justify-between border-b border-gray-600">
                                        <span class="flex-wrap">Tax:</span>
                                        <span class="">{{ $tax_amount ? "$$tax_amount" : '-' }}</span>
                                    </div>
                                    <div class="pb-1 flex justify-between">
                                        <span class="font-bold flex-wrap">Total:</span>
                                        <span class="font-bold">${{ $this->computedTotalBeforeTax + $this->tax_amount }}</span>
                                    </div>
                                </div>
                                <div class="flex justify-center w-auto">
                                    @if (in_array($country_id, [178, 233, 251, 39]))
                                    {{-- <button wire:ignore id="paypal-button" --}}
                                    {{-- class="px-8 py-2 bg-indigo-700 text-white text-sm font-medium rounded hover:bg-indigo-500 focus:outline-none focus:bg-indigo-500">CHECKOUT --}}
                                    {{-- WITH PAYPAL</button> --}}
                                    <div wire:ignore id="paypal-button" style="z-index: 1"></div>
                                    @endif
                                </div>
                                <div class="pt-4 flex justify-center w-auto">
                                    @if ($items_weights_kg < 30 && !in_array($country_id, [39, 233])) <button wire:click="$toggle('manual_checkout',true)" class="px-16 sm:px-20 py-2 text-base text-white bg-gray-900 border border-gray-900 hover:bg-gray-200 hover:border hover:border-gray-200 hover:text-gray-900 p-3 duration-300">MANUAL
                                        CHECKOUT<BR>
                                        <div class="text-xs">(Bank wire, Interac e-Transfer, Money Order,
                                            Western
                                            Union,
                                            MoneyGram)</div>
                                        </button>
                                        @endif
                                        @if (($items_weights_kg > 30 && in_array($country_id, [39, 233])) || ($items_weights_kg < 30 && in_array($country_id, [39, 233]))) <button wire:click="$toggle('manual_checkout',true)" class="px-16 sm:px-20 py-2 text-base text-white bg-gray-900 border border-gray-900 hover:bg-gray-200 hover:border hover:border-gray-200 hover:text-gray-900 p-3 duration-300">MANUAL
                                            CHECKOUT<BR>
                                            <div class="text-xs">(Bank wire, Interac e-Transfer, Money Order,
                                                Western
                                                Union,
                                                MoneyGram)</div>
                                            </button>
                                            @endif
                                </div>
                                @if ($manual_checkout)
                                <div class="pt-4">
                                    <p class="font-bold tracking-tight pt-1 pb-4">Shipping Address</p>
                                    <div>
                                        <label for="user_email" class="text-sm font-bold text-gray-700">Email</label>
                                        <input id="user_email" wire:model="order.user_email" class="p-1 mt-1 form-input border border-gray-400 w-full">
                                    </div>
                                    <div>
                                        <label for="contact_phone" class="text-sm font-bold text-gray-700">Contact
                                            Phone</label>
                                        <input id="contact_phone" wire:model="order.contact_phone" class="p-1 mt-1 form-input border border-gray-400 w-full">
                                    </div>
                                    <div>
                                        <label for="address_name" class="text-sm font-bold text-gray-700">Full
                                            name</label>
                                        <input id="address_name" wire:model="order.address_name" class="p-1 mt-1 form-input border border-gray-400 w-full">
                                    </div>
                                    <div>
                                        <label for="address_company" class="text-sm font-bold text-gray-700">Company</label>
                                        <input id="address_company" wire:model="order.address_company" class="p-1 mt-1 form-input border border-gray-400 w-full">
                                    </div>
                                    <div>
                                        <label for="address_street_1" class="text-sm font-bold text-gray-700">Address
                                            line 1</label>
                                        <input id="address_street_1" wire:model="order.address_street_1" class="p-1 mt-1 form-input border border-gray-400 w-full">
                                    </div>
                                    <div>
                                        <label for="address_street_2" class="text-sm font-bold text-gray-700">Address
                                            line 2</label>
                                        <input id="address_street_2" wire:model="order.address_street_2" class="p-1 mt-1 form-input border border-gray-400 w-full">
                                    </div>
                                    <div>
                                        <label for="address_country" class="text-sm font-bold text-gray-700">Country</label>
                                        <select wire:change="refreshStates" name="address_country" wire:model="order.address_country" class="py-1 p-0 mt-1 form-input border border-gray-400 w-full">
                                            <option value="0" selected="selected">Select country...</option>
                                            @foreach ($countries as $country)
                                            <option value="{{ $country->id }}">{{ $country->name }}
                                            </option>
                                            @endforeach
                                        </select>
                                    </div>
                                    <div>
                                        <label for="address_state" class="text-sm font-bold text-gray-700">State</label>
                                        <select wire:change="refreshCities" name="address_state" wire:model="order.address_state" class="py-1 p-0 mt-1 form-input border border-gray-400 w-full">
                                            <option value="0" selected="selected">Select state...</option>
                                            @foreach ($states as $state)
                                            <option value="{{ $state->id }}">{{ $state->name }}
                                            </option>
                                            @endforeach
                                        </select>
                                    </div>
                                    <div>
                                        <label for="address_city" class="text-sm font-bold text-gray-700">City</label>
                                        <select {{ !isset($country_id) || !isset($order->address_state) ? 'disabled' : '' }} id="address_city" name="address_city" wire:model="order.address_city" class="py-1 p-0 mt-1 form-input border border-gray-400 w-full">
                                            <option value="0" selected="selected">Select city...</option>
                                            @foreach ($cities as $city)
                                            <option value="{{ $city->id }}">{{ $city->name }}
                                            </option>
                                            @endforeach
                                        </select>
                                    </div>
                                    <div>
                                        <label for="address_zip" class="text-sm font-bold text-gray-700">Postal
                                            Code</label>
                                        <input id="address_zip" wire:model="order.address_zip" class="p-1 mt-1 form-input border border-gray-400 w-full">
                                    </div>
                                    <div class="pt-4 flex justify-center w-auto">
                                        <button wire:click="manualCheckout" class="px-16 sm:px-20 py-2 text-base text-white bg-gray-900 border border-gray-900 hover:bg-gray-200 hover:border hover:border-gray-200 hover:text-gray-900 p-3 duration-300">PLACE
                                            YOUR ORDER</button>
                                    </div>

                                </div>
                                <div class="pt-4 flex justify-center w-auto text-gray-700 text-sm">We will
                                    e-mail
                                    you payment instructions after you place your order.</div>
                                @endif
                            </div>
                        </div>

                    </div>
                    <!-- Shopping cart totals end -->
                </div>
            </div>
            @else
            <div class="mt-10 mb-10 mx-2">Your cart is empty...</div>
            <a href="{{ route('home') }}" class="whitespace-nowrap px-16 sm:px-20 py-2 text-base text-gray-900 bg-white border border-gray-900 hover:bg-gray-200 hover:border hover:border-gray-200 p-3 duration-300">CONTINUE
                SHOPPING</a>
            @endif
        </div>


    </div>
    <div>
        @if (in_array($country_id, [178, 233, 251, 39]) && $cartItems->count())
        <script src="https://www.paypal.com/sdk/js?client-id={{ $paypal_clientId }}"></script>
        <script>
            window.addEventListener('contentChanged', event => {
                init();
            });

            function init() {
                paypal.Buttons({
                    env: '{{ $paypal_mode }}',
                    createOrder: function(data, actions) {
                        // console.log(data,actions)
                        // return actions.request.post('/api/create-payment').then(function(res) {
                        //     console.log(res)
                        //     return res.id;
                        // })
                        return fetch('/api/create-payment', {
                                method: 'post',
                                headers: {
                                    'content-type': 'application/json'
                                }
                            }).then(res => res.json())
                            .then(data => data.id)
                            .catch(err => {
                                alert(err.message)
                            })
                    },
                    onApprove: function(data, actions) {
                        @this.set('verifyingPayPalPayment', true);
                        @this.postCheckout(data.orderID);
                    }
                }).render('#paypal-button')
            }
            init();
        </script>
        @endif
    </div>
</div>

This is the Deliver To Country trait that also plays a role.


<?php

namespace App\Http\Traits;

use Exception;
use App\Models\Country;
use App\Models\FedexRate;
use App\Models\CanadapostRate;
use App\Models\CanadapostRule;

trait DeliverTo
{
    public $countries = [];
    public $country_id;
    public $country_name;
    public $country_code = 'US';
    public $volumetric_weight;

    public function fetchCountry()
    {
        if(session()->get('shipping_country_id')){
            $this->country_id = session()->get('shipping_country_id');
            $this->country_name = session()->get('shipping_country_name');

            return;
        }

        $remote  = @$_SERVER['REMOTE_ADDR'];
        $country = Country::getCountryFromExternalApi($remote );
        $this->country_id =  $country ? $country->id : '233';
        $this->country_name =  $country ? $country->name : 'United States - Continental';
        session()->put('shipping_country_id',$this->country_id);
        session()->put('shipping_country_name', $this->country_name);
    }

}

0 likes
6 replies
Snapey's avatar

Do you think you can boil the question down to just the relevant facts?

2 likes
jlrdw's avatar

If this is a project you need to get done in a certain time, have you considered getting help from a Laravel / Livewire developer on the larajobs site or hire a consultant from some where.

That is a lot of code you posted to troubleshoot.

Triumfator's avatar

Basically here's what happens in summary...

I have a variable $active_shipping_rate In my livewire component, i have this declaration: public $active_shipping_rate = 'ground';

I have radio buttons with a name "active_shipping_rate"

Sometimes only one radio button is displayed if either ground or air rates aren't available for a particular country.

My cart has a function computedShippingCost that returns $shipping value.

This $shipping value is an array that is controlled by $active_shippiing_rate variable. The array has two values, one of which can null depending if a country that user specifies has available ground or air rates. Sometimes only ground rates are available. In other cases only air rates are available and in other instances there can be 2 rates available.

My blade file displays selected shipping rate via this variable {{ $this->computedShippingCost ? "$$this->computedShippingCost" : '-' }}

Problem exists in livewire updating everything perfectly each time a user changes their country as you can try out yourself at the url i posted in original post.

I checked out Larajobs and there are pretty much serious full time job posts. I haven't been able to find anyone who could do it on Fiverr. It seems that this is a pretty crazy situation.

My problem can be solved if somehow I could bind radio buttons to wire.model AND AT THE SAME TIMEuse a wire.click=$set('active_shipping_rate','air') feature but i hear you can't do that with livewire.

If anyone is willing to help me out, I'll gladly PAY for your time.

I have a github, so getting to the entire project should not be a problem if you decide to tackle it.

Snapey's avatar

Still too many words, and the problem is yet not clear.

My problem can be solved if somehow I could bind radio buttons to wire.model AND AT THE SAME TIMEuse a wire.click=$set('active_shipping_rate','air') feature but i hear you can't do that with livewire.

why would you need to do that? You can change the shipping rate in the backend when the radios change.

Snapey's avatar

Its not possible to see the issue with the polling enabled

Triumfator's avatar

It's no longer possible to see the problem with polling enabled and I know it's not the best solution but a temporary bandaid fix. i'll rewrite the shopping cart soon and this won't be happening.

Please or to participate in this conversation.