Prechádzať zdrojové kódy

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

Samson Mutunga 3 rokov pred
rodič
commit
c9f3c82b38
34 zmenil súbory, kde vykonal 1087 pridanie a 136 odobranie
  1. 34 0
      app/Http/Controllers/AdminController.php
  2. 99 15
      app/Http/Controllers/StatTreeController.php
  3. 10 6
      app/Http/Controllers/StatTreeLineController.php
  4. 10 0
      app/Models/Client.php
  5. 12 0
      app/Models/Point.php
  6. 3 2
      app/Models/StatTreeLine.php
  7. 4 4
      config/app.php
  8. 15 6
      js-dev/pro-suggest.js
  9. 18 0
      public/css/style.css
  10. 3 0
      resources/views/app/admin/patients-table-extended.blade.php
  11. 26 0
      resources/views/app/admin/patients_filters.blade.php
  12. 12 0
      resources/views/app/patient/note/segment.blade.php
  13. 32 0
      resources/views/app/patient/segment-templates/covid_follow-up/log.blade.php
  14. 32 0
      resources/views/app/patient/segment-templates/covid_intake/log.blade.php
  15. 10 7
      resources/views/app/patient/segment-templates/history_family/edit.blade.php
  16. 92 0
      resources/views/app/patient/segment-templates/history_family/log.blade.php
  17. 6 10
      resources/views/app/patient/segment-templates/history_family/summary.blade.php
  18. 10 5
      resources/views/app/patient/segment-templates/history_screenings/edit.blade.php
  19. 47 0
      resources/views/app/patient/segment-templates/history_screenings/log.blade.php
  20. 5 8
      resources/views/app/patient/segment-templates/history_screenings/summary.blade.php
  21. 10 6
      resources/views/app/patient/segment-templates/history_social/edit.blade.php
  22. 89 0
      resources/views/app/patient/segment-templates/history_social/log.blade.php
  23. 5 9
      resources/views/app/patient/segment-templates/history_social/summary.blade.php
  24. 10 6
      resources/views/app/patient/segment-templates/history_surgical/edit.blade.php
  25. 88 0
      resources/views/app/patient/segment-templates/history_surgical/log.blade.php
  26. 5 9
      resources/views/app/patient/segment-templates/history_surgical/summary.blade.php
  27. 11 7
      resources/views/app/patient/segment-templates/past_medical_history/edit.blade.php
  28. 9 3
      resources/views/app/patient/segment-templates/past_medical_history/summary.blade.php
  29. 15 6
      resources/views/app/patient/segment-templates/ros/edit.blade.php
  30. 261 0
      resources/views/app/patient/segment-templates/ros/log.blade.php
  31. 4 9
      resources/views/app/patient/segment-templates/ros/summary.blade.php
  32. 1 1
      resources/views/app/stat-tree/stat-tree-lines/view-data.blade.php
  33. 98 17
      resources/views/app/stat-tree/stat-trees/sub/edit.blade.php
  34. 1 0
      routes/web.php

+ 34 - 0
app/Http/Controllers/AdminController.php

@@ -108,6 +108,40 @@ class AdminController extends Controller
         $this->filterMultiQuery($request, $patients, 'most_recent_weight_at', 'last_weighed_in_category', 'last_weighed_in_value_1', 'last_weighed_in_value_2');
         $this->filterMultiQuery($request, $patients, 'most_recent_bp_at', 'last_bp_category', 'last_bp_value_1', 'last_bp_value_2');
 
+        if($request->input('number_of_measurements')){
+            $keyName = $request->input('number_of_measurements');
+            $measurementCountQuery = '(SELECT COUNT(*) FROM measurement WHERE measurement.client_id = client.id AND is_active IS TRUE AND is_cellular IS TRUE AND is_cellular_zero IS NOT TRUE)';
+            switch($keyName) {
+                case 'EXACTLY':
+                    if($request->input('number_of_measurements_value_1')) {
+                        $patients->whereRaw($measurementCountQuery . '='.$request->input('number_of_measurements_value_1'));
+                    }
+                    break;
+                case 'LESS_THAN':
+                    if($request->input('number_of_measurements_value_1')) {
+                        $patients->whereRaw($measurementCountQuery . '<='.$request->input('number_of_measurements_value_1'));
+                    }
+                    break;
+                case 'GREATER_THAN':
+                    if($request->input('number_of_measurements_value_1')) {
+                        $patients->whereRaw($measurementCountQuery . '>='.$request->input('number_of_measurements_value_1'));
+                    }
+                    break;
+                case 'BETWEEN':
+                    if($request->input('number_of_measurements_value_1') && $request->input('number_of_measurements_value_2')) { 
+                        $patients->whereRaw($measurementCountQuery.'>='.$request->input('number_of_measurements_value_1') .' AND '. $measurementCountQuery . '<='.$request->input('number_of_measurements_value_2'));
+                    }
+                    break;
+                case 'NOT_BETWEEN':
+                    if($request->input('number_of_measurements_value_1') && $request->input('number_of_measurements_value_2')) {
+                        $patients->where(function ($q) use ($request, $measurementCountQuery) {
+                                $q->whereRaw($measurementCountQuery . '<'.$request->input('number_of_measurements_value_1') .' OR '. $measurementCountQuery . '>'.$request->input('number_of_measurements_value_2'));                               
+                        });
+                    }
+                    break;
+            }
+        }
+
         switch($request->input('status')) {
             case 'ACTIVE':
                 $patients->where('is_active', true)->where('has_mcp_done_onboarding_visit', true);

+ 99 - 15
app/Http/Controllers/StatTreeController.php

@@ -81,6 +81,7 @@ class StatTreeController extends Controller
         $statTree->model = $request->input('model');
         $statTree->slug = $request->input('slug');
         $statTree->is_template = (bool)$request->input('isTemplate');
+        $statTree->pro_id = NULL;
         if($request->input('proUid')) {
             $pro = Pro::where('uid', $request->input('proUid'))->first();
             if($pro) {
@@ -207,7 +208,7 @@ class StatTreeController extends Controller
                         $statTreeLineClauseArg->clause_arg_id = $clauseArg->id;
                         $statTreeLineClauseArg->access_level = 'ADMIN';
                         $statTreeLineClauseArg->stat_tree_id = $statTree->id;
-                        $statTreeLineClauseArg->default_value = null;
+                        $statTreeLineClauseArg->value = null;
 
                         // TODO: need to copy clause arg values from parent node for all except last clause
 
@@ -278,7 +279,7 @@ class StatTreeController extends Controller
             $children = [];
 
             // clause text child
-            $children[] = [
+            /*$children[] = [
                 "text" => $clause->clause_text,
                 "icon" => "fa fa-laptop-code text-primary text-sm",
                 "state" => [
@@ -295,7 +296,7 @@ class StatTreeController extends Controller
                 "data" => [
                     "type" => "clause_text"
                 ]
-            ];
+            ];*/
 
             // clause arg children
             $argsSystem = [];
@@ -304,7 +305,7 @@ class StatTreeController extends Controller
                     "text" => $clauseArg->arg_text . '<span class="text-secondary text-sm ml-2">' . $clauseArg->field_type . '</span>',
                     "icon" => "fa fa-cubes text-info",
                     "state" => [
-                        "opened" => false,
+                        "opened" => true,
                         "disabled" => false,
                         "selected" => false,
                     ],
@@ -320,7 +321,7 @@ class StatTreeController extends Controller
                 $argsSystem[] = [
                     "arg_text" => $clauseArg->arg_text,
                     "field_type" => $clauseArg->field_type,
-                    "default_value" => null,
+                    "value" => null,
                     "access_level" => null
                 ];
             }
@@ -328,7 +329,7 @@ class StatTreeController extends Controller
             $nodes[] = [
                 "text" => $clause->label,
                 "state" => [
-                    "opened" => false,
+                    "opened" => true,
                     "disabled" => false,
                     "selected" => false,
                 ],
@@ -376,7 +377,7 @@ class StatTreeController extends Controller
                 $value = null;
                 foreach ($lineClause->lineClauseArgs as $lineClauseArg) {
                     if($lineClauseArg->clause_arg_id === $clauseArg->id) {
-                        $value = $lineClauseArg->default_value;
+                        $value = $lineClauseArg->value;
                     }
                 }
 
@@ -388,10 +389,11 @@ class StatTreeController extends Controller
                 }
             }
 
-            $isValid = $this->cleanupClause($clauseText);
-            if ($isValid) {
+            //dump($clauseText);
+            /*$isValid = $this->cleanupClause($clauseText);
+            if ($isValid) {*/
                 array_push($clauses, $clauseText);
-            }
+            //}
         }
 
         // if stat tree bound to a pro, apply pro_scope_clause
@@ -410,6 +412,70 @@ class StatTreeController extends Controller
 
         $query = 'SELECT COUNT(*) FROM '.$model.' WHERE '. implode(" AND ", $clauses);
         try {
+            //dump($query);
+            $result = DB::select($query);
+        }
+        catch (\Exception $ex) {
+            $result = 'error';
+        }
+        return $result;
+    }
+
+    private function applyStatTreeLineQueryClausesGroupByPros(StatTreeLine $statTreeLine, $proUids)
+    {
+        $model = $statTreeLine->statTree->model;
+        $clauses = [];
+        foreach ($statTreeLine->lineClauses as $lineClause) {
+            $clauseText = $lineClause->clause->clause_text;
+
+            // apply arg values
+            foreach ($lineClause->clause->clauseArgs as $clauseArg) {
+
+                $value = null;
+                foreach ($lineClause->lineClauseArgs as $lineClauseArg) {
+                    if($lineClauseArg->clause_arg_id === $clauseArg->id) {
+                        $value = $lineClauseArg->value;
+                    }
+                }
+
+                if(!is_null($value)) {
+                    $clauseText = str_replace(
+                        ':' . $clauseArg->arg_text,                         // search for :xxx
+                        "'" . $value . "'::" . $clauseArg->field_type,      // replace with '$value'::$field_type
+                        $clauseText);
+                }
+            }
+
+            //dump($clauseText);
+            /*$isValid = $this->cleanupClause($clauseText);
+            if ($isValid) {*/
+            array_push($clauses, $clauseText);
+            //}
+        }
+
+        // if stat tree bound to a pro, apply pro_scope_clause
+        /*if(!$proUid) {
+            if($statTreeLine->statTree->pro && $statTreeLine->statTree->pro_scope_clause) {
+                $clauses[] = str_replace('@PRO_ID', $statTreeLine->statTree->pro->id, $statTreeLine->statTree->pro_scope_clause);
+            }
+        }
+        else {
+            $mvPro = Pro::where('uid', $proUid)->first();
+            if($statTreeLine->statTree->pro_scope_clause) {
+                $clauses[] = str_replace('@PRO_ID', $mvPro->id, $statTreeLine->statTree->pro_scope_clause);
+            }
+            $query = 'SELECT COUNT(*) FROM '.$model.' WHERE '. implode(" AND ", $clauses);
+        }*/
+
+        $proUids = explode(",", $proUids);
+        $proUids = array_map(function($_x) {
+            return "'{$_x}'";
+        }, $proUids);
+        $clauses[] = "_j_pro.uid IN (" . implode(",", $proUids) . ")";
+        $proJoinClause = 'JOIN pro _j_pro on ' . str_replace('@PRO_ID', '_j_pro.id', $statTreeLine->statTree->pro_scope_clause);
+        $query = "SELECT COUNT(*), _j_pro.uid as _v_pro_uid FROM {$model} {$proJoinClause} WHERE " . implode(" AND ", $clauses) . " GROUP BY _j_pro.uid";
+        try {
+            //dump($query);
             $result = DB::select($query);
         }
         catch (\Exception $ex) {
@@ -458,6 +524,24 @@ class StatTreeController extends Controller
         return json_encode($result);
     }
 
+    public function getCountsForPros(Request $request) {
+        $statTreeUid = $request->get('uid');
+        if (!$statTreeUid) return $this->fail('No specified stat tree!');
+        $statTree = StatTree::where('uid',  $statTreeUid)->first();
+        $lines = $statTree->lines;
+        $result = [];
+        foreach ($lines as $line) {
+            $query = $this->applyStatTreeLineQueryClausesGroupByPros($line, $request->input('proUids'));
+            if ($query && $query !== 'error') {
+                $result[$line->uid] = $query;
+            }
+            else {
+                $result[$line->uid] = -1;
+            }
+        }
+        return json_encode($result);
+    }
+
     private function lineObject(StatTreeLine  $line) {
 
         // columns
@@ -479,10 +563,10 @@ class StatTreeController extends Controller
                 $args[] = [
                     "arg_text" => $stlcArg->clauseArg->arg_text,
                     "field_type" => $stlcArg->clauseArg->field_type,
-                    "default_value" => $stlcArg->default_value,
+                    "value" => $stlcArg->value,
                     "access_level" => $stlcArg->access_level
                 ];
-                $argsLabel[] = $stlcArg->clauseArg->arg_text . ': ' . $stlcArg->default_value;
+                $argsLabel[] = $stlcArg->clauseArg->arg_text . ': ' . $stlcArg->value;
             }
         }
         $clause = [
@@ -598,7 +682,7 @@ class StatTreeController extends Controller
                     $statTreeLineClauseArg->id = $nextId[0]->nextval;
                     $statTreeLineClauseArg->stat_tree_line_clause_id = $statTreeLineClause->id; // this line cause
                     $statTreeLineClauseArg->clause_arg_id = $parentLineClauseArg->clause_arg_id;
-                    $statTreeLineClauseArg->default_value = $parentLineClauseArg->default_value;
+                    $statTreeLineClauseArg->value = $parentLineClauseArg->value;
                     $statTreeLineClauseArg->access_level = $parentLineClauseArg->access_level;
                     $statTreeLineClauseArg->stat_tree_id = $statTree->id;
                     $statTreeLineClauseArg->save();
@@ -629,12 +713,12 @@ class StatTreeController extends Controller
             $statTreeLineClauseArg->id = $nextId[0]->nextval;
             $statTreeLineClauseArg->stat_tree_line_clause_id = $statTreeLineClause->id;
             $statTreeLineClauseArg->clause_arg_id = $clauseArg->id;
-            $statTreeLineClauseArg->default_value = null;
+            $statTreeLineClauseArg->value = null;
             $statTreeLineClauseArg->access_level = 'ADMIN';
             for ($j=0; $j<count($line->clause->args); $j++) { // find the arg matching text and type from line->args and use that
                 if($line->clause->args[$j]->arg_text === $clauseArg->arg_text &&
                     $line->clause->args[$j]->field_type === $clauseArg->field_type) {
-                    $statTreeLineClauseArg->default_value = $line->clause->args[$j]->default_value;
+                    $statTreeLineClauseArg->value = $line->clause->args[$j]->value;
                     $statTreeLineClauseArg->access_level = $line->clause->args[$j]->access_level;
                     break;
                 }

+ 10 - 6
app/Http/Controllers/StatTreeLineController.php

@@ -174,7 +174,7 @@ class StatTreeLineController extends Controller
                 $value = null;
                 foreach ($lineClause->lineClauseArgs as $lineClauseArg) {
                     if($lineClauseArg->clause_arg_id === $clauseArg->id) {
-                        $value = $lineClauseArg->default_value;
+                        $value = $lineClauseArg->value;
                     }
                 }
 
@@ -186,14 +186,18 @@ class StatTreeLineController extends Controller
                 }
             }
 
-            $isValid = $this->cleanupClause($clauseText);
-            if ($isValid) {
-                array_push($clauses, $clauseText);
-            }
+            array_push($clauses, $clauseText);
+
         }
 
         // if stat tree bound to a pro, apply pro_scope_clause
-        if($statTreeLine->statTree->pro && $statTreeLine->statTree->pro_scope_clause) {
+        if($request->input('proUid') && $statTreeLine->statTree->pro_scope_clause) {
+            $pro = Pro::where('uid', $request->input('proUid'))->first();
+            if($pro) {
+                $clauses[] = str_replace('@PRO_ID', $pro->id, $statTreeLine->statTree->pro_scope_clause);
+            }
+        }
+        elseif($statTreeLine->statTree->pro && $statTreeLine->statTree->pro_scope_clause) {
             $clauses[] = str_replace('@PRO_ID', $statTreeLine->statTree->pro->id, $statTreeLine->statTree->pro_scope_clause);
         }
 

+ 10 - 0
app/Models/Client.php

@@ -208,6 +208,16 @@ class Client extends Model
             ->orderByRaw('ts DESC NULLS LAST');
     }
 
+    public function cellularMeasurements()
+    {
+        return $this->hasMany(Measurement::class, 'client_id', 'id')
+            /*->distinct('label')*/
+            ->where('is_active', true)
+            ->where('is_cellular', true)
+            ->where('is_cellular_zero', false)
+            ->orderByRaw('ts DESC NULLS LAST');
+    }
+
     public function recentMeasurements()
     {
         return $this->hasMany(Measurement::class, 'client_id', 'id')

+ 12 - 0
app/Models/Point.php

@@ -316,6 +316,18 @@ class Point extends Model
         return $point;
     }
 
+    public static function getOnlyTopLevelPointOfCategory(Note $_note, String $_category, $_assoc = false) {
+        $point = Point
+            ::where('client_id', $_note->client_id)
+            ->where('category', $_category)
+            ->where('intention', 'TOP_LEVEL')
+            ->first();
+        if ($point && $point->data) {
+            $point->data = json_decode($point->data, $_assoc);
+        }
+        return $point;
+    }
+
     public static function getOrCreateOnlyTopLevelPointOfCategory(Note $_note, String $_category, $_sessionKey, $_assoc = false) {
         $point = Point
             ::where('client_id', $_note->client_id)

+ 3 - 2
app/Models/StatTreeLine.php

@@ -72,7 +72,7 @@ class StatTreeLine extends Model
                     "uid" => $stlcArg->uid,
                     "arg_text" => $stlcArg->clauseArg->arg_text,
                     "field_type" => $stlcArg->clauseArg->field_type,
-                    "default_value" => $stlcArg->default_value,
+                    "value" => $stlcArg->value,
                     "access_level" => $stlcArg->access_level,
                 ];
             }
@@ -114,7 +114,7 @@ class StatTreeLine extends Model
                 $newStatTreeLineClauseArg->clause_arg_id = $srcLineClauseArg->clause_arg_id;
                 $newStatTreeLineClauseArg->access_level = $srcLineClauseArg->access_level;
                 $newStatTreeLineClauseArg->stat_tree_id = $newStatTree->id;
-                $newStatTreeLineClauseArg->default_value = $srcLineClauseArg->default_value;
+                $newStatTreeLineClauseArg->value = $srcLineClauseArg->value;
                 $newStatTreeLineClauseArg->save();
             }
         }
@@ -129,6 +129,7 @@ class StatTreeLine extends Model
             $newStatTreeLineReportColumn->label = $srcReportColumn->label;
             $newStatTreeLineReportColumn->position_index = $srcReportColumn->position_index;
             $newStatTreeLineReportColumn->display_key = $srcReportColumn->display_key;
+            $newStatTreeLineReportColumn->field_type = $srcReportColumn->field_type;
             $newStatTreeLineReportColumn->display_function = $srcReportColumn->display_function;
             $newStatTreeLineReportColumn->record_route_name = $srcReportColumn->record_route_name;
             $newStatTreeLineReportColumn->stat_tree_id = $newStatTree->id;

+ 4 - 4
config/app.php

@@ -65,7 +65,7 @@ return [
 
     'hrm2_url' => env('HRM2_URL'),
 
-    'asset_version' => 45,
+    'asset_version' => 46,
 
     'temp_dir' => env('TEMP_DIR'),
 
@@ -271,9 +271,9 @@ return [
         'medications',
         'past_medical_history',
         'problems',
-        'family_history',
-        'social_history',
-        'surgical_history',
+        'history_family',
+        'history_social',
+        'history_surgical',
         'nutrition',
         'exercise',
         'behavior',

+ 15 - 6
js-dev/pro-suggest.js

@@ -18,14 +18,23 @@
     var lastTerm = '';
     var returnedFunction = debounce(function (elem) {
         var term = elem.val();
-        if (!!term && lastTerm !== term) {
-            $.get('/pro-suggest?term=' + $.trim(term) + '&type=' + elem.attr('provider-type'), function (_data) {
-                suggestionsOuter.html(_data).removeClass('d-none');
-            });
-            lastTerm = term;
-        } else {
+        if(term === '') {
+            let select = suggestionsOuter.closest('.position-relative')
+                .prev('.pro-suggest-input')
+                .prev('select[provider-search]');
+            select.empty().val('').append($('<option value="" selected/>').text('')).trigger('change');
             suggestionsOuter.addClass('d-none');
         }
+        else {
+            if (!!term && lastTerm !== term) {
+                $.get('/pro-suggest?term=' + $.trim(term) + '&type=' + elem.attr('provider-type'), function (_data) {
+                    suggestionsOuter.html(_data).removeClass('d-none');
+                });
+                lastTerm = term;
+            } else {
+                suggestionsOuter.addClass('d-none');
+            }
+        }
     }, 250);
 
     function handleKeydown(elem, e) {

+ 18 - 0
public/css/style.css

@@ -1752,6 +1752,9 @@ canvas.pdf-viewer-page.pdf-preview-page {
 .bg-aliceblue {
     background: aliceblue !important;
 }
+.bg-treeblue {
+    background: linear-gradient(to bottom, #beebff 0, #a8e4ff 100%);
+}
 .text-danger-dark {
     color: #8b1621 !important;
 }
@@ -2840,6 +2843,7 @@ table.stag-compact-grid>tbody>tr>td [if-grid-view] {
     background: #eee;
     line-height: 22px;
     padding: 0 5px;
+    padding-right: 0;
     font-weight: normal;
     color: #777;
     border: 0;
@@ -2892,6 +2896,20 @@ table.stag-compact-grid>tbody>tr>td [if-grid-view] {
     font-weight: bold;
     color: #777;
 }
+.multi-pro-view th .mv-delete-pro-trigger {
+    position: absolute;
+    right: 2px;
+    top: 2px;
+    width: 16px;
+    height: 16px;
+    line-height: 16px;
+    font-size: 10px;
+    text-align: center;
+    display: none;
+}
+.multi-pro-view th:hover .mv-delete-pro-trigger {
+    display: block;
+}
 body .vakata-context li>a {
     padding: 1px 5px;
     padding-right: 10px;

+ 3 - 0
resources/views/app/admin/patients-table-extended.blade.php

@@ -27,6 +27,8 @@
             <th class="border-0">Weight</th>
             <th class="border-0">Weight Timestamp</th>
 
+            <th class="border-0"># Cellular Measurements</th>
+
             {{-- <th>Scale <i class="fa fa-battery"></i></th>--}}
             {{-- <th class="border-0">RPM</th>--}}
             {{-- <th class="border-0">CCM</th>--}}
@@ -304,6 +306,7 @@
                     <?php $m = $patient->lastMeasurementOfType('BP'); ?>
                     {{$m && $m->value ? $m->value : '-'}}
                 </td>
+                <td>{{count($patient->cellularMeasurements)}}</td>
                 <td>{{$patient->getMcpAssignedOn()}}</td>
                 @if($pro->pro_type == 'ADMIN')
                     <td>{{@$patient->mcp ? $patient->mcp->displayName() : '--'}}</td>

+ 26 - 0
resources/views/app/admin/patients_filters.blade.php

@@ -207,6 +207,29 @@
 	</div>
 	@endif
 
+	<!-- Number of measurements	 -->
+	<div class="sm-section">
+		<div class="">
+			<label># Measurements:</label>
+			<select name="number_of_measurements" class="form-control input-sm" v-model="filters.number_of_measurements">
+				<option value="">All</option>
+				<option value="EXACTLY">Exactly</option>
+				<option value="LESS_THAN">Less Than</option>
+				<option value="GREATER_THAN">Greater Than</option>
+				<option value="BETWEEN">Between</option>
+				<option value="NOT_BETWEEN">Not Between</option>
+			</select>
+			<div v-show="filters.number_of_measurements" class="mt-2">
+				<div>
+					<input  name="number_of_measurements_value_1" v-model="filters.number_of_measurements_value_1" type="number" class="form-control input-sm" :placeholder="(filters.number_of_measurements === 'BETWEEN' || filters.number_of_measurements === 'NOT_BETWEEN') ? 'From' : 'Number of measurements'" />
+				</div>
+				<div v-show="filters.number_of_measurements === 'BETWEEN' || filters.number_of_measurements === 'NOT_BETWEEN'" class="mt-2">
+					<input name="number_of_measurements_value_2" v-model="filters.number_of_measurements_value_2" type="number" class="form-control input-sm" placeholder="To" />
+				</div>
+			</div>
+		</div>
+	</div>
+
 	@if($performer->pro->pro_type == 'ADMIN')
 	<div class="sm-section">
 		<div class="">
@@ -302,6 +325,9 @@ $allFilterKeys = [
 	'initiative',
 	'insurance',
 	'include_test_records',
+	'number_of_measurements',
+	'number_of_measurements_value_1',
+	'number_of_measurements_value_2'
 ];
 for ($i=0; $i < count($allFilterKeys); $i++) {
 	if (!isset($loadedFilters[$allFilterKeys[$i]]) || !$loadedFilters[$allFilterKeys[$i]]) {

+ 12 - 0
resources/views/app/patient/note/segment.blade.php

@@ -97,6 +97,18 @@
 
         @endif
 
+        {{-- if segment has log feature, link --}}
+        @if($pro->pro_type === 'ADMIN' && file_exists(resource_path("views/app/patient/segment-templates/{$segment->segmentTemplate->internal_name}/log.blade.php")))
+            <a native="" target="_blank"
+               class="c-pointer ml-3 text-decoration-none"
+               open-in-stag-popup=""
+               title="{{$segment->display_title}} - Change Log"
+               popup-style="medium"
+               href="/note-segment-view/{{$patient->uid}}/{{$note->uid}}/{{$segment->uid}}/<?= $segment->segmentTemplate->internal_name ?>/log">
+                <span>Change Log</span>
+            </a>
+        @endif
+
     </div>
 
     <?php if(!$isLSSegment): ?>

+ 32 - 0
resources/views/app/patient/segment-templates/covid_follow-up/log.blade.php

@@ -0,0 +1,32 @@
+<?php
+
+use App\Models\Point;
+
+$category = 'COVID_FOLLOW-UP';
+
+$point = Point::getOnlyTopLevelPointOfCategory($note, 'COVID_FOLLOW-UP', true);
+
+if($point) {
+    ?> <div class="popup-content-container px-3"> <?php
+    foreach ($point->childReviews as $childReview) {
+        $contentData = $parsed = false;
+        if ($childReview->data) {
+            $childReview->data = json_decode($childReview->data, true);
+            $contentData = $parsed = $childReview->data;
+            ?>
+            <div class="mb-1 font-weight-bold">{{$childReview->creatorPro->displayName()}} - {{friendly_date($childReview->note->effective_dateest)}}</div>
+            <div class="pl-3 bg-light border p-3 mb-3">
+            <?php
+            foreach ($contentData as $key => $value) {
+                if(!!$value) {
+                    ?>
+                    <div><span class="text-secondary mr-2">{{ucwords(str_replace('_', ' ', substr($key, 4)))}}:</span><?= $value ?></div>
+                    <?php
+                }
+            }
+            ?> </div> <?php
+        }
+    }
+    ?> </div> <?php
+}
+?>

+ 32 - 0
resources/views/app/patient/segment-templates/covid_intake/log.blade.php

@@ -0,0 +1,32 @@
+<?php
+
+use App\Models\Point;
+
+$category = 'COVID_INTAKE';
+
+$point = Point::getOnlyTopLevelPointOfCategory($note, 'COVID_INTAKE', true);
+
+if($point) {
+    ?> <div class="popup-content-container px-3"> <?php
+    foreach ($point->childReviews as $childReview) {
+        $contentData = $parsed = false;
+        if ($childReview->data) {
+            $childReview->data = json_decode($childReview->data, true);
+            $contentData = $parsed = $childReview->data;
+            ?>
+            <div class="mb-1 font-weight-bold">{{$childReview->creatorPro->displayName()}} - {{friendly_date($childReview->note->effective_dateest)}}</div>
+            <div class="pl-3 bg-light border p-3 mb-3">
+            <?php
+            foreach ($contentData as $key => $value) {
+                if(!!$value) {
+                    ?>
+                    <div><span class="text-secondary mr-2">{{ucwords(str_replace('_', ' ', substr($key, 4)))}}:</span><?= $value ?></div>
+                    <?php
+                }
+            }
+            ?> </div> <?php
+        }
+    }
+    ?> </div> <?php
+}
+?>

+ 10 - 7
resources/views/app/patient/segment-templates/history_family/edit.blade.php

@@ -8,10 +8,14 @@ use App\Models\Note;
 
 if(!@$segment) $segment = null;
 
-// try loading afresh - since base section might have gotten dynamically updated
-$point = Point::getGlobalSingletonOfCategory($patient, 'FAMILY_HISTORY', true);
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'FAMILY_HISTORY', $sessionKey, true);
 
-$contentData = $parsed = @$point && @$point->data ? $point->data : false;
+$contentData = $parsed = false;
+
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $parsed = $point->lastChildReview->data;
+}
 
 if(!$contentData) {
     $contentData = [
@@ -51,14 +55,13 @@ if(!$contentData) {
 <hr class="hide-outside-popup mt-3 mb-0">
 <div class="p-3 mcp-theme-1">
     <div {{!!$segment ? 'visit-moe' : 'moe'}} close-on-save close-on-cancel class="d-block">
-        <form show url="/api/visitPoint/upsertGlobalSingleton" class="mcp-theme-1"
+        <form show url="/api/visitPoint/upsertChildReview" class="mcp-theme-1"
                     {{!$segment ? 'hook=onHxPopupClosure' : ''}}>
             @if(!!@$segment)
                 <input type="hidden" name="segmentUid" value="<?= $segment->uid ?>">
-            @else
-                <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
             @endif
-            <input type="hidden" name="category" value="FAMILY_HISTORY">
+            <input type="hidden" name="uid" value="<?= $point->uid ?>">
+            <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
             <input type="hidden" name="data">
 
             <div id="edit-univ_history_family-container">

+ 92 - 0
resources/views/app/patient/segment-templates/history_family/log.blade.php

@@ -0,0 +1,92 @@
+<?php
+
+use App\Models\Client;
+use App\Models\Point;
+use App\Models\Note;
+/** @var Client $patient */
+/** @var Note $note */
+
+$labels = [
+    'general_no_health_concern' => 'No health concern',
+    'general_arthritis' => 'Arthritis',
+    'general_asthma' => 'Asthma',
+    'general_bleeding_disorder' => 'Bleeding disorder',
+    'general_cad_lt_age_55' => 'CAD &gt; age 55',
+    'general_copd' => 'COPD',
+    'general_diabetes' => 'Diabetes',
+    'general_heart_attack' => 'Heart attack',
+    'general_heart_disease' => 'Heart disease',
+    'general_high_cholesterol' => 'High cholesterol',
+    'general_hypertension' => 'Hypertension',
+    'general_mental_illness' => 'Mental illness',
+    'general_osteoporosis' => 'Osteoporosis',
+    'general_stroke' => 'Stroke',
+    'cancer_breast_ca' => 'Breast cancer',
+    'cancer_colon_ca' => 'Colon cancer',
+    'cancer_other_ca' => 'Other cancer',
+    'cancer_ovarian_ca' => 'Ovarian cancer',
+    'cancer_uterine_ca' => 'Uterine cancer',
+];
+
+$point = Point::getOnlyTopLevelPointOfCategory($note, 'FAMILY_HISTORY', true);
+
+if($point) {
+    ?> <div class="popup-content-container px-3"> <?php
+    foreach ($point->childReviews as $childReview) {
+        $contentData = $parsed = false;
+        if ($childReview->data) {
+            $childReview->data = json_decode($childReview->data, true);
+            $contentData = $parsed = $childReview->data;
+
+            if($contentData && !$contentData['unknown'] && !!$contentData['count']) {
+                ?>
+                <div class="mb-1 font-weight-bold">{{$childReview->creatorPro->displayName()}} - {{friendly_date($childReview->note->effective_dateest)}}</div>
+                <div class="pl-3 bg-light border p-3 mb-3">
+                <?php
+                for ($i = 0; $i < $contentData['count']; $i++) {
+                    ?>
+                    <div class="<?= $i > 0 ? 'mt-2' : '' ?>">
+                        <div class="">
+                            <b><?= isset($contentData['items'][$i]['relationship']) ? $contentData['items'][$i]['relationship'] : '--' ?></b>
+                            <?php if(isset($contentData['items'][$i]['status']) && !empty($contentData['items'][$i]['status'])): ?>
+                            <span class="ml-1 text-secondary">(<?= $contentData['items'][$i]['status'] ?>)</span>
+                            <?php endif; ?>
+                        </div>
+                        <div class="ml-3">
+                            <?php
+                            $positives = [];
+                            $negatives = [];
+                            foreach ($labels as $k => $v) {
+                                if(isset($contentData['items'][$i][$k])) {
+                                    if(strtolower($contentData['items'][$i][$k]) === 'yes') {
+                                        $positives[] = $v;
+                                    }
+                                    else {
+                                        $negatives[] = $v;
+                                    }
+                                }
+                            }
+                            ?>
+                            @if(count($positives))
+                                <div class="pt-1"><b>Positive for</b>: {!!  implode(', ', $positives) !!}</div>
+                            @endif
+                            @if(count($negatives))
+                                <div class="pt-1"><b>Negative for</b>: {!!  implode(', ', $negatives) !!}</div>
+                            @endif
+                        </div>
+                        <?php if(isset($contentData['items'][$i]['comments']) && !empty($contentData['items'][$i]['comments'])): ?>
+                        <div class="ml-3 pt-1 client-rs-contents">
+                            <b>Comments: </b><?= $contentData['items'][$i]['comments'] ?>
+                        </div>
+                        <?php endif; ?>
+                    </div>
+                    <?php
+                }
+                ?>
+                </div>
+                <?php
+            }
+        }
+    }
+    ?> </div> <?php
+}

+ 6 - 10
resources/views/app/patient/segment-templates/history_family/summary.blade.php

@@ -6,17 +6,13 @@ use App\Models\Note;
 /** @var Client $patient */
 /** @var Note $note */
 
-$contentData = [
-    "count" => 0,
-    "unknown" => false,
-    "items" => []
-];
-$isempty = false;
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'FAMILY_HISTORY', $sessionKey, true);
 
-$point = Point::getGlobalSingletonOfCategory($patient, 'FAMILY_HISTORY', true);
+$contentData = $parsed = false;
 
-if ($point && @$point->data) {
-    $contentData = $point->data;
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $parsed = $point->lastChildReview->data;
 }
 
 $labels = [
@@ -41,7 +37,7 @@ $labels = [
     'cancer_uterine_ca' => 'Uterine cancer',
 ];
 
-if(!$contentData['unknown'] && !!$contentData['count']) {
+if($contentData && !$contentData['unknown'] && !!$contentData['count']) {
     for ($i = 0; $i < $contentData['count']; $i++) {
 ?>
 <div class="<?= $i > 0 ? 'mt-2' : '' ?>">

+ 10 - 5
resources/views/app/patient/segment-templates/history_screenings/edit.blade.php

@@ -6,10 +6,14 @@ use App\Models\Note;
 /** @var Client $patient */
 /** @var Note $note */
 
-// try loading afresh - since base section might have gotten dynamically updated
-$point = Point::getGlobalSingletonOfCategory($patient, 'SCREENINGS_HISTORY', true);
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'SCREENINGS_HISTORY', $sessionKey, true);
 
-$contentData = $parsed = @$point && @$point->data ? $point->data : false;
+$contentData = $parsed = false;
+
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $parsed = $point->lastChildReview->data;
+}
 
 if(!$contentData) {
     $contentData = [
@@ -28,9 +32,10 @@ if(!$contentData) {
 <hr class="hide-outside-popup mt-3 mb-0">
 <div class="p-3 mcp-theme-1">
     <div visit-moe close-on-save close-on-cancel class="d-block">
-        <form show url="/api/visitPoint/upsertGlobalSingleton" class="mcp-theme-1">
+        <form show url="/api/visitPoint/upsertChildReview" class="mcp-theme-1">
             <input type="hidden" name="segmentUid" value="<?= $segment->uid ?>">
-            <input type="hidden" name="category" value="SCREENINGS_HISTORY">
+            <input type="hidden" name="uid" value="<?= $point->uid ?>">
+            <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
             <input type="hidden" name="data">
 
             <div id="edit-univ_history_screenings-container">

+ 47 - 0
resources/views/app/patient/segment-templates/history_screenings/log.blade.php

@@ -0,0 +1,47 @@
+<?php
+
+use App\Models\Client;
+use App\Models\Point;
+use App\Models\Note;
+/** @var Client $patient */
+/** @var Note $note */
+
+$point = Point::getOnlyTopLevelPointOfCategory($note, 'SCREENINGS_HISTORY', true);
+
+if($point) {
+    ?> <div class="popup-content-container px-3"> <?php
+    foreach ($point->childReviews as $childReview) {
+        $contentData = $parsed = false;
+        if ($childReview->data) {
+            $childReview->data = json_decode($childReview->data, true);
+            $contentData = $parsed = $childReview->data;
+
+            if($contentData && $contentData['count']) {
+                ?>
+                    <div class="mb-1 font-weight-bold">{{$childReview->creatorPro->displayName()}} - {{friendly_date($childReview->note->effective_dateest)}}</div>
+                    <div class="pl-3 bg-light border p-3 mb-3">
+                    <table class="table table-bordered table-sm mb-0 table-cage">
+                        <?php
+                        for ($i = 0; $i < $contentData['count']; $i++) {
+                        ?>
+                        <tr>
+                            <td class="width-300px">
+                                <?= isset($contentData['items'][$i]['screening']) ? $contentData['items'][$i]['screening'] : '--' ?>
+                            </td>
+                            <td class="width-300px pl-3">
+                                <?php if(isset($contentData['items'][$i]['comments']) && !empty($contentData['items'][$i]['comments'])): ?>
+                                <span class="ml-1 text-secondary">(<?= $contentData['items'][$i]['comments'] ?>)</span>
+                                <?php endif; ?>
+                            </td>
+                            <td></td>
+                        </tr>
+                        <?php
+                        }
+                        ?>
+                    </table>
+                <?php
+            }
+        }
+    }
+    ?> </div> <?php
+}

+ 5 - 8
resources/views/app/patient/segment-templates/history_screenings/summary.blade.php

@@ -6,16 +6,13 @@ use App\Models\Note;
 /** @var Client $patient */
 /** @var Note $note */
 
-$contentData = [
-    "count" => 0,
-    "items" => []
-];
-$isempty = false;
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'SCREENINGS_HISTORY', $sessionKey, true);
 
-$point = Point::getGlobalSingletonOfCategory($patient, 'SCREENINGS_HISTORY', true);
+$contentData = $parsed = false;
 
-if ($point && @$point->data) {
-    $contentData = $point->data;
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $parsed = $point->lastChildReview->data;
     ?>
     <table class="table table-bordered table-sm mb-0 table-cage">
         <?php

+ 10 - 6
resources/views/app/patient/segment-templates/history_social/edit.blade.php

@@ -34,9 +34,14 @@ $customFields = $pro->canvasCustomItems('sochx');
 
 if(!$customFields) $customFields = [];
 
-$point = Point::getGlobalSingletonOfCategory($patient, 'SOCIAL_HISTORY',true);
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'SOCIAL_HISTORY', $sessionKey, true);
 
-$contentData = $parsed = @$point && @$point->data ? $point->data : false;
+$contentData = $parsed = false;
+
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $parsed = $point->lastChildReview->data;
+}
 
 if(!$contentData) {
     $contentData = [
@@ -58,14 +63,13 @@ for ($i = 0; $i < count($fields); $i++) {
 <hr class="hide-outside-popup mt-3 mb-0">
 <div class="p-3 mcp-theme-1">
     <div {{!!$segment ? 'visit-moe' : 'moe'}} close-on-save close-on-cancel class="d-block">
-        <form show url="/api/visitPoint/upsertGlobalSingleton" class="mcp-theme-1"
+        <form show url="/api/visitPoint/upsertChildReview" class="mcp-theme-1"
                 {{!$segment ? 'hook=onHxPopupClosure' : ''}}>
             @if(!!@$segment)
                 <input type="hidden" name="segmentUid" value="<?= $segment->uid ?>">
-            @else
-                <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
             @endif
-            <input type="hidden" name="category" value="SOCIAL_HISTORY">
+            <input type="hidden" name="uid" value="<?= $point->uid ?>">
+            <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
             <input type="hidden" name="data">
 
             <div id="edit-univ_history_social-container">

+ 89 - 0
resources/views/app/patient/segment-templates/history_social/log.blade.php

@@ -0,0 +1,89 @@
+<?php
+
+use App\Models\Client;
+use App\Models\Point;
+use App\Models\Note;
+/** @var Client $patient */
+/** @var Note $note */
+
+$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 "],
+    ],
+    [
+        "Alcohol" => ["Do not drink", "Drink daily", "Frequently drink", "Hx of Alcoholism", "Occasional drink"],
+        "Drug Abuse" => ["IVDU", "Illicit drug use", "No illicit drug use"],
+    ],
+    [
+        "Cardiovascular" => ["Eat healthy meals", "Regular exercise", "Take daily aspirin"],
+        "Safety" => ["Household Smoke detector", "Keep Firearms in home", "Wear seatbelts"],
+    ],
+    [
+        "Sexual Activity" => ["Exposure to STI", "Homosexual encounters", "Not sexually active", "Safe sex practices", "Sexually active"],
+        "Birth Gender" => ["Male", "Female", "Undifferentiated"],
+    ]
+];
+
+$point = Point::getOnlyTopLevelPointOfCategory($note, 'SOCIAL_HISTORY', true);
+
+if($point) {
+    ?> <div class="popup-content-container px-3"> <?php
+    foreach ($point->childReviews as $childReview) {
+        $contentData = $parsed = false;
+        if ($childReview->data) {
+            $childReview->data = json_decode($childReview->data, true);
+            $contentData = $parsed = $childReview->data;
+            ?>
+            <div class="mb-1 font-weight-bold">{{$childReview->creatorPro->displayName()}} - {{friendly_date($childReview->note->effective_dateest)}}</div>
+            <div class="pl-3 bg-light border p-3 mb-3">
+            <?php
+
+            for ($i = 0; $i < count($fields); $i++):
+            foreach($fields[$i] as $head => $values):
+            for($k = 0; $k < count($values); $k++):
+            $fName = $head . '_' . sanitize_field_name($values[$k]);
+            if(@$contentData['common'][$fName]): ?>
+            <div>
+                <?= ucwords($head) ?>
+                <i class="fa fa-arrow-right text-sm text-secondary"></i>
+                <span class="font-weight-bold"><?= $values[$k] ?></span>
+                <?php if(@$contentData['common'][$fName . '__comments']): ?>
+                <span class="text-sm ml-1 text-secondary">(<?= $contentData['common'][$fName . '__comments'] ?>)</span>
+                <?php endif; ?>
+            </div>
+            <?php
+            endif;
+            endfor;
+            endforeach;
+            endfor;
+
+            // custom fields
+
+            if(isset($contentData['customFields']) && count($contentData['customFields'])):
+            ?> <div class=""> <?php
+                for ($i = 0; $i < count($contentData['customFields']); $i++):
+                $item = $contentData['customFields'][$i];
+                if($item['value']): ?>
+                <div>
+                    Custom
+                    <i class="fa fa-arrow-right text-sm text-secondary"></i>
+                    <span class="font-weight-bold"><?= $item['label'] ?></span>
+                    <?php if($item['comments']): ?>
+                    <span class="text-sm ml-1 text-secondary">(<?= $item['comments'] ?>)</span>
+                    <?php endif; ?>
+                </div>
+                <?php
+                endif;
+                endfor;
+                ?> </div> <?php
+            endif;
+
+            if(isset($contentData['comments']) && !empty(trim($contentData['comments']))) { ?>
+            <div class="mt-2 mb-1">
+                <b>Comments: </b><?= $contentData['comments'] ?>
+            </div>
+            <?php }
+        }
+    }
+    ?> </div> <?php
+}

+ 5 - 9
resources/views/app/patient/segment-templates/history_social/summary.blade.php

@@ -25,17 +25,13 @@ $fields = [
     ]
 ];
 
-$contentData = [
-    "common" => [],
-    "customFields" => [],
-    "comments" => "",
-];
-
-$point = Point::getGlobalSingletonOfCategory($patient, 'SOCIAL_HISTORY', true);
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'SOCIAL_HISTORY', $sessionKey, true);
 
-if ($point && @$point->data) {
+$contentData = $parsed = false;
 
-    $contentData = $point->data;
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $parsed = $point->lastChildReview->data;
 
     for ($i = 0; $i < count($fields); $i++):
         foreach($fields[$i] as $head => $values):

+ 10 - 6
resources/views/app/patient/segment-templates/history_surgical/edit.blade.php

@@ -31,9 +31,14 @@ $customFields = $pro->canvasCustomItems('pshx');
 
 if(!$customFields) $customFields = [];
 
-$point = Point::getGlobalSingletonOfCategory($patient, 'SURGICAL_HISTORY', true);
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'SURGICAL_HISTORY', $sessionKey, true);
 
-$contentData = $parsed = @$point && @$point->data ? $point->data : false;
+$contentData = $parsed = false;
+
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $parsed = $point->lastChildReview->data;
+}
 
 if(!$contentData) {
     $contentData = [
@@ -55,14 +60,13 @@ for ($i = 0; $i < count($fields); $i++) {
 <hr class="hide-outside-popup mt-3 mb-0">
 <div class="p-3 mcp-theme-1">
     <div {{!!$segment ? 'visit-moe' : 'moe'}} close-on-save close-on-cancel class="d-block">
-        <form show url="/api/visitPoint/upsertGlobalSingleton" class="mcp-theme-1"
+        <form show url="/api/visitPoint/upsertChildReview" class="mcp-theme-1"
                 {{!$segment ? 'hook=onHxPopupClosure' : ''}}>
             @if(!!@$segment)
                 <input type="hidden" name="segmentUid" value="<?= $segment->uid ?>">
-            @else
-                <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
             @endif
-            <input type="hidden" name="category" value="SURGICAL_HISTORY">
+            <input type="hidden" name="uid" value="<?= $point->uid ?>">
+            <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
             <input type="hidden" name="data">
 
             <div id="edit-univ_history_surgical-container">

+ 88 - 0
resources/views/app/patient/segment-templates/history_surgical/log.blade.php

@@ -0,0 +1,88 @@
+<?php
+
+use App\Models\Client;
+use App\Models\Point;
+use App\Models\Note;
+/** @var Client $patient */
+/** @var Note $note */
+
+$fields = [
+    [
+        "" => ["Aneurysm repair", "Appendectomy", "Back surgery", "Bariatric surgery/gastric bypass", "Bilateral tubal ligation", "Breast resection/mastectomy", "CABG", "Carotid endarterectomy/stent", "Carpal tunnel release surgery",]
+    ],
+    [
+        "" => ["Cataract/lens surgery", "Cesarean section", "Cholecystectomy/bile duct surgery", "Dilation and curettage", "Hemorrhoid surgery", "Hip arthroplasty", "Hip replacement", "Hysterectomy", "Inguinal hernia repair",]
+    ],
+    [
+        "" => ["Knee arthroplasty", "LASIK", "Laminectomy", "Nasal surgery", "PTCA/PCI", "Pacemaker/defibrillator", "Prostate surgery", "Prostatectomy", "Rotator cuff surgery",]
+    ],
+    [
+        "" => ["Sinus surgery", "Skin cancer excision", "Spinal fusion", "TAH-BSO", "TURP", "Tonsillectomy/Adenoidectomy", "Vasectomy",]
+    ]
+];
+
+
+$point = Point::getOnlyTopLevelPointOfCategory($note, 'SURGICAL_HISTORY', true);
+
+if($point) {
+    ?> <div class="popup-content-container px-3"> <?php
+    foreach ($point->childReviews as $childReview) {
+        $contentData = $parsed = false;
+        if ($childReview->data) {
+            $childReview->data = json_decode($childReview->data, true);
+            $contentData = $parsed = $childReview->data;
+
+            ?>
+            <div class="mb-1 font-weight-bold">{{$childReview->creatorPro->displayName()}} - {{friendly_date($childReview->note->effective_dateest)}}</div>
+            <div class="pl-3 bg-light border p-3 mb-3">
+            <?php
+
+            for ($i = 0; $i < count($fields); $i++):
+            foreach($fields[$i] as $head => $values):
+            for($k = 0; $k < count($values); $k++):
+            $fName = $head . '_' . sanitize_field_name($values[$k]);
+            if(@$contentData['common'][$fName]): ?>
+            <div>
+                <!--Common
+                <i class="fa fa-arrow-right text-sm text-secondary"></i>-->
+                <span class="font-weight-bold"><?= $values[$k] ?></span>
+                <?php if(@$contentData['common'][$fName . '__comments']): ?>
+                <span class="text-sm ml-1 text-secondary">(<?= $contentData['common'][$fName . '__comments'] ?>)</span>
+                <?php endif; ?>
+            </div>
+            <?php
+            endif;
+            endfor;
+            endforeach;
+            endfor;
+
+            // custom fields
+
+            if(isset($contentData['customFields']) && count($contentData['customFields'])):
+            ?> <div class=""> <?php
+                for ($i = 0; $i < count($contentData['customFields']); $i++):
+                $item = $contentData['customFields'][$i];
+                if($item['value']): ?>
+                <div>
+                    <!--Custom
+                    <i class="fa fa-arrow-right text-sm text-secondary"></i>-->
+                    <span class="font-weight-bold"><?= $item['label'] ?></span>
+                    <?php if($item['comments']): ?>
+                    <span class="text-sm ml-1 text-secondary">(<?= $item['comments'] ?>)</span>
+                    <?php endif; ?>
+                </div>
+                <?php
+                endif;
+                endfor;
+                ?> </div> <?php
+            endif;
+
+            if(isset($contentData['comments']) && !empty(trim($contentData['comments']))) { ?>
+            <div class="mt-2 mb-1">
+                <b>Comments: </b><?= $contentData['comments'] ?>
+            </div>
+            <?php }
+        }
+    }
+    ?> </div> <?php
+}

+ 5 - 9
resources/views/app/patient/segment-templates/history_surgical/summary.blade.php

@@ -22,17 +22,13 @@ $fields = [
     ]
 ];
 
-$contentData = [
-    "common" => [],
-    "customFields" => [],
-    "comments" => "",
-];
-
-$point = Point::getGlobalSingletonOfCategory($patient, 'SURGICAL_HISTORY', true);
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'SURGICAL_HISTORY', $sessionKey, true);
 
-if ($point && @$point->data) {
+$contentData = $parsed = false;
 
-    $contentData = $point->data;
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $parsed = $point->lastChildReview->data;
 
     for ($i = 0; $i < count($fields); $i++):
         foreach($fields[$i] as $head => $values):

+ 11 - 7
resources/views/app/patient/segment-templates/past_medical_history/edit.blade.php

@@ -43,9 +43,14 @@ $customFields = $pro->canvasCustomItems('pmhx');
 
 if(!$customFields) $customFields = [];
 
-$point = Point::getGlobalSingletonOfCategory($patient, 'PAST_MEDICAL_HISTORY', true);
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'PAST_MEDICAL_HISTORY', $sessionKey, true);
 
-$contentData = $parsed = @$point && @$point->data ? $point->data : false;
+$contentData = $parsed = false;
+
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $parsed = $point->lastChildReview->data;
+}
 
 if(!$contentData) {
     $contentData = [
@@ -69,14 +74,13 @@ for ($i = 0; $i < count($fields); $i++) {
 <hr class="hide-outside-popup mt-3 mb-0">
 <div class="p-3 mcp-theme-1">
     <div {{!!$segment ? 'visit-moe' : 'moe'}} close-on-save close-on-cancel class="d-block">
-        <form show url="/api/visitPoint/upsertGlobalSingleton" class="mcp-theme-1"
+        <form show url="/api/visitPoint/upsertChildReview" class="mcp-theme-1"
                 {{!$segment ? 'hook=onHxPopupClosure' : ''}}>
             @if(!!@$segment)
                 <input type="hidden" name="segmentUid" value="<?= $segment->uid ?>">
-            @else
-                <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
             @endif
-            <input type="hidden" name="category" value="PAST_MEDICAL_HISTORY">
+            <input type="hidden" name="uid" value="<?= $point->uid ?>">
+            <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
             <input type="hidden" name="data">
 
             <div id="edit-univ_history_past_medical-container">
@@ -118,7 +122,7 @@ for ($i = 0; $i < count($fields); $i++) {
                                                         <a href="#" start show>
                                                             <i class="fa-comment" :class="common['{{$fName}}__comments'] ? 'fas' : 'far'"></i>
                                                         </a>
-                                                        <div url="/nop" right>
+                                                        <div url="/nop">
                                                             <div class="mb-2">
                                                                 <textarea class="form-control form-control-sm ns-custom-comment min-width-200px"
                                                                           v-model="common['{{$fName}}__comments']"></textarea>

+ 9 - 3
resources/views/app/patient/segment-templates/past_medical_history/summary.blade.php

@@ -42,10 +42,16 @@ $contentData = [
 ];
 $isempty = false;
 
-$point = Point::getGlobalSingletonOfCategory($patient, 'PAST_MEDICAL_HISTORY', true);
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'PAST_MEDICAL_HISTORY', $sessionKey, true);
 
-if ($point && @$point->data) {
-    $contentData = $point->data;
+$contentData = $parsed = false;
+
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $parsed = $point->lastChildReview->data;
+}
+
+if ($contentData) {
 
     $blood = [];
     if(isset($contentData['bloodType'])) {

+ 15 - 6
resources/views/app/patient/segment-templates/ros/edit.blade.php

@@ -193,9 +193,19 @@ $fields = [
     ]
 ];
 
-$point = Point::getGlobalSingletonOfCategory($patient, 'ROS', true);
+// only for ros - since ros edit markup is loaded via AJAX GET from the UI
+if(!@$sessionKey) {
+    $sessionKey = request()->cookie('sessionKey');
+}
+
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'ROS', $sessionKey, true);
 
-$contentData = $parsed = ($point && @$point->data && !@($point->data['free_text'])) ? $point->data : false;
+$contentData = $parsed = false;
+
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $parsed = $point->lastChildReview->data;
+}
 
 if(!$contentData) {
     $contentData = [
@@ -217,14 +227,13 @@ for ($i = 0; $i < count($fields); $i++) {
 <hr class="hide-outside-popup mt-3 mb-0">
 <div class="p-3 mcp-theme-1">
     <div {{!!$segment ? 'visit-moe' : 'moe'}} close-on-save close-on-cancel class="d-block">
-        <form show url="/api/visitPoint/upsertGlobalSingleton" class="mcp-theme-1"
+        <form show url="/api/visitPoint/upsertChildReview" class="mcp-theme-1"
                 {{!$segment ? 'hook=onHxPopupClosure' : ''}}>
             @if(!!@$segment)
                 <input type="hidden" name="segmentUid" value="<?= $segment->uid ?>">
-            @else
-                <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
             @endif
-            <input type="hidden" name="category" value="ROS">
+            <input type="hidden" name="uid" value="<?= $point->uid ?>">
+            <input type="hidden" name="noteUid" value="<?= $note->uid ?>">
             <input type="hidden" name="data" value='{!! json_encode($contentData) !!}'>
 
             <div id="edit-ros-container">

+ 261 - 0
resources/views/app/patient/segment-templates/ros/log.blade.php

@@ -0,0 +1,261 @@
+<?php
+
+use App\Models\Client;
+use App\Models\Point;
+use App\Models\Note;
+/** @var Client $patient */
+/** @var Note $note */
+
+$fields = [
+    [
+        "Constitutional" => [
+            "Fatigue",
+            "Fever",
+            "Weight gain",
+            "Weight loss"],
+
+        "Eyes" => [
+            "Blurry vision",
+            "Double vision",
+            "Dry eyes",
+            "Floaters",
+            "Halos",
+            "Headache",
+            "Irritation",
+            "Loss of peripheral vision",
+            "Pain",
+            "Pinpoint pupils",
+            "Teary",
+            "Visual changes"],
+
+        "ENMT" => [
+            "Altered sense of smell",
+            "Dental caries",
+            "Dentures",
+            "Dizziness",
+            "Dry mouth",
+            "Ear pain/pressure",
+            "Hearing loss",
+            "Mouth pain",
+            "Nasal congestion",
+            "Neck pain/stiffness",
+            "Post nasal drainage",
+            "Sinus pain / pressure",
+            "Sore throat",
+            "Teeth missing",
+            "Tinnitus",
+            "Trouble swallowing"],
+        "Allergy / Immune" => [
+            "Congestion",
+            "Difficulty healing",
+            "Frequent infections",
+            "Headache",
+            "Hives",
+            "Itching",
+            "Running nose",
+            "Sneezing",
+            "Watery eyes"]
+    ],
+    [
+        "Cardiovascular" => [
+            "Chest pain / pressure at rest",
+            "Chest pain / pressure with excursion",
+            "Cold hands / feet",
+            "Dizziness",
+            "Exercise intolerance",
+            "Fainting",
+            "Feeling faint",
+            "Left arm pain",
+            "Light headed",
+            "Lower leg cramps",
+            "Muscle weakness",
+            "Palpitations",
+            "Shortness of breath",
+            "Sweating",
+            "Swelling"],
+
+        "Respiratory" => [
+            "Cough – dry",
+            "Cough – wet",
+            "Coughing up blood",
+            "Pain with breathing",
+            "Productive cough",
+            "Shortness of breath at rest",
+            "Shortness of breath on excursion",
+            "Wheezing"],
+
+        "Gastrointestinal" => [
+            "Abdominal pain",
+            "Constipation",
+            "Coughing up blood",
+            "Diarrhea",
+            "Difficulty swallowing",
+            "Fecal incontinence",
+            "Heartburn",
+            "Loose stool",
+            "Nausea",
+            "Painful swallowing",
+            "Rectal pain",
+            "Stool – black tarry",
+            "Stool – bloody"],
+    ],
+    [
+        "Genitourinary" => [
+            "Blood in urine",
+            "Discharge",
+            "Foley",
+            "Incontinence",
+            "Lesions",
+            "Sexual dysfunction",
+            "Tenderness",
+            "Urinary retention",
+            "Urination - frequent",
+            "Urination - painful",
+            "Urination wakes you up at night"],
+
+        "Musculoskeletal" => [
+            "Decreased range of motion",
+            "Fracture",
+            "Gait - unstable",
+            "Joint instability",
+            "Joint pain",
+            "Joint stiffness",
+            "Joint swelling",
+            "Muscle pain",
+            "Muscle weakness",
+            "Sprain"],
+
+        "Skin" => [
+            "Bruises",
+            "Color changes",
+            "Dry skin",
+            "Goosebumps",
+            "Itchy",
+            "IVDU marks",
+            "Lesions",
+            "Nodules",
+            "Rash",
+            "Scars",
+            "Swelling",
+            "Track marks",
+            "Ulcer",
+            "Wound"],
+
+    ],
+    [
+        "Neurological" => [
+            "Coordination problem",
+            "Dizziness",
+            "Double vision",
+            "Fainting",
+            "Head trauma",
+            "Headache",
+            "Imbalance",
+            "Muscle twitching",
+            "Numbness",
+            "Problems walking",
+            "Restlessness",
+            "Seizures",
+            "Speech disturbance",
+            "TBI",
+            "Tingling",
+            "Tinnitus",
+            "Tremor",
+            "Vertigo",
+            "Weakness"],
+
+        "Endocrine" => [
+            "Change in hair growth",
+            "Cold intolerance",
+            "Diabetes",
+            "Excessive hunger",
+            "Excessive thirst",
+            "Excessive urination",
+            "Exhausted",
+            "Goiter",
+            "Heat intolerance",
+            "Hot and cold flashes",
+            "Sleeplessness",
+            "Weight gain",
+            "Weight loss"],
+
+        "Lymphatic" => [
+            "Anemia",
+            "Bleeding tendency",
+            "Bruises",
+            "Lymph node pain enlargement",
+            "Pain",
+            "Swelling",
+            "Transfusions"],
+    ]
+];
+
+$point = Point::getOnlyTopLevelPointOfCategory($note, 'ROS', true);
+
+if($point) {
+    ?> <div class="popup-content-container px-3"> <?php
+    foreach ($point->childReviews as $childReview) {
+        $contentData = $parsed = false;
+        if ($childReview->data) {
+            $childReview->data = json_decode($childReview->data, true);
+            $contentData = $parsed = $childReview->data;
+
+            ?>
+            <div class="mb-1 font-weight-bold">{{$childReview->creatorPro->displayName()}} - {{friendly_date($childReview->note->effective_dateest)}}</div>
+            <div class="pl-3 bg-light border p-3 mb-3">
+            <?php
+
+            if(!!@$contentData['declaration']) {
+                echo '<div class="mb-2">';
+                echo '<i class="fa fa-check"></i>&nbsp;';
+                echo "Except for the systems documented in the HPI or detailed below, all other systems were reviewed and negative.";
+                echo '</div>';
+            }
+
+            // group by "head" and separate fields with values
+            $grouped = [];
+            for ($i = 0; $i < count($fields); $i++) {
+                foreach ($fields[$i] as $head => $values) {
+                    for ($k = 0; $k < count($values); $k++) {
+                        $fName = $head . '_' . sanitize_field_name($values[$k]);
+                        if (@$contentData['common'][$fName]) {
+                            if(!isset($grouped[$head])) $grouped[$head] = [];
+                            $grouped[$head][] = [
+                                "label" => $values[$k],
+                                "value" => @$contentData['common'][$fName],
+                                "comments" => @$contentData['common'][$fName . '__comments']
+                            ];
+                        }
+                    }
+                }
+            }
+
+            $display = [];
+            foreach($grouped as $head => $items) {
+                $combined = [];
+                for ($i = 0; $i < count($items); $i++) {
+                    $combined[] = $items[$i]['label'] . ' (' . $items[$i]['value'] . ')' .
+                        (@$items[$i]['comments'] ? '<span class="text-secondary font-italic text-sm">&nbsp;' . @$items[$i]['comments'] . '</span>' : '');
+                }
+                $display[$head] = implode(' • ', $combined);
+            }
+
+            foreach($display as $head => $line) {
+            ?>
+            <div class="mb-2">
+                <span class="font-weight-bold mr-1">{{$head}}:</span>
+                <span class="">{!! $line !!}</span>
+            </div>
+            <?php
+            }
+            if(isset($contentData['comments']) && !empty(trim($contentData['comments']))) {
+            ?>
+                <div class="mt-2 mb-1">
+                    <b>Comments: </b><?= $contentData['comments'] ?>
+                </div>
+            <?php
+            }
+        }
+    }
+    ?> </div> <?php
+}

+ 4 - 9
resources/views/app/patient/segment-templates/ros/summary.blade.php

@@ -190,16 +190,11 @@ $fields = [
     ]
 ];
 
-$contentData = [
-    "common" => [],
-    "comments" => "",
-];
-$isempty = false;
-
-$point = Point::getGlobalSingletonOfCategory($patient, 'ROS', true);
+$point = Point::getOrCreateOnlyTopLevelPointOfCategory($note, 'ROS', $sessionKey, true);
 
-if ($point && @$point->data && !@($point->data['free_text'])) {
-    $contentData = $point->data;
+if ($point->lastChildReview && $point->lastChildReview->data) {
+    $point->lastChildReview->data = json_decode($point->lastChildReview->data, true);
+    $contentData = $point->lastChildReview->data;
 
     if(!!@$contentData['declaration']) {
         echo '<div class="mb-2">';

+ 1 - 1
resources/views/app/stat-tree/stat-tree-lines/view-data.blade.php

@@ -18,7 +18,7 @@
                             <?php
                             $argsLabel = [];
                             foreach($lineClause->lineClauseArgs as $lineClauseArg) {
-                                $argLabel = $lineClauseArg->clauseArg->arg_text . ': ' . $lineClauseArg->default_value;
+                                $argLabel = $lineClauseArg->clauseArg->arg_text . ': ' . $lineClauseArg->value;
                                 $argsLabel[] = $argLabel;
                             }
                             ?>

+ 98 - 17
resources/views/app/stat-tree/stat-trees/sub/edit.blade.php

@@ -96,7 +96,7 @@
                 <div id="statTreeEdit-{{$statTree->id}}" class="row m-0 h-100 stat-tree {{$multiProView ? 'multi-pro-view' : ''}}">
 
                     <!-- clauses -->
-                    <div class="col-3 p-0 h-100 clauses-column">
+                    <div class="col-3 p-0 h-100 clauses-column overflow-auto">
 
                         <div class="d-flex flex-column h-100">
                             <div class="d-flex align-items-center pl-2 height-35px border-bottom bg-light">
@@ -266,7 +266,7 @@
 
 
                     <!-- tree -->
-                    <div class="col-9 p-0 h-100 border-left tree-column">
+                    <div class="col-9 p-0 h-100 border-left tree-column overflow-auto">
                         <div class="row m-0 h-100">
                             <div class="{{$multiProView ? 'col-12' : 'col-6'}} tree-lhs-column border-right h-100 p-0">
                                 <div class="d-flex flex-column h-100">
@@ -302,7 +302,7 @@
                                             <div class="stat-tree-view overflow-auto min-height-300px" id="stat-tree-edit-{{$statTree->id}}"></div>
                                         @else
                                             <div class="d-flex align-items-start">
-                                                <div class="mv-tree">
+                                                <div class="mv-tree overflow-auto">
                                                     <div class="multi-pro-view-stat-label">Stat</div>
                                                     <div class="stat-tree-view overflow-auto" id="stat-tree-edit-{{$statTree->id}}"></div>
                                                 </div>
@@ -315,7 +315,9 @@
                                                             </th>
                                                             @foreach($multiPros as $multiPro)
                                                                 <th data-pro-uid="{{$multiPro->uid}}" count-required>
-                                                                    <div class="pro-label" title="{{$multiPro->name_display}}">{{$multiPro->name_display}}</div>
+                                                                    <div class="pro-label position-relative" title="{{$multiPro->name_display}}">{{$multiPro->name_display}}
+                                                                        <a href="#" class="mv-delete-pro-trigger rounded-circle bg-white c-pointer" data-pro-uid="{{$multiPro->uid}}"><i class="fa fa-times text-danger"></i></a>
+                                                                    </div>
                                                                 </th>
                                                             @endforeach
                                                         </tr>
@@ -323,14 +325,14 @@
                                                         <tbody>
                                                         @foreach($linesFlat as $line)
                                                             <tr data-line-uid="{{$line->uid}}" {!! $line->parent ? 'data-parent-line-uid="' . $line->parent->uid . '"' : '' !!}>
-                                                                <td class="p-0">
+                                                                <td class="p-0 on-hover-aliceblue c-pointer mv-view-data-trigger">
                                                                     <div class="count-label">
                                                                         <div class="count">{{$line->last_refresh_count}}</div>
                                                                         <div class="drop-percent"></div>
                                                                     </div>
                                                                 </td>
                                                                 @foreach($multiPros as $multiPro)
-                                                                    <td class="p-0" data-pro-uid="{{$multiPro->uid}}">
+                                                                    <td class="p-0 on-hover-aliceblue c-pointer mv-view-data-trigger" data-pro-uid="{{$multiPro->uid}}">
                                                                         <div class="count-label">
                                                                             <div class="count"></div>
                                                                             <div class="drop-percent"></div>
@@ -596,7 +598,7 @@
                                                                     "action": function (obj) {
                                                                         openDynamicStagPopup('/practice-management/stat-tree-lines/view-data/' + node.data.uid,
                                                                             null,
-                                                                            node.data.extendedLabel,
+                                                                            'View Data',
                                                                             false,
                                                                             'medium');
                                                                     },
@@ -762,7 +764,7 @@
                                         let stateNode = JSON.parse(JSON.stringify(node));
                                         for (let j = 0; j < stateNode.data.clause.args.length; j++) {
                                             if(stateNode.data.clause.args[j].arg_text === 'state' && stateNode.data.clause.args[j].field_type === 'text') {
-                                                stateNode.data.clause.args[j].default_value = states[i];
+                                                stateNode.data.clause.args[j].value = states[i];
                                             }
                                         }
                                         stateNode.text = stateNode.text.replace(/state:\s[A-Z]{2}/g, 'state: ' + states[i]);
@@ -1099,12 +1101,14 @@
 
                                 onSelected: function(_e, _data) {
 
+                                    let selected = this.selectedNode();
+
                                     @if($multiProView)
-                                    return;
+                                        $('.multi-pro-stats-table tr.bg-treeblue').removeClass('bg-treeblue');
+                                        $('.multi-pro-stats-table tr[data-line-uid="' + selected.data.uid + '"]').addClass('bg-treeblue');
+                                        return;
                                     @endif
 
-                                    let selected = this.selectedNode();
-
                                     if(selected) console.log(selected.data)
 
                                     if(!(selected && selected.data && selected.data.type === 'stat_tree_line')) return;
@@ -1134,7 +1138,7 @@
                                                     )
                                                     .append(
                                                         $('<td/>')
-                                                            .text(args[i].default_value)
+                                                            .text(args[i].value)
                                                             .append(edit ? '<a href="#" class="edit-arg-value ml-2" data-index="' + i + '"><i class="fa fa-edit text-primary text-sm on-hover-opaque"></i></a>': '')
                                                     )
                                                     .append(
@@ -1156,7 +1160,7 @@
                                             $('<tr/>')
                                                 .append($('<td/>').text(i + 1))
                                                 .append($('<td/>').text(columns[i].label).append('<a href="#" class="edit-column-label ml-2" data-index="' + i + '"><i class="fa fa-edit text-primary text-sm on-hover-opaque"></i></a>'))
-                                                .append($('<td/>').text(columns[i].display_key))
+                                                .append($('<td/>').text(columns[i].display_key).append('<a href="#" class="edit-column-column ml-2" data-index="' + i + '"><i class="fa fa-edit text-primary text-sm on-hover-opaque"></i></a>'))
                                                 .append($('<td/>').text(columns[i].type))
                                                 .append(
                                                     $('<td/>')
@@ -1237,9 +1241,9 @@
                                 .off('click', '.edit-arg-value')
                                 .on('click', '.edit-arg-value', function() {
                                     let args = StatTree.getSelectedNodeClauseArgs();
-                                    let value = window.prompt('New value:', args[+($(this).attr('data-index'))].default_value || '');
+                                    let value = window.prompt('New value:', args[+($(this).attr('data-index'))].value || '');
                                     if(value !== null) {
-                                        args[+($(this).attr('data-index'))].default_value = value;
+                                        args[+($(this).attr('data-index'))].value = value;
                                         StatTree.onSelected();
                                         StatTree.setDirty();
                                     }
@@ -1274,6 +1278,21 @@
                                     return false;
                                 });
 
+                            $(document)
+                                .off('click', '.edit-column-column')
+                                .on('click', '.edit-column-column', function() {
+                                    let columns = StatTree.getSelectedNodeColumns();
+                                    let index = +($(this).attr('data-index'));
+                                    let value = window.prompt('New column:', columns[+($(this).attr('data-index'))].display_key || '');
+                                    if(value !== null) {
+                                        columns[index].display_key = value;
+                                        StatTree.setSelectedNodeColumns(columns);
+                                        StatTree.onSelected();
+                                        StatTree.setDirty();
+                                    }
+                                    return false;
+                                });
+
                             $(document)
                                 .off('click', '.clause-expand-all')
                                 .on('click', '.clause-expand-all', function() {
@@ -1342,8 +1361,33 @@
                                     return false;
                                 });
 
+                            $(document)
+                                .off('click', '.mv-view-data-trigger')
+                                .on('click', '.mv-view-data-trigger', function() {
+                                    let title = 'View Data';
+                                    if($(this).attr('data-pro-uid')) {
+                                        let tdIndex = $(this).index();
+                                        title = 'View Data for ' + $(this).closest('table').find('thead tr th:eq(' + tdIndex + ')').text();
+                                    }
+                                    openDynamicStagPopup('/practice-management/stat-tree-lines/view-data/' + $(this).closest('tr').attr('data-line-uid') + '?proUid=' + $(this).attr('data-pro-uid'),
+                                        null,
+                                        title,
+                                        false,
+                                        'medium');
+                                    return false;
+                                });
+
+                            $(document)
+                                .off('click', '.mv-delete-pro-trigger')
+                                .on('click', '.mv-delete-pro-trigger', function() {
+                                    debugger
+                                    let proUids = '{{request()->input('multi-pro-uids')}}'.split(',').filter(_x => _x !== $(this).attr('data-pro-uid'));
+                                    fastLoad('/practice-management/stat-trees/view/{{$statTree->uid}}/edit?multi-pro=1&multi-pro-uids=' + proUids.join(','));
+                                    return false;
+                                });
+
                             @if($multiProView)
-                            $('[count-required]').each(function() {
+                            /*$('[count-required]').each(function() {
                                 $.post('{{route('practice-management.api.statTree.getCountsForPro')}}', {
                                     uid: '{{$statTree->uid}}',
                                     proUid: $(this).attr('data-pro-uid')
@@ -1380,7 +1424,44 @@
                                     });
 
                                 }, 'json');
-                            });
+                            });*/
+                            $.get('{{route('practice-management.api.statTree.getCountsForPros')}}', {
+                                uid: '{{$statTree->uid}}',
+                                proUids: '{{request()->input('multi-pro-uids')}}'
+                            }, _data => {
+                                for(let x in _data) {
+                                    let lineTR = $('.multi-pro-stats-table tr[data-line-uid="' + x + '"]');
+                                    for (let i = 0; i < _data[x].length; i++) {
+                                        lineTR.find('>td[data-pro-uid="' + _data[x][i]._v_pro_uid + '"] .count').text(_data[x][i].count);
+                                    }
+                                }
+                                // calculate drop %
+                                $('.multi-pro-stats-table tr[data-line-uid][data-parent-line-uid]').each(function() {
+                                    for (let i = 0; i < $(this).find('>td').length; i++) {
+                                        let parentCount = $('.multi-pro-stats-table tr[data-line-uid="' + $(this).attr('data-parent-line-uid') + '"]>td:eq(' + i + ') .count').first().text(),
+                                            myCount = $(this).find('>td:eq(' + i + ') .count').first().text();
+                                        if(parentCount && myCount && !Number.isNaN(+parentCount) && !Number.isNaN(+myCount) && +parentCount > 0) {
+                                            parentCount = +parentCount;
+                                            myCount = +myCount;
+                                            let element = $(this).find('>td:eq(' + i + ') .drop-percent').first(), cssClass = '';
+                                            let dropPercent = ((parentCount - myCount) / parentCount) * 100;
+                                            if(dropPercent > 75) {
+                                                cssClass = 'mv-drop-76-100';
+                                            }
+                                            else if(dropPercent > 50 && dropPercent <= 75) {
+                                                cssClass = 'mv-drop-51-75';
+                                            }
+                                            else if(dropPercent > 25 && dropPercent <= 50) {
+                                                cssClass = 'mv-drop-26-50';
+                                            }
+                                            else if(dropPercent > 0 && dropPercent <= 25) {
+                                                cssClass = 'mv-drop-0-25';
+                                            }
+                                            element.removeClass().addClass('drop-percent').addClass(cssClass).text(dropPercent.toFixed(1) + '% ⤵');
+                                        }
+                                    }
+                                });
+                            }, 'json');
                             @endif
 
                             ClausesTree.load();

+ 1 - 0
routes/web.php

@@ -376,6 +376,7 @@ Route::middleware('pro.auth')->group(function () {
                 Route::post('replace-all-lines-json', 'StatTreeController@replaceAllLinesJSON')->name('replaceAllLinesJSON');
                 Route::post('refresh-tree-count-queries', 'StatTreeController@refreshTreeCountQueries')->name('refreshTreeCountQueries');
                 Route::post('get-counts-for-pro', 'StatTreeController@getCountsForPro')->name('getCountsForPro');
+                Route::any('get-counts-for-pros', 'StatTreeController@getCountsForPros')->name('getCountsForPros');
             });
 
             //Stat Tree Line