فهرست منبع

Nutrition segments (wip)

Vijayakrishnan 3 سال پیش
والد
کامیت
5e21792da7

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

@@ -398,6 +398,10 @@ class NoteController extends Controller
         return view('app.patient.supplements-reconcile', compact('patient', 'note'));
     }
 
+    public function nutritionCenter(Request $request, Client $patient, Note $note) {
+        return view('app.patient.nutrition-center', compact('patient', 'note'));
+    }
+
     public function ccmAgreement(Request $request, Note $note) {
         return view('app.patient.note.ccm-agreement', compact('note'));
     }

+ 13 - 0
app/Models/Point.php

@@ -254,6 +254,19 @@ class Point extends Model
         ];
     }
 
+    public static function getOnlyPointOfCategory(Client $_patient, String $_category) {
+        $point = Point
+            ::where('client_id', $_patient->id)
+            ->where('category', $_category)
+            ->first();
+
+        if ($point && $point->data) {
+            $point->data = json_decode($point->data);
+        }
+
+        return $point;
+    }
+
     public static function fillPointStateAndBadge(Point $point, Note $note)
     {
 

+ 1 - 1
public/css/style.css

@@ -446,7 +446,7 @@ body [note-rte][data-field-name="planValue"] {
 body [note-rte][slim-rte] .ql-editor[contenteditable],
 body [note-rte][data-field-name="reviewValue"] .ql-editor[contenteditable],
 body [note-rte][data-field-name="planValue"] .ql-editor[contenteditable] {
-    min-height: 28px !important;
+    min-height: 56px !important;
     padding: .25rem .5rem !important;
 }
 .ql-container p {

+ 9 - 0
resources/views/app/patient/note/dashboard_script.blade.php

@@ -155,6 +155,15 @@
                             return false;
                         }
 
+                        if(editParent.is('[data-segment-template-name="plan_nutrition"]') ||
+                            editParent.is('[data-segment-template-name="intake_nutrition"]')) {
+                            openDynamicStagPopup('/nutrition-center/{{$note->client->uid}}/{{$note->uid}}',
+                                'nutrition-center-{{$note->id}}',
+                                "Nutrition Rx", false,
+                                "medium-large overflow-visible");
+                            return false;
+                        }
+
                         // OPEN popup for if note-segment-view exists
                         if($('.' + editParent.attr('data-segment-template-name') + '-trigger').length) {
                             $('.' + editParent.attr('data-segment-template-name') + '-trigger').trigger('click');

+ 109 - 0
resources/views/app/patient/nutrition-center.blade.php

@@ -0,0 +1,109 @@
+<?php
+
+use App\Models\Point;
+use App\Models\Client;
+use App\Models\Note;
+use App\Models\Segment;
+
+/** @var Client $patient */
+/** @var Note $note */
+
+$highSugarBeverages = Point::getOnlyPointOfCategory($patient, 'HIGH_SUGAR_BEVERAGES');
+$waterIntake = Point::getOnlyPointOfCategory($patient, 'WATER_INTAKE');
+$fastFood = Point::getOnlyPointOfCategory($patient, 'FAST_FOOD');
+$snacks = Point::getOnlyPointOfCategory($patient, 'SNACKS');
+$vegetables = Point::getOnlyPointOfCategory($patient, 'VEGETABLES');
+$portionSizes = Point::getOnlyPointOfCategory($patient, 'PORTION_SIZES');
+$dailyIntakeCarbohydrates = Point::getOnlyPointOfCategory($patient, 'DAILY_INTAKE_CARBOHYDRATES');
+$dailyIntakeCalories = Point::getOnlyPointOfCategory($patient, 'DAILY_INTAKE_CALORIES');
+
+$points = [
+    ["category" => 'HIGH_SUGAR_BEVERAGES', "name" => 'High Sugar Beverages', "point" => $highSugarBeverages],
+    /*["category" => 'WATER_INTAKE', "name" => 'Water Intake', "point" => $waterIntake],
+    ["category" => 'FAST_FOOD', "name" => 'Fast Food', "point" => $fastFood],
+    ["category" => 'SNACKS', "name" => 'Snacks', "point" => $snacks],
+    ["category" => 'VEGETABLES', "name" => 'Vegetables', "point" => $vegetables],
+    ["category" => 'PORTION_SIZES', "name" => 'Portion Sizes', "point" => $portionSizes],
+    ["category" => 'DAILY_INTAKE_CARBOHYDRATES', "name" => 'Daily Intake Carbohydrates', "point" => $dailyIntakeCarbohydrates],
+    ["category" => 'DAILY_INTAKE_CALORIES', "name" => 'Daily Intake Calories', "point" => $dailyIntakeCalories],*/
+];
+?>
+
+<div class="mt-3 p-3 border-top" id="nutrition-center-{{$note->id}}">
+    <div class="point-table-container">
+
+        <table class="table table-sm table-bordered mb-0 bg-white mb-2 point-table">
+            <thead>
+            <tr class="">
+                <th class="border-bottom-0 text-secondary">Category</th>
+                <th class="border-bottom-0 text-secondary w-35">Current/Subjective</th>
+                <th class="border-bottom-0 text-secondary w-35">Plan</th>
+            </tr>
+            </thead>
+
+            @foreach($points as $p)
+                <?php $point = $p['point']; ?>
+                <tr class="point-row" data-uid="{{$point ? $point->uid : ''}}">
+                    <td>
+                        {{$p['name']}}
+                    </td>
+                    <td>
+                        <div class="d-flex align-items-start">
+                            <div class="flex-grow-1">
+                                @if($point)
+                                    <?php
+                                    include resource_path('views/app/patient/segment-templates/_child_review/' . $p['category'] . '/last-review.php');
+                                    ?>
+                                @else
+                                    -
+                                @endif
+                            </div>
+                            <div class="d-inline-flex flex-column ml-1">
+                                <?php
+                                $segment = $note->getSegmentByInternalName('intake_nutrition');
+                                if($segment) {
+                                    include resource_path('views/app/patient/segment-templates/_child_review/' . $p['category'] . '/edit-review.php');
+                                }
+                                ?>
+                            </div>
+                        </div>
+                    </td>
+                    <td>
+                        <div class="d-flex align-items-start position-relative">
+                            <div class="flex-grow-1">
+                                @if($point)
+                                    <?php
+                                    include resource_path('views/app/patient/segment-templates/_child_plan/' . $p['category'] . '/last-plan.php');
+                                    ?>
+                                @else
+                                    -
+                                @endif
+                            </div>
+                            <div class="d-inline-flex flex-column ml-1">
+                                <?php
+                                $segment = $note->getSegmentByInternalName('intake_nutrition');
+                                if($segment) {
+                                    include resource_path('views/app/patient/segment-templates/_child_plan/' . $p['category'] . '/edit-plan.php');
+                                }
+                                ?>
+                            </div>
+                        </div>
+                    </td>
+                </tr>
+            @endforeach
+
+        </table>
+
+    </div>
+</div>
+<script>
+    (function() {
+        function init() {
+            let parentSegment = $('#nutrition-center-{{$note->id}}');
+            @include('app.patient.wizard-partials.common-script', ['label' => 'nutrition', 'segment_part' => 'nutrition'])
+            initSegmentMoes(parentSegment);
+            __initRTEs(parentSegment.find('[note-rte]:not(.ql-container)'));
+        }
+        addMCInitializer('nutrition-center-{{$note->id}}', init, '#nutrition-center-{{$note->id}}');
+    }).call(window);
+</script>

+ 118 - 0
resources/views/app/patient/segment-templates/_child_plan/HIGH_SUGAR_BEVERAGES/edit-plan.php

@@ -0,0 +1,118 @@
+<?php
+$currentValue = '';
+$previousValue = '';
+$previousChildPlan = null;
+if (@$point) {
+    if ($point->lastChildPlan && $point->last_child_plan_point_scoped_note_id === $note->id) {
+        $parsedPlan = json_decode($point->lastChildPlan->data);
+        if(@$parsedPlan->value) {
+            $currentValue = $parsedPlan->value;
+            $previousChildPlan = \App\Models\Point::where('id', '<', $point->lastChildPlan->id)
+                ->where('category', 'PLAN')
+                ->where('parent_point_id', $point->id)
+                ->orderBy('id', 'DESC')
+                ->first();
+            if($previousChildPlan && $previousChildPlan->data) {
+                $parsedPlan = json_decode($previousChildPlan->data);
+                $previousValue = $parsedPlan->value;
+            }
+        }
+    }
+    else {
+        $previousChildPlan = \App\Models\Point::where('parent_point_id', $point->id)
+            ->where('category', 'PLAN')
+            ->orderBy('id', 'DESC')
+            ->first();
+        if($previousChildPlan && $previousChildPlan->data) {
+            $parsedPlan = json_decode($previousChildPlan->data);
+            if(@$parsedPlan->value) {
+                $previousValue = $parsedPlan->value;
+            }
+        }
+    }
+}
+?>
+<div moe wide relative class="d-inline">
+    <a start show href="#" class="px-1 text-center d-block" title="<?= !empty($currentValue) ? 'Edit Plan' : 'Add Plan'?>">
+        <i class="fa <?= !empty($currentValue) ? 'fa-pencil-alt' : 'fa-plus-square'?>"></i>
+    </a>
+    <?php if($point): ?>
+        <form url="/api/visitPoint/upsertChildPlan" class="mcp-theme-1" right>
+            <input type="hidden" name="uid" value="<?= $point->uid ?>">
+            <input type="hidden" name="segmentUid" value="<?= $segment->uid ?>">
+            <input type="hidden" name="data">
+
+            <?php if($segment->segmentTemplate->internal_name === 'intake_problems' && $previousValue): ?>
+                <div class="d-none disallow-if-value-same-as"><?= str_compact($previousValue) ?></div>
+            <?php endif; ?>
+
+            <?php if($previousValue): ?>
+                <div class="mb-2">
+                    <div class="d-flex align-items-baseline mb-1">
+                        <span class="text-sm text-secondary">Previous Plan / <?= friendlier_date($previousChildPlan->created_at) ?>) (click to copy)</span>
+                    </div>
+                    <div class="p-2 bg-light border inline-html-container click-to-copy"><?= $previousValue ?></div>
+                </div>
+            <?php endif; ?>
+
+            <p class="mb-2"><b>Change goal:</b></p>
+
+            <div class="mb-2">
+                <div note-rte
+                    <?= $segment->segmentTemplate->internal_name === 'intake_problems' ? 'use-shortcuts="hpi,user"' : '' ?>
+                     class="form-group mb-2 border-left border-right rte-holder"
+                     data-field-name="value"><?= $currentValue ?></div>
+            </div>
+            <div>
+                <button submit class="btn btn-sm btn-primary mr-2">Save</button>
+                <button cancel class="btn btn-sm btn-default border">Cancel</button>
+            </div>
+        </form>
+    <?php else: ?>
+        <form url="/api/visitPoint/addTopLevel" class="mcp-theme-1 frm-add-review-plan-nutrition" right>
+            <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
+            <input type="hidden" name="category" value="<?= $p['category'] ?>">
+            <input type="hidden" name="additionReasonCategory" value="ON_INTAKE">
+            <input type="hidden" name="data">
+
+            <?php if($previousValue): ?>
+                <div class="mb-2">
+                    <div class="d-flex align-items-baseline mb-1">
+                        <span class="text-sm text-secondary">Previous Plan / <?= friendlier_date($previousChildPlan->created_at) ?>) (click to copy)</span>
+                    </div>
+                    <div class="p-2 bg-light border inline-html-container click-to-copy"><?= $previousValue ?></div>
+                </div>
+            <?php endif; ?>
+
+            <p class="mb-2"><b>Current Consumption (soda, sweet-tea, coffee, juice, etc.)</b></p>
+
+            <div class="mb-2">
+                <div note-rte
+                     class="form-group mb-2 border-left border-right rte-holder"
+                     data-field-name="planValue"><?= $currentValue ?></div>
+            </div>
+            <div>
+                <button type="submit" class="btn btn-sm btn-primary mr-2">Save</button>
+                <button cancel class="btn btn-sm btn-default border">Cancel</button>
+            </div>
+        </form>
+    <?php endif; ?>
+</div>
+<?php if(!empty($currentValue)): ?>
+    <div visit-moe relative class="d-inline">
+        <a start show href="#" class="px-1 text-center d-block" title="Delete Plan">
+            <i class="fa fa-trash-alt text-danger on-hover-opaque"></i>
+        </a>
+        <form url="/api/visitPoint/destroyCurrentChildPlan" class="mcp-theme-1" right>
+            <input type="hidden" name="uid" value="<?= $point->uid ?>">
+
+            <p class="mb-2">Delete this plan?</p>
+
+            <div>
+                <button submit class="btn btn-sm btn-danger mr-2">Delete</button>
+                <button cancel class="btn btn-sm btn-default border">Cancel</button>
+            </div>
+        </form>
+    </div>
+<?php endif; ?>
+

+ 32 - 0
resources/views/app/patient/segment-templates/_child_plan/HIGH_SUGAR_BEVERAGES/last-plan.php

@@ -0,0 +1,32 @@
+<?php if ($point->lastChildPlan): ?>
+    <?php $parsedPlan = json_decode($point->lastChildPlan->data); ?>
+    <div class="<?= $point->last_child_plan_point_scoped_note_id === $note->id ? 'bg-warning-mellow p-2 rounded' : '' ?>">
+        <div class="inline-html-container"><?= $parsedPlan->value ?></div>
+        <div class="text-secondary text-sm"></div>
+
+        <?php if ($point->last_child_plan_point_scoped_note_id === $patient->core_note_id): ?>
+            <span class="text-sm">(updated on the patient's chart)</span>
+        <?php else: ?>
+            <?php if ($point->last_child_plan_point_scoped_note_id === $note->id): ?>
+                <span class="text-sm">(updated on this note)</span>
+            <?php else: ?>
+                <div class="d-inline position-relative on-click-menu">
+                    <span class="text-sm text-primary c-pointer">
+                        <?= relative_friendly_date($point->last_child_plan_effective_date) ?>
+                        <?php if($point->lastChildPlan->creatorPro): ?>
+                            by <?= $point->lastChildPlan->creatorPro->displayName() ?>
+                        <?php endif; ?>
+                    </span>
+                    <div menu right class="bg-white border">
+                        <a native target="_blank"
+                           href="<?= route('patients.view.notes.view.dashboard', ['patient' => $patient, 'note' => $point->lastChildPlanNote]) ?>"
+                           class="px-2 py-1 d-block text-nowrap text-sm">Go to note</a>
+                    </div>
+                </div>
+            <?php endif; ?>
+        <?php endif; ?>
+
+    </div>
+<?php else: ?>
+    <span class="text-secondary text-sm">None</span>
+<?php endif; ?>

+ 83 - 0
resources/views/app/patient/wizard-partials/common-script.blade.php

@@ -448,6 +448,89 @@ parentSegment.find('.frm-edit-{{$label}}')
         return false;
     });
 
+// special case for nutrition form handling
+parentSegment.find('.frm-add-review-plan-{{$label}}')
+    .off('submit')
+    .on('submit', function () {
+
+        debugger
+
+        let form = $(this);
+
+        showMask();
+
+        // add [data-name] values to payload
+        let dataField = form.find('[name="data"]').first();
+        let parsed = null;
+        if(dataField.val()) {
+            parsed = JSON.parse(dataField.val());
+        }
+
+        @if(1 || $patient->core_note_id !== $note->id)
+            // store plan content
+            let planContent = parsed && parsed.planValue ? parsed.planValue : '';
+            let reviewContent = parsed && parsed.reviewValue ? parsed.reviewValue : '';
+            // if(!$.trim($('<div/>').html(planContent).text())) {
+            //     toastr.error('Directions cannot be empty');
+            //     return false;
+            // }
+            if(parsed.planValue) delete parsed.planValue;
+            if(parsed.reviewValue) delete parsed.reviewValue;
+        @endif
+
+        form.find('[data-name]').each(function() {
+            if(!parsed) parsed = {};
+
+            let keys = $(this).attr('data-name').split('->');
+            let currentNode = parsed;
+            for (let i = 0; i < keys.length; i++) {
+                if(i !== keys.length - 1) {
+                    if(typeof currentNode[keys[i]] === 'undefined') {
+                        currentNode[keys[i]] = {};
+                    }
+                    currentNode = currentNode[keys[i]];
+                }
+                else {
+                    if($(this).is(':checkbox')) {
+                        currentNode[keys[i]] = $(this).prop('checked');
+                    }
+                    else {
+                        currentNode[keys[i]] = $(this).val();
+                    }
+                }
+            }
+
+        });
+        if(parsed) {
+            dataField.val(JSON.stringify(parsed));
+        }
+
+        let payload = {};
+        form.serializeArray().map(x => {payload[x.name] = x.value;});
+        @if(1 || $patient->core_note_id !== $note->id)
+            if(!!reviewContent && $.trim($('<div/>').html(reviewContent).text())) {
+                payload.childReviewData = JSON.stringify({
+                    value: reviewContent
+                })
+            }
+            if(!!planContent && $.trim($('<div/>').html(planContent).text())) {
+                payload.childPlanData = JSON.stringify({
+                    value: planContent
+                })
+            }
+        @endif
+
+        $.post(form.attr('url'), payload, _data => {
+            if(!hasResponseError(_data)) {
+                hideMask();
+                refreshDynamicStagPopup();
+                $('.visit-segment[data-segment-template-name="intake_{{$segment_part}}"]').find('.refresh-segment').trigger('click');
+                $('.visit-segment[data-segment-template-name="plan_{{$segment_part}}"]').find('.refresh-segment').trigger('click');
+            }
+        }, 'json');
+        return false;
+    });
+
 parentSegment.find('.toggle-relevance')
     .off('click.toggle-relevance')
     .on('click.toggle-relevance', function () {

+ 2 - 0
routes/web.php

@@ -473,6 +473,8 @@ Route::middleware('pro.auth')->group(function () {
     Route::get('/memos-thread/{patient}', 'PatientController@memosThread')->name('memos-thread');
     Route::get('/messages-thread/{patient}', 'PatientController@messagesThread')->name('messages-thread');
 
+    Route::get('/nutrition-center/{patient}/{note}', 'NoteController@nutritionCenter')->name('nutrition-center');
+
     Route::get('/problems-quick-add/{patient}/{note}', 'NoteController@problemsQuickAdd')->name('problems-quick-add');
 
     //mb claim single view