Skip to content

Commit

Permalink
patient resource list and card (#501)
Browse files Browse the repository at this point in the history
  • Loading branch information
dwradcliffe authored Aug 13, 2024
1 parent 7b7a005 commit 4642223
Show file tree
Hide file tree
Showing 18 changed files with 507 additions and 59 deletions.
3 changes: 3 additions & 0 deletions frontend/src/app/components/fhir-card/fhir-card.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {MedicationComponent} from './resources/medication/medication.component';
import {MedicationRequestComponent} from './resources/medication-request/medication-request.component';
import {ObservationComponent} from './resources/observation/observation.component';
import {OrganizationComponent} from './resources/organization/organization.component';
import {PatientComponent} from './resources/patient/patient.component';
import {PractitionerComponent} from './resources/practitioner/practitioner.component';
import {ProcedureComponent} from './resources/procedure/procedure.component';
import {FhirCardComponent} from './fhir-card/fhir-card.component';
Expand Down Expand Up @@ -67,6 +68,7 @@ import { ObservationVisualizationComponent } from './common/observation-visualiz
MedicationRequestComponent,
ObservationComponent,
OrganizationComponent,
PatientComponent,
PractitionerComponent,
ProcedureComponent,

Expand Down Expand Up @@ -108,6 +110,7 @@ import { ObservationVisualizationComponent } from './common/observation-visualiz
MedicationRequestComponent,
ObservationComponent,
OrganizationComponent,
PatientComponent,
PractitionerComponent,
ProcedureComponent,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {LocationComponent} from '../resources/location/location.component';
import {OrganizationComponent} from '../resources/organization/organization.component';
import {ObservationComponent} from '../resources/observation/observation.component';
import {EncounterComponent} from '../resources/encounter/encounter.component';
import {PatientComponent} from '../resources/patient/patient.component';


@Component({
Expand Down Expand Up @@ -152,6 +153,9 @@ export class FhirCardComponent implements OnInit, OnChanges {
case "Organization": {
return OrganizationComponent;
}
case "Patient": {
return PatientComponent;
}
case "Procedure": {
return ProcedureComponent;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
import { RouterTestingModule } from '@angular/router/testing';

import { ImmunizationComponent } from './immunization.component';
import {NgbCollapseModule} from '@ng-bootstrap/ng-bootstrap';
import {RouterTestingModule} from '@angular/router/testing';

describe('ImmunizationComponent', () => {
let component: ImmunizationComponent;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
import {FhirCardComponentInterface} from '../../fhir-card/fhir-card-component-interface';
import {Router, RouterModule} from '@angular/router';
import {ImmunizationModel} from '../../../../../lib/models/resources/immunization-model';
import {TableRowItem, TableRowItemDataType} from '../../common/table/table-row-item';
import { CommonModule } from "@angular/common";
import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { Router, RouterModule } from '@angular/router';
import { NgbCollapseModule } from "@ng-bootstrap/ng-bootstrap";
import * as _ from "lodash";
import {NgbCollapseModule} from "@ng-bootstrap/ng-bootstrap";
import {CommonModule} from "@angular/common";
import {BadgeComponent} from "../../common/badge/badge.component";
import {TableComponent} from "../../common/table/table.component";
import { ImmunizationModel } from '../../../../../lib/models/resources/immunization-model';
import { BadgeComponent } from "../../common/badge/badge.component";
import { TableRowItem, TableRowItemDataType } from '../../common/table/table-row-item';
import { TableComponent } from "../../common/table/table.component";
import { FhirCardComponentInterface } from '../../fhir-card/fhir-card-component-interface';

@Component({
standalone: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<div class="patient-card card">
<div class="card-header bg-fasten-purple">
<h2 class="mb-0 text-white">{{ displayModel.patient_name }}</h2>
</div>
<div class="card-body">
<div class="row">
<!-- Basic Information -->
<div class="col-md-6 mb-4">
<h3 class="h5 mb-3">Basic Information</h3>
<ul class="list-unstyled">
<li><strong>Date of Birth:</strong> {{ displayModel.patient_birthdate | date:'mediumDate' }}</li>
<li><strong>Age:</strong> {{ displayModel.patient_age }}</li>
<li><strong>Gender:</strong> {{ displayModel.patient_gender | titlecase }}</li>
<li><strong>Birth Sex:</strong> {{ displayModel.birth_sex }}</li>
<li><strong>Marital Status:</strong> {{ displayModel.marital_status }}</li>
<li><strong>Race:</strong> {{ displayModel.race }}</li>
<li><strong>Ethnicity:</strong> {{ displayModel.ethnicity }}</li>
</ul>
</div>

<!-- Contact Information -->
<div class="col-md-6 mb-4">
<h3 class="h5 mb-3">Contact Information</h3>
<ul class="list-unstyled">
<li><strong>Address:</strong>
<address class="mb-0 ml-3">
<div *ngFor="let line of displayModel.patient_address">{{line}}</div>
</address>
</li>
<li><strong>Phone{{ displayModel.patient_phones.length > 0 ? '' : 's' }}:</strong>
<ul class="list-unstyled ml-3">
<li *ngFor="let phone of displayModel.patient_phones">{{ phone.value }} ({{ phone.use }})</li>
</ul>
</li>
<li><strong>Language{{ displayModel.communication_languages.length > 0 ? '' : 's' }}:</strong>
<span *ngFor="let language of displayModel.communication_languages; let last = last">
{{ language.display }}{{last ? '' : ', '}}
</span>
</li>
</ul>
</div>

<!-- Additional Information -->
<div class="col-md-6 mb-4">
<h3 class="h5 mb-3">Additional Information</h3>
<ul class="list-unstyled">
<li><strong>Mother's Maiden Name:</strong> {{ displayModel.mothers_maiden_name }}</li>
<li><strong>Birth Place:</strong> {{ displayModel.birth_place }}</li>
<li><strong>Multiple Birth:</strong> {{ displayModel.multiple_birth ? 'Yes' : 'No' }}</li>
</ul>
</div>

<!-- Identifiers -->
<div class="col-md-6 mb-4">
<h3 class="h5 mb-3">Identifiers</h3>
<ul class="list-unstyled">
<li *ngIf="displayModel.mrn"><strong>Medical Record Number:</strong> <code class="ml-2 text-muted">{{ displayModel.mrn }}</code></li>
<li *ngIf="displayModel.ssn"><strong>SSN:</strong> <code class="ml-2 text-muted">{{ displayModel.ssn }}</code></li>
</ul>
<ng-container *ngIf="displayModel.identifiers && displayModel.identifiers.length > 0">
<h4 class="h6 mt-3">Other Identifiers:</h4>
<ul class="list-unstyled ml-3">
<li *ngFor="let identifier of displayModel.identifiers">
<strong>{{ identifier.type }}:</strong> <code class="ml-2 text-muted">{{ identifier.value }}</code>
</li>
</ul>
</ng-container>
</div>


</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.bg-fasten-purple {
background-color: #5b47fb;
}

.patient-card {
border: 1px solid #ccc;
border-radius: 4px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);

h2 {
margin-top: 0;
margin-bottom: 15px;
font-size: 1.5rem;
}

.patient-info {
p {
margin: 5px 0;
}

strong {
font-weight: bold;
margin-right: 5px;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';

import { PatientModel } from 'src/lib/models/resources/patient-model';
import { PatientComponent } from './patient.component';

describe('PatientComponent', () => {
let component: PatientComponent;
let fixture: ComponentFixture<PatientComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ PatientComponent, NgbCollapseModule, RouterTestingModule ]
})
.compileComponents();

fixture = TestBed.createComponent(PatientComponent);
component = fixture.componentInstance;
component.displayModel = new PatientModel({});
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { Router, RouterModule } from '@angular/router';
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
import { PatientModel } from '../../../../../lib/models/resources/patient-model';
import { BadgeComponent } from '../../common/badge/badge.component';
import { TableComponent } from '../../common/table/table.component';
import { FhirCardComponentInterface } from '../../fhir-card/fhir-card-component-interface';

@Component({
standalone: true,
imports: [NgbCollapseModule, CommonModule, BadgeComponent, TableComponent, RouterModule],
selector: 'fhir-patient',
templateUrl: './patient.component.html',
styleUrls: ['./patient.component.scss']
})
export class PatientComponent implements OnInit, FhirCardComponentInterface {
@Input() displayModel: PatientModel;
@Input() showDetails: boolean = true;
@Input() isCollapsed: boolean = false;

constructor(public changeRef: ChangeDetectorRef, public router: Router) { }

ngOnInit(): void {
}

markForCheck(){
this.changeRef.markForCheck()
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div>
<ngx-datatable
#table
class="bootstrap"
class="bootstrap fhir-resource-datatable"
[columns]="columns"
[columnMode]="ColumnMode.force"
[headerHeight]="50"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {Component} from '@angular/core';
import {attributeXTime} from './utils';
import {GenericColumnDefn, DatatableGenericResourceComponent} from './datatable-generic-resource.component';

@Component({
selector: 'fhir-datatable-patient',
templateUrl: './datatable-generic-resource.component.html',
styleUrls: ['./datatable-generic-resource.component.scss']
})
export class DatatablePatientComponent extends DatatableGenericResourceComponent {
columnDefinitions: GenericColumnDefn[] = [
{ title: 'Name', versions: '*', format: 'humanName', getter: p => p.name?.[0] },
{ title: 'DOB', versions: '*', getter: p => p.birthDate, format: 'date' },
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ export function getPath(obj, path = ""): string {
}

export const FORMATTERS = {
age: (patientDOB: number|string): number => {
if (patientDOB == null) { return NaN; }
const dob = typeof patientDOB === 'string' ? new Date(patientDOB) : new Date(patientDOB);
const today = new Date();
let age = today.getFullYear() - dob.getFullYear();
const monthDiff = today.getMonth() - dob.getMonth();

if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < dob.getDate())) {
age--;
}

return age;
},
date: (str) => str ? moment(str).format('YYYY-MM-DD') : '',
time: (str) => str ? moment(str).format('HH:mm') : '',
dateTime: (str) => str ? moment(str).format('YYYY-MM-DD - h:mm a') : '',
Expand All @@ -24,15 +37,13 @@ export const FORMATTERS = {
if(codeableConcept.text) return codeableConcept.text
return codeableConcept.coding && codeableConcept.coding[0] ? `${codeableConcept.coding[0].code}: ${codeableConcept.coding[0].display ? codeableConcept.coding[0].display : ''}` : ''
},
address: (address) => {
if(!address) return ''
address: (address): Array<string> => {
if(!address) return []
var addressParts = []
if(address.line) addressParts.push(address.line.join(', '))
if(address.city) addressParts.push(address.city)
if(address.state) addressParts.push(address.state)
if(address.postalCode) addressParts.push(address.postalCode)
if(address.line) addressParts.push(...address.line)
addressParts.push(`${address.city}, ${address.state} ${address.postalCode}`)
if(address.country) addressParts.push(address.country)
return addressParts.join(', ')
return addressParts
},
humanName: (humanName) => {
if(!humanName) return ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {DatatableMedicationRequestComponent} from './datatable-generic-resource/
import {DatatableNutritionOrderComponent} from './datatable-generic-resource/datatable-nutrition-order.component';
import {DatatableObservationComponent} from './datatable-generic-resource/datatable-observation.component';
import {DatatableOrganizationComponent} from './datatable-generic-resource/datatable-organization.component';
import {ListPatientComponent} from './list-patient/list-patient.component';
import {DatatablePatientComponent} from './datatable-generic-resource/datatable-patient.component';
import {DatatablePractitionerComponent} from './datatable-generic-resource/datatable-practitioner.component';
import {DatatableProcedureComponent} from './datatable-generic-resource/datatable-procedure.component';
import {DatatableServiceRequestComponent} from './datatable-generic-resource/datatable-service-request.component';
Expand Down Expand Up @@ -65,7 +65,7 @@ import {NgxDatatableModule} from '@swimlane/ngx-datatable';
DatatableNutritionOrderComponent,
DatatableObservationComponent,
DatatableOrganizationComponent,
ListPatientComponent,
DatatablePatientComponent,
DatatablePractitionerComponent,
DatatableProcedureComponent,
DatatableServiceRequestComponent,
Expand Down Expand Up @@ -99,7 +99,7 @@ import {NgxDatatableModule} from '@swimlane/ngx-datatable';
DatatableNutritionOrderComponent,
DatatableObservationComponent,
DatatableOrganizationComponent,
ListPatientComponent,
DatatablePatientComponent,
DatatablePractitionerComponent,
DatatableProcedureComponent,
DatatableServiceRequestComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {DatatableMedicationRequestComponent} from '../datatable-generic-resource
import {DatatableNutritionOrderComponent} from '../datatable-generic-resource/datatable-nutrition-order.component';
import {DatatableObservationComponent} from '../datatable-generic-resource/datatable-observation.component';
import {DatatableOrganizationComponent} from '../datatable-generic-resource/datatable-organization.component';
import {DatatablePatientComponent} from '../datatable-generic-resource/datatable-patient.component';
import {DatatablePractitionerComponent} from '../datatable-generic-resource/datatable-practitioner.component';
import {DatatableProcedureComponent} from '../datatable-generic-resource/datatable-procedure.component';
import {DatatableServiceRequestComponent} from '../datatable-generic-resource/datatable-service-request.component';
Expand Down Expand Up @@ -162,6 +163,9 @@ export class FhirDatatableComponent implements OnInit, OnChanges {
case "Organization": {
return DatatableOrganizationComponent;
}
case "Patient": {
return DatatablePatientComponent;
}
case "Practitioner": {
return DatatablePractitionerComponent;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { HttpClient } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { HTTP_CLIENT_TOKEN } from '../../dependency-injection';

import { FormRequestHealthSystemComponent } from './form-request-health-system.component';

Expand All @@ -8,7 +13,15 @@ describe('FormRequestHealthSystemComponent', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FormRequestHealthSystemComponent ]
declarations: [ FormRequestHealthSystemComponent ],
imports: [HttpClientTestingModule, FormsModule],
providers: [
NgbActiveModal,
{
provide: HTTP_CLIENT_TOKEN,
useClass: HttpClient,
},
]
})
.compileComponents();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { Component, OnInit } from '@angular/core';
import {NgbActiveModal, NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {SupportRequest} from '../../models/fasten/support-request';
import {FormRequestHealthSystem} from '../../models/fasten/form-request-health-system';
import {environment} from '../../../environments/environment';
import {versionInfo} from '../../../environments/versions';
import {FastenApiService} from '../../services/fasten-api.service';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { FormRequestHealthSystem } from '../../models/fasten/form-request-health-system';
import { FastenApiService } from '../../services/fasten-api.service';

@Component({
selector: 'app-form-request-health-system',
Expand Down
Loading

0 comments on commit 4642223

Please sign in to comment.