Skip to content

Commit

Permalink
Merge branch 'develop' into encounter-info-card
Browse files Browse the repository at this point in the history
  • Loading branch information
amjithtitus09 authored Feb 27, 2025
2 parents 179a98b + 6a6d67a commit 95a277d
Show file tree
Hide file tree
Showing 31 changed files with 941 additions and 528 deletions.
3 changes: 3 additions & 0 deletions .example.env
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ REACT_ALLOWED_LOCALES="en,hi,ta,ml,mr,kn"

# ISO 3166-1 Alpha-2 code for the default country code (default: "IN")
REACT_DEFAULT_COUNTRY=

# Maps fallback URL template (default:"https://www.openstreetmap.org/?mlat={lat}&mlon={long}&zoom=15")
REACT_MAPS_FALLBACK_URL_TEMPLATE=
4 changes: 4 additions & 0 deletions care.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ const careConfig = {
defaultEncounterType: (env.REACT_DEFAULT_ENCOUNTER_TYPE ||
"hh") as EncounterClass,

mapFallbackUrlTemplate:
env.REACT_MAPS_FALLBACK_URL_TEMPLATE ||
"https://www.openstreetmap.org/?mlat={lat}&mlon={long}&zoom=15",

gmapsApiKey:
env.REACT_GMAPS_API_KEY || "AIzaSyDsBAc3y7deI5ZO3NtK5GuzKwtUzQNJNUk",

Expand Down
3 changes: 3 additions & 0 deletions public/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1510,6 +1510,7 @@
"next_sessions": "Next Sessions",
"next_week_short": "Next wk",
"no": "No",
"no_active_medication_recorded": "No Active Medication Recorded",
"no_address_provided": "No address provided",
"no_allergies_recorded": "No allergies recorded",
"no_appointments": "No appointments found",
Expand Down Expand Up @@ -1551,6 +1552,7 @@
"no_log_update_delta": "No changes since previous log update",
"no_log_updates": "No log updates found",
"no_medical_history_available": "No Medical History Available",
"no_medication_recorded": "No Medication Recorded",
"no_medications": "No Medications",
"no_medications_found_for_this_encounter": "No medications found for this encounter.",
"no_medications_to_administer": "No medications to administer",
Expand Down Expand Up @@ -2132,6 +2134,7 @@
"select_policy_to_add_items": "Select a Policy to Add Items",
"select_practitioner": "Select Practitioner",
"select_previous": "Select Previous Fields",
"show_on_map": "Show on Map",
"select_priority": "Select Priority",
"select_prn_reason": "Select reason for PRN",
"select_register_patient": "Select/Register Patient",
Expand Down
12 changes: 11 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,23 @@ import AuthUserProvider from "@/Providers/AuthUserProvider";
import HistoryAPIProvider from "@/Providers/HistoryAPIProvider";
import Routers from "@/Routers";
import { handleHttpError } from "@/Utils/request/errorHandler";
import { HTTPError } from "@/Utils/request/types";

import { PubSubProvider } from "./Utils/pubsubContext";

const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 2,
retry: (failureCount, error) => {
// Only retry network errors or server errors (502, 503, 504) up to 3 times
if (
error.message === "Network Error" ||
(error instanceof HTTPError && [502, 503, 504].includes(error.status))
) {
return failureCount < 3;
}
return false;
},
refetchOnWindowFocus: false,
},
},
Expand Down
8 changes: 6 additions & 2 deletions src/Routers/routes/ConsultationRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ const consultationRoutes: AppRoutes = {
/>
),
"/facility/:facilityId/patient/:patientId/encounter/:encounterId/treatment_summary":
({ facilityId, encounterId }) => (
<TreatmentSummary facilityId={facilityId} encounterId={encounterId} />
({ facilityId, encounterId, patientId }) => (
<TreatmentSummary
facilityId={facilityId}
encounterId={encounterId}
patientId={patientId}
/>
),
"/facility/:facilityId/patient/:patientId/encounter/:encounterId/questionnaire":
({ facilityId, encounterId, patientId }) => (
Expand Down
11 changes: 11 additions & 0 deletions src/Utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import careConfig from "@careConfig";
import { differenceInMinutes, format } from "date-fns";
import { toPng } from "html-to-image";

Expand Down Expand Up @@ -94,6 +95,16 @@ export const isUserOnline = (user: { last_login: DateLike }) => {
: false;
};

export const isAndroidDevice = /android/i.test(navigator.userAgent);

export const getMapUrl = (latitude: string, longitude: string) => {
return isAndroidDevice
? `geo:${latitude},${longitude}`
: careConfig.mapFallbackUrlTemplate
.replace("{lat}", latitude)
.replace("{long}", longitude);
};

const getRelativeDateSuffix = (abbreviated: boolean) => {
return {
day: abbreviated ? "d" : "days",
Expand Down
66 changes: 66 additions & 0 deletions src/components/Common/PrintTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { t } from "i18next";

import { cn } from "@/lib/utils";

import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";

type HeaderRow = {
key: string;
width?: number;
};

type TableRowType = Record<string, string | undefined>;
interface GenericTableProps {
headers: HeaderRow[];
rows: TableRowType[] | undefined;
}

export default function PrintTable({ headers, rows }: GenericTableProps) {
return (
<div className="overflow-hidden rounded-lg border border-gray">
<Table className="w-full">
<TableHeader>
<TableRow className="bg-transparent hover:bg-transparent divide-x divide-gray border-b-gray">
{headers.map(({ key, width }, index) => (
<TableHead
className={cn(
index == 0 && "first:rounded-l-md",
"h-auto py-1 pl-2 pr-2 text-black text-center ",
width && `w-${width}`,
)}
key={key}
>
{t(key)}
</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{!!rows &&
rows.map((row, index) => (
<TableRow
key={index}
className="bg-transparent hover:bg-transparent divide-x divide-gray"
>
{headers.map(({ key }) => (
<TableCell
className="break-words whitespace-normal text-center"
key={key}
>
{row[key] || "-"}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,23 @@ function StructuredResponseBadge({
);
}

function ResponseCard({ item }: { item: QuestionnaireResponse }) {
function ResponseCard({
item,
isPrintPreview,
}: {
item: QuestionnaireResponse;
isPrintPreview?: boolean;
}) {
const isStructured = !item.questionnaire;
const structuredType = Object.keys(item.structured_responses || {})[0];

return (
<Card className="flex flex-col py-3 px-4 transition-colors hover:bg-muted/50">
<Card
className={cn(
"flex flex-col py-3 px-4 transition-colors hover:bg-muted/50",
isPrintPreview && "shadow-none",
)}
>
<div className="flex items-start justify-between">
<div className="space-y-1">
<div className="flex items-center gap-2 text-xs text-gray-500">
Expand Down Expand Up @@ -317,7 +328,12 @@ export default function QuestionnaireResponsesList({
) : (
<div>
{questionnarieResponses?.results?.length === 0 ? (
<Card className="p-6">
<Card
className={cn(
"p-6",
isPrintPreview && "shadow-none border-gray",
)}
>
<div className="text-lg font-medium text-gray-500">
{t("no_questionnaire_responses")}
</div>
Expand All @@ -327,7 +343,11 @@ export default function QuestionnaireResponsesList({
{questionnarieResponses?.results?.map(
(item: QuestionnaireResponse) => (
<li key={item.id} className="w-full">
<ResponseCard key={item.id} item={item} />
<ResponseCard
key={item.id}
item={item}
isPrintPreview={isPrintPreview}
/>
</li>
),
)}
Expand Down
20 changes: 15 additions & 5 deletions src/components/Facility/FacilityForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,20 @@ export default function FacilityForm({

const handleFeatureChange = (value: string[]) => {
const features = value.map((val) => Number(val));
form.setValue("features", features);
form.setValue("features", features, { shouldDirty: true });
};

const handleGetCurrentLocation = () => {
if (navigator.geolocation) {
setIsGettingLocation(true);
navigator.geolocation.getCurrentPosition(
(position) => {
form.setValue("latitude", position.coords.latitude);
form.setValue("longitude", position.coords.longitude);
form.setValue("latitude", position.coords.latitude, {
shouldDirty: true,
});
form.setValue("longitude", position.coords.longitude, {
shouldDirty: true,
});
setIsGettingLocation(false);
toast.success(t("location_updated_successfully"));
},
Expand Down Expand Up @@ -346,7 +350,9 @@ export default function FacilityForm({
value={form.watch("geo_organization")}
selected={selectedLevels}
onChange={(value) =>
form.setValue("geo_organization", value)
form.setValue("geo_organization", value, {
shouldDirty: true,
})
}
required
/>
Expand Down Expand Up @@ -418,6 +424,7 @@ export default function FacilityForm({
form.setValue(
"latitude",
e.target.value ? Number(e.target.value) : undefined,
{ shouldDirty: true },
);
}}
data-cy="facility-latitude"
Expand Down Expand Up @@ -445,6 +452,7 @@ export default function FacilityForm({
form.setValue(
"longitude",
e.target.value ? Number(e.target.value) : undefined,
{ shouldDirty: true },
);
}}
data-cy="facility-longitude"
Expand Down Expand Up @@ -493,7 +501,9 @@ export default function FacilityForm({
type="submit"
className="w-full"
variant="primary"
disabled={facilityId ? isUpdatePending : isPending}
disabled={
facilityId ? isUpdatePending || !form.formState.isDirty : isPending
}
data-cy={facilityId ? "update-facility" : "submit-facility"}
>
{facilityId ? (
Expand Down
11 changes: 9 additions & 2 deletions src/components/Facility/FacilityHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import type {
} from "@/types/organization/organization";
import { getOrgLabel } from "@/types/organization/organization";

import { FacilityMapsLink } from "./FacilityMapLink";

type Props = {
facilityId: string;
};
Expand Down Expand Up @@ -322,8 +324,13 @@ export const FacilityHome = ({ facilityId }: Props) => {
<span className="font-semibold text-lg">
{t("location_details")}
</span>
<span className="text-gray-800 truncate">
{/* Add Location Link Here */}
<span>
{facilityData.latitude && facilityData.longitude && (
<FacilityMapsLink
latitude={facilityData.latitude.toString()}
longitude={facilityData.longitude.toString()}
/>
)}
</span>
</div>
</div>
Expand Down
42 changes: 42 additions & 0 deletions src/components/Facility/FacilityMapLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { SquareArrowOutUpRight } from "lucide-react";
import { Link } from "raviger";
import { useTranslation } from "react-i18next";

import { getMapUrl, isAndroidDevice } from "@/Utils/utils";

const isValidLatitude = (latitude: string) => {
const lat = parseFloat(latitude.trim());
return Number.isFinite(lat) && lat >= -90 && lat <= 90;
};

const isValidLongitude = (longitude: string) => {
const long = parseFloat(longitude.trim());
return Number.isFinite(long) && long >= -180 && long <= 180;
};

export const FacilityMapsLink = ({
latitude,
longitude,
}: {
latitude: string;
longitude: string;
}) => {
const { t } = useTranslation();

if (!isValidLatitude(latitude) || !isValidLongitude(longitude)) {
return null;
}
const target = isAndroidDevice ? "_self" : "_blank";

return (
<Link
className="text-primary flex items-center gap-1 w-max"
href={getMapUrl(latitude, longitude)}
target={target}
rel="noreferrer"
>
{t("show_on_map")}
<SquareArrowOutUpRight className="h-3 w-3" />
</Link>
);
};
Loading

0 comments on commit 95a277d

Please sign in to comment.