浏览代码

Merge branch 'master' of rav.triplestart.com:jmudaka/stagfe2

root 3 年之前
父节点
当前提交
4c93c0279a
共有 77 个文件被更改,包括 2442 次插入465 次删除
  1. 39 0
      app/Helpers/helpers.php
  2. 45 1
      app/Http/Controllers/HomeController.php
  3. 1 0
      app/Http/Controllers/NoteController.php
  4. 10 0
      app/Http/Controllers/PatientController.php
  5. 46 15
      app/Http/Controllers/PracticeManagementController.php
  6. 4 0
      app/Models/Bill.php
  7. 4 0
      app/Models/ClientBDTDevice.php
  8. 15 0
      app/Models/ClientProChange.php
  9. 1 0
      app/Models/Note.php
  10. 9 0
      app/Models/Pro.php
  11. 25 0
      public/css/style.css
  12. 56 0
      resources/views/app/dashboard.blade.php
  13. 11 0
      resources/views/app/generic-bills/add-bill-form/Note.blade.php
  14. 56 0
      resources/views/app/generic-bills/add-bill-form/_default-fields.blade.php
  15. 48 0
      resources/views/app/generic-bills/add-bill-form/_default-script.blade.php
  16. 5 0
      resources/views/app/generic-bills/add-bill-form/default.blade.php
  17. 71 0
      resources/views/app/generic-bills/context.blade.php
  18. 9 0
      resources/views/app/generic-bills/create_generic-bill.blade.php
  19. 276 0
      resources/views/app/generic-bills/inline.blade.php
  20. 7 0
      resources/views/app/generic-bills/modal.blade.php
  21. 4 0
      resources/views/app/patient/appointments.blade.php
  22. 14 6
      resources/views/app/patient/canvas-sections/allergies/default.php
  23. 16 6
      resources/views/app/patient/canvas-sections/allergies/summary.php
  24. 3 0
      resources/views/app/patient/canvas-sections/canvas-editor-modal.blade.php
  25. 14 6
      resources/views/app/patient/canvas-sections/care-team/default.php
  26. 14 4
      resources/views/app/patient/canvas-sections/care-team/summary.php
  27. 71 23
      resources/views/app/patient/canvas-sections/cc_hpi/default.php
  28. 18 4
      resources/views/app/patient/canvas-sections/cc_hpi/summary.php
  29. 29 9
      resources/views/app/patient/canvas-sections/cc_may21/default.php
  30. 15 6
      resources/views/app/patient/canvas-sections/cc_may21/summary.php
  31. 20 11
      resources/views/app/patient/canvas-sections/dx/default.php
  32. 17 6
      resources/views/app/patient/canvas-sections/dx/summary.php
  33. 13 6
      resources/views/app/patient/canvas-sections/fhx/default.php
  34. 16 6
      resources/views/app/patient/canvas-sections/fhx/summary.php
  35. 113 104
      resources/views/app/patient/canvas-sections/lifestyle_rx_review/default.php
  36. 107 95
      resources/views/app/patient/canvas-sections/lifestyle_rx_review/summary.php
  37. 18 7
      resources/views/app/patient/canvas-sections/lifestyle_rx_update/default.php
  38. 69 4
      resources/views/app/patient/canvas-sections/lifestyle_rx_update/summary.php
  39. 18 7
      resources/views/app/patient/canvas-sections/next_fu/default.php
  40. 15 4
      resources/views/app/patient/canvas-sections/next_fu/summary.php
  41. 15 6
      resources/views/app/patient/canvas-sections/pmhx/default.php
  42. 18 7
      resources/views/app/patient/canvas-sections/pmhx/summary.php
  43. 14 6
      resources/views/app/patient/canvas-sections/pshx/default.php
  44. 21 9
      resources/views/app/patient/canvas-sections/pshx/summary.php
  45. 20 6
      resources/views/app/patient/canvas-sections/ros/summary.php
  46. 15 6
      resources/views/app/patient/canvas-sections/rx/default.php
  47. 4 2
      resources/views/app/patient/canvas-sections/rx/form.blade.php
  48. 13 9
      resources/views/app/patient/canvas-sections/rx/summary.php
  49. 15 6
      resources/views/app/patient/canvas-sections/sochx/default.php
  50. 17 7
      resources/views/app/patient/canvas-sections/sochx/summary.php
  51. 16 6
      resources/views/app/patient/canvas-sections/vitals/default.php
  52. 23 13
      resources/views/app/patient/canvas-sections/vitals/summary.php
  53. 14 6
      resources/views/app/patient/canvas-sections/vitals_may21/default.php
  54. 17 0
      resources/views/app/patient/canvas-sections/vitals_may21/summary.php
  55. 9 2
      resources/views/app/patient/care-month/dashboard.blade.php
  56. 4 0
      resources/views/app/patient/devices.blade.php
  57. 7 0
      resources/views/app/patient/generic-bills.blade.php
  58. 6 0
      resources/views/app/patient/measurements.blade.php
  59. 17 3
      resources/views/app/patient/note/dashboard.blade.php
  60. 397 0
      resources/views/app/patient/rm-setup.blade.php
  61. 3 0
      resources/views/app/patient/shipments.blade.php
  62. 4 0
      resources/views/app/patient/supply-orders.blade.php
  63. 26 22
      resources/views/app/patient/tickets.blade.php
  64. 18 6
      resources/views/app/patient/tickets/erx.blade.php
  65. 12 0
      resources/views/app/patient/tickets/imaging.blade.php
  66. 12 0
      resources/views/app/patient/tickets/lab.blade.php
  67. 37 0
      resources/views/app/patient/tickets/other-data.blade.php
  68. 105 0
      resources/views/app/patient/tickets/other.blade.php
  69. 11 0
      resources/views/app/practice-management/generic-bills.blade.php
  70. 57 0
      resources/views/app/practice-management/na-billable-signed-notes.blade.php
  71. 22 10
      resources/views/app/practice-management/processing-bill-matrix.blade.php
  72. 1 1
      resources/views/app/ticket/lab.blade.php
  73. 52 0
      resources/views/app/ticket/other.blade.php
  74. 12 0
      resources/views/layouts/patient.blade.php
  75. 2 1
      resources/views/layouts/template.blade.php
  76. 7 1
      routes/web.php
  77. 57 0
      spec/note_implementation_spec_june_30_2021.txt

+ 39 - 0
app/Helpers/helpers.php

@@ -7,9 +7,48 @@
  */
 
 use App\Models\AppSession;
+use App\Models\Client;
+use App\Models\Pro;
+use App\Models\Bill;
 //require_once './class.Diff.php';
 use Soundasleep\Html2Text as Html2Text;
 
+if(!function_exists('genericBills')) {
+    function genericBills(Pro $performerPro, $patient, $entityType, $entityUid) {
+        $genericBills = Bill::where('bill_service_type', 'GENERIC');
+        if($performerPro->pro_type !== 'ADMIN') {
+            $genericBills = $genericBills->where('generic_pro_id', $performerPro->id);
+        }
+        if($patient) {
+            $genericBills = $genericBills->where('client_id', $patient->id);
+        }
+        if($entityType && $entityUid) {
+            $genericBills = $genericBills
+                ->where('generic_target_entity_type', $entityType)
+                ->where('generic_target_entity_uid', $entityUid);
+        }
+        return $genericBills->orderBy('created_at', 'DESC')->get();
+    }
+}
+
+if(!function_exists('hasActiveGenericBill')) {
+    function hasActiveGenericBill(Pro $performerPro, $patient, $entityType, $entityUid) {
+        $genericBills = Bill::where('bill_service_type', 'GENERIC')->where('is_cancelled', false);
+        if($performerPro->pro_type !== 'ADMIN') {
+            $genericBills = $genericBills->where('generic_pro_id', $performerPro->id);
+        }
+        if($patient) {
+            $genericBills = $genericBills->where('client_id', $patient->id);
+        }
+        if($entityType && $entityUid) {
+            $genericBills = $genericBills
+                ->where('generic_target_entity_type', $entityType)
+                ->where('generic_target_entity_uid', $entityUid);
+        }
+        return $genericBills->count() > 0;
+    }
+}
+
 if(!function_exists('queryLineExcept')) {
     function queryLineExcept($except = []) {
         $params = request()->all();

+ 45 - 1
app/Http/Controllers/HomeController.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
 use App\Lib\Backend;
 use App\Models\Appointment;
 use App\Models\AppSession;
+use App\Models\ClientProChange;
 use App\Models\ClientSMS;
 use App\Models\Facility;
 use App\Models\IncomingReport;
@@ -377,10 +378,49 @@ class HomeController extends Controller
             ->whereRaw('created_by_session_id IN (SELECT id FROM app_session where pro_id = ?)', [$performer->pro->id])
             ->count();
 
+        $newMCPAssociations = ClientProChange
+            ::where('new_pro_id', $performerProID)
+            ->where('responsibility_type', 'MCP')
+            ->whereNull('current_client_pro_change_decision_id')
+            ->get();
+
+        $newNAAssociations = ClientProChange
+            ::where('new_pro_id', $performerProID)
+            ->where('responsibility_type', 'DEFAULT_NA')
+            ->whereNull('current_client_pro_change_decision_id')
+            ->get();
+
+        $naBillableSignedNotes = DB::select(DB::raw("
+SELECT count(note.id) as na_billable_notes
+FROM note
+WHERE
+        note.is_signed_by_hcp = TRUE AND
+        note.ally_pro_id = :pro_id AND
+        note.is_cancelled = FALSE AND
+        (
+            SELECT count(bill.id) 
+            FROM bill 
+            WHERE 
+                  bill.is_cancelled = FALSE AND 
+                  bill.generic_pro_id = :pro_id AND 
+                  bill.note_id = note.id
+        ) = 0
+        "), ["pro_id" => $performerProID]);
+
+        if(!$naBillableSignedNotes || !count($naBillableSignedNotes)) {
+            $naBillableSignedNotes = 0;
+        }
+        else {
+            $naBillableSignedNotes = $naBillableSignedNotes[0]->na_billable_notes;
+        }
+
+        $keyNumbers['naBillableSignedNotes'] = $naBillableSignedNotes;
+
         return view('app/dashboard', compact('keyNumbers', 'reimbursement', 'milliseconds',
             'businessNumbers',
             'incomingReports', 'tickets', 'supplyOrders',
-            'numERx', 'numLabs', 'numImaging', 'numSupplyOrders'));
+            'numERx', 'numLabs', 'numImaging', 'numSupplyOrders',
+            'newMCPAssociations', 'newNAAssociations'));
     }
 
     public function dashboardMeasurementsTab(Request $request, $page = 1) {
@@ -859,4 +899,8 @@ WHERE measurement.label NOT IN ('SBP', 'DBP')
         $ticket->initiatingPro;
         return json_encode($ticket);
     }
+
+    public function genericBill(Request $request, $entityType, $entityUid) {
+        return view('app.generic-bills.inline', ['class' => 'p-3 border-top mt-3', 'entityType' => $entityType, 'entityUid' => $entityUid]);
+    }
 }

+ 1 - 0
app/Http/Controllers/NoteController.php

@@ -183,6 +183,7 @@ class NoteController extends Controller
             $response = null;
             $data = [
                 'uid' => $client->uid,
+                'noteUid'=> $note?$note->uid:null,
                 'key' => $key,
                 'data' => $newCanvasNodeData
             ];

+ 10 - 0
app/Http/Controllers/PatientController.php

@@ -260,6 +260,16 @@ class PatientController extends Controller
         return view('app.patient.notes', compact('patient','pros', 'filter'));
     }
 
+    public function genericBills(Request $request, Client $patient)
+    {
+        return view('app.patient.generic-bills', compact('patient'));
+    }
+
+    public function rmSetup(Request $request, Client $patient)
+    {
+        return view('app.patient.rm-setup', compact('patient'));
+    }
+
     public function sections(Request $request, Client $patient )
     {
         $pros = $this->pros;

+ 46 - 15
app/Http/Controllers/PracticeManagementController.php

@@ -129,6 +129,27 @@ class PracticeManagementController extends Controller
         return view('app.practice-management.notes', compact('notes', 'filter'));
     }
 
+    public function naBillableSignedNotes(Request $request)
+    {
+
+        $notes = Note
+            ::where('is_signed_by_hcp', TRUE)
+            ->where('ally_pro_id', $this->performer()->pro->id)
+            ->where('is_cancelled', FALSE)
+            ->whereRaw("
+            (
+                SELECT count(bill.id) 
+                FROM bill WHERE 
+                      bill.is_cancelled = FALSE AND 
+                      bill.generic_pro_id = {$this->performer()->pro->id} AND 
+                      bill.note_id = note.id
+            ) = 0
+            ");
+
+        $notes = $notes->orderBy('created_at', 'desc')->get();
+        return view('app.practice-management.na-billable-signed-notes', compact('notes'));
+    }
+
     public function bills(Request $request, $filter = '')
     {
         $proID = $this->performer()->pro->id;
@@ -492,30 +513,35 @@ class PracticeManagementController extends Controller
         $proUid = $proUid ? $proUid : $request->get('pro-uid');
         $performerPro = $this->performer->pro;
         $targetPro = null;
-        $allPros = [];
         if ($performerPro->pro_type == 'ADMIN') {
-            $allPros = Pro::all();
             $targetPro = Pro::where('uid', $proUid)->first();
         } else {
             $targetPro = $performerPro;
         }
-        $bills = [];
+
+        $bills = Bill
+            ::where('has_hcp_been_paid', false)
+            ->where('is_cancelled', false)
+            ->where('is_signed_by_hcp', true);
+
         if ($targetPro) {
-            $bills = Bill::where('hcp_pro_id', $targetPro->id)->
-            where('has_hcp_been_paid', false)->
-            where('is_cancelled', false)->
-            where('is_signed_by_hcp', true)->
-            orderBy('effective_date', 'desc')->paginate();
-        } else {
-            $bills = Bill::where('has_hcp_been_paid', false)->
-            where('is_cancelled', false)->
-            where('is_signed_by_hcp', true)->
-            orderBy('effective_date', 'desc')->
-            paginate();
+            $bills = $bills->where('hcp_pro_id', $targetPro->id);
         }
+
+        $filter = $request->input('f');
+        switch ($filter) {
+            case 'verified':
+                $bills = $bills->where('is_verified', true);
+                break;
+            case 'not-verified':
+                $bills = $bills->where('is_verified', false);
+                break;
+        }
+
+        $bills = $bills->orderBy('effective_date', 'desc')->paginate();
+
         $viewData = [
             'bills' => $bills,
-            'allPros' => $allPros,
             'targetPro' => $targetPro,
             'performerPro' => $performerPro,
             'proUid' => $proUid
@@ -1398,4 +1424,9 @@ ORDER BY claim.created_at ASC
         return $response;
     }
 
+    public function genericBills(Request $request)
+    {
+        return view('app.practice-management.generic-bills');
+    }
+
 }

+ 4 - 0
app/Models/Bill.php

@@ -28,4 +28,8 @@ class Bill extends Model
     public function ally() {
         return $this->hasOne(Pro::class, 'id', 'na_pro_id');
     }
+
+    public function genericPro() {
+        return $this->hasOne(Pro::class, 'id', 'generic_pro_id');
+    }
 }

+ 4 - 0
app/Models/ClientBDTDevice.php

@@ -10,4 +10,8 @@ class ClientBDTDevice extends Model
         return $this->hasOne(BDTDevice::class, 'id', 'device_id');
     }
 
+    public function client() {
+        return $this->hasOne(Client::class, 'id', 'client_id');
+    }
+
 }

+ 15 - 0
app/Models/ClientProChange.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Database\Eloquent\Relations\HasOne;
+
+class ClientProChange extends Model
+{
+    protected $table = 'client_pro_change';
+
+    public function patient(){
+        return $this->hasOne(Client::class, 'id', 'client_id');
+    }
+}

+ 1 - 0
app/Models/Note.php

@@ -36,6 +36,7 @@ class Note extends Model
     public function bills()
     {
         return $this->hasMany(Bill::class, 'note_id', 'id')
+            ->where('bill_service_type', '<>', 'GENERIC')
             ->orderBy('id', 'asc');
     }
 

+ 9 - 0
app/Models/Pro.php

@@ -78,6 +78,15 @@ class Pro extends Model
             ->where('pro_id', $this->id)
             ->where('code', 'NOT LIKE', 'CM%')
             ->where('code', 'NOT LIKE', 'RM%')
+            ->where('responsibility', '<>', 'GENERIC')
+            ->get();
+    }
+
+    public function genericRates() {
+        return ProRate::distinct('code')
+            ->where('is_active', true)
+            ->where('pro_id', $this->id)
+            ->where('responsibility', 'GENERIC')
             ->get();
     }
 

+ 25 - 0
public/css/style.css

@@ -582,6 +582,12 @@ input.search_field, textarea.search_field {
     font-weight: bold !important;
     color: #000 !important;
 }
+#caremonth-measurements-calendar table.table-condensed td[has-events],
+#caremonth-measurements-calendar td.has-events a {
+    background: #c5e4ff !important;
+    font-weight: bold !important;
+    color: #000 !important;
+}
 .ui-state-active,
 .ui-widget-content .ui-state-active,
 .ui-widget-header .ui-state-active,
@@ -1009,10 +1015,15 @@ body .node input[type="number"] {
     box-shadow: 0 0 5px #ddd;
     margin: 0 auto;
     padding: 0.75rem;
+    min-height: 220px;
 }
 .stag-popup.wide>form, .stag-popup.wide>.stag-popup-content {
     width: calc(100% - 4rem);
 }
+.stag-popup.tall>form, .stag-popup.tall>.stag-popup-content {
+    height: 100%;
+    min-height: 500px;
+}
 .stag-popup.narrow>form, .stag-popup.narrow>.stag-popup-content {
     max-width: 500px;
 }
@@ -1680,6 +1691,16 @@ th.only-screen, td.only-screen {
     width: 100%;
     border: 0 !important;
 }
+#caremonth-measurements-calendar>.ui-datepicker-inline {
+    width: 100%;
+}
+#caremonth-measurements-calendar .ui-datepicker-prev,
+#caremonth-measurements-calendar .ui-datepicker-next {
+    display: none;
+}
+#caremonth-measurements-calendar {
+    pointer-events: none !important;
+}
 #simpleSMSReminderComponent input[type="time"] {
     max-width: 90px;
     min-width: unset !important;
@@ -1835,3 +1856,7 @@ form.non-interactive .form-content * {
     text-align: center;
     border-radius: 100%;
 }*/
+.no-overflow-menu {
+    overflow-y: auto;
+    max-height: calc(100vh - 60px);
+}

+ 56 - 0
resources/views/app/dashboard.blade.php

@@ -74,6 +74,14 @@
                                         <a href="/patients/having-birthday-today">Patients having birthday today</a>
                                     </th>
                                 </tr>
+                                @if(@$keyNumbers['naBillableSignedNotes'])
+                                    <tr>
+                                        <th class="px-2 text-center">{{$keyNumbers['naBillableSignedNotes']}}</th>
+                                        <th class="pl-2">
+                                            <a href="/practice-management/na-billable-signed-notes">Billable signed notes</a>
+                                        </th>
+                                    </tr>
+                                @endif
                             </tbody>
                         </table>
                     </div>
@@ -144,6 +152,29 @@
             </div>
             <div class="col-md-9">
 
+                <!-- new associations -->
+                @if(count($newMCPAssociations))
+                    <div class="mb-3 border rounded px-3 py-2 ack-container">
+                        <p class="pt-1 mb-2"><b>New Patients</b></p>
+                        @foreach($newMCPAssociations as $assoc)
+                            <div class="mb-1">You have been assigned as the MCP for {{$assoc->patient->displayName()}}.
+                            <a href="#" class="ack-client-pro-change" data-uid="{{$assoc->uid}}">Acknowledge</a>
+                            </div>
+                        @endforeach
+                    </div>
+                @endif
+
+                @if(count($newNAAssociations))
+                    <div class="mb-3 border rounded px-3 py-2 ack-container">
+                        <p class="pt-1 mb-2"><b>New Patients</b></p>
+                        @foreach($newNAAssociations as $assoc)
+                            <div class="mb-1">You have been assigned as the Care Coordinator for {{$assoc->patient->displayName()}}.
+                                <a href="#" class="ack-client-pro-change" data-uid="{{$assoc->uid}}">Acknowledge</a>
+                            </div>
+                        @endforeach
+                    </div>
+                @endif
+
                 <ul class="nav nav-tabs">
                     <li class="nav-item">
                         <a native data-tab="appointments" class="nav-link"
@@ -591,6 +622,31 @@
                     });
                     return false;
                 });
+
+            $(document)
+                .off('click', '.ack-client-pro-change')
+                .on('click', '.ack-client-pro-change', function() {
+                    let trigger = $(this).text('…');
+                    $.post('/api/clientProPage/accept', {
+                        uid: $(this).attr('data-uid')
+                    }, _data => {
+                        if(!hasResponseError(_data)) {
+                            trigger.hide();
+                            let doneElem = $('<i class="text-success fa fa-check"></i>');
+                            doneElem.insertAfter(trigger);
+                            setTimeout(() => {
+                                let ackContainer = trigger.closest('.ack-container');
+                                trigger.closest('div').slideUp('fast', function() {
+                                    $(this).remove();
+                                    if(!ackContainer.find('>div').length) {
+                                        ackContainer.remove();
+                                    }
+                                });
+                            }, 500);
+                        }
+                    }, 'json');
+                    return false;
+                });
         }
         addMCInitializer('pro-dashboard', init, '#pro-dashboard-container');
     })();

+ 11 - 0
resources/views/app/generic-bills/add-bill-form/Note.blade.php

@@ -0,0 +1,11 @@
+<form url="/api/bill/createForGeneric">
+    @if(hasActiveGenericBill($pro, @$patient, @$entityType, @$entityUid))
+        <div class="border rounded bg-aliceblue p-2 width-200px">
+            <i class="fa fa-exclamation-triangle text-warning-mellow mr-1"></i>
+            An uncancelled NA bill already exists for this note!
+        </div>
+    @else
+        @include('app.generic-bills.add-bill-form._default-fields')
+    @endif
+</form>
+@include('app.generic-bills.add-bill-form._default-script')

+ 56 - 0
resources/views/app/generic-bills/add-bill-form/_default-fields.blade.php

@@ -0,0 +1,56 @@
+<div class="mb-2">
+    <label for="" class="text-secondary text-sm">Pro</label>
+    <input type="text" class="form-control form-control-sm" value="{{$pro->displayName()}}" readonly>
+</div>
+<input type="hidden" name="genericProUid" value="{{$pro->uid}}">
+@if(@$note)
+    <input type="hidden" name="optionalNoteUid" value="{{$note->uid}}">
+@endif
+@if(@$patient)
+    <input type="hidden" name="optionalClientUid" value="{{$patient->uid}}">
+@endif
+@if(@$entityType)
+    <input type="hidden" name="genericTargetEntityType" value="{{$entityType}}">
+@endif
+@if(@$entityUid)
+    <input type="hidden" name="genericTargetEntityUid" value="{{$entityUid}}">
+@endif
+<div class="mb-2">
+    <label for="" class="text-secondary text-sm">Service</label>
+    <select autofocus class="form-control" name="code"
+            data-entity-type="{{$entityType}}"
+            onchange="switchGenericRate(this)">
+        <option value="">-- Select Code --</option>
+        @foreach($pro->genericRates() as $genericRate)
+            <option data-amount="{{ $genericRate->amount }}" value="{{ $genericRate->code }}">
+                {{ $genericRate->code }} (${{ $genericRate->amount }})
+            </option>
+        @endforeach
+    </select>
+</div>
+<div class="mb-2">
+    <?php $maxMinutes = 240; ?>
+    <label for="" class="text-secondary text-sm">Minutes</label>
+    <div class="mb-2">
+        <select name="numberOfUnits" class="form-control form-control-sm"
+                onchange="calculateGenericBillAmount(this)">
+            <option value=""> -- select -- </option>
+            <?php for ($i = 5; $i <= $maxMinutes; $i+=5) { ?>
+            <option value="{{ $i/60 }}">{{ $i }} minutes</option>
+            <?php } ?>
+        </select>
+    </div>
+    <div class="mb-2" calculated-generic-amount></div>
+</div>
+<div class="mb-2">
+    <label for="" class="text-secondary text-sm">Description</label>
+    <input type="text" name="genericDescription" class="form-control form-control-sm" value="">
+</div>
+<div class="mb-2">
+    <label for="" class="text-secondary text-sm">Effective Date</label>
+    <input type="date" name="effectiveDate" class="form-control form-control-sm" value="{{date('Y-m-d')}}" required>
+</div>
+<div class="">
+    <button class="btn btn-primary btn-sm" submit>Submit</button>
+    <button class="btn btn-default border btn-sm" cancel>Cancel</button>
+</div>

+ 48 - 0
resources/views/app/generic-bills/add-bill-form/_default-script.blade.php

@@ -0,0 +1,48 @@
+<script>
+    (function() {
+        let selectedGenericRate = 0;
+        window.switchGenericRate = function(_trigger) {
+            selectedGenericRate = 0;
+            if($(_trigger).find('option:selected').first().length) {
+                selectedGenericRate = +($(_trigger).find('option:selected').first().attr('data-amount'));
+            }
+            $(_trigger).closest('form').find('[name="numberOfUnits"]').val('');
+
+            // max num units to limit at $15
+            if($(_trigger).attr('data-entity-type') === 'Note') {
+                let maxNABillableAmount = 15,
+                    amountPer5Minutes = selectedGenericRate / 12,
+                    maxNumberOf5Minutes =  Math.ceil(maxNABillableAmount / amountPer5Minutes),
+                    maxHours = (maxNumberOf5Minutes * 5) / 60,
+                    unitsSelect = $(_trigger).closest('form').find('[name="numberOfUnits"]');
+                unitsSelect.find('option').each(function() {
+                    if(this.value) {
+                        if(+this.value > maxHours) {
+                            $(this).hide();
+                        }
+                        else {
+                            $(this).show();
+                        }
+                    }
+                    else {
+                        $(this).show();
+                    }
+                });
+            }
+
+            calculateGenericBillAmount($(_trigger).closest('form').find('[name="numberOfUnits"]'));
+        };
+        window.calculateGenericBillAmount = function(_trigger) {
+            _trigger = $(_trigger);
+            let amountTarget = _trigger.closest('form').find('[calculated-generic-amount]');
+            if(!_trigger.find('option:selected').length) {
+                amountTarget.text('');
+                return;
+            }
+            let hours = +_trigger.find('option:selected').attr('value'),
+                reimbursable = hours * selectedGenericRate;
+            if(isNaN(reimbursable)) reimbursable = 0;
+            amountTarget.html('<b>Reimbursable:</b> $' + reimbursable.toFixed(2));
+        }
+    }).call(window);
+</script>

+ 5 - 0
resources/views/app/generic-bills/add-bill-form/default.blade.php

@@ -0,0 +1,5 @@
+<form url="/api/bill/createForGeneric">
+    @include('app.generic-bills.add-bill-form._default-fields')
+</form>
+@include('app.generic-bills.add-bill-form._default-script')
+

+ 71 - 0
resources/views/app/generic-bills/context.blade.php

@@ -0,0 +1,71 @@
+<?php
+switch ($bill->generic_target_entity_type) {
+    case 'Ticket':
+        $ticket = \App\Models\Ticket::where('uid', $bill->generic_target_entity_uid)->first();
+        ?>
+        <div class="mb-1">Ticket > {{strtoupper($ticket->category)}}
+            <a class="ml-2"
+               native target="_blank"
+               open-in-stag-popup
+               mc-initer="patient-tickets"
+               popup-style="tall"
+               title="Ticket Details"
+               href="/patients/view/{{$ticket->patient->uid}}/tickets/{{$ticket->category}}/{{$ticket->uid}}">
+                View
+            </a>
+        </div>
+        <div class="pl-3 text-sm">
+            <div class="text-secondary mb-1">Patient: <a href="{{route('patients.view.dashboard', ['patient' => $ticket->patient])}}">{{$ticket->patient->displayName()}}</a></div>
+            <div class="text-secondary mb-1">Created: {{friendlier_date_time($ticket->created_at)}}</div>
+        </div>
+        <?php
+        break;
+    case 'Appointment':
+        $appointment = \App\Models\Appointment::where('uid', $bill->generic_target_entity_uid)->first();
+        ?>
+        <div class="mb-1">Appointment
+            <a class="ml-2"
+               native target="_blank"
+               href="/patients/view/{{$appointment->client->uid}}/calendar/{{$appointment->uid}}">
+                View
+            </a>
+        </div>
+        <div class="pl-3 text-sm">
+            <div class="text-secondary mb-1">Patient: <a href="{{route('patients.view.dashboard', ['patient' => $appointment->client])}}">{{$appointment->client->displayName()}}</a></div>
+            <div class="text-secondary mb-1">Pro: {{$appointment->pro->displayName()}}</div>
+            <div class="text-secondary mb-1">Date: <b>{{friendlier_date_time($appointment->raw_start_time)}}</b></div>
+            <div class="text-secondary mb-1">Created: {{friendlier_date_time($appointment->created_at)}}</div>
+        </div>
+        <?php
+        break;
+    case 'ClientBDTDevice':
+        $device = \App\Models\ClientBDTDevice::where('uid', $bill->generic_target_entity_uid)->first();
+        ?>
+        <div class="mb-1">Device > {{strtoupper($device->device->category)}}</div>
+        <div class="pl-3 text-sm">
+            <div class="text-secondary mb-1">Patient: <a href="{{route('patients.view.dashboard', ['patient' => $device->client])}}">{{$device->client->displayName()}}</a></div>
+            <div class="text-secondary mb-1">Created: {{friendlier_date_time($device->created_at)}}</div>
+        </div>
+        <?php
+        break;
+    case 'Note':
+        $note = \App\Models\Note::where('uid', $bill->generic_target_entity_uid)->first();
+        ?>
+        <div class="mb-1">Note
+            <a class="ml-2"
+               native target="_blank"
+               href="/patients/view/{{$note->client->uid}}/notes/view/{{$note->uid}}">
+                View
+            </a>
+        </div>
+        <div class="pl-3 text-sm">
+            <div class="text-secondary mb-1">Patient: <a href="{{route('patients.view.dashboard', ['patient' => $note->client])}}">{{$note->client->displayName()}}</a></div>
+            <div class="text-secondary mb-1">Eff. Date: {{friendlier_date_time($note->effective_dateest, false)}}</div>
+            <div class="text-secondary mb-1">Created: {{friendlier_date_time($note->created_at)}}</div>
+        </div>
+        <?php
+        break;
+    default:
+        echo $bill->generic_target_entity_type ? $bill->generic_target_entity_type : '-';
+}
+?>

+ 9 - 0
resources/views/app/generic-bills/create_generic-bill.blade.php

@@ -0,0 +1,9 @@
+<span class="mx-2 text-secondary">|</span>
+<div moe wide relative class="">
+    <a class="" href="" show start>Create {{@$label ? $label : 'Generic'}} Bill</a>
+    @if (!!@$entityType && file_exists(resource_path('views/app/generic-bills/add-bill-form/' . $entityType . '.blade.php')))
+        @include('app.generic-bills.add-bill-form.' . $entityType)
+    @else
+        @include('app.generic-bills.add-bill-form.default')
+    @endif
+</div>

+ 276 - 0
resources/views/app/generic-bills/inline.blade.php

@@ -0,0 +1,276 @@
+<?php
+
+use App\Models\Note;
+use App\Models\Pro;
+use App\Models\Client;
+
+/** @var Note $note */
+/** @var Pro $genericPro */
+/** @var Pro $pro */
+/** @var Client $patient */
+/** @var $entityType */
+/** @var $entityUid */
+
+$genericBills = genericBills($pro, @$patient, @$entityType, @$entityUid);
+?>
+
+@if(!count($genericBills))
+    <div class="{{@$class ? $class : ''}} d-flex align-items-center">
+        <p class="font-weight-bold mb-0 text-secondary">No {{@$label ? $label : 'Generic'}} bills</p>
+        @include('app.generic-bills.create_generic-bill')
+    </div>
+@else
+    <div class="{{@$class ? $class : ''}}">
+        <div class="d-flex align-items-center mb-2">
+            <p class="font-weight-bold text-secondary font-size-13 m-0">{{@$label ? $label : 'Generic'}} Bills</p>
+            @if(!@$noCreate)
+                @include('app.generic-bills.create_generic-bill')
+            @endif
+        </div>
+            <table class="table table-sm tabe-striped mb-0 table-bordered">
+                <thead class="bg-light">
+                <tr class="text-secondary">
+                    <th class="border-bottom-0">Date</th>
+                    <th class="border-bottom-0">Pro</th>
+                    @if(@$adminView)
+                        <th class="border-bottom-0">Context</th>
+                    @endif
+                    <th class="border-bottom-0">Service</th>
+                    <th class="border-bottom-0">Billable</th>
+                    <th class="border-bottom-0 screen-only">Total</th>
+                    <th class="border-bottom-0">Sign</th>
+                    <th class="border-bottom-0">Cancellation</th>
+                    @if($pro->pro_type === 'ADMIN')
+                    <th class="border-bottom-0">Verification</th>
+                    <th class="border-bottom-0 screen-only">Payment</th>
+                    @endif
+                </tr>
+                </thead>
+                <tbody>
+                @foreach ($genericBills as $bill)
+                    <tr class="{{$bill->is_cancelled ? 'bg-light text-secondary' : ''}}">
+                        <td class="text-nowrap">{{friendlier_date_time($bill->effective_date, false)}}</td>
+                        <td class="">
+                            <div class="text-nowrap font-weight-bold text-secondary">{{ $bill->genericPro->displayName() }}</div>
+                            <div class="text-nowrap mt-1 screen-only">
+                                <span class="text-secondary">Paid: </span>
+                                <span>{{ $bill->has_generic_pro_been_paid ? 'Yes' : 'No' }}</span>
+                            </div>
+                            @if(!$bill->has_generic_pro_been_paid)
+                                <div class="text-nowrap mt-1 screen-only">
+                                    <span class="text-secondary">Expected: </span>
+                                    <span class="font-weight-bold">${{ round($bill->total_expected, 2) }}</span>
+                                </div>
+                            @else
+                                <div class="text-nowrap mt-1 screen-only">
+                                    <span class="text-secondary">Amount: </span>
+                                    <span class="font-weight-bold">${{ round($bill->total_paid, 2) }}</span>
+                                </div>
+                            @endif
+                        </td>
+                        @if(@$adminView)
+                            <td>
+                                @include('app.generic-bills.context')
+                            </td>
+                        @endif
+                        <td>{{$bill->code}}</td>
+                        <td class="">
+                            <?php
+                            $totalSeconds = $bill->number_of_units * 3600;
+                            $remainder = $totalSeconds % 60;
+                            if ($remainder !== 0) {
+                                if ($remainder < 30) {
+                                    $totalSeconds = $totalSeconds - $remainder;
+                                }
+                                else {
+                                    $totalSeconds = $totalSeconds + (60 - $remainder);
+                                }
+                            }
+                            ?>
+                            {{ time_in_hrminsec($totalSeconds) }}
+                        </td>
+                        <td class="pr-3 screen-only">
+                            @if($bill->has_generic_pro_been_paid)
+                                <span class="text-secondary">Paid. </span>
+                                <span class="font-weight-bold">${{ round($bill->total_paid, 2) }}</span>
+                            @else
+                                <span class="text-secondary">Exp. </span>
+                                <span class="font-weight-bold">{{ $bill->total_expected ? '$' . round($bill->total_expected, 2) : '-' }}</span>
+                            @endif
+                        </td>
+                        <td>
+                            @if(!$bill->is_cancelled)
+                                @if($bill->is_signed_by_generic_pro)
+                                    <div class="d-block text-secondary text-nowrap">
+                                        <i class="fa fa-check"></i>
+                                        Pro Signed
+                                    </div>
+                                @else
+                                    <div moe
+                                          class="d-block {{ $bill->generic_pro_id !== $pro->id ? 'moe-disabled' : '' }}"
+                                          title="{{ $bill->generic_pro_id !== $pro->id ? 'Only the bill\'s pro can sign' : '' }}">
+                                        <a class="" href="" show start>Sign As Pro</a>
+                                        <form url="/api/bill/signAsGenericPro">
+                                            <input type="hidden" name="uid" value="{{$bill->uid}}">
+                                            <p>Sign this bill as pro?</p>
+                                            <div class="mb-0">
+                                                <button class="btn btn-success btn-sm" submit>Sign</button>
+                                                <button class="btn btn-default border btn-sm" cancel>Cancel</button>
+                                            </div>
+                                        </form>
+                                    </div>
+                                @endif
+                            @endif
+                        </td>
+                        <td>  <!-- cancellation -->
+                            @if($bill->is_cancelled)
+                                <div class="text-warning-mellow font-weight-bold">Cancelled</div>
+                                @if($bill->cancellation_memo)
+                                    <div class="text-dark text-sm font-italic my-1">{{$bill->cancellation_memo}}</div>
+                                @endif
+                                @if($bill->is_cancelled_by_administrator)
+                                    <div class="text-secondary text-sm">(by Administrator)</div>
+                                @endif
+                                <div moe class="mt-1">
+                                    <a class="" href="" show start>Update Memo</a>
+                                    <form url="/api/bill/updateCancellationMemo">
+                                        <input type="hidden" name="uid" value="{{$bill->uid}}">
+                                        <p>Update Cancellation Memo</p>
+                                        <div class="mb-2">
+                                            <textarea class="text form-control form-control-sm" name="cancellationMemo"
+                                                      placeholder="">{{$bill->cancellation_memo ? $bill->cancellation_memo : 'Please contact billing.'}}</textarea>
+                                        </div>
+                                        <div>
+                                            <button class="btn btn-success btn-sm" submit>Submit</button>
+                                            <button class="btn btn-default border btn-sm" cancel>Cancel</button>
+                                        </div>
+                                    </form>
+                                </div>
+                            @else
+                                <div class="d-block" moe relative="">
+                                    <a class="text-danger" href="" show start>Cancel</a>
+                                    <form url="/api/bill/markCancelled" right="">
+                                        <input type="hidden" name="uid" value="{{$bill->uid}}">
+                                        <p class="mb-2">Cancel this bill?</p>
+                                        <div class="mb-2">
+                                            <label class="mb-1 text-secondary">Cancellation Memo</label>
+                                            <textarea type="text" name="memo" placeholder="Memo" class="form-control form-control-sm">Please contact billing.</textarea>
+                                        </div>
+                                        <div class="mb-0">
+                                            <button class="btn btn-danger btn-sm" submit>Yes</button>
+                                            <button class="btn btn-default border btn-sm" cancel>No</button>
+                                        </div>
+                                    </form>
+                                </div>
+                            @endif
+
+                            @if($bill->is_cancelled && !$bill->is_cancellation_acknowledged)
+                                <div class="mt-2 text-secondary">
+                                    <i class="fa fa-exclamation-triangle"></i>
+                                    Not Acknowledged
+                                </div>
+                                <div class="d-block mt-1" moe>
+                                    <a class="" href="" show start>Ack. Cancellation</a>
+                                    <form url="/api/bill/acknowledgeCancellation">
+                                        <input type="hidden" name="uid" value="{{$bill->uid}}">
+                                        <p>Acknowledge Cancellation?</p>
+                                        <div class="mb-0">
+                                            {{--<input type="text" class="text form-control form-control-sm" name="cancellationMemo" value="{{$bill->cancellation_memo}}" placeholder=""><br>--}}
+                                            <button class="btn btn-primary btn-sm" submit>Submit</button>
+                                            <button class="btn btn-default border btn-sm" cancel>Cancel</button>
+                                        </div>
+                                    </form>
+                                </div>
+                            @endif
+
+                            @if($bill->is_cancellation_acknowledged)
+                                <div class="mt-2 text-secondary">
+                                    <i class="fa fa-check"></i>
+                                    Acknowledged
+                                </div>
+                                <div class="d-block mt-1" moe>
+                                    <a class="" href="" show start>Undo Cancellation Ack.</a>
+                                    <form url="/api/bill/undoAcknowledgeCancellation">
+                                        <input type="hidden" name="uid" value="{{$bill->uid}}">
+                                        <p>Undo Acknowledge Cancellation?</p>
+                                        <div class="mb-0">
+                                            <button class="btn btn-success btn-sm" submit>Submit</button>
+                                            <button class="btn btn-default border btn-sm" cancel>Cancel</button>
+                                        </div>
+                                    </form>
+                                </div>
+                            @endif
+
+                        </td>
+                        @if($pro->pro_type === 'ADMIN')
+                        <td> <!-- verification -->
+                            @if(!$bill->is_cancelled)
+                                @if(!$bill->is_verified)
+                                    <div class="text-warning-mellow font-weight-bold">Not Verified</div>
+                                    <div class="d-block mt-1" moe>
+                                        <a href="" show start>Mark Verified</a>
+                                        <form url="/api/bill/markAsVerified">
+                                            <input type="hidden" name="uid" value="{{$bill->uid}}">
+                                            <p>Mark As Verified?</p>
+                                            <div class="mb-0">
+                                                <button class="btn btn-success btn-sm" submit>Submit</button>
+                                                <button class="btn btn-default border btn-sm" cancel>Cancel</button>
+                                            </div>
+                                        </form>
+                                    </div>
+                                @else
+                                    <div class="text-success font-weight-bold"><i class="fa fa-check"></i> Verified</div>
+                                    <div class="d-block mt-1" moe>
+                                        <a class="" href="" show start>Undo</a>
+                                        <form url="/api/bill/undoMarkAsVerified">
+                                            <input type="hidden" name="uid" value="{{$bill->uid}}">
+                                            <p>Undo Mark As Verified?</p>
+                                            <div class="mb-0">
+                                                <button class="btn btn-success btn-sm" submit>Submit</button>
+                                                <button class="btn btn-default border btn-sm" cancel>Cancel</button>
+                                            </div>
+                                        </form>
+                                    </div>
+                                @endif
+                            @endif
+                        </td>
+                        <td class="screen-only"> <!-- submit payment -->
+                            <div class="my-1">
+                                @if(!$bill->is_cancelled && !$bill->has_generic_pro_been_paid )
+                                    @if(+$bill->total_expected && $bill->is_signed_by_generic_pro)
+                                        <div class="d-block" moe relative="">
+                                            <a class="font-weight-bold" href="" show start>Submit Payment</a>
+                                            <form url="/api/bill/payGenericProAmount" right>
+                                                <input type="hidden" name="uid" value="{{$bill->uid}}">
+                                                <p>Submit Payment</p>
+                                                <div class="mb-0">
+                                                    <input type="text" class="text form-control form-control-sm" name="genericProPaymentAmount" value="{{$bill->total_expected}}" placeholder="amount"><br>
+                                                    <button class="btn btn-success btn-sm" submit>Submit</button>
+                                                    <button class="btn btn-default border btn-sm" cancel>Cancel</button>
+                                                </div>
+                                            </form>
+                                        </div>
+                                    @else
+                                        @if(!+$bill->total_expected)
+                                            <div class="mb-1 text-danger">
+                                                <i class="fa fa-exclamation-triangle"></i>
+                                                Pro expected amount is invalid
+                                            </div>
+                                        @endif
+                                        @if(!$bill->is_signed_by_generic_pro)
+                                            <div class="mb-1 text-danger">
+                                                <i class="fa fa-exclamation-triangle"></i>
+                                                Pro has not signed the bill
+                                            </div>
+                                        @endif
+                                    @endif
+                                @endif
+                            </div>
+                        </td>
+                        @endif
+                    </tr>
+                @endforeach
+                </tbody>
+            </table>
+    </div>
+@endif

+ 7 - 0
resources/views/app/generic-bills/modal.blade.php

@@ -0,0 +1,7 @@
+<a native target="_blank"
+   open-in-stag-popup
+   popup-style="tall"
+   title="{{@$label ? $label : 'Generic'}} bills"
+   href="{{route('generic-bill-view', ['entityType' => @$entityType, 'entityUid' => @$entityUid])}}">
+    {{@$label ? $label : 'Generic'}} bills
+</a>

+ 4 - 0
resources/views/app/patient/appointments.blade.php

@@ -33,6 +33,7 @@
                     <th class="px-2 text-secondary border-bottom-0">Description</th>
                     <th class="px-2 text-secondary border-bottom-0">Status</th>
                     <th class="px-2 text-secondary border-bottom-0">Confirmation</th>
+                    <th class="px-2 text-secondary border-bottom-0"></th>
                 </tr>
                 </thead>
                 <tbody>
@@ -50,6 +51,9 @@
                         <td class="px-2">
                             @include('app.patient.partials.appointment-confirmation')
                         </td>
+                        <td>
+                            @include('app.generic-bills.modal', ['entityType' => 'Appointment', 'entityUid' => $appointment->uid])
+                        </td>
                     </tr>
                 @endforeach
                 </tbody>

+ 14 - 6
resources/views/app/patient/canvas-sections/allergies/default.php

@@ -1,10 +1,18 @@
 <?php
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["allergies"])) {
-        $canvasData = $canvasData["allergies"];
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'allergies')->first();
+
+$contentData = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["allergies"])) {
+            $contentData = $canvasData["allergies"];
+        }
     }
 }
-$contentData = $canvasData;

+ 16 - 6
resources/views/app/patient/canvas-sections/allergies/summary.php

@@ -1,18 +1,28 @@
 <?php
 
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'allergies')->first();
+
 $contentData = [
     "items" => []
 ];
-if($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if(isset($canvasData["allergies"])) {
-        $contentData = $canvasData["allergies"];
-        if(!isset($contentData['items'])){
-            $contentData['items'] = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if(isset($canvasData["allergies"])) {
+            $contentData = $canvasData["allergies"];
+            if(!isset($contentData['items'])){
+                $contentData['items'] = [];
+            }
         }
     }
 }
 
+
 if(count($contentData['items'])) {
     for ($i = 0; $i < count($contentData['items']); $i++) {
         $item = $contentData['items'][$i];

+ 3 - 0
resources/views/app/patient/canvas-sections/canvas-editor-modal.blade.php

@@ -14,6 +14,9 @@
     <form method="POST" action="/api/client/updateCanvasData">
         <input type="hidden" name="uid" value="{{$patient->uid}}">
         <input type="hidden" name="key" value="{{$key}}">
+        @if(isset($note))
+        <input type="hidden" name="noteUid" value="{{$note->uid}}">
+        @endif
 
         @include("app.patient.canvas-sections.{$key}.form")
 

+ 14 - 6
resources/views/app/patient/canvas-sections/care-team/default.php

@@ -1,10 +1,18 @@
 <?php
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["care-team"])) {
-        $canvasData = $canvasData["care-team"];
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'care-team')->first();
+
+$contentData = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["care-team"])) {
+            $contentData = $canvasData["care-team"];
+        }
     }
 }
-$contentData = $canvasData;

+ 14 - 4
resources/views/app/patient/canvas-sections/care-team/summary.php

@@ -1,15 +1,25 @@
 <?php
 
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'care-team')->first();
+
 $contentData = [
     "items" => []
 ];
-if($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if(isset($canvasData["care-team"])) {
-        $contentData = $canvasData["care-team"];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if(isset($canvasData["care-team"])) {
+            $contentData = $canvasData["care-team"];
+        }
     }
 }
 
+
 if(count($contentData['items'])) {
     for ($i = 0; $i < count($contentData['items']); $i++) {
         $item = $contentData['items'][$i];

+ 71 - 23
resources/views/app/patient/canvas-sections/cc_hpi/default.php

@@ -1,4 +1,10 @@
-<?php
+<?php 
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'cc_hpi')->first();
+$nextFuPage = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'next_fu')->first();
+
 
 /** @var \App\Models\Pro $hcpPro */
 /** @var \App\Models\Pro $pro */
@@ -14,34 +20,76 @@ if(!@$hcpPro) {
 }
 
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
+$contentData = [];
 
-    if(!isset($canvasData["cc_hpi"])) $canvasData["cc_hpi"] = [];
-    if(!isset($canvasData["cc_hpi"][$hcpPro->id])) {
-        $canvasData["cc_hpi"][$hcpPro->id] = [];
+if($page){
+    $contentData = json_decode($page->data, true);
+        
+    if(!isset($contentData[$hcpPro->id])) {
+        $contentData[$hcpPro->id] = [
+            'current_cc' => []
+        ];
     }
 
-    // if next_fu->next_cc available, prefill with that
-    if (isset($canvasData["next_fu"]) && isset($canvasData["next_fu"][$hcpPro->id])) {
-
-        $nextFU = $canvasData["next_fu"][$hcpPro->id];
-        if(isset($nextFU['next_cc']) && isset($nextFU['next_cc']['list']) && count($nextFU['next_cc']['list'])) {
-            $prefillData = array_map(function($_x) {
-                if(!isset($_x['icd'])) $_x['icd'] = '';
-                if(!isset($_x['memo'])) $_x['memo'] = '';
-                $_x['hpi'] = [
-                    'free_text' => ''
+    if($nextFuPage){
+        if (isset($canvasData["next_fu"]) && isset($canvasData["next_fu"][$hcpPro->id])) {
+            $nextFuData = json_decode($page->data, true);
+            $nextFU = $nextFuData[$hcpPro->id];
+            if(isset($nextFU['next_cc']) && isset($nextFU['next_cc']['list']) && count($nextFU['next_cc']['list'])) {
+                $prefillData = array_map(function($_x) {
+                    if(!isset($_x['icd'])) $_x['icd'] = '';
+                    if(!isset($_x['memo'])) $_x['memo'] = '';
+                    $_x['hpi'] = [
+                        'free_text' => ''
+                    ];
+                    return $_x;
+                }, $nextFU['next_cc']['list']);
+                $contentData[$hcpPro->id]['current_cch'] = [
+                    'list' => $prefillData
                 ];
-                return $_x;
-            }, $nextFU['next_cc']['list']);
-            $canvasData["cc_hpi"][$hcpPro->id]['current_cch'] = [
-                'list' => $prefillData
+            }
+        }
+    }
+    $contentData = $contentData[$hcpPro->id];
+    
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+    
+        if(!isset($canvasData["cc_hpi"])) $canvasData["cc_hpi"] = [];
+
+
+        if(!isset($canvasData["cc_hpi"][$hcpPro->id])) {
+            $canvasData["cc_hpi"][$hcpPro->id] = [
+                'current_cc' => []
             ];
         }
+
+        if (isset($canvasData["next_fu"]) && isset($canvasData["next_fu"][$hcpPro->id])) {
+    
+            $nextFU = $canvasData["next_fu"][$hcpPro->id];
+            if(isset($nextFU['next_cc']) && isset($nextFU['next_cc']['list']) && count($nextFU['next_cc']['list'])) {
+                $prefillData = array_map(function($_x) {
+                    if(!isset($_x['icd'])) $_x['icd'] = '';
+                    if(!isset($_x['memo'])) $_x['memo'] = '';
+                    $_x['hpi'] = [
+                        'free_text' => ''
+                    ];
+                    return $_x;
+                }, $nextFU['next_cc']['list']);
+                $contentData[$hcpPro->id]['current_cch'] = [
+                    'list' => $prefillData
+                ];
+            }
+        }
+
+        $contentData = $canvasData['cc_hpi'][$hcpPro->id];
+        
     }
-    $canvasData = $canvasData['cc_hpi'][$hcpPro->id];
+}
 
+if(!isset($contentData['current_cc'])){
+    $contentData['current_cc'] = [];
 }
-$contentData = $canvasData;
+
+

+ 18 - 4
resources/views/app/patient/canvas-sections/cc_hpi/summary.php

@@ -1,5 +1,9 @@
 <?php
 
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'cc_hpi')->first();
+
 // HUMONGOUS FIX! This CRITICAL "if" was never there till now!
 if(!@$contentData) {
 
@@ -17,10 +21,20 @@ if(!@$contentData) {
     }
 
     $contentData = false;
-    if ($patient->canvas_data) {
-        $canvasData = json_decode($patient->canvas_data, true);
-        if(isset($canvasData["cc_hpi"]) && isset($canvasData["cc_hpi"][$hcpPro->id])) {
-            $contentData = $canvasData["cc_hpi"][$hcpPro->id];
+    if($page){
+        $contentData = json_decode($page->data, true);
+        if(!isset($contentData[$hcpPro->id])) {
+            $contentData[$hcpPro->id] = [
+                'current_cc' => []
+            ];
+        }
+        $contentData = $contentData[$hcpPro->id];
+    }else{
+        if ($patient->canvas_data) {
+            $canvasData = json_decode($patient->canvas_data, true);
+            if(isset($canvasData["cc_hpi"]) && isset($canvasData["cc_hpi"][$hcpPro->id])) {
+                $contentData = $canvasData["cc_hpi"][$hcpPro->id];
+            }
         }
     }
 }

+ 29 - 9
resources/views/app/patient/canvas-sections/cc_may21/default.php

@@ -1,30 +1,50 @@
 <?php
 
+
 use App\Models\Client;
 use App\Models\Note;
 
 /** @var Client $patient */
 /** @var Note $note */
 
-$canvasData = [
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'cc_may21')->first();
+
+$dxPage = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'dx')->first();
+
+$contentData =[
     "text" => '',
     "was_confirmed" => false,
     "note_uid" => '',
 ];
 
+
 $patientDx = null;
 
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["dx"])) {
-        $patientDx = $canvasData["dx"];
-    }
-    if (isset($canvasData["cc_may21"])) {
-        $canvasData = $canvasData["cc_may21"];
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["cc_may21"])) {
+            $contentData = $canvasData["cc_may21"];
+        }
     }
 }
-$contentData = $canvasData;
 
+if($dxPage){
+    $patientDx = json_decode($dxPage->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["dx"])) {
+            $patientDx = $canvasData["dx"];
+        }
+    }
+}
+ 
 if (!isset($contentData['note_uid']) || $contentData['note_uid'] !== @$note->uid) {
     $prefix = $patient->name_prefix ?: '';
     if (!$prefix) {

+ 15 - 6
resources/views/app/patient/canvas-sections/cc_may21/summary.php

@@ -3,6 +3,10 @@
 use App\Models\Client;
 use App\Models\Note;
 
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'cc_may21')->first();
+
 /** @var Client $patient */
 /** @var Note $note */
 
@@ -12,12 +16,17 @@ if(!@$contentData) {
         "was_confirmed" => false,
         "note_uid" => (@$note ? $note->uid : '')
     ];
-    if ($patient->canvas_data) {
-        $canvasData = json_decode($patient->canvas_data, true);
-        if (isset($canvasData["cc_may21"])) {
-            $contentData = $canvasData["cc_may21"];
-            if (!isset($contentData['text'])) $contentData['text'] = '';
-            if (!isset($contentData['was_confirmed'])) $contentData['was_confirmed'] = false;
+
+    if($page){
+        $contentData = json_decode($page->data, true);
+    }else{
+        if ($patient->canvas_data) {
+            $canvasData = json_decode($patient->canvas_data, true);
+            if (isset($canvasData["cc_may21"])) {
+                $contentData = $canvasData["cc_may21"];
+                if (!isset($contentData['text'])) $contentData['text'] = '';
+                if (!isset($contentData['was_confirmed'])) $contentData['was_confirmed'] = false;
+            }
         }
     }
 }

+ 20 - 11
resources/views/app/patient/canvas-sections/dx/default.php

@@ -1,17 +1,26 @@
 <?php
-$canvasData = [
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'dx')->first();
+
+$contentData = [
     "items" => []
 ];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["dx"])) {
-        $canvasData = $canvasData["dx"];
-        if(!isset($canvasData["items"])) {
-            $canvasData["items"] = [];
-        }
-        for ($i = 0; $i < count($canvasData["items"]); $i++) {
-            $canvasData["items"][$i]["included"] = 1;
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else {
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["dx"])) {
+            $contentData = $canvasData["dx"];
+            if(!isset($contentData["items"])) {
+                $contentData["items"] = [];
+            }
+            for ($i = 0; $i < count($contentData["items"]); $i++) {
+                $contentData["items"][$i]["included"] = 1;
+            }
         }
     }
 }
-$contentData = $canvasData;
+

+ 17 - 6
resources/views/app/patient/canvas-sections/dx/summary.php

@@ -1,17 +1,28 @@
 <?php
 
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'dx')->first();
+
+
 $contentData = [
     "items" => []
 ];
-if($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if(isset($canvasData["dx"])) {
-        $contentData = $canvasData["dx"];
 
-        if(!isset($contentData['items'])){
-            $contentData['items'] = [];
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if(isset($canvasData["dx"])) {
+            $contentData = $canvasData["dx"];
+    
+            if(!isset($contentData['items'])){
+                $contentData['items'] = [];
+            }
         }
     }
+    
 }
 
 if(count($contentData['items'])) {

+ 13 - 6
resources/views/app/patient/canvas-sections/fhx/default.php

@@ -1,10 +1,17 @@
 <?php
 
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'fhx')->first();
+
 $canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["fhx"])) {
-        $canvasData = $canvasData["fhx"];
-    }
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["fhx"])) {
+            $contentData = $canvasData["fhx"];
+        }
+    }    
 }
-$contentData = $canvasData;

+ 16 - 6
resources/views/app/patient/canvas-sections/fhx/summary.php

@@ -1,20 +1,30 @@
 <?php
 
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'fhx')->first();
+
 $contentData = [
     "count" => 0,
     "unknown" => false,
     "items" => []
 ];
-if($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if(isset($canvasData["fhx"])) {
-        $contentData = $canvasData["fhx"];
-        if(!isset($contentData['items'])){
-            $contentData['items'] = [];
+
+if($page) {
+    $contentData = json_decode($page->data, true);
+}else{
+    if($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if(isset($canvasData["fhx"])) {
+            $contentData = $canvasData["fhx"];
+            if(!isset($contentData['items'])){
+                $contentData['items'] = [];
+            }
         }
     }
 }
 
+
 $labels = [
     'general_no_health_concern' => 'No health concern',
     'general_arthritis' => 'Arthritis',

+ 113 - 104
resources/views/app/patient/canvas-sections/lifestyle_rx_review/default.php

@@ -4,6 +4,10 @@
 /** @var \App\Models\Pro $pro */
 /** @var \App\Models\Note $note */
 
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'lifestyle_rx_review')->first();
+
 if(!@$hcpPro) {
     if(@$note) {
         $hcpPro = $note->hcpPro;
@@ -13,134 +17,139 @@ if(!@$hcpPro) {
     }
 }
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if(!isset($canvasData["lifestyle_rx_review"])) $canvasData["lifestyle_rx_review"] = [];
-    if(!isset($canvasData["lifestyle_rx_review"][$hcpPro->id])) {
-        $canvasData["lifestyle_rx_review"][$hcpPro->id] = [
-            'physical_activity' => [
-                'type' => '',
-                'frequency' => '',
-                'time' => '',
-                'intensity' => '',
-                'enjoyment' => '',
+$contentData = [];
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if(!isset($canvasData["lifestyle_rx_review"])) $canvasData["lifestyle_rx_review"] = [];    
+        $contentData = $canvasData["lifestyle_rx_review"];
+    }
+}
+
+
+if(!isset($contentData[$hcpPro->id])) {
+    $contentData[$hcpPro->id] = [
+        'physical_activity' => [
+            'type' => '',
+            'frequency' => '',
+            'time' => '',
+            'intensity' => '',
+            'enjoyment' => '',
+        ],
+        'barriers' => '',   // free text
+        'assessment' => '', // Inactive, Insufficiently Active, Active, Highly Active
+        'adherence' => [
+            'seated' => [
+                'active' => false,
+                'memo' => '',
+                'adherence' => '',
+                'adherence_memo' => '',
+            ],
+            'arm' => [
+                'active' => false,
+                'memo' => '',
+                'adherence' => '',
+                'adherence_memo' => '',
             ],
-            'barriers' => '',   // free text
-            'assessment' => '', // Inactive, Insufficiently Active, Active, Highly Active
-            'adherence' => [
-                'seated' => [
+            'aquatic' => [
+                'active' => false,
+                'memo' => '',
+                'adherence' => '',
+                'adherence_memo' => '',
+            ],
+            'aerobic' => [
+                'active' => false,
+                'walk' => [
                     'active' => false,
+                    'days_per_week' => '',
+                    'minutes_per_day' => '',
+                    'intensity' => '', // Light, Moderate, Vigorous
                     'memo' => '',
                     'adherence' => '',
                     'adherence_memo' => '',
                 ],
-                'arm' => [
+                'jog' => [
                     'active' => false,
+                    'days_per_week' => '',
+                    'minutes_per_day' => '',
+                    'intensity' => '', // Light, Moderate, Vigorous
                     'memo' => '',
                     'adherence' => '',
                     'adherence_memo' => '',
                 ],
-                'aquatic' => [
+                'elliptical' => [
                     'active' => false,
+                    'days_per_week' => '',
+                    'minutes_per_day' => '',
+                    'intensity' => '', // Light, Moderate, Vigorous
                     'memo' => '',
                     'adherence' => '',
                     'adherence_memo' => '',
                 ],
-                'aerobic' => [
+                'swim' => [
                     'active' => false,
-                    'walk' => [
-                        'active' => false,
-                        'days_per_week' => '',
-                        'minutes_per_day' => '',
-                        'intensity' => '', // Light, Moderate, Vigorous
-                        'memo' => '',
-                        'adherence' => '',
-                        'adherence_memo' => '',
-                    ],
-                    'jog' => [
-                        'active' => false,
-                        'days_per_week' => '',
-                        'minutes_per_day' => '',
-                        'intensity' => '', // Light, Moderate, Vigorous
-                        'memo' => '',
-                        'adherence' => '',
-                        'adherence_memo' => '',
-                    ],
-                    'elliptical' => [
-                        'active' => false,
-                        'days_per_week' => '',
-                        'minutes_per_day' => '',
-                        'intensity' => '', // Light, Moderate, Vigorous
-                        'memo' => '',
-                        'adherence' => '',
-                        'adherence_memo' => '',
-                    ],
-                    'swim' => [
-                        'active' => false,
-                        'days_per_week' => '',
-                        'minutes_per_day' => '',
-                        'intensity' => '', // Light, Moderate, Vigorous
-                        'memo' => '',
-                        'adherence' => '',
-                        'adherence_memo' => '',
-                    ],
-                    'bike' => [
-                        'active' => false,
+                    'days_per_week' => '',
+                    'minutes_per_day' => '',
+                    'intensity' => '', // Light, Moderate, Vigorous
+                    'memo' => '',
+                    'adherence' => '',
+                    'adherence_memo' => '',
+                ],
+                'bike' => [
+                    'active' => false,
+                    'days_per_week' => '',
+                    'minutes_per_day' => '',
+                    'intensity' => '', // Light, Moderate, Vigorous
+                    'memo' => '',
+                    'adherence' => '',
+                    'adherence_memo' => '',
+                ],
+            ],
+            'strength' => [
+                'active' => false,
+                'exercises' => [
+                    [
+                        'name' => '',
                         'days_per_week' => '',
-                        'minutes_per_day' => '',
+                        'reps' => '',
                         'intensity' => '', // Light, Moderate, Vigorous
                         'memo' => '',
                         'adherence' => '',
                         'adherence_memo' => '',
-                    ],
-                ],
-                'strength' => [
-                    'active' => false,
-                    'exercises' => [
-                        [
-                            'name' => '',
-                            'days_per_week' => '',
-                            'reps' => '',
-                            'intensity' => '', // Light, Moderate, Vigorous
-                            'memo' => '',
-                            'adherence' => '',
-                            'adherence_memo' => '',
-                        ]
-                    ]
-                ],
-                'neat' => [
-                    'active' => false,
-                    'recommendations' => [
-                        'park_farther' => false,
-                        'park_farther_adherence' => '',
-                        'park_farther_adherence_memo' => '',
-                        'steps_instead_of_elevator' => false,
-                        'steps_instead_of_elevator_adherence' => '',
-                        'steps_instead_of_elevator_adherence_memo' => '',
-                        'stand_instead_of_sit' => false,
-                        'stand_instead_of_sit_adherence' => '',
-                        'stand_instead_of_sit_adherence_memo' => '',
-                        'steps_goal_per_day' => '',
-                        'steps_goal_per_day_adherence' => '',
-                        'steps_goal_per_day_adherence_memo' => '',
-                        'other' => '',
-                        'other_adherence' => '',
-                        'other_adherence_memo' => '',
                     ]
                 ]
+            ],
+            'neat' => [
+                'active' => false,
+                'recommendations' => [
+                    'park_farther' => false,
+                    'park_farther_adherence' => '',
+                    'park_farther_adherence_memo' => '',
+                    'steps_instead_of_elevator' => false,
+                    'steps_instead_of_elevator_adherence' => '',
+                    'steps_instead_of_elevator_adherence_memo' => '',
+                    'stand_instead_of_sit' => false,
+                    'stand_instead_of_sit_adherence' => '',
+                    'stand_instead_of_sit_adherence_memo' => '',
+                    'steps_goal_per_day' => '',
+                    'steps_goal_per_day_adherence' => '',
+                    'steps_goal_per_day_adherence_memo' => '',
+                    'other' => '',
+                    'other_adherence' => '',
+                    'other_adherence_memo' => '',
+                ]
             ]
-        ];
-    }
-
-    // if lifestyle_rx_update available, prefill with that
-    if (isset($canvasData["lifestyle_rx_update"]) &&
-        isset($canvasData["lifestyle_rx_update"][$hcpPro->id]) &&
-        isset($canvasData["lifestyle_rx_update"][$hcpPro->id]['prescription'])) {
-        $canvasData["lifestyle_rx_review"][$hcpPro->id]['adherence'] = $canvasData["lifestyle_rx_update"][$hcpPro->id]['prescription'];
-    }
-
-    $canvasData = $canvasData['lifestyle_rx_review'][$hcpPro->id];
+        ]
+    ];
+}
 
+// if lifestyle_rx_update available, prefill with that
+if (isset($contentData) &&
+    isset($contentData[$hcpPro->id]) &&
+    isset($contentData[$hcpPro->id]['prescription'])) {
+    $contentData[$hcpPro->id]['adherence'] =$contentData[$hcpPro->id]['prescription'];
 }
-$contentData = $canvasData;
+
+$contentData = $contentData[$hcpPro->id];

+ 107 - 95
resources/views/app/patient/canvas-sections/lifestyle_rx_review/summary.php

@@ -1,5 +1,10 @@
 <?php
 
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'lifestyle_rx_review')->first();
+
+
 // HUMONGOUS FIX! This CRITICAL "if" was never there till now!
 if(!@$contentData) {
     /** @var \App\Models\Pro $hcpPro */
@@ -16,126 +21,133 @@ if(!@$contentData) {
     }
 
     $contentData = false;
-    if ($patient->canvas_data) {
-        $canvasData = json_decode($patient->canvas_data, true);
-        if(isset($canvasData["lifestyle_rx_review"]) && isset($canvasData["lifestyle_rx_review"][$hcpPro->id])) {
-            $contentData = $canvasData["lifestyle_rx_review"][$hcpPro->id];
-        }
-        else { // default data structure
-            $contentData = [
-                'physical_activity' => [
-                    'type' => '',
-                    'frequency' => '',
-                    'time' => '',
-                    'intensity' => '',
-                    'enjoyment' => '',
+
+    if($page){
+        $contentData = json_decode($page->data, true);
+    }else{
+        if ($patient->canvas_data) {
+            $canvasData = json_decode($patient->canvas_data, true);
+            $contentData = $canvasData["lifestyle_rx_review"];
+        }    
+    }
+
+    
+    if(isset($contentData) && isset($contentData[$hcpPro->id])) {
+        $contentData = $contentData[$hcpPro->id];
+    }else { // default data structure
+        $contentData = [
+            'physical_activity' => [
+                'type' => '',
+                'frequency' => '',
+                'time' => '',
+                'intensity' => '',
+                'enjoyment' => '',
+            ],
+            'barriers' => '',   // free text
+            'assessment' => '', // Inactive, Insufficiently Active, Active, Highly Active
+            'adherence' => [
+                'seated' => [
+                    'active' => false,
+                    'memo' => '',
+                    'adherence' => '',
+                    'adherence_memo' => '',
+                ],
+                'arm' => [
+                    'active' => false,
+                    'memo' => '',
+                    'adherence' => '',
+                    'adherence_memo' => '',
+                ],
+                'aquatic' => [
+                    'active' => false,
+                    'memo' => '',
+                    'adherence' => '',
+                    'adherence_memo' => '',
                 ],
-                'barriers' => '',   // free text
-                'assessment' => '', // Inactive, Insufficiently Active, Active, Highly Active
-                'adherence' => [
-                    'seated' => [
+                'aerobic' => [
+                    'active' => false,
+                    'walk' => [
                         'active' => false,
+                        'days_per_week' => '',
+                        'minutes_per_day' => '',
+                        'intensity' => '', // Light, Moderate, Vigorous
                         'memo' => '',
                         'adherence' => '',
                         'adherence_memo' => '',
                     ],
-                    'arm' => [
+                    'jog' => [
                         'active' => false,
+                        'days_per_week' => '',
+                        'minutes_per_day' => '',
+                        'intensity' => '', // Light, Moderate, Vigorous
                         'memo' => '',
                         'adherence' => '',
                         'adherence_memo' => '',
                     ],
-                    'aquatic' => [
+                    'elliptical' => [
                         'active' => false,
+                        'days_per_week' => '',
+                        'minutes_per_day' => '',
+                        'intensity' => '', // Light, Moderate, Vigorous
                         'memo' => '',
                         'adherence' => '',
                         'adherence_memo' => '',
                     ],
-                    'aerobic' => [
+                    'swim' => [
                         'active' => false,
-                        'walk' => [
-                            'active' => false,
-                            'days_per_week' => '',
-                            'minutes_per_day' => '',
-                            'intensity' => '', // Light, Moderate, Vigorous
-                            'memo' => '',
-                            'adherence' => '',
-                            'adherence_memo' => '',
-                        ],
-                        'jog' => [
-                            'active' => false,
-                            'days_per_week' => '',
-                            'minutes_per_day' => '',
-                            'intensity' => '', // Light, Moderate, Vigorous
-                            'memo' => '',
-                            'adherence' => '',
-                            'adherence_memo' => '',
-                        ],
-                        'elliptical' => [
-                            'active' => false,
-                            'days_per_week' => '',
-                            'minutes_per_day' => '',
-                            'intensity' => '', // Light, Moderate, Vigorous
-                            'memo' => '',
-                            'adherence' => '',
-                            'adherence_memo' => '',
-                        ],
-                        'swim' => [
-                            'active' => false,
-                            'days_per_week' => '',
-                            'minutes_per_day' => '',
-                            'intensity' => '', // Light, Moderate, Vigorous
-                            'memo' => '',
-                            'adherence' => '',
-                            'adherence_memo' => '',
-                        ],
-                        'bike' => [
-                            'active' => false,
+                        'days_per_week' => '',
+                        'minutes_per_day' => '',
+                        'intensity' => '', // Light, Moderate, Vigorous
+                        'memo' => '',
+                        'adherence' => '',
+                        'adherence_memo' => '',
+                    ],
+                    'bike' => [
+                        'active' => false,
+                        'days_per_week' => '',
+                        'minutes_per_day' => '',
+                        'intensity' => '', // Light, Moderate, Vigorous
+                        'memo' => '',
+                        'adherence' => '',
+                        'adherence_memo' => '',
+                    ],
+                ],
+                'strength' => [
+                    'active' => false,
+                    'exercises' => [
+                        [
+                            'name' => '',
                             'days_per_week' => '',
-                            'minutes_per_day' => '',
+                            'reps' => '',
                             'intensity' => '', // Light, Moderate, Vigorous
                             'memo' => '',
                             'adherence' => '',
                             'adherence_memo' => '',
-                        ],
-                    ],
-                    'strength' => [
-                        'active' => false,
-                        'exercises' => [
-                            [
-                                'name' => '',
-                                'days_per_week' => '',
-                                'reps' => '',
-                                'intensity' => '', // Light, Moderate, Vigorous
-                                'memo' => '',
-                                'adherence' => '',
-                                'adherence_memo' => '',
-                            ]
-                        ]
-                    ],
-                    'neat' => [
-                        'active' => false,
-                        'recommendations' => [
-                            'park_farther' => false,
-                            'park_farther_adherence' => '',
-                            'park_farther_adherence_memo' => '',
-                            'steps_instead_of_elevator' => false,
-                            'steps_instead_of_elevator_adherence' => '',
-                            'steps_instead_of_elevator_adherence_memo' => '',
-                            'stand_instead_of_sit' => false,
-                            'stand_instead_of_sit_adherence' => '',
-                            'stand_instead_of_sit_adherence_memo' => '',
-                            'steps_goal_per_day' => '',
-                            'steps_goal_per_day_adherence' => '',
-                            'steps_goal_per_day_adherence_memo' => '',
-                            'other' => '',
-                            'other_adherence' => '',
-                            'other_adherence_memo' => '',
                         ]
                     ]
+                ],
+                'neat' => [
+                    'active' => false,
+                    'recommendations' => [
+                        'park_farther' => false,
+                        'park_farther_adherence' => '',
+                        'park_farther_adherence_memo' => '',
+                        'steps_instead_of_elevator' => false,
+                        'steps_instead_of_elevator_adherence' => '',
+                        'steps_instead_of_elevator_adherence_memo' => '',
+                        'stand_instead_of_sit' => false,
+                        'stand_instead_of_sit_adherence' => '',
+                        'stand_instead_of_sit_adherence_memo' => '',
+                        'steps_goal_per_day' => '',
+                        'steps_goal_per_day_adherence' => '',
+                        'steps_goal_per_day_adherence_memo' => '',
+                        'other' => '',
+                        'other_adherence' => '',
+                        'other_adherence_memo' => '',
+                    ]
                 ]
-            ];
-        }
+            ]
+        ];
     }
 }
 

+ 18 - 7
resources/views/app/patient/canvas-sections/lifestyle_rx_update/default.php

@@ -1,5 +1,9 @@
 <?php
 
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'lifestyle_rx_update')->first();
+
 /** @var \App\Models\Pro $hcpPro */
 /** @var \App\Models\Pro $pro */
 /** @var \App\Models\Note $note */
@@ -13,11 +17,18 @@ if(!@$hcpPro) {
     }
 }
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if(!isset($canvasData["lifestyle_rx_update"])) $canvasData["lifestyle_rx_update"] = [];
-    if(!isset($canvasData["lifestyle_rx_update"][$hcpPro->id])) $canvasData["lifestyle_rx_update"][$hcpPro->id] = [];
-    $canvasData = $canvasData['lifestyle_rx_update'][$hcpPro->id];
+$contentData = [];
+
+if($page) {
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if(!isset($canvasData["lifestyle_rx_update"])) $canvasData['lifestyle_rx_update'] = [];
+        $contentData = $canvasData["lifestyle_rx_update"];
+    }
 }
-$contentData = $canvasData;
+if(!isset($contentData[$hcpPro->id])) $contentData[$hcpPro->id] = [];
+$contentData = $contentData[$hcpPro->id];
+
+

+ 69 - 4
resources/views/app/patient/canvas-sections/lifestyle_rx_update/summary.php

@@ -1,5 +1,10 @@
 <?php
 
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'lifestyle_rx_update')->first();
+
 // HUMONGOUS FIX! This CRITICAL "if" was never there till now!
 if(!@$contentData) {
     /** @var \App\Models\Pro $hcpPro */
@@ -16,12 +21,72 @@ if(!@$contentData) {
     }
 
     $contentData = false;
-    if ($patient->canvas_data) {
-        $canvasData = json_decode($patient->canvas_data, true);
-        if(isset($canvasData["lifestyle_rx_update"]) && isset($canvasData["lifestyle_rx_update"][$hcpPro->id])) {
-            $contentData = $canvasData["lifestyle_rx_update"][$hcpPro->id];
+    if($page) {
+        $contentData = json_decode($page->data, true);
+    }else{
+        if ($patient->canvas_data) {
+            $canvasData = json_decode($patient->canvas_data, true);
+            if(!isset($canvasData["lifestyle_rx_update"])) $canvasData["lifestyle_rx_update"] = [];
+            $contentData = $canvasData["lifestyle_rx_update"];
         }
     }
+    if(!isset($contentData[$hcpPro->id])) $contentData[$hcpPro->id] = [];
+    $contentData = $contentData[$hcpPro->id];    
+
+    if(!isset($contentData['prescription'])) $contentData['prescription'] = [];
+    if(!isset($contentData['prescription']['seated'])) $contentData['prescription']['seated'] = [];
+    if(!isset($contentData['prescription']['seated']['memo'])) $contentData['prescription']['seated']['memo'] = "";
+    if(!isset($contentData['prescription']['seated']['active'])) $contentData['prescription']['seated']['active'] = false;
+
+    if(!isset($contentData['prescription']['arm'])) $contentData['prescription']['arm'] = [];
+    if(!isset($contentData['prescription']['arm']['active'])) $contentData['prescription']['arm']['active'] = [];
+    if(!isset($contentData['prescription']['arm']['memo'])) $contentData['prescription']['arm']['memo'] = [];
+    if(!isset($contentData['prescription']['aquatic'])) $contentData['prescription']['aquatic'] = [];
+    if(!isset($contentData['prescription']['aquatic']['active'])) $contentData['prescription']['aquatic']['active'] = [];
+    if(!isset($contentData['prescription']['aquatic']['memo'])) $contentData['prescription']['aquatic']['memo'] = [];
+    if(!isset($contentData['prescription']['aerobic'])) $contentData['prescription']['aerobic'] = [];
+    if(!isset($contentData['prescription']['aerobic']['active'])) $contentData['prescription']['aerobic']['active'] = [];
+    if(!isset($contentData['prescription']['aerobic']['walk']['active'])) $contentData['prescription']['aerobic']['walk']['active'] = [];
+    if(!isset($contentData['prescription']['aerobic']['walk']['days_per_week'])) $contentData['prescription']['aerobic']['walk']['days_per_week'] = [];
+    if(!isset($contentData['prescription']['aerobic']['walk']['minutes_per_day'])) $contentData['prescription']['aerobic']['walk']['minutes_per_day'] = [];
+    if(!isset($contentData['prescription']['aerobic']['walk']['intensity'])) $contentData['prescription']['aerobic']['walk']['intensity'] = [];
+    if(!isset($contentData['prescription']['aerobic']['walk']['memo'])) $contentData['prescription']['aerobic']['walk']['memo'] = [];
+    if(!isset($contentData['prescription']['aerobic']['jog'])) $contentData['prescription']['aerobic']['jog'] = [];
+    if(!isset($contentData['prescription']['aerobic']['jog']['active'])) $contentData['prescription']['aerobic']['jog']['active'] = [];
+    if(!isset($contentData['prescription']['aerobic']['jog']['days_per_week'])) $contentData['prescription']['aerobic']['jog']['days_per_week'] = [];
+    if(!isset($contentData['prescription']['aerobic']['jog']['minutes_per_day'])) $contentData['prescription']['aerobic']['jog']['minutes_per_day'] = [];
+    if(!isset($contentData['prescription']['aerobic']['jog']['intensity'])) $contentData['prescription']['aerobic']['jog']['intensity'] = [];
+    if(!isset($contentData['prescription']['aerobic']['jog']['memo'])) $contentData['prescription']['aerobic']['jog']['memo'] = [];
+    if(!isset($contentData['prescription']['aerobic']['elliptical'])) $contentData['prescription']['aerobic']['elliptical'] = [];
+    if(!isset($contentData['prescription']['aerobic']['elliptical']['active'])) $contentData['prescription']['aerobic']['elliptical']['active'] = [];
+    if(!isset($contentData['prescription']['aerobic']['elliptical']['days_per_week'])) $contentData['prescription']['aerobic']['elliptical']['days_per_week'] = [];
+    if(!isset($contentData['prescription']['aerobic']['elliptical']['minutes_per_day'])) $contentData['prescription']['aerobic']['elliptical']['minutes_per_day'] = [];
+    if(!isset($contentData['prescription']['aerobic']['elliptical']['intensity'])) $contentData['prescription']['aerobic']['elliptical']['intensity'] = [];
+    if(!isset($contentData['prescription']['aerobic']['elliptical']['memo'])) $contentData['prescription']['aerobic']['elliptical']['memo'] = [];
+    if(!isset($contentData['prescription']['aerobic']['swim'])) $contentData['prescription']['aerobic']['swim'] = [];
+    if(!isset($contentData['prescription']['aerobic']['swim']['active'])) $contentData['prescription']['aerobic']['swim']['active'] = [];
+    if(!isset($contentData['prescription']['aerobic']['swim']['days_per_week'])) $contentData['prescription']['aerobic']['swim']['days_per_week'] = [];
+    if(!isset($contentData['prescription']['aerobic']['swim']['minutes_per_day'])) $contentData['prescription']['aerobic']['swim']['minutes_per_day'] = [];
+    if(!isset($contentData['prescription']['aerobic']['swim']['intensity'])) $contentData['prescription']['aerobic']['swim']['intensity'] = [];
+    if(!isset($contentData['prescription']['aerobic']['swim']['memo'])) $contentData['prescription']['aerobic']['swim']['memo'] = [];
+    if(!isset($contentData['prescription']['aerobic']['bike'])) $contentData['prescription']['aerobic']['bike'] = [];
+    if(!isset($contentData['prescription']['aerobic']['bike']['active'])) $contentData['prescription']['aerobic']['bike']['active'] = [];
+    if(!isset($contentData['prescription']['aerobic']['bike']['days_per_week'])) $contentData['prescription']['aerobic']['bike']['days_per_week'] = [];
+    if(!isset($contentData['prescription']['aerobic']['bike']['minutes_per_day'])) $contentData['prescription']['aerobic']['bike']['minutes_per_day'] = [];
+    if(!isset($contentData['prescription']['aerobic']['bike']['intensity'])) $contentData['prescription']['aerobic']['bike']['intensity'] = [];
+    if(!isset($contentData['prescription']['aerobic']['bike']['memo'])) $contentData['prescription']['aerobic']['bike']['memo'] = [];
+    if(!isset($contentData['prescription']['strength'])) $contentData['prescription']['strength'] = [];
+    if(!isset($contentData['prescription']['strength']['active'])) $contentData['prescription']['strength']['active'] = [];
+    if(!isset($contentData['prescription']['strength']['exercises'])) $contentData['prescription']['strength']['exercises'] = [];
+    if(!isset($contentData['prescription']['neat'])) $contentData['prescription']['neat'] = [];
+    if(!isset($contentData['prescription']['neat']['active'])) $contentData['prescription']['neat']['active'] = [];
+    if(!isset($contentData['prescription']['neat']['recommendations'])) $contentData['prescription']['neat']['recommendations'] = [];
+    if(!isset($contentData['prescription']['neat']['recommendations']['park_farther'])) $contentData['prescription']['neat']['recommendations']['park_farther'] = [];
+    if(!isset($contentData['prescription']['neat']['recommendations']['steps_instead_of_elevator'])) $contentData['prescription']['neat']['recommendations']['steps_instead_of_elevator'] = [];
+    if(!isset($contentData['prescription']['neat']['recommendations']['stand_instead_of_sit'])) $contentData['prescription']['neat']['recommendations']['stand_instead_of_sit'] = [];
+    if(!isset($contentData['prescription']['neat']['recommendations']['steps_goal_per_day'])) $contentData['prescription']['neat']['recommendations']['steps_goal_per_day'] = [];
+    if(!isset($contentData['prescription']['neat']['recommendations']['other'])) $contentData['prescription']['neat']['recommendations']['other'] = [];
+
 }
 
 if($contentData === false) {

+ 18 - 7
resources/views/app/patient/canvas-sections/next_fu/default.php

@@ -1,5 +1,10 @@
 <?php
 
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'next_fu')->first();
+
 /** @var \App\Models\Pro $hcpPro */
 /** @var \App\Models\Pro $pro */
 /** @var \App\Models\Note $note */
@@ -13,11 +18,17 @@ if(!@$hcpPro) {
     }
 }
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if(!isset($canvasData["next_fu"])) $canvasData["next_fu"] = [];
-    if(!isset($canvasData["next_fu"][$hcpPro->id])) $canvasData["next_fu"][$hcpPro->id] = [];
-    $canvasData = $canvasData['next_fu'][$hcpPro->id];
+$contentData = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if(!isset($canvasData["next_fu"])) $canvasData["next_fu"] = [];
+        $contentData = $canvasData['next_fu'];
+    }
 }
-$contentData = $canvasData;
+
+if(!isset($contentData[$hcpPro->id])) $contentData[$hcpPro->id] = [];
+$contentData = $canvasData['next_fu'][$hcpPro->id];

+ 15 - 4
resources/views/app/patient/canvas-sections/next_fu/summary.php

@@ -1,5 +1,9 @@
 <?php
 
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'next_fu')->first();
+
 // HUMONGOUS FIX! This CRITICAL "if" was never there till now!
 if(!@$contentData) {
 
@@ -17,13 +21,20 @@ if(!@$contentData) {
     }
 
     $contentData = false;
-    if ($patient->canvas_data) {
-        $canvasData = json_decode($patient->canvas_data, true);
-        if(isset($canvasData["next_fu"]) && isset($canvasData["next_fu"][$hcpPro->id])) {
-            $contentData = $canvasData["next_fu"][$hcpPro->id];
+
+    if($page){
+
+    }else{
+        if ($patient->canvas_data) {
+            $canvasData = json_decode($patient->canvas_data, true);
+            if(!isset($canvasData["next_fu"])) $canvasData["next_fu"] = [];
+            $contentData = $canvasData['next_fu'];
         }
     }
 
+    if(!isset($contentData[$hcpPro->id])) $contentData[$hcpPro->id] = [];
+    $contentData = $canvasData['next_fu'][$hcpPro->id];
+
 }
 
 if($contentData === false) {

+ 15 - 6
resources/views/app/patient/canvas-sections/pmhx/default.php

@@ -1,10 +1,19 @@
 <?php
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["pmhx"])) {
-        $canvasData = $canvasData["pmhx"];
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'pmhx')->first();
+
+$contentData = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["pmhx"])) {
+            $contentData = $canvasData["pmhx"];
+        }
     }
 }
-$contentData = $canvasData;

+ 18 - 7
resources/views/app/patient/canvas-sections/pmhx/summary.php

@@ -1,4 +1,9 @@
 <?php
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'pmhx')->first();
+
 $fields = [
     [
         "Head" => ["Trauma"],
@@ -34,18 +39,24 @@ $contentData = [
     "comments" => "",
 ];
 $isempty = false;
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["pmhx"])) {
-        $contentData = $canvasData["pmhx"];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["pmhx"])) {
+            $contentData = $canvasData["pmhx"];
+        }
+        else {
+            $isempty = true;
+        }
     }
     else {
         $isempty = true;
     }
 }
-else {
-    $isempty = true;
-}
+
 
 if($isempty) {
     echo '<span class="text-secondary">No medical history in the system</span>';

+ 14 - 6
resources/views/app/patient/canvas-sections/pshx/default.php

@@ -1,10 +1,18 @@
 <?php
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["pshx"])) {
-        $canvasData = $canvasData["pshx"];
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'pshx')->first();
+
+$contentData = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["pshx"])) {
+            $contentData = $canvasData["pshx"];
+        }
     }
 }
-$contentData = $canvasData;

+ 21 - 9
resources/views/app/patient/canvas-sections/pshx/summary.php

@@ -1,4 +1,9 @@
 <?php
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'pshx')->first();
+
 $fields = [
     [
         "" => ["Aneurysm repair", "Appendectomy", "Back surgery", "Bariatric surgery/gastric bypass", "Bilateral tubal ligation", "Breast resection/mastectomy", "CABG", "Carotid endarterectomy/stent", "Carpal tunnel release surgery",]
@@ -20,21 +25,28 @@ $contentData = [
     "comments" => "",
 ];
 $isempty = false;
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["pshx"])) {
-        $contentData = $canvasData["pshx"];
-        if(!isset($contentData['customFields'])){
-            $contentData['customFields'] = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["pshx"])) {
+            $contentData = $canvasData["pshx"];
+            if(!isset($contentData['customFields'])){
+                $contentData['customFields'] = [];
+            }
+        }
+        else {
+            $isempty = true;
         }
     }
     else {
         $isempty = true;
     }
 }
-else {
-    $isempty = true;
-}
+
+
 
 if($isempty) {
     echo '<span class="text-secondary">No surgical history in the system</span>';

+ 20 - 6
resources/views/app/patient/canvas-sections/ros/summary.php

@@ -1,19 +1,33 @@
 <?php 
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'ros')->first();
+
 $contentData = [
     'value'=>''
 ];
 $isempty = false;
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["ros"])) {
-        $contentData = $canvasData["ros"];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else {
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["ros"])) {
+            $contentData = $canvasData["ros"];
+        }
+        else {
+            $isempty = true;
+        }
     }
     else {
         $isempty = true;
     }
 }
-else {
-    $isempty = true;
+
+if(!isset($contentData['value'])){
+    $contentData['value'] = '';
 }
 
 if($isempty) {

+ 15 - 6
resources/views/app/patient/canvas-sections/rx/default.php

@@ -1,10 +1,19 @@
 <?php
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["rx"])) {
-        $canvasData = $canvasData["rx"];
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'rx')->first();
+
+$contentData = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["rx"])) {
+            $contentData = $canvasData["rx"];
+        }
     }
 }
-$contentData = $canvasData;

+ 4 - 2
resources/views/app/patient/canvas-sections/rx/form.blade.php

@@ -362,8 +362,10 @@ $formID = rand(0, 100000);
                                 'https://clinicaltables.nlm.nih.gov/api/rxterms/v3/search?ef=STRENGTHS_AND_FORMS');
                             window.Def.Autocompleter.Event.observeListSelections(dynID, function() {
                                 var autocomp = elem.autocomp, acData = autocomp.getSelectedItemData();
-                                self.items[vueIndex].title = acData[0].code;
-                                self.onItemChange(vueIndex);
+                                if(acData[0].code) {
+                                    self.items[vueIndex].title = acData[0].code;
+                                    self.onItemChange(vueIndex);
+                                }
                                 var strengths = acData[0].data['STRENGTHS_AND_FORMS'];
                                 if (strengths) {
                                     strengthElem.autocomp.setListAndField(strengths, '');

+ 13 - 9
resources/views/app/patient/canvas-sections/rx/summary.php

@@ -1,14 +1,18 @@
 <?php
 
-$contentData = [
-    "items" => []
-];
-if($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if(isset($canvasData["rx"])) {
-        $contentData = $canvasData["rx"];
-        if(!isset($contentData['items'])){
-            $contentData['items'] = [];
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'rx')->first();
+
+$contentData = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["rx"])) {
+            $contentData = $canvasData["rx"];
         }
     }
 }

+ 15 - 6
resources/views/app/patient/canvas-sections/sochx/default.php

@@ -1,10 +1,19 @@
 <?php
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["sochx"])) {
-        $canvasData = $canvasData["sochx"];
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'sochx')->first();
+
+$contentData = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["sochx"])) {
+            $contentData = $canvasData["sochx"];
+        }
     }
 }
-$contentData = $canvasData;
+

+ 17 - 7
resources/views/app/patient/canvas-sections/sochx/summary.php

@@ -1,4 +1,9 @@
 <?php
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'sochx')->first();
+
 $fields = [
     [
         "Tobacco" => ["Current every day smoker", "Current some day smoker", "Former smoker", "Heavy tobacco smoker", "Light tobacco smoker", "Never smoker", "Smoker, current status unknown", "Unknown if ever smoked "],
@@ -23,18 +28,23 @@ $contentData = [
     "comments" => "",
 ];
 $isempty = false;
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["sochx"])) {
-        $contentData = $canvasData["sochx"];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["sochx"])) {
+            $contentData = $canvasData["sochx"];
+        }
+        else {
+            $isempty = true;
+        }
     }
     else {
         $isempty = true;
     }
 }
-else {
-    $isempty = true;
-}
 
 if($isempty) {
     echo '<span class="text-secondary">No social history in the system</span>';

+ 16 - 6
resources/views/app/patient/canvas-sections/vitals/default.php

@@ -1,10 +1,20 @@
 <?php
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["vitals"])) {
-        $canvasData = $canvasData["vitals"];
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'vitals')->first();
+
+$contentData = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["vitals"])) {
+            $contentData = $canvasData["vitals"];
+        }
     }
 }
-$contentData = $canvasData;
+

+ 23 - 13
resources/views/app/patient/canvas-sections/vitals/summary.php

@@ -1,4 +1,9 @@
 <?php
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'vitals')->first();
+
 $vitalLabels = [
     "heightInInches" => "Ht. (in.)",
     "weightPounds" => "Wt. (lbs.)",
@@ -64,21 +69,26 @@ $contentData = [
     ],
 ];
 
-if($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if(isset($canvasData["vitals"])) {
-        $contentData = $canvasData["vitals"];
-        // ensure $contentData has all the expected vitals and correct labels!
-        foreach ($vitalLabels as $k => $v) {
-            if(!isset($contentData[$k])) {
-                $contentData[$k] = [
-                    "label" => $v,
-                    "value" => "",
-                    "date" => "",
-                ];
-            }
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if(isset($canvasData["vitals"])) {
+            $contentData = $canvasData["vitals"];
+            // ensure $contentData has all the expected vitals and correct labels!
         }
+    }    
+}
 
+foreach ($vitalLabels as $k => $v) {
+    if(!isset($contentData[$k])) {
+        $contentData[$k] = [
+            "label" => $v,
+            "value" => "",
+            "date" => "",
+        ];
     }
 }
 

+ 14 - 6
resources/views/app/patient/canvas-sections/vitals_may21/default.php

@@ -1,10 +1,18 @@
 <?php
 
-$canvasData = [];
-if ($patient->canvas_data) {
-    $canvasData = json_decode($patient->canvas_data, true);
-    if (isset($canvasData["vitals_may21"])) {
-        $canvasData = $canvasData["vitals_may21"];
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'vitals_may21')->first();
+
+$contentData = [];
+
+if($page){
+    $contentData = json_decode($page->data, true);
+}else{
+    if ($patient->canvas_data) {
+        $canvasData = json_decode($patient->canvas_data, true);
+        if (isset($canvasData["vitals_may21"])) {
+            $contentData = $canvasData["vitals_may21"];
+        }
     }
 }
-$contentData = $canvasData;

+ 17 - 0
resources/views/app/patient/canvas-sections/vitals_may21/summary.php

@@ -1,6 +1,12 @@
 <?php
+
 use App\Models\Note;
 use App\Models\Client;
+
+use App\Models\Page;
+
+$page = Page::where('client_id', $patient->id)->where('category', 'CANVAS')->where('key', 'vitals_may21')->first();
+
 /** @var Note $note */
 /** @var Client $patient */
 if(!@$contentData) {
@@ -80,6 +86,17 @@ if(!@$contentData) {
             }
         }
     }
+
+    if($page){
+        $contentData = json_decode($page->data, true);
+    }else{
+        if($patient->canvas_data) {
+            $canvasData = json_decode($patient->canvas_data, true);
+            if (isset($canvasData["vitals_may21"]["note_uid"]) && $canvasData["vitals_may21"]["note_uid"] === @$note->uid) {
+                $contentData = $canvasData["vitals_may21"];
+            }
+        }    
+    }
 }
 ?>
 <table class="table table-sm table-bordered mb-2">

+ 9 - 2
resources/views/app/patient/care-month/dashboard.blade.php

@@ -1409,7 +1409,8 @@
                                                         <input type="hidden" name="uid" value="{{$bill->uid}}">
                                                         <p>Update Cancellation Memo</p>
                                                         <div class="mb-2">
-                                                            <textarea class="text form-control form-control-sm" name="cancellationMemo" placeholder="">{{$bill->cancellation_memo ? $bill->cancellation_memo : 'Insufficient documentation for billable service.'}}</textarea>
+                                                            <textarea class="text form-control form-control-sm" name="cancellationMemo"
+                                                                      placeholder="">{{$bill->cancellation_memo ? $bill->cancellation_memo : 'Please contact billing.'}}</textarea>
                                                         </div>
                                                         <div>
                                                             <button class="btn btn-success btn-sm" submit>Submit</button>
@@ -1425,7 +1426,7 @@
                                                         <p class="mb-2">Cancel this bill?</p>
                                                         <div class="mb-2">
                                                             <label class="mb-1 text-secondary">Cancellation Memo</label>
-                                                            <textarea type="text" name="memo" placeholder="Memo" class="form-control form-control-sm">Insufficient documentation for billable service.</textarea>
+                                                            <textarea type="text" name="memo" placeholder="Memo" class="form-control form-control-sm">Please contact billing.</textarea>
                                                         </div>
                                                         <div class="mb-0">
                                                             <button class="btn btn-danger btn-sm" submit>Yes</button>
@@ -2010,6 +2011,12 @@
 
         @endif
 
+        <hr class="m-negator my-3">
+
+        {{-- generic bills --}}
+        <div class="row">
+            @include('app.generic-bills.inline', ['patient' => $patient, 'class' => 'col-12', 'entityType' => 'CareMonth', 'entityUid' => $careMonth->uid])
+        </div>
 
     </div>
 

+ 4 - 0
resources/views/app/patient/devices.blade.php

@@ -54,6 +54,7 @@
                     <th class="px-2 text-secondary w-25">Category</th>
                     <th class="px-2 text-secondary w-50">IMEI</th>
                     <th class="px-2 text-secondary"></th>
+                    <th class="px-2 text-secondary"></th>
                 </tr>
                 </thead>
                 <tbody>
@@ -75,6 +76,9 @@
                                 </form>
                             </div>
                         </td>
+                        <td>
+                            @include('app.generic-bills.modal', ['entityType' => 'ClientBDTDevice', 'entityUid' => $device->uid])
+                        </td>
                     </tr>
                 @endforeach
                 </tbody>

+ 7 - 0
resources/views/app/patient/generic-bills.blade.php

@@ -0,0 +1,7 @@
+@extends ('layouts.patient')
+
+@section('inner-content')
+
+    @include('app.generic-bills.inline', ['patient' => $patient, 'entityType' => 'Client', 'entityUid' => $patient->uid])
+
+@endsection

+ 6 - 0
resources/views/app/patient/measurements.blade.php

@@ -74,6 +74,7 @@
                     <th class="px-2 text-secondary">Source</th>
                     {{--<th class="px-2 text-secondary">Memo</th>--}}
                     <th class="px-2 text-secondary"></th>
+                    <th class="px-2 text-secondary"></th>
                 </tr>
                 </thead>
                 <tbody>
@@ -139,6 +140,11 @@
                                     </form>
                                 </span>
                             </td>
+                            <td class="px-2">
+                                @if(!$measurement->is_cellular_zero)
+                                    @include('app.generic-bills.modal', ['entityType' => 'Measurement', 'entityUid' => $measurement->uid])
+                                @endif
+                            </td>
                         </tr>
                         @endif
                     @endif

+ 17 - 3
resources/views/app/patient/note/dashboard.blade.php

@@ -479,6 +479,12 @@
                                class="ticket-popup-trigger note-dashboard-action d-block text-nowrap screen-only">
                                 + Imaging
                             </a>
+                            <span class="mx-2 text-secondary screen-only">|</span>
+                            <a href="/patients/view/{{$patient->uid}}/tickets/other/create?popupmode=1&note-uid={{$note->uid}}"
+                               native target="_blank"
+                               class="ticket-popup-trigger note-dashboard-action d-block text-nowrap screen-only">
+                                + Other
+                            </a>
                         </div>
 
                         <div class="p-3 border">
@@ -616,7 +622,7 @@
                                     <tbody>
                                     @foreach($otherOpenTickets as $ticket)
                                         <?php $data = json_decode($ticket->data); ?>
-                                        @if($ticket->category === 'erx' || $ticket->category === 'lab' || $ticket->category === 'imaging')
+                                        @if($ticket->category === 'erx' || $ticket->category === 'lab' || $ticket->category === 'imaging' || $ticket->category === 'other')
                                             <tr class="{{$ticket->is_open ? '' : 'bg-light on-hover-opaque'}}">
                                                 <td class="px-2 text-nowrap">
                                                     {{friendly_time($ticket->created_at)}}
@@ -703,6 +709,11 @@
                                                             </div>
                                                         @endif
                                                     @endif
+                                                    @if($ticket->category === 'other')
+                                                        <div>
+                                                            {{$data->title}}
+                                                        </div>
+                                                    @endif
                                                 </td>
                                             </tr>
                                         @endif
@@ -1309,7 +1320,8 @@
                                                     <input type="hidden" name="uid" value="{{$bill->uid}}">
                                                     <p>Update Cancellation Memo</p>
                                                     <div class="mb-2">
-                                                        <textarea class="text form-control form-control-sm" name="cancellationMemo" placeholder="">{{$bill->cancellation_memo ? $bill->cancellation_memo : 'Insufficient documentation for billable service.'}}</textarea>
+                                                        <textarea class="text form-control form-control-sm" name="cancellationMemo"
+                                                                  placeholder="">{{$bill->cancellation_memo ? $bill->cancellation_memo : 'Please contact billing.'}}</textarea>
                                                     </div>
                                                     <div>
                                                         <button class="btn btn-success btn-sm" submit>Submit</button>
@@ -1325,7 +1337,7 @@
                                                     <p class="mb-2">Cancel this bill?</p>
                                                     <div class="mb-2">
                                                         <label class="mb-1 text-secondary">Cancellation Memo</label>
-                                                        <textarea type="text" name="memo" placeholder="Memo" class="form-control form-control-sm">Insufficient documentation for billable service.</textarea>
+                                                        <textarea type="text" name="memo" placeholder="Memo" class="form-control form-control-sm">Please contact billing.</textarea>
                                                     </div>
                                                     <div class="mb-0">
                                                         <button class="btn btn-danger btn-sm" submit>Yes</button>
@@ -1990,6 +2002,8 @@
                 @endif
                 @endif
 
+                {{-- generic bills --}}
+                @include('app.generic-bills.inline', ['patient' => $patient, 'note' => $note, 'class' => 'p-3 border-top', 'label' => 'NA', 'entityType' => 'Note', 'entityUid' => $note->uid])
 
                 <div class="border-top p-3 screen-only">
                     @if($note->addendums->count())

+ 397 - 0
resources/views/app/patient/rm-setup.blade.php

@@ -0,0 +1,397 @@
+@extends ('layouts.patient')
+
+@section('inner-content')
+
+    <h4 class="font-weight-bold mb-3 text-secondary font-size-16" id="rm-setup">RM Setup</h4>
+
+    <hr class="m-neg-4">
+    <div class="d-flex align-items-baseline mb-3">
+        <span class="width-200px">Is Eligible for RM?</span>
+        <div class="ml-3">
+            <div class="d-inline-flex align-items-start">
+                <b>{{ ucwords($patient->is_eligible_for_rm ? $patient->is_eligible_for_rm : '-') }}</b>
+                <div moe class="ml-2">
+                    <a start show><i class="fa fa-edit"></i></a>
+                    <form url="/api/client/updateRmEligibility" class="mcp-theme-1">
+                        <input type="hidden" name="uid" value="{{$patient->uid}}">
+                        <div class="mb-2">
+                            <label class="text-sm mb-1 text-secondary">Is Eligible?</label>
+                            <select name="isEligibleForRm"
+                                    class="form-control form-control-sm"
+                                    onchange="toggleDisabledAsNeeded(this, 'NO', 'not-eligible-for-rm')">
+                                <option value="">-- Select Status --</option>
+                                <option value="YES" {{ $patient->is_eligible_for_rm === 'YES' ? 'selected' : '' }}>YES</option>
+                                <option value="NO" {{ $patient->is_eligible_for_rm === 'NO' ? 'selected' : '' }}>NO</option>
+                                <option value="UNKNOWN" {{ $patient->is_eligible_for_rm === 'UNKNOWN' ? 'selected' : '' }}>UNKNOWN</option>
+                            </select>
+                        </div>
+                        <div class="mb-2">
+                            <label class="text-sm mb-1 text-secondary">Why not eligible category</label>
+                            <input type="text" class="not-eligible-for-rm form-control form-control-sm"
+                                   {{$patient->is_eligible_for_rm === 'NO' ? '' : 'disabled' }}
+                                   name="whyNotEligibleForRmCategory" value="{{$patient->why_not_eligible_for_rm_category}}">
+                        </div>
+                        <div class="mb-2">
+                            <label class="text-sm mb-1 text-secondary">Why not eligible memo</label>
+                            <input type="text" class="not-eligible-for-rm form-control form-control-sm"
+                                   {{$patient->is_eligible_for_rm === 'NO' ? '' : 'disabled' }}
+                                   name="whyNotEligibleForRmMemo" value="{{$patient->why_not_eligible_for_rm_memo}}">
+                        </div>
+                        <div>
+                            <button submit class="btn btn-sm btn-primary mr-1">Submit</button>
+                            <button cancel class="btn btn-sm btn-default border">Cancel</button>
+                        </div>
+                    </form>
+                </div>
+            </div>
+            @if($patient->is_eligible_for_rm === 'NO')
+                <div class="mt-1">
+                    <span>{{$patient->why_not_eligible_for_rm_category ?: '-'}}</span>
+                    /
+                    <span class="text-secondary">{{$patient->why_not_eligible_for_rm_memo ?: '-'}}</span>
+                </div>
+            @endif
+        </div>
+    </div>
+
+    <hr class="m-neg-4">
+    <div class="d-flex align-items-baseline mb-3">
+        <span class="width-200px">RM Enrollment Status:</span>
+        <div class="ml-3">
+            <div class="d-inline-flex align-items-start">
+                <b>{{ ucwords($patient->is_enrolled_in_rm ? $patient->is_enrolled_in_rm : '-') }}</b>
+                <div moe class="ml-2">
+                    <a start show>Toggle</a>
+                    <form url="/api/client/{{$patient->is_enrolled_in_rm === 'YES' ? 'setIsEnrolledInRmToFalse' : 'setIsEnrolledInRmToTrue'}}" class="mcp-theme-1">
+                        <input type="hidden" name="uid" value="{{$patient->uid}}">
+                        <p>Toggle RM enrollment?</p>
+                        <div>
+                            <button submit class="btn btn-sm btn-primary mr-1">Submit</button>
+                            <button cancel class="btn btn-sm btn-default border">Cancel</button>
+                        </div>
+                    </form>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <hr class="m-neg-4">
+    <div class="d-flex align-items-baseline mb-3">
+        <span class="width-200px">RM Reasons:</span>
+        <div class="ml-3">
+            <div class="d-inline-flex align-items-start">
+                <b>{{ $patient->rm_reasons ?: '-' }}</b>
+                <div moe class="ml-2">
+                    <a start show><i class="fa fa-edit"></i></a>
+                    <form url="/api/client/updateRmReasons" class="mcp-theme-1">
+                        <input type="hidden" name="uid" value="{{$patient->uid}}">
+                        <div class="mb-2">
+                            <label class="text-sm mb-1 text-secondary">RM Reasons</label>
+                            <input type="text" class="form-control form-control-sm"
+                                   name="rmReasons" value="{{$patient->rm_reasons}}">
+                        </div>
+                        <div>
+                            <button submit class="btn btn-sm btn-primary mr-1">Submit</button>
+                            <button cancel class="btn btn-sm btn-default border">Cancel</button>
+                        </div>
+                    </form>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    @if($pro->pro_type === 'ADMIN')
+        <hr class="m-neg-4">
+        <div class="d-flex align-items-baseline mb-3">
+            <span class="width-200px">RME Pro:</span>
+            <div class="ml-3">
+                <div class="d-inline-flex align-items-start">
+                    <b>{{ $patient->rme ? $patient->rme->displayName() : '-' }}</b>
+                    <div moe class="ml-2">
+                        <a start show><i class="fa fa-edit"></i></a>
+                        <form url="/api/client/putRmePro" class="mcp-theme-1">
+                            <input type="hidden" name="uid" value="{{$patient->uid}}">
+                            <div class="mb-2">
+                                <label class="text-secondary text-sm">RME Pro</label>
+                                <select provider-search data-pro-uid="{{ @$patient->rme->uid }}" name="rmeProUid" class="form-control form-control-sm">
+                                    <option value=""> --select--</option>
+                                </select>
+                            </div>
+                            <div>
+                                <button submit class="btn btn-sm btn-primary mr-1">Submit</button>
+                                <button cancel class="btn btn-sm btn-default border">Cancel</button>
+                            </div>
+                        </form>
+                    </div>
+                    @if($patient->rme)
+                        <div moe class="ml-2">
+                            <a start show><i class="fa fa-trash-alt text-danger on-hover-opaque"></i></a>
+                            <form url="/api/client/removeRmePro" class="mcp-theme-1">
+                                <input type="hidden" name="uid" value="{{$patient->uid}}">
+                                <p>Remove RME Pro?</p>
+                                <div>
+                                    <button submit class="btn btn-sm btn-primary mr-1">Submit</button>
+                                    <button cancel class="btn btn-sm btn-default border">Cancel</button>
+                                </div>
+                            </form>
+                        </div>
+                    @endif
+                </div>
+            </div>
+        </div>
+
+        <hr class="m-neg-4">
+        <div class="d-flex align-items-baseline mb-3">
+            <span class="width-200px">RMM Pro:</span>
+            <div class="ml-3">
+                <div class="d-inline-flex align-items-start">
+                    <b>{{ $patient->rmm ? $patient->rmm->displayName() : '-' }}</b>
+                    <div moe class="ml-2">
+                        <a start show><i class="fa fa-edit"></i></a>
+                        <form url="/api/client/putRmmPro" class="mcp-theme-1">
+                            <input type="hidden" name="uid" value="{{$patient->uid}}">
+                            <div class="mb-2">
+                                <label class="text-secondary text-sm">RMM Pro</label>
+                                <select provider-search data-pro-uid="{{ @$patient->rmm->uid }}" name="rmmProUid" class="form-control form-control-sm">
+                                    <option value=""> --select--</option>
+                                </select>
+                            </div>
+                            <div>
+                                <button submit class="btn btn-sm btn-primary mr-1">Submit</button>
+                                <button cancel class="btn btn-sm btn-default border">Cancel</button>
+                            </div>
+                        </form>
+                    </div>
+                    @if($patient->rmm)
+                        <div moe class="ml-2">
+                            <a start show><i class="fa fa-trash-alt text-danger on-hover-opaque"></i></a>
+                            <form url="/api/client/removeRmmPro" class="mcp-theme-1">
+                                <input type="hidden" name="uid" value="{{$patient->uid}}">
+                                <p>Remove RMM Pro?</p>
+                                <div>
+                                    <button submit class="btn btn-sm btn-primary mr-1">Submit</button>
+                                    <button cancel class="btn btn-sm btn-default border">Cancel</button>
+                                </div>
+                            </form>
+                        </div>
+                    @endif
+                </div>
+            </div>
+        </div>
+    @endif
+
+    <?php
+    $bpDevice = null;
+    $weightScale = null;
+    if(count($patient->devices)) {
+        foreach($patient->devices as $device) {
+            if(!$bpDevice && $device->device->category === 'BP') {
+                $bpDevice = $device;
+            }
+            elseif(!$weightScale && $device->device->category === 'WEIGHT') {
+                $weightScale = $device;
+            }
+            if($bpDevice && $weightScale) break;
+        }
+    }
+    $bpMeasurements = [];
+    if($bpDevice) {
+        $bpMeasurements["first"] = \App\Models\Measurement
+            ::where('imei', $bpDevice->device->imei)
+            ->where('client_id', $patient->id)
+            ->where('is_cellular_zero', false)
+            ->orderBy('ts')
+            ->first();
+        $bpMeasurements["last"] = \App\Models\Measurement
+            ::where('imei', $bpDevice->device->imei)
+            ->where('client_id', $patient->id)
+            ->where('is_cellular_zero', false)
+            ->orderBy('ts', 'DESC')
+            ->first();
+    }
+    $weightMeasurements = [];
+    if($weightScale) {
+        $weightMeasurements["first"] = \App\Models\Measurement
+            ::where('imei', $weightScale->device->imei)
+            ->where('client_id', $patient->id)
+            ->where('is_cellular_zero', false)
+            ->orderBy('ts')
+            ->first();
+        $weightMeasurements["last"] = \App\Models\Measurement
+            ::where('imei', $weightScale->device->imei)
+            ->where('client_id', $patient->id)
+            ->where('is_cellular_zero', false)
+            ->orderBy('ts', 'DESC')
+            ->first();
+    }
+    $careMonth = $patient->currentCareMonth();
+    ?>
+
+    <hr class="m-neg-4">
+    @if($bpDevice)
+        <div class="mb-3">
+            <div class="d-flex align-items-baseline mb-2">
+                <span class="width-200px font-weight-bold">Cellular BP Device</span>
+                <b class="ml-3">Yes</b>
+                <span class="ml-3 text-secondary">IMEI: {{$bpDevice->device->imei}}</span>
+            </div>
+            <div class="border-left">
+                <div class="d-flex align-items-baseline mb-1">
+                    <span class="width-200px pl-3">Arrived:</span>
+                    <span class="ml-3">Yes</span>*
+                </div>
+                <div class="d-flex align-items-baseline mb-1">
+                    <span class="width-200px pl-3">First Measurement:</span>
+                    @if($bpMeasurements["first"])
+                        <span class="ml-3">{{ $bpMeasurements["first"]->sbp_mm_hg . '/' . $bpMeasurements["first"]->dbp_mm_hg . ' mmHg' }}</span>
+                        <span class="ml-3 text-secondary">{{date("Y-m-d", $bpMeasurements["first"]->ts/1000)}}</span>
+                        <span class="ml-3">{{date_diff(date_create(date("Y-m-d", $bpMeasurements["first"]->ts/1000)), date_create('now'))->days}} days ago</span>
+                    @else
+                        -
+                    @endif
+                </div>
+                <div class="d-flex align-items-baseline mb-1">
+                    <span class="width-200px pl-3">Last Measurement:</span>
+                    @if($bpMeasurements["last"])
+                        <span class="ml-3">{{ $bpMeasurements["last"]->sbp_mm_hg . '/' . $bpMeasurements["last"]->dbp_mm_hg . ' mmHg' }}</span>
+                        <span class="ml-3 text-secondary">{{date("Y-m-d", $bpMeasurements["last"]->ts/1000)}}</span>
+                        <span class="ml-3">{{date_diff(date_create(date("Y-m-d", $bpMeasurements["last"]->ts/1000)), date_create('now'))->days}} days ago</span>
+                    @else
+                        -
+                    @endif
+                </div>
+                <div class="d-flex align-items-baseline mb-1">
+                    <span class="width-200px pl-3">How often to measure:</span>
+                    <span class="ml-3"> -- </span>
+                </div>
+                <div class="d-flex align-items-baseline mb-1">
+                    <span class="width-200px pl-3">SMS reminders:</span>
+                    <span class="ml-3"> -- </span>
+                </div>
+            </div>
+        </div>
+    @else
+        <div class="d-flex align-items-baseline mb-3">
+            <span class="width-200px">Cellular BP Device</span>
+            <b class="ml-3">No</b>
+        </div>
+    @endif
+
+    <hr class="m-neg-4">
+    @if($weightScale)
+        <div class="mb-3">
+            <div class="d-flex align-items-baseline mb-2">
+                <span class="width-200px font-weight-bold">Cellular Weight Scale</span>
+                <b class="ml-3">Yes</b>
+                <span class="ml-3 text-secondary">IMEI: {{$weightScale->device->imei}}</span>
+            </div>
+            <div class="border-left">
+                <div class="d-flex align-items-baseline mb-1">
+                    <span class="width-200px pl-3">Arrived:</span>
+                    <span class="ml-3">Yes</span>*
+                </div>
+                <div class="d-flex align-items-baseline mb-1">
+                    <span class="width-200px pl-3">First Measurement:</span>
+                    @if($weightMeasurements["first"])
+                        <span class="ml-3">{{ round($weightMeasurements["first"]->value, 2) . ' lbs' }}</span>
+                        <span class="ml-3 text-secondary">{{date("Y-m-d", $weightMeasurements["first"]->ts/1000)}}</span>
+                        <span class="ml-3">{{date_diff(date_create(date("Y-m-d", $weightMeasurements["first"]->ts/1000)), date_create('now'))->days}} days ago</span>
+                    @else
+                        -
+                    @endif
+                </div>
+                <div class="d-flex align-items-baseline mb-1">
+                    <span class="width-200px pl-3">Last Measurement:</span>
+                    @if($weightMeasurements["last"])
+                        <span class="ml-3">{{ round($weightMeasurements["last"]->value, 2) . ' lbs' }}</span>
+                        <span class="ml-3 text-secondary">{{date("Y-m-d", $weightMeasurements["last"]->ts/1000)}}</span>
+                        <span class="ml-3">{{date_diff(date_create(date("Y-m-d", $weightMeasurements["last"]->ts/1000)), date_create('now'))->days}} days ago</span>
+                    @else
+                        -
+                    @endif
+                </div>
+                <div class="d-flex align-items-baseline mb-1">
+                    <span class="width-200px pl-3">How often to measure:</span>
+                    <span class="ml-3"> -- </span>
+                </div>
+                <div class="d-flex align-items-baseline mb-1">
+                    <span class="width-200px pl-3">SMS reminders:</span>
+                    <span class="ml-3"> -- </span>
+                </div>
+            </div>
+        </div>
+    @else
+        <div class="d-flex align-items-baseline mb-3">
+            <span class="width-200px">Cellular Weight Scale</span>
+            <b class="ml-3">No</b>
+        </div>
+    @endif
+
+    @if($careMonth && ($bpDevice || $weightScale))
+        <hr class="m-neg-4">
+        <div class="d-flex align-items-baseline mb-1">
+            <span class="width-200px">Measurement days this month:</span>
+            <div class="ml-3">
+                <b>{{$careMonth->number_of_days_with_remote_measurements}} days</b>
+                <div id="caremonth-measurements-calendar" class="width-300px mt-2"></div>
+            </div>
+        </div>
+
+        <hr class="m-neg-4">
+        <?php
+        $measurementsInCareMonth = $patient->measurementsInCareMonth($careMonth);
+        $datesWithMeasurements = [];
+        foreach($measurementsInCareMonth as $measurement) {
+            if(!empty($measurement->label) && !in_array($measurement->label, ["SBP", "DBP"])/* && !$measurement->is_cellular_zero*/) {
+                if ($measurement->ts) {
+                    $timestampInSec = floor($measurement->ts / 1000);
+                    $measurement->start = postgres_date_time_short_with_tz_from_timestamp($timestampInSec, 'EASTERN');
+                    $start_date_only = substr($measurement->start, 0, 10);
+                    if(!in_array($start_date_only, $datesWithMeasurements)) {
+                        $datesWithMeasurements[] = $start_date_only;
+                    }
+                }
+            }
+        }
+        ?>
+
+    @endif
+
+    <link href='/fullcalendar-5.3.2/lib/main.css' rel='stylesheet' />
+    <script src='/fullcalendar-5.3.2/lib/main.js'></script>
+    <script>
+        (function() {
+            function formatDate(date) {
+                let d = new Date(date),
+                    month = '' + (d.getMonth() + 1),
+                    day = '' + d.getDate(),
+                    year = d.getFullYear();
+                if (month.length < 2)
+                    month = '0' + month;
+                if (day.length < 2)
+                    day = '0' + day;
+                return [year, month, day].join('-');
+            }
+            function init() {
+                @if(count($datesWithMeasurements))
+                let datesWithMeasurements = {!! json_encode($datesWithMeasurements) !!};
+                let calendarElem = $('#caremonth-measurements-calendar');
+                calendarElem.datepicker({
+                    dateFormat: 'yy-mm-dd',
+                    onSelect: function(_date) {},
+                    onChangeMonthYear: function(_year, _month) {},
+                    beforeShowDay: function(d) {
+                        if(datesWithMeasurements.indexOf(formatDate(d)) !== -1) {
+                            return [true, 'has-events'];
+                        }
+                        return [true, 'no-events'];
+                    }
+                });
+
+                @endif
+            }
+            addMCInitializer('rm-setup', init, '#rm-setup')
+        }).call(window);
+    </script>
+
+@endsection

+ 3 - 0
resources/views/app/patient/shipments.blade.php

@@ -413,6 +413,9 @@
                         </div>
                     @endif
 
+                    <hr class="m-neg-4">
+                    @include('app.generic-bills.inline', ['patient' => $patient, 'entityType' => 'Shipment', 'entityUid' => $shipment->uid])
+
                 </div>
             @endif
 

+ 4 - 0
resources/views/app/patient/supply-orders.blade.php

@@ -454,6 +454,10 @@
                             </div>
                         @endif
                     @endif
+
+                    <hr class="m-neg-4">
+                    @include('app.generic-bills.inline', ['patient' => $patient, 'entityType' => 'SupplyOrder', 'entityUid' => $supplyOrder->uid])
+
                 </div>
             @endif
         </div>

+ 26 - 22
resources/views/app/patient/tickets.blade.php

@@ -3,7 +3,7 @@
 
     <?php
 
-    $categories = ['erx', 'lab', 'imaging', 'equipment'];
+    $categories = ['erx', 'lab', 'imaging', 'other'];
 
     function adjustBrightness($hex, $steps) {
         $steps = max(-255, min(255, $steps));
@@ -60,6 +60,7 @@
                 <option value="erx" {{$type === 'erx' ? 'selected' : ''}}>ERx</option>
                 <option value="lab" {{$type === 'lab' ? 'selected' : ''}}>Lab Orders</option>
                 <option value="imaging" {{$type === 'imaging' ? 'selected' : ''}}>Imaging Orders</option>
+                <option value="other" {{$type === 'other' ? 'selected' : ''}}>Other Orders</option>
             </select>
             <select class="hide-inside-ticket-popup ml-2 max-width-200px form-control form-control-sm pr-2"
                     v-model="statusFilter">
@@ -78,6 +79,9 @@
         @if($type === '' || $type === 'imaging')
             @include('app.patient.tickets.imaging')
         @endif
+        @if($type === '' || $type === 'other')
+            @include('app.patient.tickets.other')
+        @endif
 
         @include('app.patient.tickets.ticket_send_fax_form')
     </div>
@@ -103,7 +107,7 @@
                 "erx" => [],
                 "lab" => [],
                 "imaging" => [],
-                "equipment" => [],
+                "other" => []
             ];
 
             $ticketsArray = [];
@@ -162,7 +166,7 @@
                         @include('app.patient.tickets.erx-data')
                         @include('app.patient.tickets.lab-data')
                         @include('app.patient.tickets.imaging-data')
-                        @include('app.patient.tickets.equipment-data')
+                        @include('app.patient.tickets.other-data')
 
                         // common
                         currentCategory: '',
@@ -335,12 +339,12 @@
                                 this.postShowPopup('imaging', _item);
                             });
                         },
-                        equipmentShowPopup: function(_item) {
-                            this.preparePopup('equipment', _item);
+                        otherShowPopup: function(_item) {
+                            this.preparePopup('other', _item);
                             Vue.nextTick(() => {
-                                showStagPopup('equipment-popup', true);
+                                showStagPopup('other-popup', true);
                                 this.reinitProSuggest();
-                                this.postShowPopup('equipment', _item);
+                                this.postShowPopup('other', _item);
                             });
                         },
 
@@ -525,8 +529,8 @@
                             this.imagingSavePopupItem(true);
                         },
 
-                        equipmentSavePopupItem: function(_autoSave = false) {
-                            let form = $('#ticketsApp [stag-popup-key="equipment-popup"] form').first();
+                        otherSavePopupItem: function(_autoSave = false) {
+                            let form = $('#ticketsApp [stag-popup-key="other-popup"] form').first();
                             if(!_autoSave) {
                                 if(!form[0].checkValidity()) {
                                     form[0].reportValidity();
@@ -535,24 +539,24 @@
                             }
                             if(!_autoSave) showMask();
                             let payload = {};
-                            if(this.equipmentPopupMode === 'add') {
+                            if(this.otherPopupMode === 'add') {
                                 payload.clientUid = '{{ $patient->uid  }}';
-                                payload.category = 'equipment';
+                                payload.category = 'other';
                                 payload.assignedProUid = '{{ $pro->uid  }}';
                                 payload.managerProUid = '{{ $pro->uid  }}';
                                 payload.orderingProUid = '{{ $pro->uid  }}';
                                 payload.initiatingProUid = '{{ $pro->uid  }}';
-                                payload.data = JSON.stringify(this.equipmentPopupItem.data);
+                                payload.data = JSON.stringify(this.otherPopupItem.data);
                             }
                             else {
-                                payload.uid = this.equipmentPopupItem.uid;
-                                payload.newData = JSON.stringify(this.equipmentPopupItem.data);
+                                payload.uid = this.otherPopupItem.uid;
+                                payload.newData = JSON.stringify(this.otherPopupItem.data);
                             }
                             @if(request()->input('note-uid'))
                                 payload.noteUid = '{{request()->input('note-uid')}}';
                             @endif
                             $.post(
-                                '/api/ticket/' + (this.equipmentPopupMode === 'add' ? 'create' : 'updateData'),
+                                '/api/ticket/' + (this.otherPopupMode === 'add' ? 'create' : 'updateData'),
                                 payload,
                                 (_data) => {
                                     if(hasResponseError(_data)) {
@@ -561,29 +565,29 @@
                                     }
                                     if(!_autoSave) {
                                         if(_data.data) {
-                                            window.localStorage.autoOpen = 'equipment|' + _data.data;
+                                            window.localStorage.autoOpen = 'other|' + _data.data;
                                             fastReload();
                                         }
                                     }
                                     else {
-                                        this.reloadPopupItem('equipment');
+                                        this.reloadPopupItem('other');
                                     }
                                 },
                                 'json');
                             return false;
                         },
-                        equipmentSaveComment: function() {
+                        otherSaveComment: function() {
                             if(!this.comment) return;
                             let comment = {
                                 pro_id: this.own_pro_id,
                                 created_at: new Date().toLocaleString(),
                                 message: this.comment
                             };
-                            if(!this.equipmentPopupItem.data.comments) {
-                                this.equipmentPopupItem.data.comments = [];
+                            if(!this.otherPopupItem.data.comments) {
+                                this.otherPopupItem.data.comments = [];
                             }
-                            this.equipmentPopupItem.data.comments.push(comment);
-                            this.equipmentSavePopupItem(true);
+                            this.otherPopupItem.data.comments.push(comment);
+                            this.otherSavePopupItem(true);
                         },
 
                         // common

+ 18 - 6
resources/views/app/patient/tickets/erx.blade.php

@@ -81,7 +81,7 @@
             <div class="px-3 pb-3 border-bottom">
 
                 <div class="row mb-2">
-                    <div class="col-9">
+                    <div class="col-12">
                         <label class="text-sm text-secondary mb-1">
                             <div class="pro-initials pro-initials-sm bg-info text-white font-size-13 mr-1 font-weight-bold">1</div>
                             Medication (<i>from Patient Rx List</i>)
@@ -92,11 +92,11 @@
                             <option v-for="(item, index) in patientRx"
                                     :value="item.title"
                                     :disabled="isRxAlreadyUsed(item.title, -1)">
-                                @{{item.title}}
+                                @{{item.title}} @{{item.strength ? item.strength : ''}}
                             </option>
                         </select>
                     </div>
-                    <div class="col-3 pl-0">
+                    <div class="d-none">
                         <label class="text-sm text-secondary mb-1">Strength</label>
                         <input type="hidden" v-model="erxPopupItem.data.strength">
                         <input readonly type="text" data-field="strength" placeholder="Strength"
@@ -157,7 +157,7 @@
             <div class="p-3 border-bottom erx-line-item" v-for="(item, itemIndex) in erxPopupItem.data.items">
 
                 <div class="row mb-2">
-                    <div class="col-9">
+                    <div class="col-12">
                         <label class="text-sm text-secondary mb-1 d-flex align-items-center">
                             <div class="pro-initials pro-initials-sm bg-info text-white font-size-13 mr-1 font-weight-bold" v-html="itemIndex + 2"></div>
                             Medication (<i>from Patient Rx List</i>)
@@ -170,11 +170,11 @@
                             <option v-for="(item, index) in patientRx"
                                     :value="item.title"
                                     :disabled="isRxAlreadyUsed(item.title, itemIndex)">
-                                @{{item.title}}
+                                @{{item.title}} @{{item.strength ? item.strength : ''}}
                             </option>
                         </select>
                     </div>
-                    <div class="col-3 pl-0">
+                    <div class="d-none">
                         <label class="text-sm text-secondary mb-1">Strength</label>
                         <input type="hidden" v-model="item.strength">
                         <input readonly type="text" data-field="strength" placeholder="Strength"
@@ -245,6 +245,18 @@
             <!-- faxes -->
             @include('app.patient.tickets.faxes', ['category' => 'erx'])
 
+            <!-- bills -->
+            <div class="px-3 py-3 border-top">
+                <a class="mb-0 font-weight-normal font-size-16 d-flex align-items-center"
+                   native target="_blank"
+                   open-in-stag-popup
+                   popup-style="tall"
+                   title="Generic Bills"
+                   :href="'/generic-bill-view/Ticket/' + erxPopupItem.uid">
+                    Generic Bills
+                </a>
+            </div>
+
             <!-- comments -->
             @include('app.patient.tickets.comments', ['category' => 'erx'])
 

+ 12 - 0
resources/views/app/patient/tickets/imaging.blade.php

@@ -132,6 +132,18 @@
             <!-- attachments -->
             @include('app.patient.tickets.attachments', ['category' => 'imaging'])
 
+            <!-- bills -->
+            <div class="px-3 py-3 border-top">
+                <a class="mb-0 font-weight-normal font-size-16 d-flex align-items-center"
+                   native target="_blank"
+                   open-in-stag-popup
+                   popup-style="tall"
+                   title="Generic Bills"
+                   :href="'/generic-bill-view/Ticket/' + imagingPopupItem.uid">
+                    Generic Bills
+                </a>
+            </div>
+
             <!-- comments -->
             @include('app.patient.tickets.comments', ['category' => 'imaging'])
         </form>

+ 12 - 0
resources/views/app/patient/tickets/lab.blade.php

@@ -136,6 +136,18 @@
             <!-- attachments -->
             @include('app.patient.tickets.attachments', ['category' => 'lab'])
 
+            <!-- bills -->
+            <div class="px-3 py-3 border-top">
+                <a class="mb-0 font-weight-normal font-size-16 d-flex align-items-center"
+                   native target="_blank"
+                   open-in-stag-popup
+                   popup-style="tall"
+                   title="Generic Bills"
+                   :href="'/generic-bill-view/Ticket/' + labPopupItem.uid">
+                    Generic Bills
+                </a>
+            </div>
+
             <!-- comments -->
             @include('app.patient.tickets.comments', ['category' => 'lab'])
 

+ 37 - 0
resources/views/app/patient/tickets/other-data.blade.php

@@ -0,0 +1,37 @@
+// other
+otherCollapsed: false,
+otherPopupMode: 'add',
+otherModel: {
+    uid: '',
+    is_open: true,
+    assigned_pro_uid: '',
+    ordering_pro_uid: '',
+    data: {
+        due_date: '',
+        title: '',
+        description: '',
+        memo: '',
+        comments: [{
+            pro_id: '',
+            message: '',
+            created_at: '',
+        }],
+    }
+},
+otherPopupItem: {
+    uid: '',
+    is_open: true,
+    assigned_pro_uid: '',
+    ordering_pro_uid: '',
+    data: {
+        due_date: '',
+        title: '',
+        description: '',
+        memo: '',
+        comments: [{
+            pro_id: '',
+            message: '',
+            created_at: '',
+        }],
+    }
+},

+ 105 - 0
resources/views/app/patient/tickets/other.blade.php

@@ -0,0 +1,105 @@
+<div class="my-4">
+    <div class="d-flex align-items-end mb-3">
+        <h4 class="font-weight-bold m-0 text-secondary font-size-16">Other
+            <span v-if="statusFilter === 'open'" class="text-secondary font-weight-normal">(@{{ otherNumOpen }} open)</span>
+            <span v-if="statusFilter === 'closed'" class="text-secondary font-weight-normal">(@{{ otherNumClosed }} closed)</span>
+            <span v-if="statusFilter === 'all'" class="text-secondary font-weight-normal">(@{{ otherNumOpen }} open, @{{ otherNumClosed }} closed)</span>
+        </h4>
+        <a class="px-3 c-pointer font-weight-bold"
+           v-on:click.prevent="otherShowPopup()">+ New</a>
+        <a class="py-0 font-weight-normal c-pointer flex-grow-1 text-right pr-2"
+           v-if="!otherCollapsed"
+           v-on:click.prevent="otherCollapsed = true">
+            <i class="text-secondary fa fa-chevron-up"></i>
+        </a>
+        <a class="py-0 font-weight-normal c-pointer flex-grow-1 text-right pr-2"
+           v-if="otherCollapsed"
+           v-on:click.prevent="otherCollapsed = false">
+            <i class="text-secondary fa fa-chevron-down"></i>
+        </a>
+    </div>
+    <div class="ticket-section" :class="otherCollapsed ? 'ticket-section-collapsed' : ''">
+        <table class="table table-sm tickets-table mb-0 border-bottom">
+            <tbody>
+            <tr v-for="(item, index) in ticketsByType.other"
+                v-if="(statusFilter === 'all' || (statusFilter === 'open' && item.is_open) || (statusFilter === 'closed' && !item.is_open))"
+                :class="(item.is_open ? ' ' : 'opacity-60 bg-light ') + (currentItemUid === item.uid ? 'current' : '')">
+                <td class="px-2 py-2 c-pointer" v-on:click.prevent="otherShowPopup(item)">
+                    <div class="d-flex align-items-center">
+                        <div class="pro-initials text-uppercase"
+                             :title="allProsFlat['pro_' + item.assigned_pro_id].displayedName"
+                             :style="'background-color: ' + allProsFlat['pro_' + item.assigned_pro_id].colors.bc + '; color: ' + allProsFlat['pro_' + item.assigned_pro_id].colors.fc + ';'">
+                            @{{allProsFlat['pro_' + item.assigned_pro_id].displayedInitials}}
+                        </div>
+                        <div class="flex-grow-1 d-inline-flex ml-2 flex-wrap align-items-center">
+                            <span class="font-weight-bold text-dark font-size-13"
+                                  v-html="item.data.title"></span>
+                            <span class="ml-3 font-weight-bold" v-if="item.data.attachments && item.data.attachments.length">
+                                <i class="fa fa-paperclip"></i>
+                            </span>
+                            <span class="text-nowrap ml-auto text-sm" v-if="item.data.due_date">
+                                <div title="Due Date" class="pro-initials text-uppercase text-white bg-info"><i class="fa fa-calendar-day"></i></div>
+                                <span class="text-secondary ml-1">@{{ item.data.due_date }}</span>
+                            </span>
+                        </div>
+                    </div>
+                    <!--
+                    <div>
+                        <span class="text-secondary text-sm mt-1">Created:</span>
+                        @{{ item.created_at }}
+                    </div>
+                    -->
+                </td>
+
+            </tr>
+            </tbody>
+        </table>
+    </div>
+    <div v-if="!preparing" class="stag-popup stag-popup-sm stag-slide mcp-theme-1" stag-popup-key="other-popup">
+        <form method="POST" action="" class="p-0">
+            <h3 class="stag-popup-title mb-0 p-3 bg-light sticky-top">
+                <span v-if="otherPopupMode === 'add'" class="flex-grow-1 text-nowrap overflow-hidden text-ellipsis mr-3">Add Other Ticket</span>
+                <span v-if="otherPopupMode === 'edit'" class="flex-grow-1 text-nowrap overflow-hidden text-ellipsis mr-3"
+                      v-html="otherPopupItem.data.title ? otherPopupItem.data.title : 'Edit Other Ticket'"></span>
+                @include('app.patient.tickets.header-end', ['category' => 'other'])
+            </h3>
+
+            <!-- common - only applicable for edit -->
+            @include('app.patient.tickets.common-fields', ['category' => 'other'])
+
+            <!-- other specific -->
+            <div class="p-3 border-bottom">
+
+                <div class="row mb-2">
+                    <div class="col-12">
+                        <label class="text-secondary mb-0 font-weight-normal font-size-16">Other</label>
+                    </div>
+                </div>
+
+                <div class="mb-2">
+                    <label class="text-sm text-secondary mb-1">Title</label>
+                    <input required type="text" v-model="otherPopupItem.data.title" placeholder="Title" class="form-control form-control-sm">
+                </div>
+                <div class="mb-2">
+                    <label class="text-sm text-secondary mb-1">Description</label>
+                    <input type="text" v-model="otherPopupItem.data.description" placeholder="Description" class="form-control form-control-sm">
+                </div>
+                <div class="mb-2">
+                    <label class="text-sm text-secondary mb-1">Memo</label>
+                    <input type="text" v-model="otherPopupItem.data.memo" placeholder="Memo" class="form-control form-control-sm">
+                </div>
+            </div>
+
+            <div v-if="otherPopupMode === 'add'" class="d-flex align-items-center justify-content-start mt-3 p-3 border-bottom">
+                <button type="button" class="btn btn-sm btn-primary mr-2" v-on:click.prevent="otherSavePopupItem()">Submit</button>
+                <button type="button" class="btn btn-sm btn-default border" onclick="return closeStagPopup()">Cancel</button>
+            </div>
+
+            <!-- attachments -->
+            @include('app.patient.tickets.attachments', ['category' => 'other'])
+
+            <!-- comments -->
+            @include('app.patient.tickets.comments', ['category' => 'other'])
+        </form>
+    </div>
+</div>

+ 11 - 0
resources/views/app/practice-management/generic-bills.blade.php

@@ -0,0 +1,11 @@
+@extends ('layouts/template')
+
+@section('content')
+
+    <div class="p-3 mcp-theme-1">
+
+    @include('app.generic-bills.inline', ['adminView' => true, 'noCreate' => true])
+
+    </div>
+
+@endsection

+ 57 - 0
resources/views/app/practice-management/na-billable-signed-notes.blade.php

@@ -0,0 +1,57 @@
+@extends ('layouts/template')
+
+@section('content')
+
+    <div class="p-3 mcp-theme-1">
+    <div class="card">
+
+        <div class="card-header px-3 py-2 d-flex align-items-center">
+            <strong class="mr-4">
+                <i class="fas fa-user-injured"></i>
+                Billable Signed Notes ({{count($notes)}})
+            </strong>
+        </div>
+        <div class="card-body p-0">
+
+            <table class="table table-sm table-condensed p-0 m-0">
+                <thead class="bg-light">
+                <tr>
+                    <th class="px-3 border-0">Created</th>
+                    <th class="border-0">Effective Date</th>
+                    <th class="border-0">Patient</th>
+                    <th class="border-0 w-50">Content</th>
+                </tr>
+                </thead>
+                <tbody>
+                @foreach ($notes as $note)
+                    <tr class="{{ $note->is_cancelled ? 'cancelled-item always-clickable' : '' }}">
+                        <td class="px-3">
+                            {{ friendly_date_time($note->created_at, true) }}
+                        </td>
+                        <td class="">
+                            <a href="/patients/view/{{ $note->client->uid }}/notes/view/{{ $note->uid }}" class="font-weight-bold">
+                                {{ friendly_date_time($note->effective_dateest, false) }}
+                            </a>
+                            <span class="ml-1">{{ $note->is_cancelled ? '[cancelled]' : '' }}</span>
+                        </td>
+                        <td class="">
+                            <a href="/patients/view/{{ $note->client->uid }}">{{ $note->client->displayName() }}</a>
+                        </td>
+                        <td class="">
+                            <?php
+                            $textContent = strip_tags($note->free_text_html);
+                            if(strlen($textContent) > 200) {
+                                $textContent = substr($textContent, 0, 200) . '…';
+                            }
+                            ?>
+                            {!! empty($textContent) ? '-' : $textContent !!}
+                        </td>
+                    </tr>
+                @endforeach
+                </tbody>
+            </table>
+        </div>
+    </div>
+    </div>
+
+@endsection

+ 22 - 10
resources/views/app/practice-management/processing-bill-matrix.blade.php

@@ -7,17 +7,29 @@
         <div class="card">
 
             <div class="card-header px-3 py-2 d-flex align-items-center">
-                <strong class="mr-4">
+                <strong class="text-nowrap">
                     <i class="fas fa-user-injured"></i>
                     Processing Bills
                 </strong>
-                <select class="ml-auto max-width-300px form-control form-control-sm"
-                        onchange="fastLoad('/practice-management/processing-bill-matrix/' + this.value, true, false, false)">
-                    <option value="" {{ $proUid === '' ? 'selected' : '' }}>All Pros</option>
-                    @foreach($allPros as $_pro)
-                        <option value="{{$_pro->uid}}" {{ $proUid === $_pro->uid ? 'selected' : '' }}>{{$_pro->displayName()}}</option>
-                    @endforeach
-                </select>
+                <span class="mx-2">for</span>
+                <div class="width-200px">
+                    <select provider-search data-pro-uid="{{ @$targetPro->uid }}"
+                            name="proUid" class="form-control form-control-sm mr-auto width-200px"
+                            onchange="fastLoad('/practice-management/processing-bill-matrix/' + this.value + '?f={{request()->input('f')}}')">
+                        <option value="" {{!@$targetPro ? 'selected' : ''}}>All Pros</option>
+                    </select>
+                </div>
+                @if(@$targetPro)
+                    <a href="/practice-management/processing-bill-matrix" class="ml-2">Clear Filter</a>
+                @endif
+                <div class="width-200px ml-2">
+                    <select name="filter" class="form-control form-control-sm mr-auto width-200px"
+                            onchange="fastLoad('/practice-management/processing-bill-matrix/{{@$targetPro ? $targetPro->uid : ''}}?f=' + this.value)">
+                        <option {{request()->input('f') === '' ? 'selected' : ''}} value="">All Bills</option>
+                        <option {{request()->input('f') === 'verified' ? 'selected' : ''}} value="verified">Verified Only</option>
+                        <option {{request()->input('f') === 'not-verified' ? 'selected' : ''}} value="not-verified">Not Verified Only</option>
+                    </select>
+                </div>
             </div>
             <div class="card-body p-0">
                 <table class="table table-sm table-condensed p-0 m-0">
@@ -70,8 +82,8 @@
                 </table>
             </div>
         </div>
-        <div>
-            {{$bills->links()}}
+        <div class="mt-3">
+            {{$bills->withQueryString()->links()}}
         </div>
     </div>
 

+ 1 - 1
resources/views/app/ticket/lab.blade.php

@@ -7,7 +7,7 @@
             <td style="padding-bottom: 0.25rem; width: 20%; opacity: 0.75;">Order Date:</td>
             <td style="padding-bottom: 0.25rem; width: 30%; opacity: 0.75; font-weight: bold;">{{date('Y-m-d h:i a')}}</td>
             <td style="padding-bottom: 0.25rem; width: 20%; opacity: 0.75;">NPI:</td>
-            <td style="padding-bottom: 0.25rem; width: 30%; opacity: 0.75; font-weight: bold;">-</td>
+            <td style="padding-bottom: 0.25rem; width: 30%; opacity: 0.75; font-weight: bold;">{{$ticket->orderingPro->hcp_npi}}</td>
         </tr>
         <tr>
             <td style="padding-bottom: 0.25rem; width: 20%; opacity: 0.75;">Test Date:</td>

+ 52 - 0
resources/views/app/ticket/other.blade.php

@@ -0,0 +1,52 @@
+<section style="padding-top: 0.1rem;">
+
+    <table cellpadding="0" cellspacing="0" border="0" style="width: 100%">
+        <tr>
+            <td style="width: 70%">
+                <b>Patient Information</b>
+            </td>
+            <td style="">
+                <div style="text-align: right">Date: <b>{{date('Y-m-d')}}</b></div>
+            </td>
+        </tr>
+    </table>
+
+    <div style="font-size: 14px; margin-top: 0.6rem; line-height: 1.4; opacity: 0.6">
+        <span>{{ $patient->displayName() }}, {{$patient->sex}}, {{$patient->age_in_years}} years old</span><br>
+        <?php
+        $addressParts = [];
+        if (!!$patient->mailing_address_line1) $addressParts[] = $patient->mailing_address_line1;
+        if (!!$patient->mailing_address_line2) $addressParts[] = $patient->mailing_address_line2;
+        $addressParts = implode(", ", $addressParts) . ", ";
+        $addressPart2 = [];
+        if (!!$patient->mailing_address_city) $addressPart2[] = $patient->mailing_address_city;
+        if (!!$patient->mailing_address_state) $addressPart2[] = $patient->mailing_address_state;
+        $addressParts .= implode(", ", $addressPart2);
+        ?>
+        <span>{!! $addressParts !!}</span>
+    </div>
+</section>
+
+<?php $otherData = json_decode($ticket->data); ?>
+<div style="margin: 1.5rem 0 1rem; font-weight: bold; opacity: 0.5"><span style="font-size: 24px">R</span><span style="font-size: 16px">x</span></div>
+<section style="font-size: 15px;">
+    <table cellpadding="0" cellspacing="0" border="0" style="width: 100%">
+        <tr>
+            <td style="width: 20px; vertical-align: top; opacity: 0.75; font-size: 14px">
+                <span>1. </span>
+            </td>
+            <td style="vertical-align: top">
+                <div>
+                    <p style="margin: 0 0 0.5rem;">
+                        <b>{{ $otherData->title }}</b>
+                    </p>
+                    <div style="">
+                        @if($otherData->description)
+                            <p style="margin: 0.5rem 0;">{{ $otherData->description }}</p>
+                        @endif
+                    </div>
+                </div>
+            </td>
+        </tr>
+    </table>
+</section>

+ 12 - 0
resources/views/layouts/patient.blade.php

@@ -50,6 +50,10 @@
                             <a class="nav-link {{ strpos($routeName, 'patients.view.notes') === 0 ? 'active' : '' }}"
                                href="{{ route('patients.view.notes', ['patient' => $patient]) }}">Notes</a>
                         </li>
+                        <li class="nav-item">
+                            <a class="nav-link {{ strpos($routeName, 'patients.view.generic-bills') === 0 ? 'active' : '' }}"
+                               href="{{ route('patients.view.generic-bills', ['patient' => $patient]) }}">Generic Bills</a>
+                        </li>
                         <li class="nav-item">
                             <a class="nav-link {{ strpos($routeName, 'patients.view.sections') === 0 ? 'active' : '' }}"
                                href="{{ route('patients.view.sections', ['patient' => $patient]) }}">Sections</a>
@@ -58,6 +62,10 @@
                             <a class="nav-link {{ strpos($routeName, 'patients.view.handouts') === 0 ? 'active' : '' }}"
                                href="{{ route('patients.view.handouts', ['patient' => $patient]) }}">Handouts</a>
                         </li>
+                        <li class="nav-item">
+                            <a class="nav-link {{ strpos($routeName, 'patients.view.rm-setup') === 0 ? 'active' : '' }}"
+                               href="{{ route('patients.view.rm-setup', ['patient' => $patient]) }}">RM Setup</a>
+                        </li>
                         <?php /* <li class="nav-item">
                             <a class="nav-link d-flex align-items-center {{ strpos($routeName, 'patients.view.action-items') === 0 ? 'active' : '' }}"
                                native onclick="return false">
@@ -102,6 +110,10 @@
                                     <a class="nav-link {{ strpos($routeName, 'patients.view.patient-tickets') === 0 && @$type === 'imaging' ? 'active' : '' }}"
                                        href="{{ route('patients.view.patient-tickets', ['patient' => $patient, 'type' => 'imaging']) }}">Imaging</a>
                                 </li>
+                                <li class="nav-item">
+                                    <a class="nav-link {{ strpos($routeName, 'patients.view.patient-tickets') === 0 && @$type === 'other' ? 'active' : '' }}"
+                                       href="{{ route('patients.view.patient-tickets', ['patient' => $patient, 'type' => 'other']) }}">Other</a>
+                                </li>
                             </ul>
                         </li>
                         <li class="nav-item">

+ 2 - 1
resources/views/layouts/template.blade.php

@@ -101,7 +101,7 @@
                 @endif
                 <li class="nav-item dropdown">
                     <a class="nav-link dropdown-toggle" href="#" id="practice-management" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="mr-1 fas fa-tasks"></i> Practice</a>
-                    <div class="dropdown-menu mcp-theme-1" aria-labelledby="practice-management">
+                    <div class="dropdown-menu mcp-theme-1 no-overflow-menu" aria-labelledby="practice-management">
                         {{--<a class="dropdown-item" href="{{ route('practice-management.dashboard') }}">Dashboard</a>--}}
                         @if($pro && $pro->pro_type == 'ADMIN')
                             <a class="dropdown-item" href="/practice-management/rates/all">Payment Rates</a>
@@ -139,6 +139,7 @@
                             <a class="dropdown-item" href="{{ route('practice-management.shipments') }}">Shipments</a>
                             <a class="dropdown-item" href="{{ route('practice-management.packs-multi-print') }}">Print Pack Labels</a>
                             <a class="dropdown-item" href="{{ route('practice-management.handouts') }}">Handouts</a>
+                            <a class="dropdown-item" href="{{ route('practice-management.generic-bills') }}">Generic Bills</a>
                         @endif
                     </div>
                 </li>

+ 7 - 1
routes/web.php

@@ -82,6 +82,7 @@ Route::middleware('pro.auth')->group(function () {
         Route::get('w9', 'PracticeManagementController@w9')->name('w9');
         Route::get('contract', 'PracticeManagementController@contract')->name('contract');
         Route::get('notes/{filter?}', 'PracticeManagementController@notes')->name('notes');
+        Route::get('na-billable-signed-notes/{filter?}', 'PracticeManagementController@naBillableSignedNotes')->name('na-billable-signed-notes');
         Route::get('bills/{filter?}', 'PracticeManagementController@bills')->name('bills');
         Route::get('unacknowledged-cancelled-bills', 'PracticeManagementController@unacknowledgedCancelledBills')->name('unacknowledged-cancelled-bills');
         Route::get('my-tickets/{filter?}', 'PracticeManagementController@myTickets')->name('myTickets');
@@ -111,7 +112,7 @@ Route::middleware('pro.auth')->group(function () {
 
             Route::get('cellular-measurements', 'PracticeManagementController@cellularMeasurements')->name('cellularMeasurements');
 
-            Route::get('processing-bill-matrix/{proUid?}', 'PracticeManagementController@processingBillMatrix')->name('processingBillMatrix');
+            Route::get('processing-bill-matrix/{proUid?}/{filter?}', 'PracticeManagementController@processingBillMatrix')->name('processingBillMatrix');
 
             //Route::get('hcp-bill-matrix/{proUid?}', 'PracticeManagementController@hcpBillMatrix')->name('hcpBillMatrix');
             Route::get('bill-matrix/{proUid?}', 'PracticeManagementController@billMatrix')->name('billMatrix');
@@ -142,6 +143,7 @@ Route::middleware('pro.auth')->group(function () {
             Route::get('packs-multi-print', 'PracticeManagementController@packsMultiPrint')->name('packs-multi-print');
             Route::get('packs-multi-pdf/{ids?}', 'PracticeManagementController@packsMultiPDF')->name('packs-multi-pdf');
             Route::get('handouts', 'PracticeManagementController@handouts')->name('handouts');
+            Route::get('generic-bills', 'PracticeManagementController@genericBills')->name('generic-bills');
         });
 
         Route::get('supply-orders/cancelled-but-unacknowledged', 'PracticeManagementController@supplyOrdersCancelledButUnacknowledged')->name('supply-orders-cancelled-but-unacknowledged');
@@ -189,8 +191,10 @@ Route::middleware('pro.auth')->group(function () {
                 Route::get('', 'NoteController@dashboard')->name('dashboard');
                 Route::get('section-view/{section}/{view}/{page?}', 'NoteController@sectionView')->name('section-view');
             });
+            Route::get('generic-bills', 'PatientController@genericBills')->name('generic-bills');
             Route::get('sections', 'PatientController@sections')->name('sections');
             Route::get('handouts', 'PatientController@handouts')->name('handouts');
+            Route::get('rm-setup', 'PatientController@rmSetup')->name('rm-setup');
             Route::get('settings', 'PatientController@settings')->name('settings');
             Route::get('sms-reminders', 'PatientController@smsReminders')->name('sms-reminders');
             Route::get('measurement-confirmation-numbers', 'PatientController@measurementConfirmationNumbers')->name('measurement-confirmation-numbers');
@@ -302,6 +306,8 @@ Route::middleware('pro.auth')->group(function () {
     Route::get('/section_create_form/{note_uid}/{section_template_uid}', 'NoteController@sectionCreateForm')->name('section_create_form');
     Route::get('/section_update_form/{section_uid}', 'NoteController@sectionUpdateForm')->name('section_update_form');
 
+    // generic bills modal
+    Route::get('/generic-bill-view/{entityType}/{entityUid}', 'HomeController@genericBill')->name('generic-bill-view');
 
     Route::get("/log_in_as", 'HomeController@logInAs')->name('log-in-as');
     Route::post("/process-log_in_as", 'HomeController@processLogInAs')->name('process-log-in-as');

+ 57 - 0
spec/note_implementation_spec_june_30_2021.txt

@@ -0,0 +1,57 @@
+
+	section
+	
+		<vue-app>
+		
+			<edit-mode v-if="view == 'edit'"> 
+				
+			</edit-mode>
+			
+			<summary-markup v-if="view == 'summary'" v-model="summaryHtml">
+			
+			<script>
+
+			{
+			
+				data: {
+					view:'edit',
+					summaryHtml:'{{$section->summary_html}}',
+					data: {
+						...
+					}
+				},
+				
+				methods: {
+					showEdit:function(){
+						// reload data
+						// view = 'edit'
+					}
+					showSummary:function(){
+						// reloadSummaryMarkup
+						// view = 'summary'
+					}
+					reloadData:function(){
+						//call php /note/section/{internalName}/getData
+						//php aggregates section data from the relevant pages / measurements / etc.
+						//php can use ob_start on /section/data.php
+					}
+					reloadSummaryMarkup:function(){
+						//call php to regenerate summary 
+						//php call java /api/section/updateSummaryHtml
+						//return summaryHtmlMarkup
+					}
+				},
+				
+				mount: function{
+				
+				}
+			}
+			</script>
+			
+		</vue-app>
+	
+		edit-mode
+		
+		summary-mode
+		
+			$section->summary_html