Bläddra i källkod

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

= 3 år sedan
förälder
incheckning
2bde0a0d81

+ 79 - 0
app/Console/Commands/InstantiateStatTree.php

@@ -0,0 +1,79 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\Client;
+use App\Models\Pro;
+use App\Models\StatTree;
+use Illuminate\Console\Command;
+use Illuminate\Support\Facades\Http;
+
+class InstantiateStatTree extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'stat-tree:instantiate {slug} {pro-class}';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Instantiate Stat Tree For Multiple Pros';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        global $argv;
+
+        // load the tree from slug and ensure it is a template
+        /** @var StatTree $statTree */
+        $statTree = StatTree::where('slug', $argv[2])->first();
+        if(!$statTree) {
+            $this->error("Tree with specified slug does not exist!");
+            return 0;
+        }
+        if(!$statTree->is_template) {
+            $this->error("Tree with specified slug is not a template!");
+            return 0;
+        }
+
+        // check pro-class and get pro uids
+        $this->info($argv[3]);
+
+        $pros = Pro::where('is_active', TRUE)->whereRaw($argv[3])->get();
+        $this->info(count($pros) . " pros found.");
+
+        $this->info("Instantiating...");
+        $doneCount = 0;
+        if(count($pros) > 0) {
+            foreach ($pros as $pro) {
+                $statTree->instantiateForPro($pro);
+                $doneCount++;
+                if($doneCount % 50 == 0) {
+                    $this->info("$doneCount / " . count($pros) . " completed.");
+                }
+            }
+            $this->info("$doneCount / " . count($pros) . " completed.");
+        }
+
+    }
+
+}

+ 1 - 1
app/Console/Kernel.php

@@ -13,7 +13,7 @@ class Kernel extends ConsoleKernel
      * @var array
      */
     protected $commands = [
-        //
+        Commands\InstantiateStatTree::class
     ];
 
     /**

+ 8 - 2
app/Http/Controllers/StatTreeController.php

@@ -465,13 +465,15 @@ class StatTreeController extends Controller
         foreach ($line->reportColumns as $column) {
             $columns[] = [
                 "label" => $column->label,
-                "display_key" => $column->display_key
+                "display_key" => $column->display_key,
+                "type" => $column->field_type
             ];
         }
 
         // clause
         $lineClause = $line->displayLineClause();
         $args = [];
+        $argsLabel = [];
         foreach($lineClause->lineClauseArgs as $stlcArg) {
             if($stlcArg->clauseArg) {
                 $args[] = [
@@ -480,6 +482,7 @@ class StatTreeController extends Controller
                     "default_value" => $stlcArg->default_value,
                     "access_level" => $stlcArg->access_level
                 ];
+                $argsLabel[] = $stlcArg->clauseArg->arg_text . ': ' . $stlcArg->default_value;
             }
         }
         $clause = [
@@ -495,6 +498,7 @@ class StatTreeController extends Controller
         }
         return [
             "text" => '<span class="stat-tree-anchor">' . $line->displayLabel() . '</span>' .
+                (count($argsLabel) ? '<span class="text-info text-sm ml-2">[' . implode(', ', $argsLabel) . ']</span>' : '') .
                 '<span class="ml-2 text-secondary line-count-label">(' .
                 (is_null($line->last_refresh_count) ? '…' :
                     ($line->last_refresh_count === -1 ?
@@ -512,6 +516,7 @@ class StatTreeController extends Controller
                 "id" => $line->id,
                 "uid" => $line->uid,
                 "displayLabel" => $line->displayLabel(),
+                "extendedLabel" => $line->displayLabel() . (count($argsLabel) ? ' [' . implode(', ', $argsLabel) . ']' : ''),
                 "lastRefreshCount" => $line->last_refresh_count,
                 "treeOrderPositionIndex" => $line->tree_order_position_index,
                 "columns" => $columns,
@@ -650,6 +655,7 @@ class StatTreeController extends Controller
             $column->stat_tree_line_id = $statTreeLine->id;
             $column->label = $line->columns[$i]->label;
             $column->display_key = $line->columns[$i]->display_key;
+            $column->field_type = $line->columns[$i]->type;
             $column->position_index = $i;
             $column->stat_tree_id = $statTree->id;
             $column->save();
@@ -676,7 +682,7 @@ class StatTreeController extends Controller
         if (!$statTree) return $this->fail('Invalid stat tree!');
         $lines = $statTree->lines;
         foreach ($lines as $line) {
-            $query = $this->applyStatTreeLineQueryClauses($line, $request);
+            $query = $this->applyStatTreeLineQueryClauses($line);
             if ($query && $query !== 'error') {
                 $line->last_refresh_count = $query[0]->count;
             }

+ 43 - 3
app/Http/Controllers/StatTreeLineController.php

@@ -71,7 +71,8 @@ class StatTreeLineController extends Controller
             $matches = array_map(function($_x) use ($tables, $i) {
                 return [
                     "text" => $tables[$i] . '.' . $_x,
-                    "label" => sanitize_state_name($_x)
+                    "label" => sanitize_state_name($_x),
+                    "type" => DB::getSchemaBuilder()->getColumnType($tables[$i], $_x)
                 ];
             }, $matches);
             $columns = array_merge($columns, $matches);
@@ -96,12 +97,13 @@ class StatTreeLineController extends Controller
             $columns[] = [
                 "label" => $reportColumn->label,
                 "column" => $reportColumn->display_key,
+                "type" => $reportColumn->field_type,
                 "as" => "v_{$reportColumn->id}"
             ];
             $selectColumns[] = "{$reportColumn->display_key} as v_{$reportColumn->id}";
         }
         if(count($line->reportColumns)) {
-            $result = $this->queryStatTreeLineData($line, $selectColumns, $request);
+            $result = $this->queryStatTreeLineData($line, $selectColumns, $columns, $request);
             $total = $result[0];
             $rows = $result[1];
             $paginator = new LengthAwarePaginator($rows, $total, $request->input('per_page') ?: 20, $request->input('page') ?: 1);
@@ -157,7 +159,7 @@ class StatTreeLineController extends Controller
         return DB::select($query);
     }
 
-    protected function queryStatTreeLineData(StatTreeLine $statTreeLine, $selectColumns, Request $request)
+    protected function queryStatTreeLineData(StatTreeLine $statTreeLine, $selectColumns, $columns, Request $request)
     {
 
         $model = $statTreeLine->statTree->model;
@@ -195,6 +197,44 @@ class StatTreeLineController extends Controller
             $clauses[] = str_replace('@PRO_ID', $statTreeLine->statTree->pro->id, $statTreeLine->statTree->pro_scope_clause);
         }
 
+        // filters from view-data UI
+        foreach ($columns as $column) {
+            if($request->input($column['as'] . '_op')) {
+                switch($column['type']) {
+                    case 'integer':
+                    case 'bigint':
+                    case 'decimal':
+                    case 'bool':
+                    case 'boolean':
+                        if($request->input($column['as'] . '_value')) {
+                            $clauses[] = "{$column['column']} " . $request->input($column['as'] . '_op') . ' ' . $request->input($column['as'] . '_value');
+                        }
+                        break;
+                    case 'string':
+                    case 'text':
+                    case 'varchar':
+                        if($request->input($column['as'] . '_value')) {
+                            if($request->input($column['as'] . '_op') === '=' || $request->input($column['as'] . '_op') === '!=') {
+                                $clauses[] = "{$column['column']} " . $request->input($column['as'] . '_op') . ' ' . $request->input($column['as'] . '_value');
+                            }
+                            elseif($request->input($column['as'] . '_op') === 'ILIKE' || $request->input($column['as'] . '_op') === 'NOT ILIKE') {
+                                $clauses[] = "{$column['column']} " . $request->input($column['as'] . '_op') . ' ' . "'%" . $request->input($column['as'] . '_value') . "%'";
+                            }
+                        }
+                        break;
+                    case 'date':
+                    case 'datetime':
+                        if($request->input($column['as'] . '_value_start')) {
+                            $clauses[] = "{$column['column']} >= " . "'" . $request->input($column['as'] . '_value_start') . "'";
+                        }
+                        if($request->input($column['as'] . '_value_end')) {
+                            $clauses[] = "{$column['column']} <= " . "'" . $request->input($column['as'] . '_value_end') . "'";
+                        }
+                        break;
+                }
+            }
+        }
+
         $result = null;
 
         // get count for paginator

+ 2 - 0
app/Models/StatTree.php

@@ -43,6 +43,7 @@ class StatTree extends Model
         $instance->is_template = false;
         $instance->pro_id = $pro->id;
         $instance->pro_scope_clause = $this->pro_scope_clause;
+        $instance->template_stat_tree_id = $this->id;
         $instance->save();
 
         // create tree lines
@@ -67,6 +68,7 @@ class StatTree extends Model
         $instance->is_template = $this->is_template;
         $instance->pro_id = $this->pro_id;
         $instance->pro_scope_clause = $this->pro_scope_clause;
+        $instance->copied_from_stat_tree_id = $this->id;
         $instance->save();
 
         // create tree lines

+ 1 - 0
composer.json

@@ -11,6 +11,7 @@
         "php": "^7.2.5",
         "ext-json": "*",
         "barryvdh/laravel-dompdf": "^0.9.0",
+        "doctrine/dbal": "2.*",
         "fideloper/proxy": "^4.2",
         "fruitcake/laravel-cors": "^1.0",
         "guzzlehttp/guzzle": "^6.5",

+ 331 - 1
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "d01222da17fb9fe201059a9f90767292",
+    "content-hash": "afcf90be7410c699587a1a4954346390",
     "packages": [
         {
             "name": "asm89/stack-cors",
@@ -203,6 +203,335 @@
             "description": "implementation of xdg base directory specification for php",
             "time": "2019-12-04T15:06:13+00:00"
         },
+        {
+            "name": "doctrine/cache",
+            "version": "2.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/cache.git",
+                "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/cache/zipball/331b4d5dbaeab3827976273e9356b3b453c300ce",
+                "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce",
+                "shasum": ""
+            },
+            "require": {
+                "php": "~7.1 || ^8.0"
+            },
+            "conflict": {
+                "doctrine/common": ">2.2,<2.4"
+            },
+            "require-dev": {
+                "alcaeus/mongo-php-adapter": "^1.1",
+                "cache/integration-tests": "dev-master",
+                "doctrine/coding-standard": "^8.0",
+                "mongodb/mongodb": "^1.1",
+                "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
+                "predis/predis": "~1.0",
+                "psr/cache": "^1.0 || ^2.0 || ^3.0",
+                "symfony/cache": "^4.4 || ^5.2 || ^6.0@dev",
+                "symfony/var-exporter": "^4.4 || ^5.2 || ^6.0@dev"
+            },
+            "suggest": {
+                "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                }
+            ],
+            "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.",
+            "homepage": "https://www.doctrine-project.org/projects/cache.html",
+            "keywords": [
+                "abstraction",
+                "apcu",
+                "cache",
+                "caching",
+                "couchdb",
+                "memcached",
+                "php",
+                "redis",
+                "xcache"
+            ],
+            "funding": [
+                {
+                    "url": "https://www.doctrine-project.org/sponsorship.html",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://www.patreon.com/phpdoctrine",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-07-17T14:49:29+00:00"
+        },
+        {
+            "name": "doctrine/dbal",
+            "version": "2.13.7",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/dbal.git",
+                "reference": "6e22f6012b42d7932674857989fcf184e9e9b1c3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/dbal/zipball/6e22f6012b42d7932674857989fcf184e9e9b1c3",
+                "reference": "6e22f6012b42d7932674857989fcf184e9e9b1c3",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/cache": "^1.0|^2.0",
+                "doctrine/deprecations": "^0.5.3",
+                "doctrine/event-manager": "^1.0",
+                "ext-pdo": "*",
+                "php": "^7.1 || ^8"
+            },
+            "require-dev": {
+                "doctrine/coding-standard": "9.0.0",
+                "jetbrains/phpstorm-stubs": "2021.1",
+                "phpstan/phpstan": "1.3.0",
+                "phpunit/phpunit": "^7.5.20|^8.5|9.5.11",
+                "psalm/plugin-phpunit": "0.16.1",
+                "squizlabs/php_codesniffer": "3.6.2",
+                "symfony/cache": "^4.4",
+                "symfony/console": "^2.0.5|^3.0|^4.0|^5.0",
+                "vimeo/psalm": "4.16.1"
+            },
+            "suggest": {
+                "symfony/console": "For helpful console commands such as SQL execution and import of files."
+            },
+            "bin": [
+                "bin/doctrine-dbal"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\DBAL\\": "lib/Doctrine/DBAL"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                }
+            ],
+            "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
+            "homepage": "https://www.doctrine-project.org/projects/dbal.html",
+            "keywords": [
+                "abstraction",
+                "database",
+                "db2",
+                "dbal",
+                "mariadb",
+                "mssql",
+                "mysql",
+                "oci8",
+                "oracle",
+                "pdo",
+                "pgsql",
+                "postgresql",
+                "queryobject",
+                "sasql",
+                "sql",
+                "sqlanywhere",
+                "sqlite",
+                "sqlserver",
+                "sqlsrv"
+            ],
+            "funding": [
+                {
+                    "url": "https://www.doctrine-project.org/sponsorship.html",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://www.patreon.com/phpdoctrine",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-06T09:08:04+00:00"
+        },
+        {
+            "name": "doctrine/deprecations",
+            "version": "v0.5.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/deprecations.git",
+                "reference": "9504165960a1f83cc1480e2be1dd0a0478561314"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/deprecations/zipball/9504165960a1f83cc1480e2be1dd0a0478561314",
+                "reference": "9504165960a1f83cc1480e2be1dd0a0478561314",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1|^8.0"
+            },
+            "require-dev": {
+                "doctrine/coding-standard": "^6.0|^7.0|^8.0",
+                "phpunit/phpunit": "^7.0|^8.0|^9.0",
+                "psr/log": "^1.0"
+            },
+            "suggest": {
+                "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
+            "homepage": "https://www.doctrine-project.org/",
+            "time": "2021-03-21T12:59:47+00:00"
+        },
+        {
+            "name": "doctrine/event-manager",
+            "version": "1.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/event-manager.git",
+                "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/event-manager/zipball/41370af6a30faa9dc0368c4a6814d596e81aba7f",
+                "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1 || ^8.0"
+            },
+            "conflict": {
+                "doctrine/common": "<2.9@dev"
+            },
+            "require-dev": {
+                "doctrine/coding-standard": "^6.0",
+                "phpunit/phpunit": "^7.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Common\\": "lib/Doctrine/Common"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                },
+                {
+                    "name": "Marco Pivetta",
+                    "email": "ocramius@gmail.com"
+                }
+            ],
+            "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.",
+            "homepage": "https://www.doctrine-project.org/projects/event-manager.html",
+            "keywords": [
+                "event",
+                "event dispatcher",
+                "event manager",
+                "event system",
+                "events"
+            ],
+            "funding": [
+                {
+                    "url": "https://www.doctrine-project.org/sponsorship.html",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://www.patreon.com/phpdoctrine",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-05-29T18:28:51+00:00"
+        },
         {
             "name": "doctrine/inflector",
             "version": "2.0.3",
@@ -2384,6 +2713,7 @@
                 "mail",
                 "mailer"
             ],
+            "abandoned": "symfony/mailer",
             "time": "2019-11-12T09:31:26+00:00"
         },
         {

+ 14 - 0
public/css/style.css

@@ -2916,6 +2916,20 @@ body .vakata-context .vakata-context-separator>a {
     margin: 0;
 }
 
+.clause-label-part:not(:last-child)::after {
+    content: 'and';
+    position: absolute;
+    color: #299ab3;
+    font-size: 90%;
+    left: 100%;
+    width: 35px;
+    text-align: center;
+}
+.clause-label-part:not(:last-child) {
+    position: relative;
+    margin-right: 35px !important;
+}
+
 .phq .btn-select {
     padding: 5px 13px;
     border-radius: 100%;

+ 11 - 11
resources/views/app/patient/segment-templates/covid_follow-up/summary.blade.php

@@ -70,13 +70,13 @@ if (!!@$point->data) {
     <div class="mb-2">
         <label>Asked patient if they have already signed up for government supplied COVID-19 home diagnostic kits? Patient replied:</label>
         @if(@$contentData['ans_has_signed_up_for_gvt_covid_kit'] == 'yes')
-        {{segment_template_summary_value_display('Yes') }}
+        <?= segment_template_summary_value_display('Yes') ?>
         @elseif(@$contentData['ans_has_signed_up_for_gvt_covid_kit'] == 'no')
-        {{segment_template_summary_value_display('No') }}
+        <?= segment_template_summary_value_display('No') ?>
         @elseif(@$contentData['ans_has_signed_up_for_gvt_covid_kit'] == 'not_sure')
-        {{segment_template_summary_value_display('Not Sure') }}
+        <?= segment_template_summary_value_display('Not Sure') ?>
         @else
-        {{segment_template_summary_value_display('') }}
+        <?= segment_template_summary_value_display('') ?>
         @endif
     </div>
 
@@ -84,13 +84,13 @@ if (!!@$point->data) {
     <div class="mb-2">
         <label>Asked patient if we can apply on CovidTests.gov for them? Patient replied:</label>
         @if(@$contentData['ans_apply_gvt_covid_kit_for_patient'] == 'yes')
-        {{segment_template_summary_value_display('Yes') }}
+        <?= segment_template_summary_value_display('Yes') ?>
         @elseif(@$contentData['ans_apply_gvt_covid_kit_for_patient'] == 'no')
-        {{segment_template_summary_value_display('No') }}
+        <?= segment_template_summary_value_display('No') ?>
         @elseif(@$contentData['ans_apply_gvt_covid_kit_for_patient'] == 'not_sure')
-        {{segment_template_summary_value_display('Not Sure') }}
+        <?= segment_template_summary_value_display('Not Sure') ?>
         @else
-        {{segment_template_summary_value_display('') }}
+        <?= segment_template_summary_value_display('') ?>
         @endif
     </div>
     @endif
@@ -149,7 +149,7 @@ if (!!@$point->data) {
     <div class="mb-2">
         @if(@$contentData['ans_has_answered_all_covid_19_questions'] == 'yes')
             <label>Answered all questions relating to COVID-19.</label>
-            {{segment_template_summary_value_display('Patient verbalizes understanding.')}}
+            <?= segment_template_summary_value_display('Patient verbalizes understanding.') ?>
         @elseif(@$contentData['ans_has_answered_all_covid_19_questions'] == 'no')
 
         @endif
@@ -182,12 +182,12 @@ if (!!@$point->data) {
 
     <div class="mb-2">
         <label>Asked patient, how are you doing regarding stress? Patient replied:</label>
-        {{segment_template_summary_value_display(@$contentData['ans_how_patient_is_doing_regarding_stress'])}}
+        <?= segment_template_summary_value_display(@$contentData['ans_how_patient_is_doing_regarding_stress']) ?>
     </div>
 
     <div class="mb-2">
         <label>Conducted PHQ-2 with patient. Patient score is:</label>
-        {{segment_template_summary_value_display(@$contentData['total_phq2'])}}
+        <?= segment_template_summary_value_display(@$contentData['total_phq2']) ?>
     </div>
 
     @if((int) @$contentData['total_phq2'] > 3)

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

@@ -13,7 +13,7 @@
         @else
             <div class="mb-2 d-flex flex-wrap">
                 @foreach($line->lineClauses as $lineClause)
-                    <div class="border rounded px-2 py-1 mr-2 bg-light">{{$lineClause->clause_label}}
+                    <div class="border rounded px-2 py-1 mr-2 bg-light clause-label-part">{{$lineClause->clause_label}}
                         @if(count($lineClause->lineClauseArgs))
                             <?php
                             $argsLabel = [];
@@ -22,12 +22,129 @@
                                 $argsLabel[] = $argLabel;
                             }
                             ?>
-                            ({{implode(', ', $argsLabel)}})
+                            [{{implode(', ', $argsLabel)}}]
                         @endif
                     </div>
                 @endforeach
             </div>
-            <table class="table table-sm table-striped table-bordered">
+
+            <!-- filters -->
+            <a href="#" class="toggle-filters" onclick="$('#view-data-filters-form').toggle(); return false;">Toggle Filter</a>
+            <form action="" id="view-data-filters-form">
+                <input type="hidden" name="sort_by" value="{{request()->input('sort_by')}}">
+                <input type="hidden" name="sort_dir" value="{{request()->input('sort_dir')}}">
+                <table class="table table-sm table-striped table-bordered mb-0 mt-2 bg-aliceblue">
+                    <thead>
+                        <?php $lastColumnRendered = false; ?>
+                        @foreach($columns as $column)
+                            <tr>
+                                <th class="border-bottom-0 width-150px font-weight-normal text-nowrap {{request()->input($column['as'] . '_op') ? 'font-weight-bold text-info' : ''}}">{{$column['label']}}</th>
+
+                                <th class="border-bottom-0 width-150px p-0">
+                                    <select class="form-control form-control-sm min-width-unset border-0 rounded-0 shadow-none" name="{{$column['as']}}_op">
+                                        <option value="">-- select --</option>
+                                        <?php
+                                        switch($column['type']) {
+                                            case 'integer':
+                                            case 'bigint':
+                                            case 'decimal':
+                                                ?>
+                                                <option {{request()->input($column['as'] . '_op') === '=' ? 'selected' : ''}} value="=">Equal</option>
+                                                <option {{request()->input($column['as'] . '_op') === '!=' ? 'selected' : ''}} value="!=">Not equal</option>
+                                                <option {{request()->input($column['as'] . '_op') === '<' ? 'selected' : ''}} value="<">Lesser than</option>
+                                                <option {{request()->input($column['as'] . '_op') === '<=' ? 'selected' : ''}} value="<=">Lesser than or equal to</option>
+                                                <option {{request()->input($column['as'] . '_op') === '>' ? 'selected' : ''}} value=">">Greater than</option>
+                                                <option {{request()->input($column['as'] . '_op') === '>=' ? 'selected' : ''}} value=">=">Greater than or equal to</option>
+                                                <?php
+                                                break;
+                                            case 'string':
+                                            case 'text':
+                                            case 'varchar':
+                                                ?>
+                                                <option {{request()->input($column['as'] . '_op') === '=' ? 'selected' : ''}} value="=">Is</option>
+                                                <option {{request()->input($column['as'] . '_op') === '!=' ? 'selected' : ''}} value="!=">Is Not</option>
+                                                <option {{request()->input($column['as'] . '_op') === 'ILIKE' ? 'selected' : ''}} value="ILIKE">Contains</option>
+                                                <option {{request()->input($column['as'] . '_op') === 'NOT ILIKE' ? 'selected' : ''}} value="NOT ILIKE">Does not contain</option>
+                                                <?php
+                                                break;
+                                            case 'bool':
+                                            case 'boolean':
+                                                ?>
+                                                <option {{request()->input($column['as'] . '_op') === '=' ? 'selected' : ''}} value="=">Is</option>
+                                                <?php
+                                                break;
+                                            case 'date':
+                                            case 'datetime':
+                                                ?>
+                                                <option {{request()->input($column['as'] . '_op') === '=' ? 'selected' : ''}} value="=">Start/End</option>
+                                                <?php
+                                                break;
+                                        }
+                                        ?>
+                                    </select>
+                                </th>
+
+                                <th class="border-bottom-0 p-0">
+                                    <div class="d-flex align-items-center">
+                                    <?php
+                                    switch($column['type']) {
+                                        case 'integer':
+                                        case 'bigint':
+                                        case 'decimal':
+                                            ?>
+                                            <input type="number" name="{{$column['as']}}_value" value="{{request()->input($column['as'] . '_value')}}" class="min-width-unset shadow-none form-control form-control-sm border-0 rounded-0">
+                                            <?php
+                                            break;
+                                        case 'string':
+                                        case 'text':
+                                        case 'varchar':
+                                            ?>
+                                            <input type="text" name="{{$column['as']}}_value" value="{{request()->input($column['as'] . '_value')}}" class="min-width-unset shadow-none form-control form-control-sm border-0 rounded-0">
+                                            <?php
+                                            break;
+                                        case 'bool':
+                                        case 'boolean':
+                                            ?>
+                                            <select class="form-control form-control-sm min-width-unset shadow-none border-0 rounded-0" name="{{$column['as']}}_value">
+                                                <option {{request()->input($column['as'] . '_value') === 'TRUE' ? 'selected' : ''}} value="TRUE">True</option>
+                                                <option {{request()->input($column['as'] . '_value') === 'FALSE' ? 'selected' : ''}} value="FALSE">False</option>
+                                            </select>
+                                            <?php
+                                            break;
+                                        case 'date':
+                                        case 'datetime':
+                                            ?>
+                                            <input type="date" name="{{$column['as']}}_value_start" value="{{request()->input($column['as'] . '_value_start')}}" class="min-width-unset shadow-none width-200px form-control form-control-sm border-0 rounded-0" placeholder="Start">
+                                            <input type="date" name="{{$column['as']}}_value_end" value="{{request()->input($column['as'] . '_value_end')}}" class="min-width-unset shadow-none width-200px form-control form-control-sm border-top-0 border-bottom-0 rounded-0" placeholder="End">
+                                            <?php
+                                            break;
+                                    }
+                                    ?>
+                                    </div>
+                                </th>
+
+                                @if(!$lastColumnRendered)
+                                    <th class="border-bottom-0 width-200px align-top bg-white" rowspan="{{count($columns)}}">
+                                        <div class="d-flex align-items-center">
+                                            <button class="btn btn-sm btn-primary mr-2"
+                                                    onclick="return refreshDynamicStagPopup('{{route('practice-management.statTreeLines.view-data', compact('line'))}}?' + $('#view-data-filters-form').serialize())">
+                                                Filter
+                                            </button>
+                                            <button class="btn btn-sm btn-default border"
+                                                    onclick="$('#view-data-filters-form table').find('input, select').val(''); return refreshDynamicStagPopup('{{route('practice-management.statTreeLines.view-data', compact('line'))}}?' + $('#view-data-filters-form').serialize())">
+                                                Reset
+                                            </button>
+                                        </div>
+                                    </th>
+                                    <?php $lastColumnRendered = true; ?>
+                                @endif
+                            </tr>
+                        @endforeach
+                    </thead>
+                </table>
+            </form>
+
+            <table class="table table-sm table-striped table-bordered mt-3">
                 <thead>
                 <tr>
                     @foreach($columns as $column)
@@ -41,7 +158,15 @@
                 @foreach($rows as $row)
                     <tr>
                         @foreach($columns as $column)
-                            <td>{{ $row->{$column['as']} }}</td>
+                            <td>
+                                @if($column['type'] === 'date')
+                                    {{friendly_date($row->{$column['as']})}}
+                                @elseif($column['type'] === 'datetime')
+                                    {{friendly_date_time($row->{$column['as']})}}
+                                @else
+                                    {{ $row->{$column['as']} }}
+                                @endif
+                            </td>
                         @endforeach
                     </tr>
                 @endforeach

+ 68 - 14
resources/views/app/stat-tree/stat-trees/sub/edit.blade.php

@@ -399,6 +399,7 @@
                                                             <th class="border-bottom-0 width-30px">#</th>
                                                             <th class="border-bottom-0 w-35">Label</th>
                                                             <th class="border-bottom-0">Column</th>
+                                                            <th class="border-bottom-0">Type</th>
                                                             <th class="border-bottom-0 width-60px"></th>
                                                         </tr>
                                                         </thead>
@@ -595,7 +596,7 @@
                                                                     "action": function (obj) {
                                                                         openDynamicStagPopup('/practice-management/stat-tree-lines/view-data/' + node.data.uid,
                                                                             null,
-                                                                            node.data.displayLabel,
+                                                                            node.data.extendedLabel,
                                                                             false,
                                                                             'medium');
                                                                     },
@@ -709,6 +710,16 @@
                                                                             StatTree.createChildTreePermutations(selected);
                                                                         }
                                                                     }
+                                                                },
+                                                                "generate_all_us_states": {
+                                                                    "label": "<span class='text-sm'>Replicate for all US states</span>",
+                                                                    "_disabled": !StatTree.hasStateArg(node),
+                                                                    "action": function (obj) {
+                                                                        let selected = StatTree.selectedNode();
+                                                                        if(selected) {
+                                                                            StatTree.replicateForAllUSStates(selected);
+                                                                        }
+                                                                    }
                                                                 }
                                                             }
                                                         }
@@ -729,6 +740,40 @@
                                     }, 'json').then(hideMask);
                                 },
 
+                                hasStateArg: function(_node) {
+                                    if(_node.data.clause && _node.data.clause.args && _node.data.clause.args.length) {
+                                        let matched = _node.data.clause.args.filter(_x => _x.arg_text === 'state' && _x.field_type === 'text');
+                                        return !!(matched.length);
+                                    }
+                                    return false;
+                                },
+
+                                replicateForAllUSStates: function(_node) {
+                                    let node = this.el.jstree(true).get_json(_node), parent = this.el.jstree(true).get_node(_node.parent);
+                                    let states = ['AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'FL', 'GA', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY'];
+
+                                    node = this.getPasteBufferForNode(node);
+
+                                    // delete node
+                                    this.el.jstree(true).delete_node(_node);
+
+                                    // create new for each state
+                                    for (let i = 0; i < states.length; i++) {
+                                        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.text = stateNode.text.replace(/state:\s[A-Z]{2}/g, 'state: ' + states[i]);
+                                        stateNode.text = stateNode.text.replace(/\([0-9]+\)/g, '(…)');
+                                        this.el.jstree(true).create_node(parent, stateNode, 'last');
+                                    }
+
+                                    this.setDirty();
+
+                                },
+
                                 createChildTreePermutations: function(_node) {
 
                                     // permute: thanks: https://stackoverflow.com/a/37580979/921204
@@ -844,12 +889,11 @@
                                 },
 
                                 dropVisualize: function() {
-                                    console.log('redrawn')
                                     function calculateDropPercent(node, parent = null) {
                                         let realNode = StatTree.el.jstree(true).get_node(node.id);
                                         if(!realNode.data) return;
-                                        if(parent && parent.data.lastRefreshCount !== null) {
-                                            if(node.data.lastRefreshCount !== null) {
+                                        if(parent && parent.data.lastRefreshCount !== null && parent.data.lastRefreshCount !== -1) {
+                                            if(node.data.lastRefreshCount !== null && node.data.lastRefreshCount !== -1) {
                                                 realNode.data.dropPercent = (((parent.data.lastRefreshCount - node.data.lastRefreshCount) / parent.data.lastRefreshCount) * 100);
                                                 if(realNode.data.dropPercent) {
                                                     let element = StatTree.el.jstree(true).get_node(node.id, true), cssClass = '';
@@ -1111,8 +1155,9 @@
                                         for (let i = 0; i < columns.length; i++) {
                                             $('<tr/>')
                                                 .append($('<td/>').text(i + 1))
-                                                .append($('<td/>').text(columns[i].label))
+                                                .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].type))
                                                 .append(
                                                     $('<td/>')
                                                         .addClass('text-right text-nowrap')
@@ -1135,7 +1180,8 @@
                                     let columns = StatTree.getSelectedNodeColumns();
                                     columns.push({
                                         label: _data.label,
-                                        display_key: _data.text
+                                        display_key: _data.text,
+                                        type: _data.type
                                     });
                                     $(_input).val('').focus();
                                     StatTree.setSelectedNodeColumns(columns);
@@ -1213,6 +1259,21 @@
                                     return false;
                                 });
 
+                            $(document)
+                                .off('click', '.edit-column-label')
+                                .on('click', '.edit-column-label', function() {
+                                    let columns = StatTree.getSelectedNodeColumns();
+                                    let index = +($(this).attr('data-index'));
+                                    let value = window.prompt('New label:', columns[+($(this).attr('data-index'))].label || '');
+                                    if(value !== null) {
+                                        columns[index].label = value;
+                                        StatTree.setSelectedNodeColumns(columns);
+                                        StatTree.onSelected();
+                                        StatTree.setDirty();
+                                    }
+                                    return false;
+                                });
+
                             $(document)
                                 .off('click', '.clause-expand-all')
                                 .on('click', '.clause-expand-all', function() {
@@ -1277,14 +1338,7 @@
                                         window.alert('Cannot refresh counts while the tree has unsaved changes.');
                                         return;
                                     }
-                                    showMask();
-                                    $.post("{{ route('practice-management.api.statTree.refreshTreeCountQueries') }}", {
-                                        statTreeID: "{{ $statTree->id }}"
-                                    }, function (response) {
-                                        if(!hasResponseError(response)) {
-                                            fastReload();
-                                        }
-                                    }, 'json').then(hideMask);
+                                    fastReload();
                                     return false;
                                 });