瀏覽代碼

Invoice-center - customer portal UI and linkage

Vijayakrishnan 3 年之前
父節點
當前提交
1164a30668

+ 7 - 0
app/Http/Controllers/InvoiceController.php

@@ -139,6 +139,13 @@ class InvoiceController extends Controller
         return view('app.invoice-center.ic-pay-invoice', compact('invoice', 'customer', 'company'));
     }
 
+    public function icCustomerPortal(Request $request, $customerSlug) {
+        $customer = Customer::where('slug', $customerSlug)->where('is_active', true)->first();
+        if (!$customer) abort(404);
+        $company = $customer->company;
+        return view('app.invoice-center.ic-customer-portal', compact('customer', 'company'));
+    }
+
     public function companySuggestJSON(Request $request) {
         $term = $request->input('term') ? trim($request->input('term')) : '';
         if (empty($term)) return '';

+ 5 - 0
resources/views/app/invoice-center/customers.blade.php

@@ -53,6 +53,7 @@
                 <th class="border-bottom-0">Company</th>
                 <th class="border-bottom-0">Customer<br>Balance</th>
                 <th class="border-bottom-0">Pending Invoices<br>Balance</th>
+                <th class="border-bottom-0">Portal</th>
                 <th class="border-bottom-0">Created</th>
                 <th class="border-bottom-0">Active?</th>
                 <th class="border-bottom-0"></th>
@@ -79,6 +80,10 @@
                     <td>{{ $record->company ? $record->company->name : '-' }}</td>
                     <td>${{ is_null($record->customer_balance) ? 0 : $record->customer_balance }}</td>
                     <td>${{ is_null($record->pending_invoices_balance_total) ? 0 : $record->pending_invoices_balance_total }}</td>
+                    <td>
+                        <a href="{{route('icCustomerPortal', ['customerSlug' => $record->slug])}}" native target="_blank">Visit</a>
+                        <a href="#" data-target="{{route('icCustomerPortal', ['customerSlug' => $record->slug])}}" native target="_blank" class="copy-target ml-1">Copy</a>
+                    </td>
                     <td>{{ friendly_date($record->created_at) }}</td>
                     <td class="{{ !$record->is_active ? 'text-warning-dark' : ''}}">{{ $record->is_active ? 'Yes' : 'No' }}</td>
                     <td>

+ 90 - 0
resources/views/app/invoice-center/ic-customer-portal.blade.php

@@ -0,0 +1,90 @@
+@extends ('layouts.ic')
+@section('content')
+<div class="container mcp-theme-1">
+    <div class="d-flex align-items-baseline mt-3 mb-2">
+        <h3 class="font-size-16 font-weight-bold text-dark">{{$customer->client->displayName()}} / {{$company->name}}</h3>
+        <a href="{{config('app.stagfe6_url')}}" class="ml-auto">
+            <i class="fa fa-power-off"></i>
+            Exit
+        </a>
+    </div>
+    <hr class="mt-0 mb-3">
+    <div class="row">
+        <div class="col-md-8">
+            <div class="mb-3 font-weight-bold">Invoices</div>
+            @if(count($customer->invoices))
+                <table class="table table-sm table-bordered">
+                    <thead>
+                    <tr>
+                        <th class="border-bottom-0 text-secondary bg-light">Date</th>
+                        <th class="border-bottom-0 text-secondary bg-light">Particulars</th>
+                        <th class="border-bottom-0 text-secondary bg-light">Total</th>
+                        <th class="border-bottom-0 text-secondary bg-light">Paid</th>
+                        <th class="border-bottom-0 text-secondary bg-light">Due</th>
+                    </tr>
+                    </thead>
+                    <tbody class="font-weight-normal">
+                    <?php
+                    $totalAmount = 0;
+                    $totalPaid = 0;
+                    $totalBalance = 0;
+                    ?>
+                    @foreach($customer->invoices as $invoice)
+                        <tr>
+                            <td>{{friendly_date($invoice->created_at)}}</td>
+                            <td><a href="{{route('icPayInvoice', ['invoiceSlug' => $invoice->payment_link_slug])}}">{{$invoice->description}}</a></td>
+                            <td class="text-dark">${{!is_null($invoice->amount) ? $invoice->amount : 0}}</td>
+                            <td class="text-success">${{!is_null($invoice->paid) ? $invoice->paid : 0}}</td>
+                            <td class="font-weight-bold text-warning-dark">${{!is_null($invoice->balance) ? $invoice->balance : 0}}</td>
+                            <?php
+                            $totalAmount += (!is_null($invoice->amount) ? $invoice->amount : 0);
+                            $totalPaid += (!is_null($invoice->paid) ? $invoice->paid : 0);
+                            $totalBalance += (!is_null($invoice->balance) ? $invoice->balance : 0);
+                            ?>
+                        </tr>
+                    @endforeach
+                    <tr>
+                        <td class="p-3 text-right" colspan="5">
+                            <div class="d-flex justify-content-end align-items-baseline mb-2">
+                                <span class="text-secondary">Total Amount: </span>
+                                <span class="width-50px text-left text-secondary font-weight-bold pl-2">${{$totalAmount}}</span>
+                            </div>
+                            <div class="d-flex justify-content-end align-items-baseline mb-2">
+                                <span class="text-secondary">Total Paid: </span>
+                                <span class="width-50px text-left text-secondary font-weight-bold pl-2">${{$totalPaid}}</span>
+                            </div>
+                            <div class="d-flex justify-content-end align-items-baseline">
+                                <span class="font-weight-bold text-secondary">Total Due: </span>
+                                <span class="width-50px text-left font-weight-bold pl-2 font-size-14">${{$totalBalance}}</span>
+                            </div>
+                        </td>
+                    </tr>
+                    </tbody>
+                </table>
+            @else
+                <div class="text-secondary">No invoices yet!</div>
+            @endif
+        </div>
+        <div class="col-md-4 border-left">
+            <div class="mb-3">
+                <span class="font-weight-bold text-secondary">Current Balance: </span>
+                <span class="font-weight-bold text-dark">${{!is_null($customer->customer_balance) ? $customer->customer_balance : 0}}</span>
+            </div>
+            <h3 class="font-weight-bold mb-2 text-secondary">Redeem Gift Card</h3>
+            <div moe>
+                <form url="/api/giftCard/redeem" show>
+                    <input type="hidden" name="customerUid" value="{{$customer->uid}}">
+                    <p class="mb-2">If you have a gift card from {{$company->name}}, please enter its code below:</p>
+                    <div class="mb-2">
+                        <input type="text" name="code" placeholder="Code" class="form-control form-control-sm">
+                    </div>
+                    <div class="text-left">
+                        <button submit class="btn btn-sm btn-primary mr-2">Submit</button>
+                        <button cancel class="btn btn-sm btn-default border">Cancel</button>
+                    </div>
+                </form>
+            </div>
+        </div>
+    </div>
+</div>
+@endsection

+ 9 - 3
resources/views/app/invoice-center/ic-pay-invoice.blade.php

@@ -1,8 +1,14 @@
-@extends ('layouts.guest_template')
+@extends ('layouts.ic')
 @section('content')
 <div class="container mcp-theme-1">
-    <h3 class="font-size-16 font-weight-bold my-3 text-dark">Invoice</h3>
-    <hr>
+    <div class="d-flex align-items-baseline mt-3 mb-2">
+        <h3 class="font-size-16 font-weight-bold text-dark">Invoice</h3>
+        <a href="{{route('icCustomerPortal', ['customerSlug' => $customer->slug])}}" class="ml-auto">
+            <i class="fa fa-chevron-left"></i>
+            Back to Home
+        </a>
+    </div>
+    <hr class="mt-0 mb-3">
     <div class="row">
         <div class="col-md-8">
             <div class="mb-3">Hi <b class="text-dark">{{$customer->client->displayName()}}</b>, please find your invoice below:</div>

+ 1 - 1
resources/views/app/invoice-center/invoices.blade.php

@@ -120,7 +120,7 @@
                     </td>
                     <td>
                         <a href="{{route('icPayInvoice', ['invoiceSlug' => $record->payment_link_slug])}}" native target="_blank">Visit</a>
-                        <a href="#" data-target="{{route('icPayInvoice', ['invoiceSlug' => $record->payment_link_slug])}}" native target="_blank" class="copy-target">Copy</a>
+                        <a href="#" data-target="{{route('icPayInvoice', ['invoiceSlug' => $record->payment_link_slug])}}" native target="_blank" class="copy-target ml-1">Copy</a>
                     </td>
                     <td>${{ is_null($record->paid) ? 0 : $record->paid }}</td>
                     <td>${{ is_null($record->balance) ? 0 : $record->balance }}</td>

+ 220 - 0
resources/views/layouts/ic.blade.php

@@ -0,0 +1,220 @@
+<!DOCTYPE html>
+<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    <title>{{ @$company ? @$company->name : config('app.name') }}</title>
+
+    <!-- Fonts -->
+    <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
+
+    {{-- mc initializers --}}
+    <script src="/js/mc-init.js?v={{config('app.asset_version')}}"></script>
+
+    {{-- vue --}}
+    <script src="/js/vue.js"></script>
+
+    {{-- Quill RTE --}}
+    <link href="/quill/quill.snow.css" rel="stylesheet">
+    <script src="/quill/quill.js"></script>
+
+    <!-- <link href="{{ asset('bootstrap-4.5.0/css/bootstrap.css') }}" rel="stylesheet"> -->
+    <link rel="stylesheet" href="/fontawesome-free-5.13.1-web/css/all.min.css">
+    <link href="{{ asset('/css/app.css') }}?v={{config('app.asset_version')}}" rel="stylesheet">
+    <link href="{{ asset('/css/style.css') }}?v={{config('app.asset_version')}}" rel="stylesheet">
+    <link href="{{ asset('/css/yemi.css') }}?v={{config('app.asset_version')}}" rel="stylesheet">
+    <link rel="stylesheet" href="{{ asset('/css/toastr.min.css') }}">
+    <link href="{{asset('/css/z.css')}}?v={{config('app.asset_version')}}" rel=stylesheet>
+    <!-- Styles -->
+
+    <script src="{{ asset('js/app.js') }}?v={{config('app.asset_version')}}" type="application/javascript"></script>
+    <script src="/js/jquery-3.5.1.min.js"></script>
+    <script src="/js/jquery.form.min.js"></script>
+    <script src="{{ asset('js/toastr.min.js') }}" type="application/javascript"></script>
+    <script src="/js/yemi.js?v={{config('app.asset_version')}}" type="application/javascript"></script>
+
+    {{-- med ac --}}
+    <link href='/css/autocomplete-lhc.min.css' rel="stylesheet">
+    <script src='/js/autocomplete-lhc.js'></script>
+
+    {{-- inline bootstrap datepicker --}}
+    <link href='/bootstrap-datepicker/css/bootstrap-datepicker.min.css' rel="stylesheet">
+    <script src='/bootstrap-datepicker/js/bootstrap-datepicker.min.js'></script>
+
+    @yield('head')
+</head>
+
+<body>
+    <div id="mask" style="background: rgba(0, 0, 0, 0) url(&quot;/vanillaspin.gif&quot;) no-repeat scroll center center; position: fixed; top: 0px; left: 0px; z-index: 9999; width: 100%; height: 100%; display: none;">
+    </div>
+    <div id="moe-form-mask" style="background: rgba(0, 0, 0, .1) no-repeat scroll center center; position: fixed; top: 0px; left: 0px; z-index: 99; width: 100%; height: 100%; display: none;">
+    </div>
+
+    <nav class="navbar navbar-expand-md navbar-dark stag-primary-bg py-1">
+        <a class="navbar-brand" href="">{{@$company ? @$company->name : config('app.name')}}</a>
+        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navBar" aria-controls="navBar" aria-expanded="false" aria-label="Toggle navigation">
+            <span class="navbar-toggler-icon"></span>
+        </button>
+
+        <div class="collapse navbar-collapse" id="navBar">
+            <ul class="navbar-nav mr-auto">
+
+            </ul>
+
+        </div>
+
+    </nav>
+
+    <main role="main" class="stag-content px-0">
+
+        @yield('content')
+
+    </main><!-- /.container -->
+
+    <!-- shortcut/suggest component -->
+    <link href="/css/shortcut.css?v={{config('app.asset_version')}}" rel=stylesheet>
+    <script src="/js/shortcut.js?v={{config('app.asset_version')}}" type="application/javascript"></script>
+
+    <!-- script to handle history/back/forward for mc/xxx pages
+    + all other JS initialization needed in fastLoaded pages  -->
+    <script src="/js/find-event-handlers.js?v={{config('app.asset_version')}}" type="application/javascript"></script>
+
+    <script>
+        window.noMc = true;
+    </script>
+
+    <script src="/js/mc.js?v={{config('app.asset_version')}}" type="application/javascript"></script>
+
+    <script>
+        $(document).ready(function() {
+            const debounce = (func, wait) => {
+                let timeout;
+                return function executedFunction(...args) {
+                    const later = () => {
+                        clearTimeout(timeout);
+                        func(...args);
+                    };
+                    clearTimeout(timeout);
+                    timeout = setTimeout(later, wait);
+                };
+            };
+            var lastTerm = '';
+            var returnedFunction = debounce(function() {
+                var term = $.trim($('#patient-search').val());
+                if (!!term && lastTerm !== term) {
+                    $.get('/patients-suggest?term=' + term, function(_data) {
+                        $('.suggestions-outer').html(_data).removeClass('d-none');
+                    });
+                    lastTerm = term;
+                } else {
+                    $('.suggestions-outer').addClass('d-none');
+                }
+            }, 250);
+            $('#patient-search')
+                .on('keydown', function(e) {
+                    var term = $.trim($('#patient-search').val());
+                    var activeItem = $('.suggestions-outer .suggest-item.active');
+                    switch (e.which) {
+                        case 27:
+                            $('.suggestions-outer').addClass('d-none');
+                            return false;
+                        case 38:
+                            if (activeItem.prev().length) {
+                                activeItem.prev()
+                                    .addClass('active')
+                                    .siblings().removeClass('active');
+                                activeItem = $('.suggestions-outer .suggest-item.active');
+                                if (activeItem.length) {
+                                    activeItem[0].scrollIntoView();
+                                }
+                            }
+                            return false;
+                        case 40:
+                            if (activeItem.next().length) {
+                                activeItem.next()
+                                    .addClass('active')
+                                    .siblings().removeClass('active');
+                                activeItem = $('.suggestions-outer .suggest-item.active');
+                                if (activeItem.length) {
+                                    activeItem[0].scrollIntoView();
+                                }
+                            }
+                            return false;
+                        case 13:
+                            if (activeItem.length) {
+                                activeItem.first().click();
+                            }
+                            return false;
+                        default:
+                            if (!!term) {
+                                $('.suggestions-outer')
+                                    .html('<span class="d-block no-suggest-items">Searching...</span>')
+                                    .removeClass('d-none');
+                                returnedFunction();
+                            } else {
+                                $('.suggestions-outer').addClass('d-none');
+                            }
+                            break;
+                    }
+                })
+                .on('keypress', function(e) {
+                    var term = $.trim($('#patient-search').val());
+                    if (!!term) {
+                        $('.suggestions-outer')
+                            .html('<span class="d-block no-suggest-items">Searching...</span>')
+                            .removeClass('d-none');
+                        returnedFunction();
+                    } else {
+                        $('.suggestions-outer').addClass('d-none');
+                    }
+                });
+            $(document).on('click', '.suggest-item.patient-suggest[data-target-uid]', function() {
+                $('#patient-search').val('');
+                $('.suggestions-outer').addClass('d-none');
+                fastLoad('/patients/view/' + $(this).attr('data-target-uid'), true, false, false);
+                return false;
+            });
+        });
+    </script>
+    <script>
+        function showStagPopup(_key) {
+            $('html, body').addClass('no-scroll');
+            let stagPopup = $('[stag-popup-key="' + _key + '"]');
+            stagPopup.addClass('show');
+            stagPopup.find('[moe][initialized]').removeAttr('initialized');
+            initMoes();
+            return false;
+        }
+        function submitStagPopup(_form) {
+            if(!_form[0].checkValidity()) {
+                _form[0].reportValidity();
+                return false;
+            }
+            showMask();
+            $.post(_form.attr('action'), _form.serialize(), function(_data) {
+                fastReload();
+            });
+            return false;
+        }
+        function closeStagPopup() {
+            $('.stag-popup').removeClass('show');
+            $('html, body').removeClass('no-scroll');
+            return false;
+        }
+        (function() {
+            window.initStagPopupEvents = function () {
+                $(document).on('click', '.stag-popup', function(_e) {
+                    if($(_e.target).is('.stag-popup')) {
+                        closeStagPopup();
+                    }
+                });
+            }
+            addMCInitializer('stag-popups', window.initStagPopupEvents);
+        })();
+    </script>
+
+</body>
+
+</html>

+ 1 - 0
routes/web.php

@@ -247,6 +247,7 @@ Route::middleware('pro.auth')->group(function () {
     });
 
     // ic pages - client facing
+    Route::get('/ic/home/{customerSlug}', 'InvoiceController@icCustomerPortal')->name('icCustomerPortal');
     Route::get('/ic/pay/{invoiceSlug}', 'InvoiceController@icPayInvoice')->name('icPayInvoice');
 
     Route::name('practice-management.')->prefix('practice-management')->group(function () {