diff --git a/public/locale/en.json b/public/locale/en.json index b0c3404f084..28a2245f470 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -331,6 +331,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", @@ -685,6 +686,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_new_tag": "Create New Tag", "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", @@ -699,6 +701,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", @@ -812,6 +815,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", @@ -1070,7 +1074,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", @@ -1239,6 +1245,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", @@ -2059,6 +2066,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", @@ -2078,6 +2086,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", @@ -2167,6 +2176,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/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/Utils/featureFlags.tsx b/src/Utils/featureFlags.tsx index 98d1cbebbf7..e4952783f3b 100644 --- a/src/Utils/featureFlags.tsx +++ b/src/Utils/featureFlags.tsx @@ -1,11 +1,10 @@ import { createContext, useContext, useEffect, useState } from "react"; -import { FacilityModel } from "@/components/Facility/models"; - import useAuthUser from "@/hooks/useAuthUser"; import routes from "@/Utils/request/api"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; +import { FacilityData } from "@/types/facility/facility"; export type FeatureFlag = "SCRIBE_ENABLED"; // "HCX_ENABLED" | "ABDM_ENABLED" | @@ -48,9 +47,9 @@ export const FeatureFlagsProvider = (props: { children: React.ReactNode }) => { ); }; -export const useFeatureFlags = (facility?: FacilityModel | string) => { +export const useFeatureFlags = (facility?: FacilityData | string) => { const [facilityObject, setFacilityObject] = useState< - FacilityModel | undefined + FacilityData | undefined >(typeof facility === "string" ? undefined : facility); const context = useContext(FeatureFlagsContext); diff --git a/src/Utils/request/api.tsx b/src/Utils/request/api.tsx index eafc48e3c81..c05bc3be748 100644 --- a/src/Utils/request/api.tsx +++ b/src/Utils/request/api.tsx @@ -196,7 +196,7 @@ const routes = { getPermittedFacility: { path: "/api/v1/facility/{id}/", method: "GET", - TRes: Type(), + TRes: Type(), }, getAnyFacility: { diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index 5b6af0ac5a6..df4905709bd 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -1,5 +1,6 @@ import { differenceInMinutes, format } from "date-fns"; import html2canvas from "html2canvas"; +import { toast } from "sonner"; import { AREACODES, IN_LANDLINE_AREA_CODES } from "@/common/constants"; import phoneCodesJson from "@/common/static/countryPhoneAndFlags.json"; @@ -112,6 +113,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/FacilityCreate.tsx b/src/components/Facility/FacilityCreate.tsx deleted file mode 100644 index 59b87633a8f..00000000000 --- a/src/components/Facility/FacilityCreate.tsx +++ /dev/null @@ -1,521 +0,0 @@ -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 { parsePhoneNumber } from "@/Utils/utils"; -import OrganizationSelector from "@/pages/Organization/components/OrganizationSelector"; - -interface FacilityProps { - facilityId?: string; -} -export const FacilityCreate = (props: FacilityProps) => { - const { t } = useTranslation(); - const { facilityId } = props; - const [isLoading, setIsLoading] = useState(false); - 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: 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 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); - } - }; - - return ( - - -
-
- -
- ( - - {t("facility_type")} - - - - )} - /> - - ( - - {t("facility_name")} - - - - - - )} - /> -
- - ( - - {t("description")} - -