From 03fd61728d5c0c66ae87e545fa203f344f7e856a Mon Sep 17 00:00:00 2001 From: mahendar Date: Thu, 2 Jan 2025 20:02:59 +0530 Subject: [PATCH 01/20] pincode updated --- src/components/Facility/FacilityCreate.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Facility/FacilityCreate.tsx b/src/components/Facility/FacilityCreate.tsx index 53a9d4cb50b..7ee81593b03 100644 --- a/src/components/Facility/FacilityCreate.tsx +++ b/src/components/Facility/FacilityCreate.tsx @@ -146,7 +146,7 @@ export const FacilityCreate = (props: FacilityProps) => { name: facilityData.name, description: facilityData.description || "", features: facilityData.features || [], - pincode: facilityData.pincode, + pincode: facilityData.pincode?.toString() || "", geo_organization: facilityData.geo_organization, address: facilityData.address, phone_number: facilityData.phone_number, From 7db9c3a867b90dbb727a8232a957d9f959bdbdb8 Mon Sep 17 00:00:00 2001 From: mahendar Date: Fri, 3 Jan 2025 10:11:25 +0530 Subject: [PATCH 02/20] populated geo_organization values --- public/locale/en.json | 1 + src/components/Facility/FacilityCreate.tsx | 5 ++-- .../components/OrganizationSelector.tsx | 28 +++++++++++++++++-- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index 6d2d774c921..0d6ee002f44 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -1581,6 +1581,7 @@ "select_investigation_groups": "Select Investigation Groups", "select_investigations": "Select Investigations", "select_local_body": "Select Local Body", + "select_location_from": "Select location from", "select_patient": "Select Patient", "select_policy": "Select an Insurance Policy", "select_policy_to_add_items": "Select a Policy to Add Items", diff --git a/src/components/Facility/FacilityCreate.tsx b/src/components/Facility/FacilityCreate.tsx index 7ee81593b03..3dd075ada35 100644 --- a/src/components/Facility/FacilityCreate.tsx +++ b/src/components/Facility/FacilityCreate.tsx @@ -214,7 +214,7 @@ export const FacilityCreate = (props: FacilityProps) => { return ( {
form.setValue("geo_organization", value)} />
@@ -411,7 +412,7 @@ export const FacilityCreate = (props: FacilityProps) => { > - Select location from map + {t("select_location_from")} diff --git a/src/pages/Organization/components/OrganizationSelector.tsx b/src/pages/Organization/components/OrganizationSelector.tsx index 14ea412cc65..ffee114020f 100644 --- a/src/pages/Organization/components/OrganizationSelector.tsx +++ b/src/pages/Organization/components/OrganizationSelector.tsx @@ -1,5 +1,5 @@ import { useQuery } from "@tanstack/react-query"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -28,10 +28,32 @@ interface AutoCompleteOption { } export default function OrganizationSelector(props: OrganizationSelectorProps) { - const { onChange, required } = props; + const { value, onChange, required } = props; const [selectedLevels, setSelectedLevels] = useState([]); const [searchQuery, setSearchQuery] = useDebouncedState("", 500); + useEffect(() => { + if (value) { + try { + const parsedValue = + typeof value === "string" ? JSON.parse(value) : value; + if (parsedValue) { + const levels: Organization[] = []; + let current = parsedValue; + + while (current.parent) { + levels.unshift(current); + current = current.parent; + } + + setSelectedLevels(levels); + } + } catch (e) { + console.error("Invalid value for geo_organization:", e); + } + } + }, [value]); + const headers = props.authToken ? { headers: { @@ -146,7 +168,7 @@ export default function OrganizationSelector(props: OrganizationSelectorProps) { required={selectedLevels.length === 0 && required} > Date: Sat, 4 Jan 2025 19:48:11 +0530 Subject: [PATCH 03/20] autofill of state and districts --- src/components/Facility/FacilityCreate.tsx | 67 ++++++++++++++++++- .../components/OrganizationSelector.tsx | 34 +++++----- 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/src/components/Facility/FacilityCreate.tsx b/src/components/Facility/FacilityCreate.tsx index 3dd075ada35..4928b81957c 100644 --- a/src/components/Facility/FacilityCreate.tsx +++ b/src/components/Facility/FacilityCreate.tsx @@ -1,3 +1,4 @@ +import careConfig from "@careConfig"; import { Popover, PopoverButton, @@ -10,6 +11,7 @@ import { navigate } from "raviger"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import * as z from "zod"; import Card from "@/CAREUI/display/Card"; @@ -58,8 +60,9 @@ import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import query from "@/Utils/request/query"; import request from "@/Utils/request/request"; -import { parsePhoneNumber } from "@/Utils/utils"; +import { getPincodeDetails, parsePhoneNumber } from "@/Utils/utils"; import OrganizationSelector from "@/pages/Organization/components/OrganizationSelector"; +import organizationApi from "@/types/organization/organizationApi"; interface FacilityProps { facilityId?: string; @@ -68,6 +71,8 @@ export const FacilityCreate = (props: FacilityProps) => { const { t } = useTranslation(); const { facilityId } = props; const [isLoading, setIsLoading] = useState(false); + const [selectedLevels, setSelectedLevels] = useState([]); + const { goBack } = useAppHistory(); const facilityFormSchema = z.object({ @@ -212,6 +217,59 @@ export const FacilityCreate = (props: FacilityProps) => { } }; + const handlePincodeChange = async (pincode: string) => { + try { + if (!validatePincode(pincode)) { + return; + } + const pincodeData = await getPincodeDetails( + pincode, + careConfig.govDataApiKey, + ); + + if (pincodeData) { + const { statename: stateName, districtname: districtName } = + pincodeData; + + const stateOrg = await fetchOrganizationByName(stateName); + if (!stateOrg) { + setSelectedLevels([]); + return; + } + + console.log("stateOrg", stateOrg); + + const districtOrg = await fetchOrganizationByName( + districtName, + stateOrg.id, + ); + + setSelectedLevels([stateOrg, districtOrg]); + } else { + throw new Error("Invalid pincode or no data found."); + } + } catch (error) { + console.error(error); + } + }; + + async function fetchOrganizationByName(name: string, parentId?: string) { + try { + const data = await query(organizationApi.list, { + queryParams: { + org_type: "govt", + parent: parentId || "", + name, + }, + })({ signal: new AbortController().signal }); + return data.results?.[0]; + } catch (error) { + console.error("Error fetching org:", error); + toast.error("Error fetching organization"); + return undefined; + } + } + return ( { required onChange={(value) => { field.onChange(value.value); + handlePincodeChange(value.value); }} error={form.formState.errors.pincode?.message} /> @@ -330,7 +389,11 @@ export const FacilityCreate = (props: FacilityProps) => { form.setValue("geo_organization", value)} + parentSelectedLevels={selectedLevels} + onChange={(value) => { + // Update geo_organization value in form + form.setValue("geo_organization", value); + }} /> diff --git a/src/pages/Organization/components/OrganizationSelector.tsx b/src/pages/Organization/components/OrganizationSelector.tsx index ffee114020f..a567c090c12 100644 --- a/src/pages/Organization/components/OrganizationSelector.tsx +++ b/src/pages/Organization/components/OrganizationSelector.tsx @@ -20,6 +20,7 @@ interface OrganizationSelectorProps { onChange: (value: string) => void; required?: boolean; authToken?: string; + parentSelectedLevels?: Organization[]; } interface AutoCompleteOption { @@ -28,31 +29,28 @@ interface AutoCompleteOption { } export default function OrganizationSelector(props: OrganizationSelectorProps) { - const { value, onChange, required } = props; + const { value, onChange, required, parentSelectedLevels } = props; const [selectedLevels, setSelectedLevels] = useState([]); const [searchQuery, setSearchQuery] = useDebouncedState("", 500); useEffect(() => { - if (value) { - try { - const parsedValue = - typeof value === "string" ? JSON.parse(value) : value; - if (parsedValue) { - const levels: Organization[] = []; - let current = parsedValue; - - while (current.parent) { - levels.unshift(current); - current = current.parent; - } - - setSelectedLevels(levels); + if (value && parentSelectedLevels?.length == 0) { + const parsedValue = typeof value === "string" ? JSON.parse(value) : value; + if (parsedValue) { + const levels: Organization[] = []; + let current = parsedValue; + + while (current.parent) { + levels.unshift(current); + current = current.parent; } - } catch (e) { - console.error("Invalid value for geo_organization:", e); + + setSelectedLevels(levels); } + } else if (parentSelectedLevels) { + setSelectedLevels(parentSelectedLevels); } - }, [value]); + }, [value, parentSelectedLevels]); const headers = props.authToken ? { From ab383d52d4267ab2eba5483a9bcdc975f5ad5519 Mon Sep 17 00:00:00 2001 From: mahendar Date: Sat, 4 Jan 2025 20:07:25 +0530 Subject: [PATCH 04/20] translation --- src/components/Facility/FacilityUsers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Facility/FacilityUsers.tsx b/src/components/Facility/FacilityUsers.tsx index 2e8e7b4a769..5b325eb7242 100644 --- a/src/components/Facility/FacilityUsers.tsx +++ b/src/components/Facility/FacilityUsers.tsx @@ -44,7 +44,7 @@ export default function FacilityUsers(props: { facilityId: number }) { return
Loading...
; } if (!userListData) { - return
No users found
; + return
{t("no_users_found")}
; } return ( From 7dff65f5b49e7b5957d57495d5ffed92061bc591 Mon Sep 17 00:00:00 2001 From: mahendar Date: Sat, 4 Jan 2025 20:16:16 +0530 Subject: [PATCH 05/20] commit --- src/components/Facility/FacilityUsers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Facility/FacilityUsers.tsx b/src/components/Facility/FacilityUsers.tsx index 5b325eb7242..2e8e7b4a769 100644 --- a/src/components/Facility/FacilityUsers.tsx +++ b/src/components/Facility/FacilityUsers.tsx @@ -44,7 +44,7 @@ export default function FacilityUsers(props: { facilityId: number }) { return
Loading...
; } if (!userListData) { - return
{t("no_users_found")}
; + return
No users found
; } return ( From 4eda986c1bd02fe8be043176717fafbd0a8db9e0 Mon Sep 17 00:00:00 2001 From: mahendar Date: Sat, 4 Jan 2025 23:29:42 +0530 Subject: [PATCH 06/20] added usequery --- src/Utils/utils.ts | 25 ++++++ src/components/Facility/FacilityCreate.tsx | 93 +++++++++------------- 2 files changed, 64 insertions(+), 54 deletions(-) diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index 65556f02bc8..a39b195b923 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -1,3 +1,4 @@ +import { useQuery } from "@tanstack/react-query"; import { differenceInMinutes, format } from "date-fns"; import html2canvas from "html2canvas"; @@ -6,10 +7,12 @@ import phoneCodesJson from "@/common/static/countryPhoneAndFlags.json"; import * as Notification from "@/Utils/Notifications"; import dayjs from "@/Utils/dayjs"; +import query from "@/Utils/request/query"; import { Time } from "@/Utils/types"; import { DoseRange, Timing } from "@/types/emr/medicationRequest"; import { Patient } from "@/types/emr/newPatient"; import { PatientModel } from "@/types/emr/patient"; +import organizationApi from "@/types/organization/organizationApi"; import { Code } from "@/types/questionnaire/code"; import { Quantity } from "@/types/questionnaire/quantity"; @@ -189,9 +192,31 @@ export const getPincodeDetails = async (pincode: string, apiKey: string) => { `https://api.data.gov.in/resource/6176ee09-3d56-4a3b-8115-21841576b2f6?api-key=${apiKey}&format=json&filters[pincode]=${pincode}&limit=1`, ); const data = await response.json(); + if (!data.records || data.records.length === 0) { + Notification.Error({ msg: "Invalid pincode" }); + return null; + } return data.records[0]; }; +export function useFetchOrganizationByName(name: string, parentId?: string) { + return useQuery({ + queryKey: ["organization", name, parentId], + queryFn: async () => { + const data = await query(organizationApi.list, { + queryParams: { + org_type: "govt", + parent: parentId || "", + name: name || "", + }, + })({ signal: new AbortController().signal }); + + return data.results?.[0]; + }, + enabled: !!name, + }); +} + export const includesIgnoreCase = (str1: string, str2: string) => { if (!str1 || !str2) return false; const lowerCaseStr1 = str1.toLowerCase(); diff --git a/src/components/Facility/FacilityCreate.tsx b/src/components/Facility/FacilityCreate.tsx index 4928b81957c..d7cbf839443 100644 --- a/src/components/Facility/FacilityCreate.tsx +++ b/src/components/Facility/FacilityCreate.tsx @@ -11,7 +11,6 @@ import { navigate } from "raviger"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; -import { toast } from "sonner"; import * as z from "zod"; import Card from "@/CAREUI/display/Card"; @@ -60,9 +59,13 @@ import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import query from "@/Utils/request/query"; import request from "@/Utils/request/request"; -import { getPincodeDetails, parsePhoneNumber } from "@/Utils/utils"; +import { + getPincodeDetails, + parsePhoneNumber, + useFetchOrganizationByName, +} from "@/Utils/utils"; import OrganizationSelector from "@/pages/Organization/components/OrganizationSelector"; -import organizationApi from "@/types/organization/organizationApi"; +import { Organization } from "@/types/organization/organization"; interface FacilityProps { facilityId?: string; @@ -71,7 +74,8 @@ export const FacilityCreate = (props: FacilityProps) => { const { t } = useTranslation(); const { facilityId } = props; const [isLoading, setIsLoading] = useState(false); - const [selectedLevels, setSelectedLevels] = useState([]); + const [selectedLevels, setSelectedLevels] = useState([]); + const [pincode, setPincode] = useState(""); const { goBack } = useAppHistory(); @@ -217,59 +221,40 @@ export const FacilityCreate = (props: FacilityProps) => { } }; - const handlePincodeChange = async (pincode: string) => { - try { - if (!validatePincode(pincode)) { - return; - } - const pincodeData = await getPincodeDetails( - pincode, - careConfig.govDataApiKey, - ); - - if (pincodeData) { - const { statename: stateName, districtname: districtName } = - pincodeData; - - const stateOrg = await fetchOrganizationByName(stateName); - if (!stateOrg) { - setSelectedLevels([]); - return; - } - - console.log("stateOrg", stateOrg); - - const districtOrg = await fetchOrganizationByName( - districtName, - stateOrg.id, - ); - - setSelectedLevels([stateOrg, districtOrg]); - } else { - throw new Error("Invalid pincode or no data found."); - } - } catch (error) { - console.error(error); - } - }; + const { data: pincodeData, isError: isPincodeError } = useQuery({ + queryKey: ["pincodeDetails", pincode], + queryFn: () => getPincodeDetails(pincode, careConfig.govDataApiKey), + enabled: validatePincode(pincode), + }); - async function fetchOrganizationByName(name: string, parentId?: string) { - try { - const data = await query(organizationApi.list, { - queryParams: { - org_type: "govt", - parent: parentId || "", - name, - }, - })({ signal: new AbortController().signal }); - return data.results?.[0]; - } catch (error) { - console.error("Error fetching org:", error); - toast.error("Error fetching organization"); - return undefined; - } + if (isPincodeError) { + Notification.Error({ msg: "Invalid pincode" }); } + const stateName = pincodeData?.statename; + + const districtName = pincodeData?.districtname; + + const { data: stateOrg } = useFetchOrganizationByName(stateName); + const { data: districtOrg } = useFetchOrganizationByName( + districtName, + stateOrg?.id, + ); + + useEffect(() => { + if (stateOrg && districtOrg) { + setSelectedLevels([stateOrg, districtOrg]); + } else { + setSelectedLevels([]); + } + }, [stateOrg, districtOrg]); + + console.log("selectedLevels", selectedLevels); + + const handlePincodeChange = (value: string) => { + setPincode(value); + }; + return ( Date: Sun, 5 Jan 2025 23:47:55 +0530 Subject: [PATCH 07/20] moved useFetchOrganizationByName organizationapi.ts --- src/Utils/utils.ts | 21 ------------------ src/components/Facility/FacilityCreate.tsx | 8 ++----- src/types/organization/organizationApi.ts | 25 +++++++++++++++++++++- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index a39b195b923..a6258dafd6c 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -1,4 +1,3 @@ -import { useQuery } from "@tanstack/react-query"; import { differenceInMinutes, format } from "date-fns"; import html2canvas from "html2canvas"; @@ -7,12 +6,10 @@ import phoneCodesJson from "@/common/static/countryPhoneAndFlags.json"; import * as Notification from "@/Utils/Notifications"; import dayjs from "@/Utils/dayjs"; -import query from "@/Utils/request/query"; import { Time } from "@/Utils/types"; import { DoseRange, Timing } from "@/types/emr/medicationRequest"; import { Patient } from "@/types/emr/newPatient"; import { PatientModel } from "@/types/emr/patient"; -import organizationApi from "@/types/organization/organizationApi"; import { Code } from "@/types/questionnaire/code"; import { Quantity } from "@/types/questionnaire/quantity"; @@ -199,24 +196,6 @@ export const getPincodeDetails = async (pincode: string, apiKey: string) => { return data.records[0]; }; -export function useFetchOrganizationByName(name: string, parentId?: string) { - return useQuery({ - queryKey: ["organization", name, parentId], - queryFn: async () => { - const data = await query(organizationApi.list, { - queryParams: { - org_type: "govt", - parent: parentId || "", - name: name || "", - }, - })({ signal: new AbortController().signal }); - - return data.results?.[0]; - }, - enabled: !!name, - }); -} - export const includesIgnoreCase = (str1: string, str2: string) => { if (!str1 || !str2) return false; const lowerCaseStr1 = str1.toLowerCase(); diff --git a/src/components/Facility/FacilityCreate.tsx b/src/components/Facility/FacilityCreate.tsx index d7cbf839443..8c04ff1352c 100644 --- a/src/components/Facility/FacilityCreate.tsx +++ b/src/components/Facility/FacilityCreate.tsx @@ -59,13 +59,10 @@ import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import query from "@/Utils/request/query"; import request from "@/Utils/request/request"; -import { - getPincodeDetails, - parsePhoneNumber, - useFetchOrganizationByName, -} from "@/Utils/utils"; +import { getPincodeDetails, parsePhoneNumber } from "@/Utils/utils"; import OrganizationSelector from "@/pages/Organization/components/OrganizationSelector"; import { Organization } from "@/types/organization/organization"; +import { useFetchOrganizationByName } from "@/types/organization/organizationApi"; interface FacilityProps { facilityId?: string; @@ -376,7 +373,6 @@ export const FacilityCreate = (props: FacilityProps) => { value={facilityData?.geo_organization} parentSelectedLevels={selectedLevels} onChange={(value) => { - // Update geo_organization value in form form.setValue("geo_organization", value); }} /> diff --git a/src/types/organization/organizationApi.ts b/src/types/organization/organizationApi.ts index 5e90f0b26b5..9bff8a3ea69 100644 --- a/src/types/organization/organizationApi.ts +++ b/src/types/organization/organizationApi.ts @@ -1,10 +1,13 @@ +import { useQuery } from "@tanstack/react-query"; + import { HttpMethod, Type } from "@/Utils/request/api"; +import query from "@/Utils/request/query"; import { PaginatedResponse } from "@/Utils/request/types"; import { Patient } from "../emr/newPatient"; import { Organization, OrganizationUserRole } from "./organization"; -export default { +const organizationApi = { listMine: { path: "/api/v1/organization/mine/", method: HttpMethod.GET, @@ -58,3 +61,23 @@ export default { TRes: Type(), }, }; + +export function useFetchOrganizationByName(name: string, parentId?: string) { + return useQuery({ + queryKey: ["organization", name, parentId], + queryFn: async () => { + const data = await query(organizationApi.list, { + queryParams: { + org_type: "govt", + parent: parentId || "", + name: name || "", + }, + })({ signal: new AbortController().signal }); + + return data.results?.[0]; + }, + enabled: !!name, + }); +} + +export default organizationApi; From 87db7674f17f70ecd2076e31920fff79a3baa8b9 Mon Sep 17 00:00:00 2001 From: mahendar Date: Mon, 6 Jan 2025 14:40:37 +0530 Subject: [PATCH 08/20] added conditions --- public/locale/en.json | 1 + src/components/Facility/FacilityCreate.tsx | 12 +++++++----- src/types/organization/organizationApi.ts | 6 +++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index 4a8aa6cffa0..db0bdd94a53 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -1879,6 +1879,7 @@ "view_users": "View Users", "village": "Village", "virtual_nursing_assistant": "Virtual Nursing Assistant", + "visibility_settings": "Visibility Settings", "vitals": "Vitals", "vitals_monitor": "Vitals Monitor", "vitals_present": "Vitals Monitor present", diff --git a/src/components/Facility/FacilityCreate.tsx b/src/components/Facility/FacilityCreate.tsx index a1ef6c366d8..3037b087702 100644 --- a/src/components/Facility/FacilityCreate.tsx +++ b/src/components/Facility/FacilityCreate.tsx @@ -11,6 +11,7 @@ import { navigate } from "raviger"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import * as z from "zod"; import Card from "@/CAREUI/display/Card"; @@ -225,11 +226,11 @@ export const FacilityCreate = (props: FacilityProps) => { const { data: pincodeData, isError: isPincodeError } = useQuery({ queryKey: ["pincodeDetails", pincode], queryFn: () => getPincodeDetails(pincode, careConfig.govDataApiKey), - enabled: validatePincode(pincode), + enabled: validatePincode(pincode) && pincode != facilityData?.pincode, }); if (isPincodeError) { - Notification.Error({ msg: "Invalid pincode" }); + toast.error("Invalid pincode"); } const stateName = pincodeData?.statename; @@ -250,10 +251,9 @@ export const FacilityCreate = (props: FacilityProps) => { } }, [stateOrg, districtOrg]); - console.log("selectedLevels", selectedLevels); - const handlePincodeChange = (value: string) => { setPincode(value); + setSelectedLevels([]); }; return ( @@ -512,7 +512,9 @@ export const FacilityCreate = (props: FacilityProps) => { {/* Visibility Settings */}
-

Visibility Settings

+

+ {t("visibility_settings")} +

Date: Fri, 10 Jan 2025 00:30:47 +0530 Subject: [PATCH 09/20] added edit option --- ...reateFacilityForm.tsx => FacilityForm.tsx} | 206 +++++++++++++++--- .../Organization/OrganizationFacilities.tsx | 101 +++++---- .../components/AddFacilitySheet.tsx | 36 ++- 3 files changed, 251 insertions(+), 92 deletions(-) rename src/components/Facility/{CreateFacilityForm.tsx => FacilityForm.tsx} (71%) diff --git a/src/components/Facility/CreateFacilityForm.tsx b/src/components/Facility/FacilityForm.tsx similarity index 71% rename from src/components/Facility/CreateFacilityForm.tsx rename to src/components/Facility/FacilityForm.tsx index ed5c87caabc..9aaa91cdee9 100644 --- a/src/components/Facility/CreateFacilityForm.tsx +++ b/src/components/Facility/FacilityForm.tsx @@ -1,8 +1,10 @@ +import careConfig from "@careConfig"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { useState } from "react"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import * as z from "zod"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -39,9 +41,14 @@ import { import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; -import { parsePhoneNumber } from "@/Utils/utils"; +import query from "@/Utils/request/query"; +import { getPincodeDetails, parsePhoneNumber } from "@/Utils/utils"; import OrganizationSelector from "@/pages/Organization/components/OrganizationSelector"; import { BaseFacility } from "@/types/facility/facility"; +import { Organization } from "@/types/organization/organization"; +import { useFetchOrganizationByName } from "@/types/organization/organizationApi"; + +import { FacilityModel } from "./models"; const facilityFormSchema = z.object({ facility_type: z.string().min(1, "Facility type is required"), @@ -49,6 +56,7 @@ const facilityFormSchema = z.object({ description: z.string().optional(), features: z.array(z.number()).default([]), pincode: z.string().refine(validatePincode, "Invalid pincode"), + geo_organization: z.string().min(1, { message: "required" }), address: z.string().min(1, "Address is required"), phone_number: z .string() @@ -69,18 +77,19 @@ const facilityFormSchema = z.object({ type FacilityFormValues = z.infer; -interface Props { +interface FacilityProps { organizationId: string; + facilityId?: string; onSubmitSuccess?: () => void; } -export default function CreateFacilityForm({ - organizationId, - onSubmitSuccess, -}: Props) { +export default function CreateFacilityForm(props: FacilityProps) { const { t } = useTranslation(); const queryClient = useQueryClient(); const [isGettingLocation, setIsGettingLocation] = useState(false); + const { organizationId, facilityId, onSubmitSuccess } = props; + const [selectedLevels, setSelectedLevels] = useState([]); + const [pincode, setPincode] = useState(""); const form = useForm({ resolver: zodResolver(facilityFormSchema), @@ -90,6 +99,7 @@ export default function CreateFacilityForm({ description: "", features: [], pincode: "", + geo_organization: "", address: "", phone_number: "+91", latitude: "", @@ -122,12 +132,56 @@ export default function CreateFacilityForm({ }, }); - const onSubmit = (data: FacilityFormValues) => { - createFacility({ - ...data, - phone_number: parsePhoneNumber(data.phone_number), - geo_organization: organizationId, - }); + const { mutate: updateFacility, isPending: isUpdatePenidng } = useMutation({ + mutationFn: mutate(routes.updateFacility, { + pathParams: { id: facilityId || "" }, + }), // Use the update route + onSuccess: (_data: FacilityModel) => { + Notification.Success({ + msg: t("facility_updated_successfully"), + }); + queryClient.invalidateQueries({ queryKey: ["organizationFacilities"] }); + form.reset(); + onSubmitSuccess?.(); + }, + onError: (error: Error) => { + const errorData = error.cause as { errors: { msg: string[] } }; + if (errorData?.errors?.msg) { + errorData.errors.msg.forEach((msg) => { + Notification.Error({ msg }); + }); + } else { + Notification.Error({ + msg: t("facility_update_error"), + }); + } + }, + }); + + const { data: facilityData } = useQuery({ + queryKey: ["facility", facilityId], + queryFn: query(routes.getPermittedFacility, { + pathParams: { id: facilityId || "" }, + }), + enabled: !!facilityId, + }); + + const onSubmit: (data: FacilityFormValues) => void = ( + data: FacilityFormValues, + ) => { + if (facilityId) { + return updateFacility({ + ...data, + phone_number: parsePhoneNumber(data.phone_number), + geo_organization: organizationId, + }); + } else { + createFacility({ + ...data, + phone_number: parsePhoneNumber(data.phone_number), + geo_organization: organizationId, + }); + } }; const handleFeatureChange = (value: any) => { @@ -135,6 +189,26 @@ export default function CreateFacilityForm({ form.setValue("features", features); }; + // Update form when facility data is loaded + useEffect(() => { + if (facilityData) { + console.log(facilityData); + form.reset({ + facility_type: facilityData.facility_type, + name: facilityData.name, + description: facilityData.description || "", + features: facilityData.features || [], + pincode: facilityData.pincode?.toString() || "", + geo_organization: facilityData.geo_organization, + address: facilityData.address, + phone_number: facilityData.phone_number, + latitude: facilityData.latitude?.toString() || "", + longitude: facilityData.longitude?.toString() || "", + is_public: facilityData.is_public, + }); + } + }, [facilityData, form]); + const handleGetCurrentLocation = () => { if (navigator.geolocation) { setIsGettingLocation(true); @@ -162,6 +236,39 @@ export default function CreateFacilityForm({ } }; + const { data: pincodeData, isError: isPincodeError } = useQuery({ + queryKey: ["pincodeDetails", pincode], + queryFn: () => getPincodeDetails(pincode, careConfig.govDataApiKey), + enabled: validatePincode(pincode) && pincode != facilityData?.pincode, + }); + + if (isPincodeError) { + toast.error("Invalid pincode"); + } + + const stateName = pincodeData?.statename; + + const districtName = pincodeData?.districtname; + + const { data: stateOrg } = useFetchOrganizationByName(stateName); + const { data: districtOrg } = useFetchOrganizationByName( + districtName, + stateOrg?.id, + ); + + useEffect(() => { + if (stateOrg && districtOrg) { + setSelectedLevels([stateOrg, districtOrg]); + } else { + setSelectedLevels([]); + } + }, [stateOrg, districtOrg]); + + const handlePincodeChange = (value: string) => { + setPincode(value); + setSelectedLevels([]); + }; + return (
@@ -294,12 +401,26 @@ export default function CreateFacilityForm({ data-cy="facility-pincode" placeholder="Enter pincode" {...field} + onChange={(e) => { + field.onChange(e); + handlePincodeChange(e.target.value); + }} /> )} /> +
+ { + form.setValue("geo_organization", value); + }} + /> +
- + {facilityId ? ( + + ) : ( + + )} ); diff --git a/src/pages/Organization/OrganizationFacilities.tsx b/src/pages/Organization/OrganizationFacilities.tsx index 3a2713f6e86..5b11084d2aa 100644 --- a/src/pages/Organization/OrganizationFacilities.tsx +++ b/src/pages/Organization/OrganizationFacilities.tsx @@ -111,62 +111,59 @@ export default function OrganizationFacilities({ ) : ( facilities?.results?.map((facility: BaseFacility) => ( - - -
- {facility.read_cover_image_url ? ( - {facility.name} - ) : ( -
- -
- )} -
- -
-
-
-

- {facility.name} -

-
- {facility.facility_type} -
+ +
+ {facility.read_cover_image_url ? ( + {facility.name} + ) : ( +
+ +
+ )} +
+ +
+
+
+

+ {facility.name} +

+
+ {facility.facility_type}
- - - + + +
+ +
+ + View Facility + - -
- - +
+ +
+ + +
+ )) )}
diff --git a/src/pages/Organization/components/AddFacilitySheet.tsx b/src/pages/Organization/components/AddFacilitySheet.tsx index 4474baaffe8..b6a15f10f3a 100644 --- a/src/pages/Organization/components/AddFacilitySheet.tsx +++ b/src/pages/Organization/components/AddFacilitySheet.tsx @@ -13,34 +13,54 @@ import { SheetTrigger, } from "@/components/ui/sheet"; -import CreateFacilityForm from "@/components/Facility/CreateFacilityForm"; +import CreateFacilityForm from "@/components/Facility/FacilityForm"; interface Props { organizationId: string; + facilityId?: string; } -export default function AddFacilitySheet({ organizationId }: Props) { +export default function AddFacilitySheet({ + organizationId, + facilityId, +}: Props) { const queryClient = useQueryClient(); const [open, setOpen] = useState(false); return ( - + {facilityId ? ( + + ) : ( + + )} - Add New Facility + + {facilityId ? "Edit Facility" : "Add New Facility"} + - Create a new facility and add it to the organization. + {facilityId + ? "Update the details of the existing facility." + : "Create a new facility and add it to the organization."}
{ setOpen(false); queryClient.invalidateQueries({ queryKey: ["currentUser"] }); From dcad86a48e3087e93a8463f58a60cb93f2c338cf Mon Sep 17 00:00:00 2001 From: mahendar Date: Fri, 10 Jan 2025 00:38:00 +0530 Subject: [PATCH 10/20] added edit option --- src/components/Facility/FacilityForm.tsx | 53 ++++++++++-------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/src/components/Facility/FacilityForm.tsx b/src/components/Facility/FacilityForm.tsx index 9aaa91cdee9..781d128c779 100644 --- a/src/components/Facility/FacilityForm.tsx +++ b/src/components/Facility/FacilityForm.tsx @@ -132,7 +132,7 @@ export default function CreateFacilityForm(props: FacilityProps) { }, }); - const { mutate: updateFacility, isPending: isUpdatePenidng } = useMutation({ + const { mutate: updateFacility, isPending: isUpdatePending } = useMutation({ mutationFn: mutate(routes.updateFacility, { pathParams: { id: facilityId || "" }, }), // Use the update route @@ -562,14 +562,14 @@ export default function CreateFacilityForm(props: FacilityProps) { )}
- {facilityId ? ( - - ) : ( - - )} + ) + ) : isPending ? ( + <> + + Creating Facility... + + ) : ( + "Create Facility" + )} + ); From 9b577596d4beee96f346fa7d4ab308fd781a4187 Mon Sep 17 00:00:00 2001 From: mahendar Date: Fri, 10 Jan 2025 20:17:42 +0530 Subject: [PATCH 11/20] resolved conflicts --- src/Utils/utils.ts | 4 ---- src/components/Facility/FacilityForm.tsx | 10 +++------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index 950f0b52c18..0d918a4398e 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -190,10 +190,6 @@ export const getPincodeDetails = async (pincode: string, apiKey: string) => { `https://api.data.gov.in/resource/6176ee09-3d56-4a3b-8115-21841576b2f6?api-key=${apiKey}&format=json&filters[pincode]=${pincode}&limit=1`, ); const data = await response.json(); - if (!data.records || data.records.length === 0) { - Notification.Error({ msg: "Invalid pincode" }); - return null; - } return data.records[0]; }; diff --git a/src/components/Facility/FacilityForm.tsx b/src/components/Facility/FacilityForm.tsx index cbd0e4ab2cd..cb8b9993ae7 100644 --- a/src/components/Facility/FacilityForm.tsx +++ b/src/components/Facility/FacilityForm.tsx @@ -132,9 +132,7 @@ export default function CreateFacilityForm(props: FacilityProps) { pathParams: { id: facilityId || "" }, }), // Use the update route onSuccess: (_data: FacilityModel) => { - Notification.Success({ - msg: t("facility_updated_successfully"), - }); + toast.success(t("facility_updated_successfully")); queryClient.invalidateQueries({ queryKey: ["organizationFacilities"] }); form.reset(); onSubmitSuccess?.(); @@ -143,12 +141,10 @@ export default function CreateFacilityForm(props: FacilityProps) { const errorData = error.cause as { errors: { msg: string[] } }; if (errorData?.errors?.msg) { errorData.errors.msg.forEach((msg) => { - Notification.Error({ msg }); + toast.error(msg); }); } else { - Notification.Error({ - msg: t("facility_update_error"), - }); + toast.error(t("facility_update_error")); } }, }); From a932b00402abf2aef988a6984e7f101bb524b167 Mon Sep 17 00:00:00 2001 From: mahendar Date: Sat, 11 Jan 2025 12:45:35 +0530 Subject: [PATCH 12/20] autopopulation of existing details --- src/components/Facility/FacilityForm.tsx | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/components/Facility/FacilityForm.tsx b/src/components/Facility/FacilityForm.tsx index cb8b9993ae7..8dd6f0a6320 100644 --- a/src/components/Facility/FacilityForm.tsx +++ b/src/components/Facility/FacilityForm.tsx @@ -130,7 +130,7 @@ export default function CreateFacilityForm(props: FacilityProps) { const { mutate: updateFacility, isPending: isUpdatePending } = useMutation({ mutationFn: mutate(routes.updateFacility, { pathParams: { id: facilityId || "" }, - }), // Use the update route + }), onSuccess: (_data: FacilityModel) => { toast.success(t("facility_updated_successfully")); queryClient.invalidateQueries({ queryKey: ["organizationFacilities"] }); @@ -160,18 +160,15 @@ export default function CreateFacilityForm(props: FacilityProps) { const onSubmit: (data: FacilityFormValues) => void = ( data: FacilityFormValues, ) => { + const requestData = { + ...data, + phone_number: parsePhoneNumber(data.phone_number), + }; + if (facilityId) { - return updateFacility({ - ...data, - phone_number: parsePhoneNumber(data.phone_number), - geo_organization: organizationId, - }); + updateFacility(requestData); } else { - createFacility({ - ...data, - phone_number: parsePhoneNumber(data.phone_number), - geo_organization: organizationId, - }); + createFacility(requestData); } }; @@ -214,7 +211,7 @@ export default function CreateFacilityForm(props: FacilityProps) { setIsGettingLocation(false); toast.error(t("unable_to_get_location") + error.message); }, - { timeout: 10000 }, // 10 second timeout + { timeout: 10000 }, ); } else { toast.error(t("geolocation_is_not_supported_by_this_browser")); From 15eb9d31b87736da3b3a5857a474ddb9a82f3cb8 Mon Sep 17 00:00:00 2001 From: mahendar Date: Sat, 11 Jan 2025 13:39:28 +0530 Subject: [PATCH 13/20] added i18n and pincode limit --- public/locale/en.json | 9 ++++++ src/Utils/utils.ts | 4 +++ src/components/Facility/FacilityForm.tsx | 28 ++++++++----------- .../components/AddFacilitySheet.tsx | 11 ++++---- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index a6e2d48b294..5e0592364e8 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -330,6 +330,7 @@ "add_insurance_details": "Add Insurance Details", "add_location": "Add Location", "add_new_beds": "Add New Bed(s)", + "add_new_facility": "Add New Facility", "add_new_patient": "Add New Patient", "add_new_user": "Add New User", "add_notes": "Add notes", @@ -663,6 +664,7 @@ "create_new_abha_address": "Create New ABHA Address", "create_new_abha_profile": "Don't have an ABHA Number", "create_new_asset": "Create New Asset", + "create_new_facility": "Create a new facility and add it to the organization.", "create_position_preset": "Create a new position preset", "create_position_preset_description": "Creates a new position preset in Care from the current position of the camera for the given name", "create_preset_prerequisite": "To create presets for this bed, you'll need to link the camera to the bed first.", @@ -675,6 +677,7 @@ "created_date": "Created Date", "created_on": "Created On", "creating": "Creating...", + "creating_facility": "Creating Facility...", "criticality": "Criticality", "csv_file_in_the_specified_format": "Select a CSV file in the specified format", "current_address": "Current Address", @@ -786,6 +789,7 @@ "edit_avatar_permission_error": "You do not have permissions to edit the avatar of this user", "edit_caution_note": "A new prescription will be added to the consultation with the edited details and the current prescription will be discontinued.", "edit_cover_photo": "Edit Cover Photo", + "edit_facility": "Edit Facility", "edit_history": "Edit History", "edit_policy": "Edit Insurance Policy", "edit_policy_description": "Add or edit patient's insurance details", @@ -1030,7 +1034,9 @@ "geolocation_is_not_supported_by_this_browser": "Geolocation is not supported by this browser", "get_auth_methods": "Get Available Authentication Methods", "get_auth_mode_error": "Could not find any supported authentication methods, Please try again with a different authentication method", + "get_current_location": "Get Current Location", "get_tests": "Get Tests", + "getting_location": "Getting Location...", "goal": "Our goal is to continuously improve the quality and accessibility of public healthcare services using digital tools.", "granted_on": "Granted On", "has_allergies": "Has Allergies", @@ -1194,6 +1200,7 @@ "local_ip_address_example": "e.g. 192.168.0.123", "location": "Location", "location_beds_empty": "No beds available in this location", + "location_details": "Location Details", "location_management": "Location Management", "location_updated_successfully": "Location updated successfully", "log_lab_results": "Log Lab Results", @@ -1951,6 +1958,7 @@ "update_asset_service_record": "Update Asset Service Record", "update_available": "Update Available", "update_bed": "Update Bed", + "update_existing_facility": "Update the details of the existing facility.", "update_facility": "Update Facility", "update_facility_middleware_success": "Facility middleware updated successfully", "update_log": "Update Log", @@ -1970,6 +1978,7 @@ "updated_on": "Updated On", "updates": "Updates", "updating": "Updating...", + "updating_facility": "Updating Facility...", "upload": "Upload", "upload_an_image": "Upload an image", "upload_file": "Upload File", diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index 0d918a4398e..d66b1076e49 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -190,6 +190,10 @@ export const getPincodeDetails = async (pincode: string, apiKey: string) => { `https://api.data.gov.in/resource/6176ee09-3d56-4a3b-8115-21841576b2f6?api-key=${apiKey}&format=json&filters[pincode]=${pincode}&limit=1`, ); const data = await response.json(); + if (!data.records || data.records.length === 0) { + toast.error("Invalid pincode"); + return null; + } return data.records[0]; }; diff --git a/src/components/Facility/FacilityForm.tsx b/src/components/Facility/FacilityForm.tsx index 8dd6f0a6320..f8ded7f17f6 100644 --- a/src/components/Facility/FacilityForm.tsx +++ b/src/components/Facility/FacilityForm.tsx @@ -180,7 +180,6 @@ export default function CreateFacilityForm(props: FacilityProps) { // Update form when facility data is loaded useEffect(() => { if (facilityData) { - console.log(facilityData); form.reset({ facility_type: facilityData.facility_type, name: facilityData.name, @@ -218,16 +217,12 @@ export default function CreateFacilityForm(props: FacilityProps) { } }; - const { data: pincodeData, isError: isPincodeError } = useQuery({ + const { data: pincodeData } = useQuery({ queryKey: ["pincodeDetails", pincode], queryFn: () => getPincodeDetails(pincode, careConfig.govDataApiKey), enabled: validatePincode(pincode) && pincode != facilityData?.pincode, }); - if (isPincodeError) { - toast.error("Invalid pincode"); - } - const stateName = pincodeData?.statename; const districtName = pincodeData?.districtname; @@ -256,7 +251,7 @@ export default function CreateFacilityForm(props: FacilityProps) {
{/* Basic Information */}
-

Basic Information

+

{t("basic_info")}

-

Contact Information

+

{t("contact_info")}

{ field.onChange(e); @@ -428,7 +424,7 @@ export default function CreateFacilityForm(props: FacilityProps) { {/* Location Information */}
-

Location Details

+

{t("location_details")}

@@ -497,7 +493,7 @@ export default function CreateFacilityForm(props: FacilityProps) { {/* Visibility Settings */}
-

Visibility Settings

+

{t("visibility_settings")}

- Updating Facility... + {t("updating_facility")} ) : ( - "Update Facility" + t("update_facility") ) ) : isPending ? ( <> @@ -568,10 +564,10 @@ export default function CreateFacilityForm(props: FacilityProps) { icon="l-spinner" className="mr-2 h-4 w-4 animate-spin" /> - Creating Facility... + {t("creating_facility")} ) : ( - "Create Facility" + t("create_facility") )} diff --git a/src/pages/Organization/components/AddFacilitySheet.tsx b/src/pages/Organization/components/AddFacilitySheet.tsx index b6a15f10f3a..037e6150f63 100644 --- a/src/pages/Organization/components/AddFacilitySheet.tsx +++ b/src/pages/Organization/components/AddFacilitySheet.tsx @@ -1,4 +1,5 @@ import { useQueryClient } from "@tanstack/react-query"; +import { t } from "i18next"; import { useState } from "react"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -37,24 +38,24 @@ export default function AddFacilitySheet({ className="text-primary-400 text-sm" > - Edit Facility + {t("edit_facility")} ) : ( )} - {facilityId ? "Edit Facility" : "Add New Facility"} + {facilityId ? t("edit_facility") : t("add_new_facility")} {facilityId - ? "Update the details of the existing facility." - : "Create a new facility and add it to the organization."} + ? t("update_existing_facility") + : t("create_new_facility")}
From f735ac92ba79880675a68d597d2bdd3ebb3eb9a7 Mon Sep 17 00:00:00 2001 From: mahendar Date: Sat, 11 Jan 2025 13:41:08 +0530 Subject: [PATCH 14/20] added i18n and pincode limit --- src/pages/Organization/OrganizationFacilities.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/Organization/OrganizationFacilities.tsx b/src/pages/Organization/OrganizationFacilities.tsx index dc693b0e96d..c3af15931df 100644 --- a/src/pages/Organization/OrganizationFacilities.tsx +++ b/src/pages/Organization/OrganizationFacilities.tsx @@ -114,7 +114,10 @@ export default function OrganizationFacilities({ ) : ( facilities?.results?.map((facility: BaseFacility) => ( - +
{facility.read_cover_image_url ? ( Date: Sat, 11 Jan 2025 15:06:19 +0530 Subject: [PATCH 15/20] link wrap in button --- src/components/Facility/FacilityForm.tsx | 2 +- .../Organization/OrganizationFacilities.tsx | 22 +++++++++---------- .../components/AddFacilitySheet.tsx | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/components/Facility/FacilityForm.tsx b/src/components/Facility/FacilityForm.tsx index f8ded7f17f6..8baf12b4039 100644 --- a/src/components/Facility/FacilityForm.tsx +++ b/src/components/Facility/FacilityForm.tsx @@ -389,7 +389,7 @@ export default function CreateFacilityForm(props: FacilityProps) { )} /> -
+
-
+
- - View Facility +
- +
)) diff --git a/src/pages/Organization/components/AddFacilitySheet.tsx b/src/pages/Organization/components/AddFacilitySheet.tsx index 037e6150f63..dfe014333de 100644 --- a/src/pages/Organization/components/AddFacilitySheet.tsx +++ b/src/pages/Organization/components/AddFacilitySheet.tsx @@ -35,7 +35,7 @@ export default function AddFacilitySheet({
diff --git a/src/pages/Appointments/AppointmentDetail.tsx b/src/pages/Appointments/AppointmentDetail.tsx index 245c049897f..463b8b56f1e 100644 --- a/src/pages/Appointments/AppointmentDetail.tsx +++ b/src/pages/Appointments/AppointmentDetail.tsx @@ -46,7 +46,6 @@ import { Separator } from "@/components/ui/separator"; import Loading from "@/components/Common/Loading"; import Page from "@/components/Common/Page"; -import { FacilityModel } from "@/components/Facility/models"; import routes from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; @@ -61,6 +60,7 @@ import { formatAppointmentSlotTime, printAppointment, } from "@/pages/Appointments/utils"; +import { FacilityData } from "@/types/facility/facility"; import { Appointment, AppointmentStatuses, @@ -207,7 +207,7 @@ const AppointmentDetails = ({ facility, }: { appointment: Appointment; - facility: FacilityModel; + facility: FacilityData; }) => { const { patient, user } = appointment; const { t } = useTranslation(); diff --git a/src/pages/Appointments/components/AppointmentTokenCard.tsx b/src/pages/Appointments/components/AppointmentTokenCard.tsx index 9f563852a82..7dc65f84c3f 100644 --- a/src/pages/Appointments/components/AppointmentTokenCard.tsx +++ b/src/pages/Appointments/components/AppointmentTokenCard.tsx @@ -4,17 +4,16 @@ import { useTranslation } from "react-i18next"; import { Card } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; -import { FacilityModel } from "@/components/Facility/models"; - import { formatName, formatPatientAge } from "@/Utils/utils"; import { formatAppointmentSlotTime } from "@/pages/Appointments/utils"; import { getFakeTokenNumber } from "@/pages/Scheduling/utils"; +import { FacilityData } from "@/types/facility/facility"; import { Appointment } from "@/types/scheduling/schedule"; interface Props { id?: string; appointment: Appointment; - facility: FacilityModel; + facility: FacilityData; } const AppointmentTokenCard = ({ id, appointment, facility }: Props) => { diff --git a/src/pages/Appointments/utils.ts b/src/pages/Appointments/utils.ts index 4b131e50382..2ff300cd8b8 100644 --- a/src/pages/Appointments/utils.ts +++ b/src/pages/Appointments/utils.ts @@ -10,8 +10,6 @@ import { import { TFunction } from "i18next"; import { toast } from "sonner"; -import { FacilityModel } from "@/components/Facility/models"; - import query from "@/Utils/request/query"; import { dateQueryString, @@ -20,6 +18,7 @@ import { getMonthStartAndEnd, } from "@/Utils/utils"; import { getFakeTokenNumber } from "@/pages/Scheduling/utils"; +import { FacilityData } from "@/types/facility/facility"; import { Appointment, AvailabilityHeatmapResponse, @@ -142,7 +141,7 @@ export const printAppointment = ({ appointment, }: { t: TFunction; - facility: FacilityModel; + facility: FacilityData; appointment: Appointment; }) => { const patient = appointment.patient; diff --git a/src/pages/Organization/OrganizationFacilities.tsx b/src/pages/Organization/OrganizationFacilities.tsx index 3cb2b40acee..e4276c27d1d 100644 --- a/src/pages/Organization/OrganizationFacilities.tsx +++ b/src/pages/Organization/OrganizationFacilities.tsx @@ -17,6 +17,7 @@ import query from "@/Utils/request/query"; import { BaseFacility } from "@/types/facility/facility"; import AddFacilitySheet from "./components/AddFacilitySheet"; +import EditFacilitySheet from "./components/EditFacilitySheet"; import OrganizationLayout from "./components/OrganizationLayout"; interface Props { @@ -147,7 +148,7 @@ export default function OrganizationFacilities({
- diff --git a/src/pages/Organization/components/AddFacilitySheet.tsx b/src/pages/Organization/components/AddFacilitySheet.tsx index dfe014333de..33bd5d40f6f 100644 --- a/src/pages/Organization/components/AddFacilitySheet.tsx +++ b/src/pages/Organization/components/AddFacilitySheet.tsx @@ -14,54 +14,32 @@ import { SheetTrigger, } from "@/components/ui/sheet"; -import CreateFacilityForm from "@/components/Facility/FacilityForm"; +import FacilityForm from "@/components/Facility/FacilityForm"; interface Props { organizationId: string; - facilityId?: string; } -export default function AddFacilitySheet({ - organizationId, - facilityId, -}: Props) { +export default function AddFacilitySheet({ organizationId }: Props) { const queryClient = useQueryClient(); const [open, setOpen] = useState(false); return ( - {facilityId ? ( - - ) : ( - - )} + - - {facilityId ? t("edit_facility") : t("add_new_facility")} - - - {facilityId - ? t("update_existing_facility") - : t("create_new_facility")} - + {t("add_new_facility")} + {t("create_new_facility")}
- { setOpen(false); queryClient.invalidateQueries({ queryKey: ["currentUser"] }); diff --git a/src/pages/Organization/components/EditFacilitySheet.tsx b/src/pages/Organization/components/EditFacilitySheet.tsx new file mode 100644 index 00000000000..a81bb4fd3aa --- /dev/null +++ b/src/pages/Organization/components/EditFacilitySheet.tsx @@ -0,0 +1,58 @@ +import { useQueryClient } from "@tanstack/react-query"; +import { t } from "i18next"; +import { useState } from "react"; + +import CareIcon from "@/CAREUI/icons/CareIcon"; + +import { Button } from "@/components/ui/button"; +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@/components/ui/sheet"; + +import FacilityForm from "@/components/Facility/FacilityForm"; + +interface Props { + organizationId?: string; + facilityId: string; +} + +export default function EditFacilitySheet({ facilityId }: Props) { + const queryClient = useQueryClient(); + const [open, setOpen] = useState(false); + console.log(open); + + return ( + + + + + + + {t("edit_facility")} + {t("update_existing_facility")} + +
+ { + setOpen(false); + queryClient.invalidateQueries({ queryKey: ["currentUser"] }); + }} + /> +
+
+
+ ); +} diff --git a/src/types/facility/facility.ts b/src/types/facility/facility.ts index b6527063616..7d5a3ca56ec 100644 --- a/src/types/facility/facility.ts +++ b/src/types/facility/facility.ts @@ -1,3 +1,5 @@ +import { FeatureFlag } from "@/Utils/featureFlags"; + import { Organization } from "../organization/organization"; export interface BaseFacility { @@ -27,5 +29,10 @@ export interface FacilityData { features: number[]; geo_organization: Organization; pincode?: string; + location?: { + latitude: number; + longitude: number; + }; + facility_flags?: FeatureFlag[]; is_public: boolean; } From 439a0611590a66d7a925cb9ca97213a811fce661 Mon Sep 17 00:00:00 2001 From: Mahendar Chikolla <119734520+Mahendar0701@users.noreply.github.com> Date: Tue, 14 Jan 2025 14:03:34 +0530 Subject: [PATCH 19/20] Update FacilityHome.tsx --- src/components/Facility/FacilityHome.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/Facility/FacilityHome.tsx b/src/components/Facility/FacilityHome.tsx index 2f0da819a56..ffc9ab5bbab 100644 --- a/src/components/Facility/FacilityHome.tsx +++ b/src/components/Facility/FacilityHome.tsx @@ -241,11 +241,7 @@ export const FacilityHome = ({ facilityId }: Props) => { {t("edit_cover_photo")} )} - { - e.stopPropagation(); - }} - > + From 0a6f61641f486e7a25546b3cb3f7cab3e5036d5e Mon Sep 17 00:00:00 2001 From: mahendar Date: Tue, 14 Jan 2025 16:20:30 +0530 Subject: [PATCH 20/20] organization error on update fixed --- src/Routers/routes/FacilityRoutes.tsx | 6 +- src/components/Facility/FacilityCreate.tsx | 567 ------------------ src/components/Facility/FacilityForm.tsx | 37 +- src/components/Facility/FacilityHome.tsx | 7 +- .../Organization/OrganizationFacilities.tsx | 13 +- .../components/EditFacilitySheet.tsx | 13 +- .../components/OrganizationSelector.tsx | 16 +- src/types/facility/facility.ts | 6 +- 8 files changed, 51 insertions(+), 614 deletions(-) delete mode 100644 src/components/Facility/FacilityCreate.tsx diff --git a/src/Routers/routes/FacilityRoutes.tsx b/src/Routers/routes/FacilityRoutes.tsx index 44637fdbcf8..655d809bd33 100644 --- a/src/Routers/routes/FacilityRoutes.tsx +++ b/src/Routers/routes/FacilityRoutes.tsx @@ -1,6 +1,5 @@ import { Redirect } from "raviger"; -import { FacilityCreate } from "@/components/Facility/FacilityCreate"; import { FacilityHome } from "@/components/Facility/FacilityHome"; import FacilityUsers from "@/components/Facility/FacilityUsers"; import ResourceCreate from "@/components/Resource/ResourceCreate"; @@ -12,10 +11,7 @@ import FacilityOrganizationView from "@/pages/FacilityOrganization/FacilityOrgan const FacilityRoutes: AppRoutes = { "/facility": () => , - "/facility/create": () => , - "/facility/:facilityId/update": ({ facilityId }) => ( - - ), + "/facility/:facilityId": ({ facilityId }) => ( ), diff --git a/src/components/Facility/FacilityCreate.tsx b/src/components/Facility/FacilityCreate.tsx deleted file mode 100644 index e832bc2cd5f..00000000000 --- a/src/components/Facility/FacilityCreate.tsx +++ /dev/null @@ -1,567 +0,0 @@ -import careConfig from "@careConfig"; -import { - Popover, - PopoverButton, - PopoverPanel, - Transition, -} from "@headlessui/react"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useQuery } from "@tanstack/react-query"; -import { navigate } from "raviger"; -import { useEffect, useState } from "react"; -import { useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; -import { toast } from "sonner"; -import * as z from "zod"; - -import Card from "@/CAREUI/display/Card"; -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import { Button } from "@/components/ui/button"; -import { Checkbox } from "@/components/ui/checkbox"; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { Textarea } from "@/components/ui/textarea"; - -import GLocationPicker from "@/components/Common/GLocationPicker"; -import Loading from "@/components/Common/Loading"; -import Page from "@/components/Common/Page"; -import { FacilityRequest } from "@/components/Facility/models"; -import { PhoneNumberValidator } from "@/components/Form/FieldValidators"; -import PhoneNumberFormField from "@/components/Form/FormFields/PhoneNumberFormField"; -import { MultiSelectFormField } from "@/components/Form/FormFields/SelectFormField"; -import TextAreaFormField from "@/components/Form/FormFields/TextAreaFormField"; -import TextFormField from "@/components/Form/FormFields/TextFormField"; - -import useAppHistory from "@/hooks/useAppHistory"; - -import { FACILITY_FEATURE_TYPES, FACILITY_TYPES } from "@/common/constants"; -import { - phonePreg, - validateLatitude, - validateLongitude, - validatePincode, -} from "@/common/validation"; - -import routes from "@/Utils/request/api"; -import query from "@/Utils/request/query"; -import request from "@/Utils/request/request"; -import { getPincodeDetails, parsePhoneNumber } from "@/Utils/utils"; -import OrganizationSelector from "@/pages/Organization/components/OrganizationSelector"; -import { Organization } from "@/types/organization/organization"; -import { useFetchOrganizationByName } from "@/types/organization/organizationApi"; - -interface FacilityProps { - facilityId?: string; -} -export const FacilityCreate = (props: FacilityProps) => { - const { t } = useTranslation(); - const { facilityId } = props; - const [isLoading, setIsLoading] = useState(false); - const [selectedLevels, setSelectedLevels] = useState([]); - const [pincode, setPincode] = useState(""); - - const { goBack } = useAppHistory(); - - const facilityFormSchema = z.object({ - facility_type: z.string().min(1, { message: t("required") }), - name: z.string().min(1, { message: t("required") }), - description: z.string().optional(), - features: z.array(z.number()).default([]), - pincode: z.string().refine(validatePincode, { - message: t("invalid_pincode"), - }), - geo_organization: z.string().min(1, { message: t("required") }), - address: z.string().min(1, { message: t("required") }), - phone_number: z - .string() - .min(1, { message: t("required") }) - .refine( - (val: string) => { - if ( - !PhoneNumberValidator(["mobile", "landline"])(val) === undefined || - !phonePreg(val) - ) { - return false; - } - return true; - }, - { - message: t("invalid_phone_number"), - }, - ), - latitude: z - .string() - .min(1, { message: t("required") }) - .refine((val) => !val || validateLatitude(val), { - message: t("latitude_invalid"), - }), - longitude: z - .string() - .min(1, { message: t("required") }) - .refine((val) => !val || validateLongitude(val), { - message: t("longitude_invalid"), - }), - is_public: z.boolean().default(false), - }); - - type FacilityFormValues = z.infer; - - const { data: facilityData } = useQuery({ - queryKey: ["facility", facilityId], - queryFn: query(routes.getPermittedFacility, { - pathParams: { id: facilityId || "" }, - }), - enabled: !!facilityId, - }); - - const form = useForm({ - resolver: zodResolver(facilityFormSchema), - defaultValues: { - facility_type: "", - name: "", - description: "", - features: [], - pincode: "", - geo_organization: "", - address: "", - phone_number: "", - latitude: "", - longitude: "", - is_public: false, - }, - }); - - // Update form when facility data is loaded - useEffect(() => { - if (facilityData) { - form.reset({ - facility_type: facilityData.facility_type, - name: facilityData.name, - description: facilityData.description || "", - features: facilityData.features || [], - pincode: facilityData.pincode?.toString() || "", - geo_organization: JSON.stringify(facilityData?.geo_organization) || "", - address: facilityData.address, - phone_number: facilityData.phone_number, - latitude: facilityData.location?.latitude?.toString() || "", - longitude: facilityData.location?.longitude?.toString() || "", - is_public: facilityData.is_public, - }); - } - }, [facilityData, form]); - - const handleLocationChange = (location: google.maps.LatLng | undefined) => { - if (location) { - form.setValue("latitude", location.lat().toFixed(7)); - form.setValue("longitude", location.lng().toFixed(7)); - } - }; - - const handleSelectCurrentLocation = ( - setCenter: (lat: number, lng: number) => void, - ) => { - if (navigator.geolocation) { - navigator.geolocation.getCurrentPosition((position) => { - form.setValue("latitude", String(position.coords.latitude)); - form.setValue("longitude", String(position.coords.longitude)); - setCenter?.(position.coords.latitude, position.coords.longitude); - }); - } - }; - - const handleFeatureChange = (value: any) => { - const { value: features }: { value: Array } = value; - form.setValue("features", features); - }; - - const onSubmit = async (data: FacilityFormValues) => { - setIsLoading(true); - try { - const requestData: FacilityRequest = { - ...data, - phone_number: parsePhoneNumber(data.phone_number), - }; - - const { res, data: responseData } = facilityId - ? await request(routes.updateFacility, { - body: requestData, - pathParams: { id: facilityId }, - }) - : await request(routes.createFacility, { - body: requestData, - }); - - if (res?.ok && responseData) { - toast.success( - facilityId - ? t("facility_updated_success") - : t("facility_added_successfully"), - ); - navigate(`/facility/${responseData.id}`); - } - } catch (error) { - console.error(error); - } finally { - setIsLoading(false); - } - }; - - const { data: pincodeData, isError: isPincodeError } = useQuery({ - queryKey: ["pincodeDetails", pincode], - queryFn: () => getPincodeDetails(pincode, careConfig.govDataApiKey), - enabled: validatePincode(pincode) && pincode != facilityData?.pincode, - }); - - if (isPincodeError) { - toast.error("Invalid pincode"); - } - - const stateName = pincodeData?.statename; - - const districtName = pincodeData?.districtname; - - const { data: stateOrg } = useFetchOrganizationByName(stateName); - const { data: districtOrg } = useFetchOrganizationByName( - districtName, - stateOrg?.id, - ); - - useEffect(() => { - if (stateOrg && districtOrg) { - setSelectedLevels([stateOrg, districtOrg]); - } else { - setSelectedLevels([]); - } - }, [stateOrg, districtOrg]); - - const handlePincodeChange = (value: string) => { - setPincode(value); - setSelectedLevels([]); - }; - - return ( - - -
-
- -
- ( - - {t("facility_type")} - - - - )} - /> - - ( - - {t("facility_name")} - - - - - - )} - /> -
- - ( - - {t("description")} - -