Skip to content

Commit

Permalink
Merge branch 'develop' into large_image_upload_error_in_editAvatar_page
Browse files Browse the repository at this point in the history
  • Loading branch information
Harsh-D-2004 authored Mar 8, 2025
2 parents f80efeb + a8932e4 commit 018abff
Show file tree
Hide file tree
Showing 12 changed files with 1,454 additions and 363 deletions.
843 changes: 647 additions & 196 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
"react-pdf": "^9.2.1",
"react-phone-number-input": "^3.4.11",
"react-webcam": "^7.2.0",
"reactflow": "^11.11.4",
"recharts": "^2.15.0",
"sonner": "^2.0.0",
"tailwind-merge": "^3.0.0",
Expand Down Expand Up @@ -182,8 +183,8 @@
"optionalDependencies": {
"@esbuild/linux-arm64": "latest",
"@esbuild/linux-x64": "latest",
"@rollup/rollup-linux-arm64-gnu": "4.34.8",
"@rollup/rollup-linux-x64-gnu": "4.34.8"
"@rollup/rollup-linux-arm64-gnu": "4.35.0",
"@rollup/rollup-linux-x64-gnu": "4.35.0"
},
"browserslist": {
"production": [
Expand Down
2 changes: 2 additions & 0 deletions public/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,7 @@
"intended": "Intended",
"intent": "Intent",
"international_mobile": "International Mobile",
"invalid_age": "Invalid age",
"invalid_asset_id_msg": "Oops! The asset ID you entered does not appear to be valid.",
"invalid_date_format": "Invalid date format, expected {{format}}",
"invalid_email": "Please enter a valid email address",
Expand Down Expand Up @@ -1358,6 +1359,7 @@
"latitude_invalid": "Latitude must be between -90 and 90",
"left": "Left",
"length": "Length ({{unit}})",
"level_inside": "Level Inside",
"license": "License",
"licenses_description": "Third-party software is used in Care, including the respective licenses and versions.",
"licenses_title": "Third-Party Software and Licenses",
Expand Down
4 changes: 3 additions & 1 deletion src/components/Patient/PatientRegistration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,9 @@ export default function PatientRegistration(
{form.getValues("age") && (
<div className="text-sm font-bold">
{Number(form.getValues("age")) <= 0 ? (
<span className="text-red-600">Invalid age</span>
<span className="text-red-600">
{t("invalid_age")}
</span>
) : (
<span className="text-violet-600">
{t("year_of_birth")}:{" "}
Expand Down
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import careConfig from "@careConfig";
import * as Sentry from "@sentry/browser";
import React from "react";
import { createRoot } from "react-dom/client";
import "reactflow/dist/style.css";
import { registerSW } from "virtual:pwa-register";

import App from "@/App";
Expand Down
159 changes: 77 additions & 82 deletions src/pages/Facility/settings/locations/LocationList.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useQuery } from "@tanstack/react-query";
import { PenLine } from "lucide-react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useCallback, useEffect, useMemo, useState } from "react";
import { Trans, useTranslation } from "react-i18next";
import { useTranslation } from "react-i18next";

import CareIcon from "@/CAREUI/icons/CareIcon";

Expand All @@ -11,12 +10,15 @@ import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";

import Page from "@/components/Common/Page";

import routes from "@/Utils/request/api";
import query from "@/Utils/request/query";
import { useView } from "@/Utils/useView";
import { LocationList as LocationListType } from "@/types/location/location";
import locationApi from "@/types/location/locationApi";

import LocationMap from "./LocationMap";
import LocationSheet from "./LocationSheet";
import { LocationInfoCard } from "./components/LocationInfoCard";
import { LocationListView } from "./components/LocationListView";

interface Props {
Expand Down Expand Up @@ -49,6 +51,7 @@ function buildLocationHierarchy(locations: LocationListType[]) {

export default function LocationList({ facilityId }: Props) {
const { t } = useTranslation();
const queryClient = useQueryClient();
const [searchQuery, setSearchQuery] = useState("");
const [selectedLocation, setSelectedLocation] =
useState<LocationListType | null>(null);
Expand All @@ -60,6 +63,13 @@ export default function LocationList({ facilityId }: Props) {
topLevelLocations: LocationListType[];
}>({ childrenMap: new Map(), topLevelLocations: [] });

const { data: facilityData } = useQuery({
queryKey: ["facility", facilityId],
queryFn: query(routes.facility.show, {
pathParams: { id: facilityId },
}),
});

const { data, isLoading } = useQuery({
queryKey: ["locations", facilityId],
queryFn: query.paginated(locationApi.list, {
Expand All @@ -77,20 +87,48 @@ export default function LocationList({ facilityId }: Props) {
if (!searchQuery) return data?.results || [];

const matchesSearch = createSearchMatcher(searchQuery);

const hasMatchingDescendant = (locationId: string): boolean => {
const children = childrenMap.get(locationId) || [];
return children.some(
(child: LocationListType) =>
matchesSearch(child.name) || hasMatchingDescendant(child.id),
);
const matchedLocations = new Set<string>();

// Helper function to add all children of a location
const addAllChildren = (locationId: string) => {
const children =
data?.results?.filter((loc) => loc.parent?.id === locationId) || [];
children.forEach((child) => {
matchedLocations.add(child.id);
// Recursively add all descendants
addAllChildren(child.id);
});
};

return data?.results?.filter(
(location) =>
matchesSearch(location.name) || hasMatchingDescendant(location.id),
// First pass: Find direct matches and their children
data?.results?.forEach((location) => {
if (matchesSearch(location.name)) {
matchedLocations.add(location.id);
// If this location matches, add all its children
addAllChildren(location.id);
}
});

// Second pass: Add parent chain for any matched location
data?.results?.forEach((location) => {
if (matchedLocations.has(location.id)) {
let current = location;
while (current.parent?.id) {
matchedLocations.add(current.parent.id);
const parent = data?.results?.find(
(loc) => loc.id === current.parent?.id,
);
if (!parent) break;
current = parent;
}
}
});

return (
data?.results?.filter((location) => matchedLocations.has(location.id)) ||
[]
);
}, [data?.results, searchQuery, childrenMap]);
}, [data?.results, searchQuery]);

const matchesSearch = useMemo(
() => createSearchMatcher(searchQuery),
Expand Down Expand Up @@ -139,6 +177,7 @@ export default function LocationList({ facilityId }: Props) {
const handleSheetClose = () => {
setIsSheetOpen(false);
setSelectedLocation(null);
queryClient.invalidateQueries({ queryKey: ["locations", facilityId] });
};

const toggleRow = (id: string) => {
Expand Down Expand Up @@ -194,8 +233,8 @@ export default function LocationList({ facilityId }: Props) {

return (
<Page title={t("locations")} hideTitleOnPage={true} className="p-0">
<div className="md:px-6 space-y-6">
<h2 className="text-black">{t("locations")}</h2>
<div className="space-y-4">
<h3 className="text-black">{t("locations")}</h3>
<div className="space-y-4">
<div className="flex flex-col lg:flex-row gap-2">
<div className="flex items-center justify-between w-full">
Expand All @@ -210,14 +249,12 @@ export default function LocationList({ facilityId }: Props) {
<span>{t("list")}</span>
</div>
</TabsTrigger>
{/* Map view will be added later
<TabsTrigger value="map" id="location-map-view">
<div className="flex items-center gap-1">
<CareIcon icon="l-map" className="text-lg" />
<span>{t("map")}</span>
</div>
</TabsTrigger>
*/}
</TabsList>
</Tabs>
</div>
Expand All @@ -242,72 +279,30 @@ export default function LocationList({ facilityId }: Props) {
</div>
</div>

{activeTab === "list" && (
<div className="rounded-lg border-2 border-blue-200 bg-blue-50 p-4">
<div className="flex gap-3">
<div className="p-2 bg-blue-100 rounded-sm shrink-0 self-center">
<CareIcon
icon="l-info-circle"
className="h-5 w-5 text-blue-900"
/>
</div>
<div className="min-w-0 space-y-2 text-xs md:text-sm text-blue-800">
<div className="flex flex-wrap items-center">
<Trans
i18nKey="click_add_main_location"
components={{
strong: <strong className="font-semibold mx-1" />,
}}
/>
</div>
{/* Desktop view text */}
<div className="hidden lg:flex items-center">
<Trans
i18nKey="click_manage_sub_locations"
components={{
ArrowIcon: (
<CareIcon
icon="l-arrow-up-right"
className="h-4 w-4 mr-1"
/>
),
strong: <strong className="font-semibold ml-1" />,
}}
/>
</div>
{/* Mobile and Tablet view text */}
<div className="lg:hidden flex flex-wrap items-center">
<Trans
i18nKey="click_manage_sub_locations_mobile"
components={{
ArrowIcon: (
<CareIcon
icon="l-arrow-up-right"
className="h-4 w-4 mx-1"
/>
),
PenLine: <PenLine className="h-4 w-4 mx-1" />,
}}
/>
</div>
</div>
</div>
</div>
{activeTab === "list" ? (
<>
<LocationInfoCard />
<LocationListView
isLoading={isLoading}
tableData={filteredData || []}
searchQuery={searchQuery}
filteredTopLevelLocations={filteredTopLevelLocations}
expandedRows={expandedRows}
toggleRow={toggleRow}
getChildren={getChildren}
handleEditLocation={handleEditLocation}
setExpandedRows={setExpandedRows}
/>
</>
) : (
<LocationMap
locations={filteredData || []}
onLocationClick={handleEditLocation}
facilityName={facilityData?.name || t("facility")}
searchQuery={searchQuery}
/>
)}

{/* Map view will be added later, for now always show list view */}
<LocationListView
isLoading={isLoading}
tableData={filteredData || []}
searchQuery={searchQuery}
filteredTopLevelLocations={filteredTopLevelLocations}
expandedRows={expandedRows}
toggleRow={toggleRow}
getChildren={getChildren}
handleEditLocation={handleEditLocation}
setExpandedRows={setExpandedRows}
/>

<LocationSheet
open={isSheetOpen}
onOpenChange={handleSheetClose}
Expand Down
Loading

0 comments on commit 018abff

Please sign in to comment.