Quellcode durchsuchen

added guest section support

Josh vor 4 Jahren
Ursprung
Commit
1f3daa9564

+ 26 - 0
app/Http/Controllers/GuestController.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\CareMonth;
+use App\Models\CareMonthEntry;
+use App\Models\Client;
+use App\Models\Pro;
+use App\Models\Section;
+use App\Models\SectionTemplate;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\File;
+
+class GuestController extends Controller
+{
+    public function section(Request $request, $guestAccessCode )
+    {
+        
+        $section = Section::where('guest_access_code', $guestAccessCode)->first();
+        abort_if(!$section, 404, 'Invalid access code');
+        abort_if($section->guest_access_level == 'NONE', 401, 'Invalid access code');
+        
+       return view('app.guest.section', compact('section'));
+    }
+
+}

+ 48 - 41
public/js/mc.js

@@ -14,10 +14,14 @@ window.top.addEventListener('popstate', function (event) {
 });
 $(document).ready(function () {
 
-    if(window.location.pathname === window.top.location.pathname) {
-        window.top.location.href = '/mc' + window.location.pathname;
-        return;
+
+    if(!window.noMc){
+        if (window.location.pathname === window.top.location.pathname) {
+            window.top.location.href = '/mc' + window.location.pathname;
+            return;
+        }
     }
+
     // window.top.ensureRHS();
     $(document).on('click', '.stag_rhs_toggle', function () {
         var state = window.top.toggleRHS(),
@@ -52,31 +56,34 @@ $(document).ready(function () {
     if (target.indexOf('/mc') === 0) {
         target = target.split('/mc')[1];
     }
-    fastLoad(target, true, false, true);
+    if(!window.noMc){
+        fastLoad(target, true, false, true);
+    }
+   
 
 });
 function enableTimeSpecificFields(_checked, _valueClass, _rangeClass) {
-    if(_valueClass) $('.' + _valueClass).prop('disabled', _checked);
-    if(_rangeClass) $('.' + _rangeClass).prop('disabled', !_checked);
+    if (_valueClass) $('.' + _valueClass).prop('disabled', _checked);
+    if (_rangeClass) $('.' + _rangeClass).prop('disabled', !_checked);
 }
 function toggleDisabledAsNeeded(_el, _targetValue, _enableClass, _disableClass) {
-    if(_el.value === _targetValue) {
-        if(_enableClass) $('.' + _enableClass).prop('disabled', false);
-        if(_disableClass) $('.' + _disableClass).prop('disabled', true);
+    if (_el.value === _targetValue) {
+        if (_enableClass) $('.' + _enableClass).prop('disabled', false);
+        if (_disableClass) $('.' + _disableClass).prop('disabled', true);
     }
     else {
-        if(_enableClass) $('.' + _enableClass).prop('disabled', true);
-        if(_disableClass) $('.' + _disableClass).prop('disabled', false);
+        if (_enableClass) $('.' + _enableClass).prop('disabled', true);
+        if (_disableClass) $('.' + _disableClass).prop('disabled', false);
     }
 }
 function toggleVisibilityAsNeeded(_el, _targetValue, _visibleClass, _hiddenClass) {
-    if(_el.value === _targetValue) {
-        if(_visibleClass) $('.' + _visibleClass).removeClass('d-none');
-        if(_hiddenClass) $('.' + _hiddenClass).addClass('d-none');
+    if (_el.value === _targetValue) {
+        if (_visibleClass) $('.' + _visibleClass).removeClass('d-none');
+        if (_hiddenClass) $('.' + _hiddenClass).addClass('d-none');
     }
     else {
-        if(_visibleClass) $('.' + _visibleClass).addClass('d-none');
-        if(_hiddenClass) $('.' + _hiddenClass).removeClass('d-none');
+        if (_visibleClass) $('.' + _visibleClass).addClass('d-none');
+        if (_hiddenClass) $('.' + _hiddenClass).removeClass('d-none');
     }
 }
 var fastCache = {};
@@ -89,12 +96,12 @@ function initFastLoad(_parent = false) {
     }
 
     // clear cache
-    if(!_parent) {
+    if (!_parent) {
         fastCache = {};
     }
     else {
         allAs.each(function () {
-            if(typeof fastCache[this.href] !== 'undefined') {
+            if (typeof fastCache[this.href] !== 'undefined') {
                 delete fastCache[this.href];
             }
         });
@@ -146,7 +153,7 @@ function onFastLoaded(_data, _href, _history) {
         content = content.html();
         content += '<script src="/js/yemi.js?_=7"></script>';
         targetParent.html(content);
-        window.setTimeout(function() {
+        window.setTimeout(function () {
             initCreateNote();
             initQuillEdit();
             initFastLoad(targetParent);
@@ -174,7 +181,7 @@ function fastLoad(_href, _history = true, _useCache = true, _replaceState = fals
 
     showMask();
 
-    if(_href === '') _href = '/';
+    if (_href === '') _href = '/';
 
     // push state
     if (_history) {
@@ -185,8 +192,8 @@ function fastLoad(_href, _history = true, _useCache = true, _replaceState = fals
                 target = target.substr(target.indexOf('/') + 1);
             }
         }
-        if(target[0] === '/') target = target.substr(1);
-        if(_replaceState) {
+        if (target[0] === '/') target = target.substr(1);
+        if (_replaceState) {
             window.top.history.replaceState(target, null, '/mc/' + target);
             console.log('ALIX replaceState: [' + target + ']');
         }
@@ -199,9 +206,9 @@ function fastLoad(_href, _history = true, _useCache = true, _replaceState = fals
     if (_useCache && !!fastCache[_href]) {
         onFastLoaded(fastCache[_href], _href, _history);
     } else {
-        $.get(_href, function(_data) {
+        $.get(_href, function (_data) {
             onFastLoaded(_data, _href, _history);
-        }).fail(function() {
+        }).fail(function () {
             onFastLoaded('error', _href, _history);
         });
     }
@@ -212,11 +219,11 @@ function initPrimaryForm(_form = false) {
     if (primaryForm.length) {
         primaryForm = primaryForm.first();
         var rte = primaryForm.find('[contenteditable="true"]').first();
-        if(rte.length) {
+        if (rte.length) {
             rte.focus().select();
         }
         else {
-            if(primaryForm.find('[autofocus]:visible').length) {
+            if (primaryForm.find('[autofocus]:visible').length) {
                 primaryForm.find('[autofocus]:visible').first().focus().select();
             }
             else {
@@ -237,10 +244,10 @@ function openInRHS(_url) {
 function initCreateNote() {
     $(document)
         .off('click.create-note', '.create-auto-note-trigger')
-        .on('click.create-note', '.create-auto-note-trigger', function() {
+        .on('click.create-note', '.create-auto-note-trigger', function () {
             createNewNote($(this).attr('data-patient-uid'), $(this).attr('data-hcp-uid'), $(this).attr('data-effective-date'));
         });
-    if($('select[name="hasMcpDoneOnboardingVisit"]').length) {
+    if ($('select[name="hasMcpDoneOnboardingVisit"]').length) {
         $('select[name="hasMcpDoneOnboardingVisit"]')[0].onchange();
     }
 }
@@ -252,7 +259,7 @@ function createNewNote(_patientUid, _hcpUid, _date) {
         clientUid: _patientUid,
         hcpProUid: _hcpUid,
         effectiveDateEST: _date,
-    }, function(_data) {
+    }, function (_data) {
         hideMask();
         if (!_data.success) {
             toastr.error(_data.message);
@@ -267,14 +274,14 @@ function initQuillEdit(_selector = '.note-content[auto-edit]') {
 
     $(document)
         .off('click.enable-edit', '.note-content:not([auto-edit]):not(.readonly)')
-        .on('click.enable-edit', '.note-content:not([auto-edit]):not(.readonly)', function() {
+        .on('click.enable-edit', '.note-content:not([auto-edit]):not(.readonly)', function () {
             $(this).attr('auto-edit', 1);
             initQuillEdit();
             initPrimaryForm();
             initPatientPresenceIndicator();
         });
 
-    if(!$(_selector).length) return;
+    if (!$(_selector).length) return;
     var noteUid = $(_selector).attr('data-note-uid');
     var qe = new Quill(_selector, {
         theme: 'snow',
@@ -283,8 +290,8 @@ function initQuillEdit(_selector = '.note-content[auto-edit]') {
                 bindings: {
                     handleEnter: {
                         key: 13,
-                        handler: function() {
-                            if(!$('.stag-shortcuts:visible').length) return true;
+                        handler: function () {
+                            if (!$('.stag-shortcuts:visible').length) return true;
                         }
                     }
                 }
@@ -294,11 +301,11 @@ function initQuillEdit(_selector = '.note-content[auto-edit]') {
     var toolbar = $(qe.container).prev('.ql-toolbar');
     var saveButton = $('<button class="btn btn-sm btn-primary w-auto px-3 py-0 text-sm text-white save-note-content">Save</button>');
     toolbar.append(saveButton);
-    saveButton.on('click', function() {
+    saveButton.on('click', function () {
         $.post('/api/note/putFreeTextHtml', {
             uid: noteUid,
             freeTextHtml: qe.root.innerHTML,
-        }, function(_data) {
+        }, function (_data) {
             if (!_data.success) {
                 toastr.error(_data.message);
             }
@@ -328,20 +335,20 @@ function initQuillEdit(_selector = '.note-content[auto-edit]') {
 
 var patientPresenceTimer = false;
 function initPatientPresenceIndicator() {
-    if(patientPresenceTimer !== false) {
+    if (patientPresenceTimer !== false) {
         window.clearInterval(patientPresenceTimer);
         patientPresenceTimer = false;
         console.log('Cancelled previous timer!');
     }
     var elem = $('.patient-presence-indicator[data-patient-uid]');
-    if(elem.length) {
+    if (elem.length) {
         var patientUid = elem.attr('data-patient-uid');
-        patientPresenceTimer = window.setInterval(function() {
+        patientPresenceTimer = window.setInterval(function () {
             var elem = $('.patient-presence-indicator[data-patient-uid]');
-            if(elem.length) {
+            if (elem.length) {
                 var patientUid = elem.attr('data-patient-uid');
-                $.get('/patients/' + patientUid + '/presence', function(_data) {
-                    if(_data.online) {
+                $.get('/patients/' + patientUid + '/presence', function (_data) {
+                    if (_data.online) {
                         elem.addClass('online');
                     }
                     else {

+ 10 - 0
resources/views/app/guest/section.blade.php

@@ -0,0 +1,10 @@
+@extends ('layouts.guest_template')
+
+@section('content')
+<?php
+$shortcuts = "";
+$latestSectionTS = 0;
+?>
+@include('app.patient.note.section')
+@include('app.patient.note.section_script')
+@endsection

+ 73 - 0
resources/views/app/patient/note/guest-access.blade.php

@@ -0,0 +1,73 @@
+<div class="d-flex">
+
+    @if($section->guest_access_level != 'READ')
+    <div moe wide class="mr-2">
+        <a start show>
+            Enable Guest Read Access
+        </a>
+        <form url="/api/section/enableGuestReadAccess">
+            <input type="hidden" name="uid" value="{{$section->uid}}">
+
+            <div class="form-group">
+                Enable guest read access?
+            </div>
+
+            <div class="form-group m-0">
+                <button submit class="btn btn-primary btn-sm mr-2">Submit</button>
+                <button cancel class="btn btn-default border btn-sm mr-2">Cancel</button>
+            </div>
+        </form>
+    </div>
+    @endif
+
+    @if($section->guest_access_level != 'WRITE')
+    <div moe wide class="mr-2">
+        <a start show>
+            Enable Guest Write Access
+        </a>
+        <form url="/api/section/enableGuestWriteAccess">
+            <input type="hidden" name="uid" value="{{$section->uid}}">
+
+            <div class="form-group">
+                Enable guest write access?
+            </div>
+
+            <div class="form-group m-0">
+                <button submit class="btn btn-primary btn-sm mr-2">Submit</button>
+                <button cancel class="btn btn-default border btn-sm mr-2">Cancel</button>
+            </div>
+        </form>
+    </div>
+    @endif
+
+    @if($section->guest_access_level != 'NONE')
+    <div class="mr-2">
+        @if($section->guest_access_level == 'READ')
+        READ ACCESS: 
+        @endif
+        
+        @if($section->guest_access_level == 'WRITE')
+        WRITE ACCESS: 
+        @endif
+        <a href="{{route('guest_section_access', $section->guest_access_code)}}"> {{route('guest_section_access', $section->guest_access_code)}} </a>
+    </div>
+    <div moe wide class="mr-2">
+        <a start show>
+            Disable Guest Access
+        </a>
+        <form url="/api/section/disableGuestAccess">
+            <input type="hidden" name="uid" value="{{$section->uid}}">
+
+            <div class="form-group">
+                Disable guest access?
+            </div>
+
+            <div class="form-group m-0">
+                <button submit class="btn btn-primary btn-sm mr-2">Submit</button>
+                <button cancel class="btn btn-default border btn-sm mr-2">Cancel</button>
+            </div>
+        </form>
+    </div>
+    @endif
+
+</div>

+ 2 - 240
resources/views/app/patient/note/note-section-list.blade.php

@@ -1,243 +1,5 @@
 <?php $canvasData = json_decode($patient->canvas_data, true); ?>
 @foreach($note->sections as $section)
-<?php
-$sectionTS = strtotime($section->created_at);
-if ($latestSectionTS === 0 || $latestSectionTS < $sectionTS) {
-    $latestSectionTS = $sectionTS;
-}
-?>
-<div data-ts="{{$sectionTS}}" class="p-3 border-bottom note-section {{ $note->is_signed_by_hcp ? 'signed-note' : '' }} {{ $section->is_initialized ? '' : 'pending-initialization' }}" {!! $note->is_signed_by_hcp ? 'title="Signed note. Cannot be edited further."' : '' !!}
-    data-section-uid="{{ $section->uid }}"
-    data-section-template-uid="{{ $section->sectionTemplate->uid }}"
-    data-section-template-name="{{ $section->sectionTemplate->internal_name }}">
-    <div class="d-flex align-items-start">
-        @if(!$note->is_signed_by_hcp)
-        <a class="font-weight-bold mb-2 d-flex align-items-center c-pointer">
-            {{$section->sectionTemplate->title}}
-            <span class="d-none if-not-edit"><i class="fa fa-edit ml-2"></i></span>
-            <span class="d-none if-edit edit-trigger"><i class="fa fa-times ml-2"></i></span>
-            <span class="edit-trigger"></span>
-        </a>
-        @else
-        <span class="font-weight-bold mb-2 d-flex align-items-center">
-            {{$section->sectionTemplate->title}}
-        </span>
-        @endif
-        <?php $sectionInternalName = $section->sectionTemplate->internal_name; ?>
-
-        @if($sectionInternalName === "exam" || $sectionInternalName === "objective")
-        @include('app/patient/note/_templates-exam-index')
-        @else
-        @include('app/patient/note/_templates-index')
-        @endif
-
-        <?php
-        if (file_exists(storage_path('sections/' . $sectionInternalName . '/actions.php'))) {
-            include(storage_path('sections/' . $sectionInternalName . '/actions.php'));
-        }
-        ?>
-        <?php
-        if (file_exists(storage_path('sections/' . $sectionInternalName . '/actions.blade.php'))) {
-        ?> @include('sections/' . $sectionInternalName . '/actions') <?php
-                                                                            }
-                                                                                ?>
-
-        <a href="#" class="d-none text-danger if-edit ml-auto remove-section-trigger mr-1" data-uid="{{$section->uid}}" title="Remove {{$section->sectionTemplate->title}}">
-            Remove {{$section->sectionTemplate->title}}
-        </a>
-
-        <a href="#" class="d-none if-edit ml-2 move-up-trigger" data-uid="{{$section->uid}}" title="Move Up">
-            <i class="fa fa-arrow-up"></i>
-        </a>
-
-        <a href="#" class="d-none if-edit ml-2 move-down-trigger" data-uid="{{$section->uid}}" title="Move Down">
-            <i class="fa fa-arrow-down"></i>
-        </a>
-
-    </div>
-    <div class="d-none if-not-edit  inset-comment summary-container">
-        {!! !empty($section->summary_html) ? $section->summary_html : '-' !!}
-    </div>
-
-    <div class="d-none if-edit">
-
-        <?php
-        // if canvas
-        if ($section->sectionTemplate->is_canvas) {
-            $contentData = false;
-            if ($canvasData) {
-                if (isset($canvasData[$sectionInternalName])) {
-                    $contentData = $canvasData[$sectionInternalName];
-                }
-            }
-        ?>
-            @include("app.patient.canvas-sections.{$sectionInternalName}.form")
-        <?php
-        }
-
-        // if form driven
-        else if (file_exists(storage_path('sections/' . $sectionInternalName . '/form.blade.php'))) {
-        ?>
-            @include('sections.' . $sectionInternalName . '.form')
-        <?php
-        }
-
-        // if neither canvas nor form driven
-        else {
-            $contentData = false;
-            if ($section) {
-                $contentData = json_decode($section->content_data, true);
-            }
-            if (!$contentData || !isset($contentData['value'])) {
-                $contentData = [
-                    'value' => ''
-                ];
-            }
-        ?>
-            <input type="hidden" name="data">
-            <div note-rte data-content="{{$contentData['value']}}" class="form-group mb-2 border-left border-right rte-holder"></div>
-        <?php
-        }
-        ?>
-
-        <div class="d-flex align-items-center">
-            <button class="btn btn-sm btn-primary" btn-save-form><i class="fa fa-save"></i></button>
-            <span class="ml-2 text-secondary text-sm text-saving d-none"><i>Saving ...</i></span>
-        </div>
-    </div>
-</div>
+@include('app.patient.note.section')
 @endforeach
-<script>
-    (function() {
-
-        function init() {
-            $('[note-rte]').each(function() {
-
-                $(this).wrap(
-                    $('<div class="border-left border-right rte-holder"/>')
-                        .attr('data-shortcuts', '')
-                );
-
-                // give a unique id to this editor instance
-                var editorID = Math.ceil(Math.random() * 99999),
-                    fieldName = this.name;
-
-                var el = this;
-                var existingContent = $(el).attr('data-content');
-                var quill = new Quill(el, {
-                    theme: 'snow',
-                    modules: {
-                        keyboard: {
-                            bindings: {
-                                handleEnter: {
-                                    key: 13,
-                                    handler: function() {
-                                        if (!$('.stag-shortcuts:visible').length) return true;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                });
-
-                var toolbar = $(quill.container).prev('.ql-toolbar');
-
-                // add button for new shortcut
-                var newSCButton = $('<button class="btn bg-white btn-sm btn-default text-primary w-auto px-2 border py-0 ' +
-                    'text-sm add-shortcut" data-editor-id="' + editorID + '">+ Shortcut</button>');
-                toolbar.append(newSCButton);
-
-                quill.root.innerHTML = existingContent;
-
-                quill.on('text-change', function(delta, oldDelta, source) {
-                    var content = quill.root.innerHTML;
-                    var dataValue = JSON.stringify({
-                        value: content
-                    });
-                    var dataField = $(el).closest('.note-section').find('input[name=data]').val(dataValue);
-                });
-
-                $(quill.container)
-                    .find('.ql-editor[contenteditable]')
-                    .attr('data-field', fieldName)
-                    .attr('data-editor-id', editorID)
-                    .attr('with-shortcuts', 1);
-            })
-
-            $('[btn-save-form]').on('click', function() {
-                doSave($(this).closest('.note-section'));
-            });
-
-            // [name="data"] change listener
-            $('.note-section input[name="data"]').each(function() {
-                initChangeListener($(this));
-            });
-
-        }
-
-        const debounce = (func, wait) => {
-            let timeout;
-
-            return function executedFunction(...args) {
-                const later = () => {
-                    clearTimeout(timeout);
-                    func(...args);
-                };
-
-                clearTimeout(timeout);
-                timeout = setTimeout(later, wait);
-            };
-        };
-
-        function doSave(_section) {
-            console.log(_section.attr('data-section-template-name'));
-
-            _section.find('[btn-save-form]').prop('disabled', true);
-            _section.find('.text-saving').removeClass('d-none');
-
-            var dataField = _section.find('input[name=data]')
-            var value = $(dataField).val();
-
-            var summaryContainer = _section.find('.summary-container')
-
-            var sectionUid = _section.attr('data-section-uid')
-
-            var _form = _section.find('form[processed]')[0];
-            if(_form){
-                console.log("Form found. submitting normally");
-                $.post("/process_form_submit", $(_form).serialize(), function(resp) {
-                    handleSubmitResponse(resp,_section, summaryContainer)
-                }, 'json');
-            }else{
-                console.log("Form not found.");
-                $.post("/process_form_submit", {
-                    "section_uid": sectionUid,
-                    "data": value
-                }, function(resp) {
-                    handleSubmitResponse(resp,_section, summaryContainer)
-                }, 'json');
-            }
-        }
-
-        function handleSubmitResponse(resp,_section, summaryContainer){
-            console.log(resp);
-            if (resp.success) {
-                summaryContainer.html(resp.newSummaryHtml);
-            }
-            _section.find('[btn-save-form]').prop('disabled', false);
-            _section.find('.text-saving').addClass('d-none');
-        }
-
-        function initChangeListener(_elem) {
-            new MutationObserver(debounce(function() {
-                    doSave(_elem.closest('.note-section'))
-                }, 250))
-                .observe(_elem[0], {
-                    attributes: true
-                });
-        }
-
-        addMCInitializer('note-sections-list-{{ $patient->uid }}', init);
-
-    })();
-</script>
+@include('app.patient.note.section_script')

+ 109 - 0
resources/views/app/patient/note/section.blade.php

@@ -0,0 +1,109 @@
+<?php
+$sectionTS = strtotime($section->created_at);
+if ($latestSectionTS === 0 || $latestSectionTS < $sectionTS) {
+    $latestSectionTS = $sectionTS;
+}
+?>
+<div data-ts="{{$sectionTS}}" class="p-3 border-bottom note-section " 
+    data-section-uid="{{ $section->uid }}"
+    data-section-template-uid="{{ $section->sectionTemplate->uid }}"
+    data-section-template-name="{{ $section->sectionTemplate->internal_name }}">
+    <div class="d-flex align-items-start">
+        @if(!isset($note) || (isset($note) && !$note->is_signed_by_hcp))
+        <a class="font-weight-bold mb-2 d-flex align-items-center c-pointer">
+            {{$section->sectionTemplate->title}}
+            <span class="d-none if-not-edit"><i class="fa fa-edit ml-2"></i></span>
+            <span class="d-none if-edit edit-trigger"><i class="fa fa-times ml-2"></i></span>
+            <span class="edit-trigger"></span>
+        </a>
+        @else
+        <span class="font-weight-bold mb-2 d-flex align-items-center">
+            {{$section->sectionTemplate->title}}
+        </span>
+        @endif
+        <?php $sectionInternalName = $section->sectionTemplate->internal_name; ?>
+
+        @if($sectionInternalName === "exam" || $sectionInternalName === "objective")
+        @include('app/patient/note/_templates-exam-index')
+        @else
+        @include('app/patient/note/_templates-index')
+        @endif
+
+        <?php
+        if (file_exists(storage_path('sections/' . $sectionInternalName . '/actions.php'))) {
+            include(storage_path('sections/' . $sectionInternalName . '/actions.php'));
+        }
+        ?>
+        <?php if (file_exists(storage_path('sections/' . $sectionInternalName . '/actions.blade.php'))): ?>
+        @include('sections/' . $sectionInternalName . '/actions') 
+        <?php endif; ?>
+
+        @if(isset($pro))
+        <div class="ml-4">
+            @include('app.patient.note.guest-access')
+        </div>   
+
+        <a href="#" class="d-none text-danger if-edit ml-auto remove-section-trigger mr-1" data-uid="{{$section->uid}}" title="Remove {{$section->sectionTemplate->title}}">
+            Remove {{$section->sectionTemplate->title}}
+        </a>
+
+        <a href="#" class="d-none if-edit ml-2 move-up-trigger" data-uid="{{$section->uid}}" title="Move Up">
+            <i class="fa fa-arrow-up"></i>
+        </a>
+
+        <a href="#" class="d-none if-edit ml-2 move-down-trigger" data-uid="{{$section->uid}}" title="Move Down">
+            <i class="fa fa-arrow-down"></i>
+        </a>
+        @endif
+    </div>
+    <div class="d-none if-not-edit  inset-comment summary-container">
+        {!! !empty($section->summary_html) ? $section->summary_html : '-' !!}
+    </div>
+
+    <div class="d-none if-edit">
+
+        <?php
+        // if canvas
+        if ($section->sectionTemplate->is_canvas) {
+            $contentData = false;
+            if ($canvasData) {
+                if (isset($canvasData[$sectionInternalName])) {
+                    $contentData = $canvasData[$sectionInternalName];
+                }
+            }
+        ?>
+            @include("app.patient.canvas-sections.{$sectionInternalName}.form")
+        <?php
+        }
+
+        // if form driven
+        else if (file_exists(storage_path('sections/' . $sectionInternalName . '/form.blade.php'))) {
+        ?>
+            @include('sections.' . $sectionInternalName . '.form')
+        <?php
+        }
+
+        // if neither canvas nor form driven
+        else {
+            $contentData = false;
+            if ($section) {
+                $contentData = json_decode($section->content_data, true);
+            }
+            if (!$contentData || !isset($contentData['value'])) {
+                $contentData = [
+                    'value' => ''
+                ];
+            }
+        ?>
+            <input type="hidden" name="data">
+            <div note-rte data-content="{{$contentData['value']}}" class="form-group mb-2 border-left border-right rte-holder"></div>
+        <?php
+        }
+        ?>
+
+        <div class="d-flex align-items-center">
+            <button class="btn btn-sm btn-primary" btn-save-form><i class="fa fa-save"></i></button>
+            <span class="ml-2 text-secondary text-sm text-saving d-none"><i>Saving ...</i></span>
+        </div>
+    </div>
+</div>

+ 134 - 0
resources/views/app/patient/note/section_script.blade.php

@@ -0,0 +1,134 @@
+<script>
+    (function() {
+
+        function init() {
+            $('[note-rte]').each(function() {
+
+                $(this).wrap(
+                    $('<div class="border-left border-right rte-holder"/>')
+                        .attr('data-shortcuts', '')
+                );
+
+                // give a unique id to this editor instance
+                var editorID = Math.ceil(Math.random() * 99999),
+                    fieldName = this.name;
+
+                var el = this;
+                var existingContent = $(el).attr('data-content');
+                var quill = new Quill(el, {
+                    theme: 'snow',
+                    modules: {
+                        keyboard: {
+                            bindings: {
+                                handleEnter: {
+                                    key: 13,
+                                    handler: function() {
+                                        if (!$('.stag-shortcuts:visible').length) return true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                });
+
+                var toolbar = $(quill.container).prev('.ql-toolbar');
+
+                // add button for new shortcut
+                var newSCButton = $('<button class="btn bg-white btn-sm btn-default text-primary w-auto px-2 border py-0 ' +
+                    'text-sm add-shortcut" data-editor-id="' + editorID + '">+ Shortcut</button>');
+                toolbar.append(newSCButton);
+
+                quill.root.innerHTML = existingContent;
+
+                quill.on('text-change', function(delta, oldDelta, source) {
+                    var content = quill.root.innerHTML;
+                    var dataValue = JSON.stringify({
+                        value: content
+                    });
+                    var dataField = $(el).closest('.note-section').find('input[name=data]').val(dataValue);
+                });
+
+                $(quill.container)
+                    .find('.ql-editor[contenteditable]')
+                    .attr('data-field', fieldName)
+                    .attr('data-editor-id', editorID)
+                    .attr('with-shortcuts', 1);
+            })
+
+            $('[btn-save-form]').on('click', function() {
+                doSave($(this).closest('.note-section'));
+            });
+
+            // [name="data"] change listener
+            $('.note-section input[name="data"]').each(function() {
+                initChangeListener($(this));
+            });
+
+        }
+
+        const debounce = (func, wait) => {
+            let timeout;
+
+            return function executedFunction(...args) {
+                const later = () => {
+                    clearTimeout(timeout);
+                    func(...args);
+                };
+
+                clearTimeout(timeout);
+                timeout = setTimeout(later, wait);
+            };
+        };
+
+        function doSave(_section) {
+            console.log(_section.attr('data-section-template-name'));
+
+            _section.find('[btn-save-form]').prop('disabled', true);
+            _section.find('.text-saving').removeClass('d-none');
+
+            var dataField = _section.find('input[name=data]')
+            var value = $(dataField).val();
+
+            var summaryContainer = _section.find('.summary-container')
+
+            var sectionUid = _section.attr('data-section-uid')
+
+            var _form = _section.find('form[processed]')[0];
+            if(_form){
+                console.log("Form found. submitting normally");
+                $.post("/process_form_submit", $(_form).serialize(), function(resp) {
+                    handleSubmitResponse(resp,_section, summaryContainer)
+                }, 'json');
+            }else{
+                console.log("Form not found.");
+                $.post("/process_form_submit", {
+                    "section_uid": sectionUid,
+                    "data": value
+                }, function(resp) {
+                    handleSubmitResponse(resp,_section, summaryContainer)
+                }, 'json');
+            }
+        }
+
+        function handleSubmitResponse(resp,_section, summaryContainer){
+            console.log(resp);
+            if (resp.success) {
+                summaryContainer.html(resp.newSummaryHtml);
+            }
+            _section.find('[btn-save-form]').prop('disabled', false);
+            _section.find('.text-saving').addClass('d-none');
+        }
+
+        function initChangeListener(_elem) {
+            new MutationObserver(debounce(function() {
+                    doSave(_elem.closest('.note-section'))
+                }, 250))
+                .observe(_elem[0], {
+                    attributes: true
+                });
+        }
+
+        addMCInitializer('note-sections-list', init);
+
+    })();
+</script>

+ 294 - 0
resources/views/layouts/guest_template.blade.php

@@ -0,0 +1,294 @@
+<!DOCTYPE html>
+<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    <title>{{ config('app.name') }}</title>
+
+    <!-- Fonts -->
+    <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
+
+    {{-- mc initializers --}}
+    <script src="/js/mc-init.js"></script>
+
+    {{-- vue --}}
+    <script src="/js/vue.js"></script>
+
+    {{-- Quill RTE --}}
+    <link href="/quill/quill.snow.css" rel="stylesheet">
+    <script src="/quill/quill.js"></script>
+
+    <!-- <link href="{{ asset('bootstrap-4.5.0/css/bootstrap.css') }}" rel="stylesheet"> -->
+    <link rel="stylesheet" href="/fontawesome-free-5.13.1-web/css/all.min.css">
+    <link href="{{ asset('/css/app.css') }}" rel="stylesheet">
+    <link href="{{ asset('/css/style.css') }}" rel="stylesheet">
+    <link href="{{ asset('/css/yemi.css') }}" rel="stylesheet">
+    <link rel="stylesheet" href="{{ asset('/css/toastr.min.css') }}">
+    <link href="{{asset('/css/z.css')}}" rel=stylesheet>
+    <!-- Styles -->
+
+    <script src="{{ asset('js/app.js') }}" type="application/javascript"></script>
+    <script src="/js/jquery-3.5.1.min.js"></script>
+    <script src="/js/jquery.form.min.js"></script>
+    <script src="{{ asset('js/toastr.min.js') }}" type="application/javascript"></script>
+    <script src="/js/yemi.js?_=7" type="application/javascript"></script>
+
+    {{-- med ac --}}
+    <link href='/css/autocomplete-lhc.min.css' rel="stylesheet">
+    <script src='/js/autocomplete-lhc.js'></script>
+
+    {{-- inline bootstrap datepicker --}}
+    <link href='/bootstrap-datepicker/css/bootstrap-datepicker.min.css' rel="stylesheet">
+    <script src='/bootstrap-datepicker/js/bootstrap-datepicker.min.js'></script>
+
+    @yield('head')
+</head>
+
+<body>
+    <div id="mask" style="background: rgba(0, 0, 0, 0) url(&quot;/vanillaspin.gif&quot;) no-repeat scroll center center; position: fixed; top: 0px; left: 0px; z-index: 9999; width: 100%; height: 100%; display: none;">
+    </div>
+    <div id="moe-form-mask" style="background: rgba(0, 0, 0, .1) no-repeat scroll center center; position: fixed; top: 0px; left: 0px; z-index: 99; width: 100%; height: 100%; display: none;">
+    </div>
+
+    <nav class="navbar navbar-expand-md navbar-dark stag-primary-bg py-1">
+        <a class="navbar-brand" href="">Scholar</a>
+        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navBar" aria-controls="navBar" aria-expanded="false" aria-label="Toggle navigation">
+            <span class="navbar-toggler-icon"></span>
+        </button>
+
+        <div class="collapse navbar-collapse" id="navBar">
+            <ul class="navbar-nav mr-auto">
+               
+            </ul>
+           
+        </div>
+
+        <a href="#" class="stag_rhs_toggle d-none d-md-block" title="Toggle Video Pane">
+            <i class="fa fa-arrow-right"></i>
+        </a>
+    </nav>
+
+    <main role="main" class="stag-content px-0">
+
+        @yield('content')
+
+    </main><!-- /.container -->
+
+    <!-- shortcut/suggest component -->
+    <link href="/css/shortcut.css" rel=stylesheet>
+    <script src="/js/shortcut.js" type="application/javascript"></script>
+
+    <!-- script to handle history/back/forward for mc/xxx pages
+    + all other JS initialization needed in fastLoaded pages  -->
+    <script src="/js/find-event-handlers.js" type="application/javascript"></script>
+    
+    <script>
+        window.noMc = true;
+    </script>
+
+    <script src="/js/mc.js?_=4" type="application/javascript"></script>
+
+    <script>
+        $(document).ready(function() {
+            const debounce = (func, wait) => {
+                let timeout;
+                return function executedFunction(...args) {
+                    const later = () => {
+                        clearTimeout(timeout);
+                        func(...args);
+                    };
+                    clearTimeout(timeout);
+                    timeout = setTimeout(later, wait);
+                };
+            };
+            var lastTerm = '';
+            var returnedFunction = debounce(function() {
+                var term = $.trim($('#patient-search').val());
+                if (!!term && lastTerm !== term) {
+                    $.get('/patients-suggest?term=' + term, function(_data) {
+                        $('.suggestions-outer').html(_data).removeClass('d-none');
+                    });
+                    lastTerm = term;
+                } else {
+                    $('.suggestions-outer').addClass('d-none');
+                }
+            }, 250);
+            $('#patient-search')
+                .on('keydown', function(e) {
+                    var term = $.trim($('#patient-search').val());
+                    var activeItem = $('.suggestions-outer .suggest-item.active');
+                    switch (e.which) {
+                        case 27:
+                            $('.suggestions-outer').addClass('d-none');
+                            return false;
+                        case 38:
+                            if (activeItem.prev().length) {
+                                activeItem.prev()
+                                    .addClass('active')
+                                    .siblings().removeClass('active');
+                                activeItem = $('.suggestions-outer .suggest-item.active');
+                                if (activeItem.length) {
+                                    activeItem[0].scrollIntoView();
+                                }
+                            }
+                            return false;
+                        case 40:
+                            if (activeItem.next().length) {
+                                activeItem.next()
+                                    .addClass('active')
+                                    .siblings().removeClass('active');
+                                activeItem = $('.suggestions-outer .suggest-item.active');
+                                if (activeItem.length) {
+                                    activeItem[0].scrollIntoView();
+                                }
+                            }
+                            return false;
+                        case 13:
+                            if (activeItem.length) {
+                                activeItem.first().click();
+                            }
+                            return false;
+                        default:
+                            if (!!term) {
+                                $('.suggestions-outer')
+                                    .html('<span class="d-block no-suggest-items">Searching...</span>')
+                                    .removeClass('d-none');
+                                returnedFunction();
+                            } else {
+                                $('.suggestions-outer').addClass('d-none');
+                            }
+                            break;
+                    }
+                })
+                .on('keypress', function(e) {
+                    var term = $.trim($('#patient-search').val());
+                    if (!!term) {
+                        $('.suggestions-outer')
+                            .html('<span class="d-block no-suggest-items">Searching...</span>')
+                            .removeClass('d-none');
+                        returnedFunction();
+                    } else {
+                        $('.suggestions-outer').addClass('d-none');
+                    }
+                });
+            $(document).on('click', '.suggest-item[data-target-uid]', function() {
+                $('#patient-search').val('');
+                $('.suggestions-outer').addClass('d-none');
+                fastLoad('/patients/view/' + $(this).attr('data-target-uid'), true, false, false);
+                return false;
+            });
+
+            window.setInterval(function() {
+                $.get('/current-work', function(_data) {
+                    $('.current-work').html(_data);
+                    initFastLoad($('.current-work'));
+                });
+            }, 15000); // once in 15 seconds
+        });
+    </script>
+    <script>
+        function showStagPopup(_key) {
+            $('html, body').addClass('no-scroll');
+            let stagPopup = $('[stag-popup-key="' + _key + '"]');
+            stagPopup.addClass('show');
+            stagPopup.find('[moe][initialized]').removeAttr('initialized');
+            initMoes();
+            return false;
+        }
+        function submitStagPopup(_form) {
+            if(!_form[0].checkValidity()) {
+                _form[0].reportValidity();
+                return false;
+            }
+            showMask();
+            $.post(_form.attr('action'), _form.serialize(), function(_data) {
+                fastReload();
+            });
+            return false;
+        }
+        function closeStagPopup() {
+            $('.stag-popup').removeClass('show');
+            $('html, body').removeClass('no-scroll');
+            return false;
+        }
+        (function() {
+            window.initStagPopupEvents = function () {
+                $(document).on('click', '.stag-popup', function(_e) {
+                    if($(_e.target).is('.stag-popup')) {
+                        closeStagPopup();
+                    }
+                });
+            }
+            addMCInitializer('stag-popups', window.initStagPopupEvents);
+        })();
+    </script>
+    <script>
+        (function() {
+            window.initAutoRxAndICDComplete = function () {
+                $('input[type="text"][name="ICD"]:not([ac-initialized])').each(function() {
+                    var elem = this,
+                        dynID = 'icd-' + Math.ceil(Math.random() * 1000000);
+                    $(elem).attr('id', dynID);
+                    new window.Def.Autocompleter.Search(dynID,
+                        'https://clinicaltables.nlm.nih.gov/api/icd10cm/v3/search?sf=code,name&ef=name', {
+                            tableFormat: true,
+                            valueCols: [0],
+                            colHeaders: ['Code', 'Name'],
+                        }
+                    );
+                    window.Def.Autocompleter.Event.observeListSelections(dynID, function() {
+                        var autocomp = elem.autocomp;
+                        var name = autocomp.getSelectedItemData()[0].data['name'];
+                        $(elem).closest('form').find('[name="contentText"]').val(name);
+                        return false;
+                    });
+                    $(elem).attr('ac-initialized', 1);
+                });
+                $('[rx-section] input[type="text"][name="contentText"]:not([ac-initialized])').each(function() {
+                    let elem = this,
+                        randPart = Math.ceil(Math.random() * 1000000),
+                        dynID = 'rx-' + randPart;
+                    $(elem).attr('id', dynID);
+                    var strengthElem = $(elem).closest('form').find('[name="strength"]')[0],
+                        dynStrengthsID = 'rx-' + randPart + '-strengths';
+                    $(strengthElem).attr('id', dynStrengthsID);
+                    $(strengthElem).attr('rx-id', dynID);
+                    new window.Def.Autocompleter.Prefetch(dynStrengthsID, []);
+                    new window.Def.Autocompleter.Search(dynID,
+                        'https://clinicaltables.nlm.nih.gov/api/rxterms/v3/search?ef=STRENGTHS_AND_FORMS');
+                    window.Def.Autocompleter.Event.observeListSelections(dynID, function() {
+                        var autocomp = elem.autocomp;
+                        var strengths =
+                            autocomp.getSelectedItemData()[0].data['STRENGTHS_AND_FORMS'];
+                        if (strengths)
+                            strengthElem.autocomp.setListAndField(strengths, '');
+                    });
+                    $(elem).attr('ac-initialized', 1);
+                });
+                window.rxEditMoeOpened = function() { // note "this" is the "form"
+                    let form = $(this),
+                        rxElem = form.find('input[type="text"][name="contentText"]').first(),
+                        strengthElem = form.find('input[type="text"][name="strength"]').first(),
+                        q = $.trim(rxElem.val());
+                    if(q !== '') {
+                        $.get('https://clinicaltables.nlm.nih.gov/api/rxterms/v3/search?' +
+                            'authenticity_token=' + (window._token || '') + '&' +
+                            'maxList=100&' +
+                            'terms=' + encodeURIComponent(q) + '&' +
+                            'ef=STRENGTHS_AND_FORMS', function(_data) {
+                            if(Array.isArray(_data) && _data.length >= 3 && Array.isArray(_data[2]['STRENGTHS_AND_FORMS']) && Array.isArray(_data[2]['STRENGTHS_AND_FORMS'][0])) {
+                                strengthElem[0].autocomp.setListAndField(_data[2]['STRENGTHS_AND_FORMS'][0], '', true);
+                            }
+                        }, 'json');
+                    }
+                }
+            }
+            addMCInitializer('patient-single', window.initAutoRxAndICDComplete);
+        })();
+    </script>
+
+</body>
+
+</html>

+ 2 - 0
routes/web.php

@@ -39,6 +39,8 @@ Route::post('/resend_sms_auth_token', 'HomeController@resendSmsAuthToken')->name
 Route::post('/set_password', 'HomeController@postSetPassword')->name('post-set_password');
 Route::post('/set_security_questions', 'HomeController@postSetSecurityQuestions')->name('post-set_security_questions');
 
+Route::get("/guest/section/{accessToken}", 'GuestController@section')->name('guest_section_access');
+
 Route::middleware('pro.auth')->group(function () {
 
     //complete authentication