diff --git a/.gitignore b/.gitignore index be05392..4c57c78 100644 --- a/.gitignore +++ b/.gitignore @@ -126,7 +126,5 @@ _modules/* /phpunit*.xml /public/.htaccess -#------------------------- -# Claude -#------------------------- -.claude \ No newline at end of file +.serena/ +.claude/ \ No newline at end of file diff --git a/app/Config/Routes.php b/app/Config/Routes.php index c95b6b5..05bd8f2 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -54,7 +54,10 @@ $routes->group('v2', ['filter' => 'auth'], function ($routes) { // Master Data - Tests & ValueSets $routes->get('master/tests', 'PagesController::masterTests'); - $routes->get('master/valuesets', 'PagesController::masterValueSets'); + + $routes->get('valueset', 'PagesController::valueSetLibrary'); + $routes->get('result/valueset', 'PagesController::resultValueSet'); + $routes->get('result/valuesetdef', 'PagesController::resultValueSetDef'); }); // Faker @@ -161,12 +164,22 @@ $routes->group('api', function ($routes) { $routes->delete('items/(:num)', 'ValueSetController::deleteItem/$1'); }); - $routes->group('valuesetdef', function ($routes) { - $routes->get('/', 'ValueSetDefController::index'); - $routes->get('(:num)', 'ValueSetDefController::show/$1'); - $routes->post('/', 'ValueSetDefController::create'); - $routes->put('(:num)', 'ValueSetDefController::update/$1'); - $routes->delete('(:num)', 'ValueSetDefController::delete/$1'); + $routes->group('result', function ($routes) { + $routes->group('valueset', function ($routes) { + $routes->get('/', 'Result\ResultValueSetController::index'); + $routes->get('(:num)', 'Result\ResultValueSetController::show/$1'); + $routes->post('/', 'Result\ResultValueSetController::create'); + $routes->put('(:num)', 'Result\ResultValueSetController::update/$1'); + $routes->delete('(:num)', 'Result\ResultValueSetController::delete/$1'); + }); + + $routes->group('valuesetdef', function ($routes) { + $routes->get('/', 'ValueSetDefController::index'); + $routes->get('(:num)', 'ValueSetDefController::show/$1'); + $routes->post('/', 'ValueSetDefController::create'); + $routes->put('(:num)', 'ValueSetDefController::update/$1'); + $routes->delete('(:num)', 'ValueSetDefController::delete/$1'); + }); }); // Counter diff --git a/app/Controllers/AreaGeoController.php b/app/Controllers/AreaGeoController.php index 2775469..c2f1797 100644 --- a/app/Controllers/AreaGeoController.php +++ b/app/Controllers/AreaGeoController.php @@ -32,16 +32,21 @@ class AreaGeoController extends BaseController { public function getProvinces() { $rows = $this->model->getProvinces(); - if (empty($rows)) { return $this->respond([ 'status' => 'success', 'message' => "data not found", 'data' => '' ], 200); } - return $this->respond([ 'status' => 'success', 'message'=> "Data fetched successfully", 'data' => $rows ], 200); + $transformed = array_map(function($row) { + return ['value' => $row['AreaGeoID'], 'label' => $row['AreaName']]; + }, $rows); + if (empty($transformed)) { return $this->respond([ 'status' => 'success', 'data' => [] ], 200); } + return $this->respond([ 'status' => 'success', 'data' => $transformed ], 200); } public function getCities() { $filter = [ 'Parent' => $this->request->getVar('Parent') ?? null ]; $rows = $this->model->getCities($filter); - - if (empty($rows)) { return $this->respond([ 'status' => 'success', 'message' => "data not found", 'data' => [] ], 200); } - return $this->respond([ 'status' => 'success', 'message'=> "Data fetched successfully", 'data' => $rows ], 200); + $transformed = array_map(function($row) { + return ['value' => $row['AreaGeoID'], 'label' => $row['AreaName']]; + }, $rows); + if (empty($transformed)) { return $this->respond([ 'status' => 'success', 'data' => [] ], 200); } + return $this->respond([ 'status' => 'success', 'data' => $transformed ], 200); } } diff --git a/app/Controllers/PagesController.php b/app/Controllers/PagesController.php index 9330317..5c3e457 100644 --- a/app/Controllers/PagesController.php +++ b/app/Controllers/PagesController.php @@ -155,13 +155,35 @@ class PagesController extends BaseController } /** - * Master Data - Value Sets + * Value Set Library - Read-only */ - public function masterValueSets() + public function valueSetLibrary() { - return view('v2/master/valuesets/valuesets_index', [ - 'pageTitle' => 'Value Sets', - 'activePage' => 'master-valuesets' + return view('v2/valueset/valueset_index', [ + 'pageTitle' => 'Value Set Library', + 'activePage' => 'valueset-library' + ]); + } + + /** + * Result Valueset - CRUD for valueset table + */ + public function resultValueSet() + { + return view('v2/result/valueset/resultvalueset_index', [ + 'pageTitle' => 'Result Valuesets', + 'activePage' => 'result-valueset' + ]); + } + + /** + * Result Valueset Definition - CRUD for valuesetdef table + */ + public function resultValueSetDef() + { + return view('v2/result/valuesetdef/resultvaluesetdef_index', [ + 'pageTitle' => 'Valueset Definitions', + 'activePage' => 'result-valuesetdef' ]); } diff --git a/app/Controllers/Result/ResultValueSetController.php b/app/Controllers/Result/ResultValueSetController.php new file mode 100644 index 0000000..21555f0 --- /dev/null +++ b/app/Controllers/Result/ResultValueSetController.php @@ -0,0 +1,144 @@ +dbModel = new ValueSetModel(); + } + + public function index() + { + $search = $this->request->getGet('search') ?? $this->request->getGet('param') ?? null; + $VSetID = $this->request->getGet('VSetID') ?? null; + + $rows = $this->dbModel->getValueSets($search, $VSetID); + + return $this->respond([ + 'status' => 'success', + 'data' => $rows + ], 200); + } + + public function show($id = null) + { + $row = $this->dbModel->getValueSet($id); + if (!$row) { + return $this->failNotFound("ValueSet item not found: $id"); + } + + return $this->respond([ + 'status' => 'success', + 'data' => $row + ], 200); + } + + public function create() + { + $input = $this->request->getJSON(true); + if (!$input) { + return $this->failValidationErrors(['Invalid JSON input']); + } + + $data = [ + 'SiteID' => $input['SiteID'] ?? 1, + 'VSetID' => $input['VSetID'] ?? null, + 'VOrder' => $input['VOrder'] ?? 0, + 'VValue' => $input['VValue'] ?? '', + 'VDesc' => $input['VDesc'] ?? '', + 'VCategory' => $input['VCategory'] ?? null + ]; + + if ($data['VSetID'] === null) { + return $this->failValidationErrors(['VSetID is required']); + } + + try { + $id = $this->dbModel->insert($data, true); + if (!$id) { + return $this->failValidationErrors($this->dbModel->errors()); + } + + $newRow = $this->dbModel->getValueSet($id); + return $this->respondCreated([ + 'status' => 'success', + 'message' => 'ValueSet item created', + 'data' => $newRow + ]); + } catch (\Exception $e) { + return $this->failServerError('Failed to create: ' . $e->getMessage()); + } + } + + public function update($id = null) + { + $input = $this->request->getJSON(true); + if (!$input) { + return $this->failValidationErrors(['Invalid JSON input']); + } + + $existing = $this->dbModel->getValueSet($id); + if (!$existing) { + return $this->failNotFound("ValueSet item not found: $id"); + } + + $data = []; + if (isset($input['VSetID'])) $data['VSetID'] = $input['VSetID']; + if (isset($input['VOrder'])) $data['VOrder'] = $input['VOrder']; + if (isset($input['VValue'])) $data['VValue'] = $input['VValue']; + if (isset($input['VDesc'])) $data['VDesc'] = $input['VDesc']; + if (isset($input['SiteID'])) $data['SiteID'] = $input['SiteID']; + if (isset($input['VCategory'])) $data['VCategory'] = $input['VCategory']; + + if (empty($data)) { + return $this->respond([ + 'status' => 'success', + 'message' => 'No changes to update', + 'data' => $existing + ], 200); + } + + try { + $updated = $this->dbModel->update($id, $data); + if (!$updated) { + return $this->failValidationErrors($this->dbModel->errors()); + } + + $newRow = $this->dbModel->getValueSet($id); + return $this->respond([ + 'status' => 'success', + 'message' => 'ValueSet item updated', + 'data' => $newRow + ], 200); + } catch (\Exception $e) { + return $this->failServerError('Failed to update: ' . $e->getMessage()); + } + } + + public function delete($id = null) + { + $existing = $this->dbModel->getValueSet($id); + if (!$existing) { + return $this->failNotFound("ValueSet item not found: $id"); + } + + try { + $this->dbModel->delete($id); + return $this->respond([ + 'status' => 'success', + 'message' => 'ValueSet item deleted' + ], 200); + } catch (\Exception $e) { + return $this->failServerError('Failed to delete: ' . $e->getMessage()); + } + } +} diff --git a/app/Controllers/TestsController.php b/app/Controllers/TestsController.php index 28fa87d..4312f69 100644 --- a/app/Controllers/TestsController.php +++ b/app/Controllers/TestsController.php @@ -158,12 +158,13 @@ class TestsController extends BaseController $row['refnum'] = array_map(function ($r) { return [ 'RefNumID' => $r['RefNumID'], - 'NumRefType' => $r['NumRefType'], - 'NumRefTypeVValue' => ValueSet::getLabel('numeric_ref_type', $r['NumRefType']), - 'RangeTypeVValue' => ValueSet::getLabel('range_type', $r['RangeType']), - 'SexVValue' => ValueSet::getLabel('gender', $r['Sex']), - 'LowSignVValue' => ValueSet::getLabel('math_sign', $r['LowSign']), - 'HighSignVValue' => ValueSet::getLabel('math_sign', $r['HighSign']), + 'NumRefTypeKey' => $r['NumRefType'], + 'NumRefType' => ValueSet::getLabel('numeric_ref_type', $r['NumRefType']), + 'RangeType' => ValueSet::getLabel('range_type', $r['RangeType']), + 'SexKey' => $r['Sex'], + 'Sex' => ValueSet::getLabel('gender', $r['Sex']), + 'LowSign' => ValueSet::getLabel('math_sign', $r['LowSign']), + 'HighSign' => ValueSet::getLabel('math_sign', $r['HighSign']), 'High' => $r['High'] !== null ? (int) $r['High'] : null, 'Flag' => $r['Flag'] ]; @@ -183,10 +184,10 @@ class TestsController extends BaseController $row['reftxt'] = array_map(function ($r) { return [ 'RefTxtID' => $r['RefTxtID'], - 'TxtRefType' => $r['TxtRefType'], - 'TxtRefTypeVValue' => ValueSet::getLabel('text_ref_type', $r['TxtRefType']), - 'Sex' => $r['Sex'], - 'SexVValue' => ValueSet::getLabel('gender', $r['Sex']), + 'TxtRefTypeKey' => $r['TxtRefType'], + 'TxtRefType' => ValueSet::getLabel('text_ref_type', $r['TxtRefType']), + 'SexKey' => $r['Sex'], + 'Sex' => ValueSet::getLabel('gender', $r['Sex']), 'AgeStart' => (int) $r['AgeStart'], 'AgeEnd' => (int) $r['AgeEnd'], 'RefTxt' => $r['RefTxt'], diff --git a/app/Controllers/ValueSetController.php b/app/Controllers/ValueSetController.php index 94a54a8..972476d 100644 --- a/app/Controllers/ValueSetController.php +++ b/app/Controllers/ValueSetController.php @@ -19,10 +19,19 @@ class ValueSetController extends \CodeIgniter\Controller public function index(?string $lookupName = null) { + $search = $this->request->getGet('search') ?? null; + if ($lookupName === null) { $all = ValueSet::getAll(); $result = []; foreach ($all as $name => $entry) { + if ($search) { + $nameLower = strtolower($name); + $searchLower = strtolower($search); + if (strpos($nameLower, $searchLower) === false) { + continue; + } + } $count = count($entry['values'] ?? []); $result[$name] = $count; } diff --git a/app/Database/Migrations/2026-01-01-000001_CreateLookups.php b/app/Database/Migrations/2026-01-01-000001_CreateValueSet.php similarity index 100% rename from app/Database/Migrations/2026-01-01-000001_CreateLookups.php rename to app/Database/Migrations/2026-01-01-000001_CreateValueSet.php diff --git a/app/Libraries/ValueSet.php b/app/Libraries/ValueSet.php index e1a2315..787988d 100644 --- a/app/Libraries/ValueSet.php +++ b/app/Libraries/ValueSet.php @@ -68,7 +68,9 @@ class ValueSet { foreach ($data as &$row) { foreach ($fieldMappings as $field => $lookupName) { if (isset($row[$field]) && $row[$field] !== null) { - $row[$field . 'Text'] = self::getLabel($lookupName, $row[$field]) ?? ''; + $keyValue = $row[$field]; + $row[$field . 'Key'] = $keyValue; + $row[$field] = self::getLabel($lookupName, $keyValue) ?? ''; } } } diff --git a/app/Models/Patient/PatientModel.php b/app/Models/Patient/PatientModel.php index 822df55..bd64106 100644 --- a/app/Models/Patient/PatientModel.php +++ b/app/Models/Patient/PatientModel.php @@ -44,7 +44,7 @@ class PatientModel extends BaseModel { $rows = $this->findAll(); $rows = ValueSet::transformLabels($rows, [ - 'Sex' => 'gender', + 'Sex' => 'sex', ]); return $rows; } @@ -81,7 +81,7 @@ class PatientModel extends BaseModel { unset($patient['Comment']); $patient = ValueSet::transformLabels([$patient], [ - 'Sex' => 'gender', + 'Sex' => 'sex', 'Country' => 'country', 'Race' => 'race', 'Religion' => 'religion', diff --git a/app/Views/v2/layout/main_layout.php b/app/Views/v2/layout/main_layout.php index aa81d9f..d33b57e 100644 --- a/app/Views/v2/layout/main_layout.php +++ b/app/Views/v2/layout/main_layout.php @@ -173,14 +173,39 @@ - +
Manage value set categories and their items
-Value Set Definitions
-Loading categories...
-| ID | -Category Name | -Items | -Actions | -
|---|---|---|---|
|
-
-
-
- No categories found - - |
- |||
| - - | -- - - | -- - | -
-
-
-
-
- |
-
- - - - - Select a category to view items - -
-Select a category
-Click on a category from the left panel to view and manage its items
-Loading items...
-| ID | -Value | -Description | -Order | -Actions | -
|---|---|---|---|---|
|
-
-
-
- No items found - - |
- ||||
| - - | -- - | -- - | -- - | -
-
-
-
-
- |
-