Skip to content

Commit

Permalink
clean up filters
Browse files Browse the repository at this point in the history
  • Loading branch information
sevenreup committed Jul 30, 2024
1 parent 4b4df81 commit d5185d7
Show file tree
Hide file tree
Showing 11 changed files with 244 additions and 112 deletions.
36 changes: 20 additions & 16 deletions src/app/(dashboard)/patients/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,38 @@

import { fhirServer } from "@/lib/api/axios";
import { FilterFormData } from "@/model/filters";
import format from "string-template";
import { createPatient } from "@/lib/fhir/patient";
import { fetchLocations, generteBaseFilter } from "@/lib/api/server";
import { createPatientFilters } from "../stats/filters";

export async function fetchRequiredData() {
const locations = await fetchLocations();
const locationMap = new Map(
locations.map((location) => [location.id, location.name])
);
return {
locations,
locationMap,
};
}

export async function fetchData(formData: FormData) {
try {
const data = JSON.parse(
formData.getAll("data")[0] as string
) as FilterFormData;

const queries: string[] = [];

data.filters.forEach((filter) => {
const template = filter.template;

const values: Record<string, any> = {};

filter.params.forEach((param) => {
values[param.name] = encodeURIComponent(param.value as any);
});

console.log({ template, values });
const { rawDate, baseFilter } = generteBaseFilter(data.filters);

queries.push(format(template, values));
const query = createPatientFilters(undefined, rawDate, baseFilter, {
hasCount: false,
onlyActive: true,
formatUrl: true,
});

console.log(queries);
console.log(query);

const res = await fhirServer.get("/Patient?" + queries, {});
const res = await fhirServer.get(query);
return (
res.data.entry?.map((entry: any) => createPatient(entry.resource)) ?? []
);
Expand Down
45 changes: 26 additions & 19 deletions src/app/(dashboard)/patients/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,56 @@ import { Patient } from "@/lib/fhir/types";
import Link from "next/link";
import React from "react";

type Props = {};
type Props = {
locationMap: Map<string, string>;
};

const Content = (props: Props) => {
const Content = ({ locationMap }: Props) => {
const { data } = useGenericContext();
const patients = data as Patient[];
return (
<div>
<div className="flex flex-col gap-2">
{patients.map((patient) => (
<div key={patient.name} className="card w-full bg-base-100 shadow-xl">
<div className="card-body">
<h2 className="card-title">
<span>{patient.name}</span>
<span>
{patient.name} ({locationMap.get(patient.locationId) ?? "NA"})
</span>
<Link href={`/patients/${patient.id}`}>
<a className="btn btn-primary">View</a>{" "}
</Link>
</h2>
<div className="flex flex-col gap-2">
<span className="badge">
ART/HCC Number: {patient.identifier}
</span>
<span className="badge">Gender: {patient.gender}</span>
<span className="badge">BirthDate: {patient.birthDate}</span>
<div className="flex flex-row gap-2 flex-wrap">
<span className="badge">
ART/HCC Number: {patient.identifier}
</span>
<span className="badge">Active: {patient.active}</span>
<span className="badge">Gender: {patient.gender}</span>
<span className="badge">BirthDate: {patient.birthDate}</span>
</div>
{patient.phoneNumbers.map((value, index) => (
<div key={value.number} className="flex flex-row gap-2">
<span className="badge">
Phone {index + 1}: {value.number}
Phone {index + 1}: {value.number} -- Owner: {value.owner}
</span>
<span className="badge">Owner: {value.owner}</span>
</div>
))}
<span className="badge">Active: {patient.active}</span>
{patient.address.map((address, index) => (
<div key={address.facility} className="flex flex-row gap-2">
<span className="badge">Facility: {address.facility}</span>
<span className="badge">Location: {address.facility}</span>
<span className="badge">Physical: {address.physical}</span>
</div>
))}
<span className="badge">
Registration Date: {patient.registrationDate}
</span>
<span className="badge">
Registered By: {patient.registratedBy}
</span>
<div className="flex flex-row gap-2 flex-wrap">
<span className="badge">
Registration Date: {patient.registrationDate}
</span>
<span className="badge">
Registered By: {patient.registratedBy}
</span>
</div>
</div>
</div>
</div>
Expand Down
6 changes: 4 additions & 2 deletions src/app/(dashboard)/patients/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fetchData } from "./actions";
import { fetchData, fetchRequiredData } from "./actions";
import FilterToolbar from "../../../components/filters/toolbar";
import { patientFilters } from "@/model/filters";
import Content from "./content";
Expand All @@ -8,14 +8,16 @@ export default async function Page({
}: {
searchParams: { q: string };
}) {
const data = await fetchRequiredData();
return (
<main className="container mt-6">
<FilterToolbar
action={fetchData}
filters={patientFilters}
defaultItem={[]}
prefillData={data}
>
<Content />
<Content locationMap={data.locationMap} />
</FilterToolbar>
</main>
);
Expand Down
47 changes: 12 additions & 35 deletions src/app/(dashboard)/stats/actions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use server";

import { fetchBundle } from "@/lib/fhir/bundle";
import { LocationData, SummaryItem } from "@/lib/models/types";
import { SummaryItem } from "@/lib/models/types";
import { FilterFormData } from "@/model/filters";
import { fhirR4 } from "@smile-cdr/fhirts";
import { fixDate } from "./model";
Expand All @@ -10,16 +10,10 @@ import {
createQuestionnaireResponseFilters,
} from "./filters";
import { eachDayOfInterval } from "@/lib/utils";
import { fetchLocations } from "@/lib/api/server";

export async function fetchRequiredData() {
const locationQuery = paramGenerator("/Location", {
_count: 100,
type: "https://d-tree.org/fhir/location-type|facility",
});
var bundle = await fetchBundle([locationQuery]);
const locations = getLocationData(
bundle.entry?.[0]?.resource as fhirR4.Bundle
);
const locations = await fetchLocations();
return {
locations,
};
Expand Down Expand Up @@ -99,9 +93,15 @@ export async function fetchData(formData: FormData) {
baseFilter,
false
),
createPatientFilters(["newly-diagnosed-client"], null, baseFilter, true),
createPatientFilters(["client-already-on-art"], null, baseFilter, true),
createPatientFilters(["exposed-infant"], null, baseFilter, true),
createPatientFilters(["newly-diagnosed-client"], null, baseFilter, {
hasCount: true,
}),
createPatientFilters(["client-already-on-art"], null, baseFilter, {
hasCount: true,
}),
createPatientFilters(["exposed-infant"], null, baseFilter, {
hasCount: true,
}),
createQuestionnaireResponseFilters(
"patient-finish-visit",
rawDate,
Expand Down Expand Up @@ -181,20 +181,6 @@ export async function fetchData(formData: FormData) {
};
}

const getLocationData = (bundle: fhirR4.Bundle | undefined): LocationData[] => {
if (bundle == undefined) {
return [];
}
return (
bundle.entry?.map((entry) => {
return {
id: entry.resource?.id ?? "",
name: (entry.resource as fhirR4.Location)?.name ?? "",
};
}) ?? []
);
};

const getResults = (
bundle: fhirR4.Bundle | undefined,
summary: string[],
Expand Down Expand Up @@ -231,12 +217,3 @@ const getResults = (
}) ?? []
);
};

const paramGenerator = (
resources: string,
params: Record<string, string | number | string>
) => {
return `${resources}?${Object.keys(params)
.map((key) => `${key}=${params[key]}`)
.join("&")}`;
};
24 changes: 17 additions & 7 deletions src/app/(dashboard)/stats/filters.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { fhirR4 } from "@smile-cdr/fhirts";
import { QueryParam, fixDate } from "./model";
import { QueryParam } from "./model";
import { format } from "date-fns";

type PatientType =
Expand Down Expand Up @@ -50,13 +49,24 @@ export const createPatientFilters = (
types: PatientType[] | undefined = undefined,
date: string | string[] | null,
baseFilter: Record<string, string>[],
onlyActive = false
options: {
onlyActive?: boolean;
hasCount?: boolean;
formatUrl?: boolean;
} = {
hasCount: true,
onlyActive: false,
formatUrl: false,
}
) => {
const query = new QueryParam({
_summary: "count",
});
const query = new QueryParam({}, options.formatUrl);

if (options.hasCount == true) {
query.add("_summary", "count");
}

query.fromArray(baseFilter);
if (onlyActive) {
if (options.onlyActive == true) {
query.add("active", true);
}
query.remove("date");
Expand Down
11 changes: 8 additions & 3 deletions src/app/(dashboard)/stats/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ export const fixDate = (date: string | string[]) => {

export class QueryParam {
queries: Map<string, string> = new Map();
constructor(values: Record<string, string>) {
encodeUrl: boolean = false;

constructor(values: Record<string, string>, encodeUrl: boolean = false) {
this.from(values);
this.encodeUrl = encodeUrl;
}

add(key: string, value: any) {
Expand Down Expand Up @@ -49,9 +52,11 @@ export class QueryParam {
const query = Array.from(this.queries)
.map(([key, value]) => {
if (key.includes("[")) {
return `${key.split("[")[0]}=${value}`;
return `${key.split("[")[0]}=${
this.encodeUrl ? encodeURIComponent(value) : value
}`;
}
return `${key}=${value}`;
return `${key}=${this.encodeUrl ? encodeURIComponent(value) : value}`;
})
.join("&");
return `${resources}?${query}`;
Expand Down
99 changes: 99 additions & 0 deletions src/lib/api/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { fetchBundle } from "../fhir/bundle";
import { eachDayOfInterval, paramGenerator } from "../utils";
import { fhirR4 } from "@smile-cdr/fhirts";
import { LocationData, SummaryItem } from "@/lib/models/types";
import { FilterFormItem } from "@/model/filters";
import { fixDate } from "@/app/(dashboard)/stats/model";
import format from "string-template";

export async function fetchLocations() {
const locationQuery = paramGenerator("/Location", {
_count: 100,
type: "https://d-tree.org/fhir/location-type|facility",
});
var bundle = await fetchBundle([locationQuery]);
const locations = getLocationData(
bundle.entry?.[0]?.resource as fhirR4.Bundle
);
return locations;
}

export const generteBaseFilter = (filters: FilterFormItem[]) => {
let rawDate: string | string[] | null = null;

const baseFilter = filters.map((filter) => {
const temp: Record<string, string> = {};

if (filter.template == "_tag_location") {
const template = `http://smartregister.org/fhir/location-tag|${
filter.params[0].value ?? ""
}`;
temp["_tag"] = template;
} else if (filter.template == "date") {
rawDate =
filter.params.find((e) => e.name == "date")?.value?.split("T")[0] ??
null;
} else if (filter.template == "dateRange") {
const value = filter.params[0].value;
if (value) {
const { from, to } = value as any;
console.log(from, to);

if (from && to) {
const start = new Date(from.split("T")[0]);
const end = new Date(to.split("T")[0]);
console.log({ start, end });

rawDate = eachDayOfInterval({
start,
end,
}).map((e) => {
console.log(e);

return e.toISOString().split("T")[0];
});
} else if (from) {
rawDate = [from.split("T")[0]];
}
}
} else {
if (filter.template.includes("={")) {
const values: Record<string, any> = {};

filter.params.forEach((param) => {
values[param.name] = encodeURIComponent(param.value as any);
});

const value = format(filter.template, values);
temp[value.split("=")[0]] = value.split("=")[1];
} else {
temp[filter.template] = filter.params[0].value ?? "";
}
}

return temp;
});

if (rawDate) {
rawDate = fixDate(rawDate);
}

return {
baseFilter,
rawDate,
};
};

const getLocationData = (bundle: fhirR4.Bundle | undefined): LocationData[] => {
if (bundle == undefined) {
return [];
}
return (
bundle.entry?.map((entry) => {
return {
id: entry.resource?.id ?? "",
name: (entry.resource as fhirR4.Location)?.name ?? "",
};
}) ?? []
);
};
Loading

0 comments on commit d5185d7

Please sign in to comment.