diff --git a/src/components/Common/DateInputV2.tsx b/src/components/Common/DateInputV2.tsx index 20027a004d2..8debee7ac7b 100644 --- a/src/components/Common/DateInputV2.tsx +++ b/src/components/Common/DateInputV2.tsx @@ -89,15 +89,18 @@ const DateInputV2: React.FC = ({ ); break; case "month": - setDatePickerHeaderDate((prev) => - dayjs(prev).subtract(1, "year").toDate(), - ); + setDatePickerHeaderDate((prev) => { + const newDate = dayjs(prev).subtract(1, "year").toDate(); + if (min && newDate < min) { + return new Date(min.getFullYear(), min.getMonth(), 1); + } + return newDate; + }); break; case "year": - setDatePickerHeaderDate((prev) => - dayjs(prev).subtract(1, "year").toDate(), - ); - setYear((prev) => dayjs(prev).subtract(10, "year").toDate()); + if (!min || year.getFullYear() - 10 >= min.getFullYear()) { + setYear((prev) => dayjs(prev).subtract(10, "year").toDate()); + } break; } }; @@ -108,11 +111,18 @@ const DateInputV2: React.FC = ({ setDatePickerHeaderDate((prev) => dayjs(prev).add(1, "month").toDate()); break; case "month": - setDatePickerHeaderDate((prev) => dayjs(prev).add(1, "year").toDate()); + setDatePickerHeaderDate((prev) => { + const newDate = dayjs(prev).add(1, "year").toDate(); + if (max && newDate > max) { + return new Date(max.getFullYear(), max.getMonth(), 1); + } + return newDate; + }); break; case "year": - setDatePickerHeaderDate((prev) => dayjs(prev).add(1, "year").toDate()); - setYear((prev) => dayjs(prev).add(10, "year").toDate()); + if (!max || year.getFullYear() + 10 <= max.getFullYear()) { + setYear((prev) => dayjs(prev).add(10, "year").toDate()); + } break; } }; @@ -209,6 +219,33 @@ const DateInputV2: React.FC = ({ return true; }; + const isMonthWithinConstraints = (month: number) => { + const year = datePickerHeaderDate.getFullYear(); + + if (min && year < min.getFullYear()) return false; + if (max && year > max.getFullYear()) return false; + + const firstDay = new Date(year, month, 1); + const lastDay = new Date(year, month + 1, 0); + if (min && lastDay < min) return false; + if (max && firstDay > max) return false; + + return true; + }; + + const isYearWithinConstraints = (year: number) => { + if (min && year < min.getFullYear()) return false; + if (max && year > max.getFullYear()) return false; + + const yearStart = new Date(year, 0, 1); + const yearEnd = new Date(year, 11, 31); + + if (min && yearEnd < min) return false; + if (max && yearStart > max) return false; + + return true; + }; + const isSelectedMonth = (month: number) => month === datePickerHeaderDate.getMonth(); @@ -216,25 +253,48 @@ const DateInputV2: React.FC = ({ year === datePickerHeaderDate.getFullYear(); const setMonthValue = (month: number) => () => { - setDatePickerHeaderDate( - new Date( + if (isMonthWithinConstraints(month)) { + const lastDayOfMonth = new Date( datePickerHeaderDate.getFullYear(), - month, - datePickerHeaderDate.getDate(), - ), - ); - setType("date"); + month + 1, + 0, + ).getDate(); + const newDate = Math.min(datePickerHeaderDate.getDate(), lastDayOfMonth); + setDatePickerHeaderDate( + new Date(datePickerHeaderDate.getFullYear(), month, newDate), + ); + setType("date"); + } else { + Notification.Error({ + msg: outOfLimitsErrorMessage ?? "Cannot select month out of range", + }); + } }; - + //min and max setting for year const setYearValue = (year: number) => () => { - setDatePickerHeaderDate( - new Date( + if (isYearWithinConstraints(year)) { + const newDate = new Date( year, datePickerHeaderDate.getMonth(), datePickerHeaderDate.getDate(), - ), - ); - setType("date"); + ); + if (min && year === min.getFullYear() && newDate < min) { + setDatePickerHeaderDate( + new Date(min.getFullYear(), min.getMonth(), min.getDate()), + ); + } else if (max && year === max.getFullYear() && newDate > max) { + setDatePickerHeaderDate( + new Date(max.getFullYear(), max.getMonth(), max.getDate()), + ); + } else { + setDatePickerHeaderDate(newDate); + } + setType("date"); + } else { + Notification.Error({ + msg: outOfLimitsErrorMessage ?? "Cannot select year out of range", + }); + } }; useEffect(() => { @@ -331,6 +391,7 @@ const DateInputV2: React.FC = ({ data-scribe-ignore className={`cui-input-base cursor-pointer disabled:cursor-not-allowed ${className}`} placeholder={placeholder ?? t("select_date")} + title={placeholder} value={value ? dayjs(value).format(dateFormat) : ""} />
@@ -371,23 +432,62 @@ const DateInputV2: React.FC = ({
- + {type === "date" && ( + + )} + {type === "month" && ( + + )} + + {type === "year" && ( + + )}
{type === "date" && ( @@ -411,23 +511,62 @@ const DateInputV2: React.FC = ({

- + {type === "date" && ( + + )} + {type === "month" && ( + + )} + + {type === "year" && ( + + )}
{type === "date" && ( @@ -510,10 +649,12 @@ const DateInputV2: React.FC = ({ key={i} id={`month-${i}`} className={classNames( - "w-1/4 cursor-pointer rounded-lg px-2 py-4 text-center text-sm font-semibold", - value && isSelectedMonth(i) - ? "bg-primary-500 text-white" - : "text-secondary-700 hover:bg-secondary-300", + "w-1/4 rounded-lg px-2 py-4 text-center text-sm font-semibold", + isSelectedMonth(i) + ? "bg-primary-500 text-white cursor-pointer" + : isMonthWithinConstraints(i) + ? "text-secondary-700 hover:bg-secondary-300 cursor-pointer" + : "!text-secondary-400 !cursor-not-allowed", )} onClick={setMonthValue(i)} > @@ -533,16 +674,18 @@ const DateInputV2: React.FC = ({ {Array(12) .fill(null) .map((_, i) => { - const y = year.getFullYear() - 11 + i; + const y = year.getFullYear() - 10 + i; return (
diff --git a/src/components/Common/Sidebar/Sidebar.tsx b/src/components/Common/Sidebar/Sidebar.tsx index 423d0d6f18b..e6d9edbc2dd 100644 --- a/src/components/Common/Sidebar/Sidebar.tsx +++ b/src/components/Common/Sidebar/Sidebar.tsx @@ -6,12 +6,7 @@ import { useTranslation } from "react-i18next"; import CareIcon, { IconName } from "@/CAREUI/icons/CareIcon"; import SlideOver from "@/CAREUI/interactive/SlideOver"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; +import { TooltipComponent, TooltipProvider } from "@/components/ui/tooltip"; import { ShrinkedSidebarItem, @@ -243,24 +238,19 @@ const ToggleShrink = ({ shrinked, toggle }: ToggleShrinkProps) => { const { t } = useTranslation(); return ( - - - - - -

{shrinked ? t("expand_sidebar") : t("collapse_sidebar")}

-
-
+ + +
); }; diff --git a/src/components/Facility/DischargedPatientsList.tsx b/src/components/Facility/DischargedPatientsList.tsx index 4fb8910f7a1..74bb6d95626 100644 --- a/src/components/Facility/DischargedPatientsList.tsx +++ b/src/components/Facility/DischargedPatientsList.tsx @@ -1,5 +1,5 @@ import { Link, navigate } from "raviger"; -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import CountBlock from "@/CAREUI/display/Count"; @@ -11,13 +11,11 @@ import PaginatedList from "@/CAREUI/misc/PaginatedList"; import Loading from "@/components/Common/Loading"; import Page from "@/components/Common/Page"; +import SearchByMultipleFields from "@/components/Common/SearchByMultipleFields"; import SortDropdownMenu from "@/components/Common/SortDropdown"; import Tabs from "@/components/Common/Tabs"; import { getDiagnosesByIds } from "@/components/Diagnosis/utils"; import { ICD11DiagnosisModel } from "@/components/Facility/models"; -import PhoneNumberFormField from "@/components/Form/FormFields/PhoneNumberFormField"; -import { FieldChangeEvent } from "@/components/Form/FormFields/Utils"; -import SearchInput from "@/components/Form/SearchInput"; import { DIAGNOSES_FILTER_LABELS, DiagnosesFilterKey, @@ -52,16 +50,79 @@ const DischargedPatientsList = ({ pathParams: { id: facility_external_id }, }); - const { qParams, updateQuery, advancedFilter, FilterBadges, updatePage } = - useFilters({ - limit: 12, - cacheBlacklist: [ - "name", - "patient_no", - "phone_number", - "emergency_phone_number", - ], - }); + const { + qParams, + updateQuery, + advancedFilter, + FilterBadges, + updatePage, + clearSearch, + } = useFilters({ + limit: 12, + cacheBlacklist: [ + "name", + "patient_no", + "phone_number", + "emergency_phone_number", + ], + }); + + const searchOptions = [ + { + key: "name", + label: "Name", + type: "text" as const, + placeholder: "search_by_patient_name", + value: qParams.name || "", + shortcutKey: "n", + }, + { + key: "patient_no", + label: "IP/OP No", + type: "text" as const, + placeholder: "search_by_patient_no", + value: qParams.patient_no || "", + shortcutKey: "u", + }, + { + key: "phone_number", + label: "Phone Number", + type: "phone" as const, + placeholder: "Search_by_phone_number", + value: qParams.phone_number || "", + shortcutKey: "p", + }, + { + key: "emergency_contact_number", + label: "Emergency Contact Phone Number", + type: "phone" as const, + placeholder: "search_by_emergency_phone_number", + value: qParams.emergency_phone_number || "", + shortcutKey: "e", + }, + ]; + + const handleSearch = useCallback( + (key: string, value: string) => { + const isValidPhoneNumber = (val: string) => + val.length >= 13 || val === ""; + + const updatedQuery = { + phone_number: + key === "phone_number" && isValidPhoneNumber(value) + ? value + : undefined, + name: key === "name" ? value : undefined, + patient_no: key === "patient_no" ? value : undefined, + emergency_phone_number: + key === "emergency_contact_number" && isValidPhoneNumber(value) + ? value + : undefined, + }; + updateQuery(updatedQuery); + }, + [updateQuery], + ); useEffect(() => { if (!qParams.phone_number && phone_number.length >= 13) { @@ -200,56 +261,11 @@ const DischargedPatientsList = ({ }); }; - const queryField = (name: string, defaultValue?: T) => { - return { - name, - value: qParams[name] || defaultValue, - onChange: (e: FieldChangeEvent) => updateQuery({ [e.name]: e.value }), - className: "grow w-full mb-2", - }; - }; const [diagnoses, setDiagnoses] = useState([]); const [phone_number, setPhoneNumber] = useState(""); - const [phoneNumberError, setPhoneNumberError] = useState(""); const [emergency_phone_number, setEmergencyPhoneNumber] = useState(""); - const [emergencyPhoneNumberError, setEmergencyPhoneNumberError] = - useState(""); const [count, setCount] = useState(0); - - const setPhoneNum = (phone_number: string) => { - setPhoneNumber(phone_number); - if (phone_number.length >= 13) { - setPhoneNumberError(""); - updateQuery({ phone_number }); - return; - } - - if (phone_number === "+91" || phone_number === "") { - setPhoneNumberError(""); - qParams.phone_number && updateQuery({ phone_number: null }); - return; - } - - setPhoneNumberError("Enter a valid number"); - }; - - const setEmergencyPhoneNum = (emergency_phone_number: string) => { - setEmergencyPhoneNumber(emergency_phone_number); - if (emergency_phone_number.length >= 13) { - setEmergencyPhoneNumberError(""); - updateQuery({ emergency_phone_number }); - return; - } - - if (emergency_phone_number === "+91" || emergency_phone_number === "") { - setEmergencyPhoneNumberError(""); - qParams.emergency_phone_number && - updateQuery({ emergency_phone_number: null }); - return; - } - - setEmergencyPhoneNumberError("Enter a valid number"); - }; + const [isLoading, setIsLoading] = useState(false); return ( } > -
-
-
- -
-
-
-
-
- - -
-
- setPhoneNum(e.value)} - error={phoneNumberError} - types={["mobile", "landline"]} - /> - setEmergencyPhoneNum(e.value)} - error={emergencyPhoneNumberError} - types={["mobile", "landline"]} - /> -
-
+
+
+
+
setCount(query.data?.count || 0)} + queryCB={(query) => { + setCount(query.data?.count || 0); + setIsLoading(query.loading); + }} initialPage={qParams.page} onPageChange={updatePage} > diff --git a/src/components/Facility/FacilityCard.tsx b/src/components/Facility/FacilityCard.tsx index fbebe8a8d0a..2f6ecec204b 100644 --- a/src/components/Facility/FacilityCard.tsx +++ b/src/components/Facility/FacilityCard.tsx @@ -6,6 +6,8 @@ import { useTranslation } from "react-i18next"; import Chip from "@/CAREUI/display/Chip"; import CareIcon from "@/CAREUI/icons/CareIcon"; +import { TooltipComponent, TooltipProvider } from "@/components/ui/tooltip"; + import { Avatar } from "@/components/Common/Avatar"; import ButtonV2, { Cancel, Submit } from "@/components/Common/ButtonV2"; import DialogModal from "@/components/Common/Dialog"; @@ -98,19 +100,28 @@ export const FacilityCard = (props: { > {facility.name} -
0.85 ? "justify-center rounded-md border border-red-600 bg-red-500 p-1 font-bold text-white" : "text-secondary-700"}`} - > - - {t("live_patients_total_beds")} - {" "} - -
- {t("occupancy")}: {facility.patient_count} /{" "} - {facility.bed_count}{" "} -
-
+ + +
+ 0.85 + ? "justify-center rounded-md border border-red-600 bg-red-500 p-1 font-bold text-white" + : "text-secondary-700" + }`} + > + +
+ {t("occupancy")}: {facility.patient_count} /{" "} + {facility.bed_count} +
+
+
+
( {!props.disabled && ( -
+
val.option) ? "-top-5" : ""}`} + > {props.isLoading ? ( ) : ( )}
diff --git a/src/components/Form/FormFields/DateFormField.tsx b/src/components/Form/FormFields/DateFormField.tsx index e867c24dd51..a3d26fa5554 100644 --- a/src/components/Form/FormFields/DateFormField.tsx +++ b/src/components/Form/FormFields/DateFormField.tsx @@ -37,7 +37,10 @@ const DateFormField = (props: Props) => { return ( ( onClick={() => handleDelete(props.item.id)} className="w-full text-xl text-red-500 hover:text-red-700 disabled:grayscale md:w-auto" > - {" "} + {t("remove")} )} diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx index 0f4a817dec4..75ca7fdc700 100644 --- a/src/components/ui/tooltip.tsx +++ b/src/components/ui/tooltip.tsx @@ -9,20 +9,38 @@ const Tooltip = TooltipPrimitive.Root; const TooltipTrigger = TooltipPrimitive.Trigger; -const TooltipContent = React.forwardRef< - React.ElementRef, +const TooltipContent = TooltipPrimitive.Content; + +const TooltipComponent = React.forwardRef< + React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - -)); -TooltipContent.displayName = TooltipPrimitive.Content.displayName; +>(({ children, content, sideOffset = 4, className }, ref) => { + const [open, setOpen] = React.useState(false); + return ( + + + setOpen(!open)}> + {children} + + + {content} + + + + ); +}); -export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; +export { + TooltipComponent, + TooltipTrigger, + TooltipContent, + TooltipProvider, + Tooltip, +};