diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 4d2333212b4..67628d414c8 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -431,3 +431,45 @@ jobs: cd kube/deployments/ sed -i -e "s/_BUILD_NUMBER_/${GITHUB_RUN_NUMBER}/g" care-fe.yaml kubectl apply -f care-fe.yaml + + deploy-production-meghalaya: + needs: build-production + name: Deploy to GKE Meghalaya + runs-on: ubuntu-latest + environment: + name: Production-Meghalaya + url: https://care.meghealth.gov.in + steps: + - name: Checkout Kube Config + uses: actions/checkout@v3 + with: + repository: coronasafe/ml-care-infra + token: ${{ secrets.GIT_ACCESS_TOKEN }} + path: kube + ref: main + + # Setup gcloud CLI + - uses: google-github-actions/setup-gcloud@94337306dda8180d967a56932ceb4ddcf01edae7 + with: + service_account_key: ${{ secrets.GKE_SA_KEY }} + project_id: ${{ secrets.GKE_PROJECT }} + + # Get the GKE credentials, so we can deploy to the cluster + - uses: google-github-actions/get-gke-credentials@fb08709ba27618c31c09e014e1d8364b02e5042e + with: + cluster_name: ${{ secrets.GKE_CLUSTER }} + location: ${{ secrets.GKE_ZONE }} + credentials: ${{ secrets.GKE_SA_KEY }} + + - name: install kubectl + uses: azure/setup-kubectl@v3.0 + with: + version: "v1.23.6" + id: install + + - name: Deploy Care Fe Production + run: | + mkdir -p $HOME/.kube/ + cd kube/deployments/ + sed -i -e "s/_BUILD_NUMBER_/${GITHUB_RUN_NUMBER}/g" care-fe.yaml + kubectl apply -f care-fe.yaml diff --git a/src/Components/Assets/AssetServiceEditModal.tsx b/src/Components/Assets/AssetServiceEditModal.tsx index 3964dfe0770..13a91e36477 100644 --- a/src/Components/Assets/AssetServiceEditModal.tsx +++ b/src/Components/Assets/AssetServiceEditModal.tsx @@ -192,6 +192,7 @@ export const AssetServiceEditModal = (props: { className="mt-2" position="LEFT" value={new Date(form.serviced_on)} + max={new Date(props.service_record.created_date)} onChange={(date) => { if ( dayjs(date.value).format("YYYY-MM-DD") > diff --git a/src/Components/Assets/AssetsList.tsx b/src/Components/Assets/AssetsList.tsx index 8c19928fbee..df6326c6e79 100644 --- a/src/Components/Assets/AssetsList.tsx +++ b/src/Components/Assets/AssetsList.tsx @@ -189,12 +189,12 @@ const AssetsList = () => {

diff --git a/src/Components/Common/DateInputV2.tsx b/src/Components/Common/DateInputV2.tsx index 95652e68638..da974fbe0e9 100644 --- a/src/Components/Common/DateInputV2.tsx +++ b/src/Components/Common/DateInputV2.tsx @@ -4,6 +4,8 @@ import CareIcon from "../../CAREUI/icons/CareIcon"; import { Popover } from "@headlessui/react"; import { classNames } from "../../Utils/utils"; import dayjs from "../../Utils/dayjs"; +import * as Notification from "../../Utils/Notifications.js"; +import { t } from "i18next"; type DatePickerType = "date" | "month" | "year"; export type DatePickerPosition = "LEFT" | "RIGHT" | "CENTER"; @@ -16,6 +18,7 @@ interface Props { value: Date | undefined; min?: Date; max?: Date; + outOfLimitsErrorMessage?: string; onChange: (date: Date) => void; position?: DatePickerPosition; disabled?: boolean; @@ -34,6 +37,7 @@ const DateInputV2: React.FC = ({ value, min, max, + outOfLimitsErrorMessage, onChange, position, disabled, @@ -100,16 +104,21 @@ const DateInputV2: React.FC = ({ ) => void; const setDateValue = (date: number, close: CloseFunction) => () => { - isDateWithinConstraints(date) && - onChange( - new Date( - datePickerHeaderDate.getFullYear(), - datePickerHeaderDate.getMonth(), - date - ) - ); - close(); - setIsOpen?.(false); + isDateWithinConstraints(date) + ? (() => { + onChange( + new Date( + datePickerHeaderDate.getFullYear(), + datePickerHeaderDate.getMonth(), + date + ) + ); + close(); + setIsOpen?.(false); + })() + : Notification.Error({ + msg: outOfLimitsErrorMessage ?? "Cannot select date out of range", + }); }; const getDayCount = (date: Date) => { @@ -220,7 +229,7 @@ const DateInputV2: React.FC = ({ readOnly disabled={disabled} className={`cui-input-base cursor-pointer disabled:cursor-not-allowed ${className}`} - placeholder={placeholder ?? "Select date"} + placeholder={placeholder ?? t("select_date")} value={value && dayjs(value).format("DD/MM/YYYY")} />

@@ -248,7 +257,7 @@ const DateInputV2: React.FC = ({ [dd, mm, yyyy].filter(Boolean).join("/") ) || "" } // Display the value in DD/MM/YYYY format - placeholder="DD/MM/YYYY" + placeholder={t("DD/MM/YYYY")} onChange={(e) => { setDisplayValue(e.target.value.replaceAll("/", "")); const value = dayjs(e.target.value, "DD/MM/YYYY", true); @@ -330,26 +339,41 @@ const DateInputV2: React.FC = ({ className="aspect-square w-[14.26%] border border-transparent p-1 text-center text-sm" /> ))} - {dayCount.map((d, i) => ( -
+ {dayCount.map((d, i) => { + const withinConstraints = isDateWithinConstraints(d); + const selected = value && isSelectedDate(d); + + const baseClasses = + "flex h-full items-center justify-center rounded text-center text-sm leading-loose transition duration-100 ease-in-out"; + let conditionalClasses = ""; + + if (withinConstraints) { + if (selected) { + conditionalClasses = + "bg-primary-500 font-bold text-white"; + } else { + conditionalClasses = + "hover:bg-gray-300 cursor-pointer"; + } + } else { + conditionalClasses = + "!cursor-not-allowed !text-gray-400"; + } + return (
- {d} +
+ {d} +
-
- ))} + ); + })}
)} diff --git a/src/Components/Common/RelativeDateUserMention.tsx b/src/Components/Common/RelativeDateUserMention.tsx index 55c7a81518b..18fb431574f 100644 --- a/src/Components/Common/RelativeDateUserMention.tsx +++ b/src/Components/Common/RelativeDateUserMention.tsx @@ -8,7 +8,7 @@ function RelativeDateUserMention(props: { tooltipPosition?: "top" | "bottom" | "left" | "right"; }) { return ( -
+
{ min={1} max={100} onChange={(e) => setNumberOfBeds(Number(e.value))} + error={ + numberOfBeds > 100 + ? "Number of beds cannot be greater than 100" + : undefined + } /> )}
- + 100} + />
diff --git a/src/Components/Facility/AddInventoryForm.tsx b/src/Components/Facility/AddInventoryForm.tsx index 22be0b9fd0c..df217cad3ec 100644 --- a/src/Components/Facility/AddInventoryForm.tsx +++ b/src/Components/Facility/AddInventoryForm.tsx @@ -16,6 +16,7 @@ import TextFormField from "../Form/FormFields/TextFormField"; import { InventoryItemsModel } from "./models"; import { Cancel, Submit } from "../Common/components/ButtonV2"; import useAppHistory from "../../Common/hooks/useAppHistory"; + const Loading = lazy(() => import("../Common/Loading")); const initForm = { @@ -122,6 +123,7 @@ export const AddInventoryForm = (props: any) => { setFacilityName(""); } } + fetchFacilityName(); }, [dispatchAction, facilityId]); @@ -327,7 +329,7 @@ export const AddInventoryForm = (props: any) => { />
-
+
goBack()} />
diff --git a/src/Components/Facility/AssetCreate.tsx b/src/Components/Facility/AssetCreate.tsx index 84fc09188d0..a1e06a8c7ab 100644 --- a/src/Components/Facility/AssetCreate.tsx +++ b/src/Components/Facility/AssetCreate.tsx @@ -883,6 +883,7 @@ const AssetCreate = (props: AssetProps) => { name="last_serviced_on" className="mt-2" position="RIGHT" + disableFuture value={last_serviced_on && new Date(last_serviced_on)} onChange={(date) => { if ( diff --git a/src/Components/Facility/ConsultationCard.tsx b/src/Components/Facility/ConsultationCard.tsx index 4859b981e8f..2c0fa54db21 100644 --- a/src/Components/Facility/ConsultationCard.tsx +++ b/src/Components/Facility/ConsultationCard.tsx @@ -112,21 +112,25 @@ export const ConsultationCard = (props: ConsultationProps) => {
{
- Created:{" "} + Created :{" "} +
+ +
+
+ } +
+ Last Modified :{" "} +
- } -
- Last Modified:{" "} -
diff --git a/src/Components/Facility/Consultations/Feed.tsx b/src/Components/Facility/Consultations/Feed.tsx index ac39be325e9..c0b708619ef 100644 --- a/src/Components/Facility/Consultations/Feed.tsx +++ b/src/Components/Facility/Consultations/Feed.tsx @@ -230,8 +230,28 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => { } }; + const startStreamFeed = () => { + startStream({ + onSuccess: () => setStreamStatus(StreamStatus.Playing), + onError: () => { + setStreamStatus(StreamStatus.Offline); + if (!statusReported) { + triggerGoal("Camera Feed Viewed", { + consultationId, + userId: authUser.id, + result: "error", + }); + setStatusReported(true); + } + }, + }); + }; + useEffect(() => { if (cameraAsset.id) { + setTimeout(() => { + startStreamFeed(); + }, 1000); getPresets({ onSuccess: (resp) => setPresets(resp), onError: (_) => { @@ -251,21 +271,8 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => { setStreamStatus(StreamStatus.Loading); } tId = setTimeout(() => { - startStream({ - onSuccess: () => setStreamStatus(StreamStatus.Playing), - onError: () => { - setStreamStatus(StreamStatus.Offline); - if (!statusReported) { - triggerGoal("Camera Feed Viewed", { - consultationId, - userId: authUser.id, - result: "error", - }); - setStatusReported(true); - } - }, - }); - }, 100); + startStreamFeed(); + }, 5000); } else if (!statusReported) { triggerGoal("Camera Feed Viewed", { consultationId, @@ -459,9 +466,9 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => { getCameraStatus({}); }} className={classNames( - "block border border-gray-500 px-4 py-2", + "block border border-gray-500 px-4 py-2 first:rounded-l last:rounded-r", currentPreset === preset - ? "rounded border-primary-500 bg-primary-500 text-white" + ? "border-primary-500 bg-primary-500 text-white" : "bg-transparent" )} > diff --git a/src/Components/Facility/Consultations/LiveFeed.tsx b/src/Components/Facility/Consultations/LiveFeed.tsx index aba473e958d..cd3f055921e 100644 --- a/src/Components/Facility/Consultations/LiveFeed.tsx +++ b/src/Components/Facility/Consultations/LiveFeed.tsx @@ -177,6 +177,9 @@ const LiveFeed = (props: any) => { useEffect(() => { if (cameraAsset?.hostname) { fetchCameraPresets(); + setTimeout(() => { + startStreamFeed(); + }, 1000); } }, []); @@ -192,6 +195,13 @@ const LiveFeed = (props: any) => { } }, [page.offset, cameraAsset.id, refreshPresetsHash]); + const startStreamFeed = () => { + startStream({ + onSuccess: () => setStreamStatus(StreamStatus.Playing), + onError: () => setStreamStatus(StreamStatus.Offline), + }); + }; + const viewOptions = (page: number) => { return presets ? Object.entries(presets) @@ -207,11 +217,8 @@ const LiveFeed = (props: any) => { if (streamStatus !== StreamStatus.Playing) { setStreamStatus(StreamStatus.Loading); tId = setTimeout(() => { - startStream({ - onSuccess: () => setStreamStatus(StreamStatus.Playing), - onError: () => setStreamStatus(StreamStatus.Offline), - }); - }, 500); + startStreamFeed(); + }, 5000); } return () => { diff --git a/src/Components/Facility/FacilityCard.tsx b/src/Components/Facility/FacilityCard.tsx index ab37ac20c96..e8e0dbef70f 100644 --- a/src/Components/Facility/FacilityCard.tsx +++ b/src/Components/Facility/FacilityCard.tsx @@ -157,109 +157,109 @@ export const FacilityCard = (props: { facility: any; userType: any }) => {
-
-
-
-
*/} +
+
+
0.85 + ? "button-danger-border bg-red-500" + : "button-primary-border bg-primary-100" + }`} + > + + Live Patients / Total beds + {" "} + 0.85 + ? "text-white" + : "text-primary-600" + )} + />{" "} +
0.85 - ? "button-danger-border bg-red-500" - : "button-primary-border bg-primary-100" + ? "text-white" + : "text-gray-700" }`} > - - Live Patients / Total beds - {" "} - 0.85 - ? "text-white" - : "text-primary-600" - )} - />{" "} -
0.85 - ? "text-white" - : "text-gray-700" - }`} - > - Occupancy: {facility.patient_count} /{" "} - {facility.bed_count}{" "} -
{" "} -
- - Notify: {facility.name} - - } - onClose={() => setNotifyModalFor(undefined)} + Occupancy: {facility.patient_count} /{" "} + {facility.bed_count}{" "} + {" "} +
+ + Notify: {facility.name} + + } + onClose={() => setNotifyModalFor(undefined)} + > +
{ + event.preventDefault(); + handleNotifySubmit(notifyModalFor); + }} + className="flex w-full flex-col bg-white text-center" > - { - event.preventDefault(); - handleNotifySubmit(notifyModalFor); - }} - className="flex w-full flex-col bg-white text-center" - > - setNotifyMessage(e.value)} - placeholder="Type your message..." - error={notifyError} + setNotifyMessage(e.value)} + placeholder="Type your message..." + error={notifyError} + /> +
+ setNotifyModalFor(undefined)} /> -
- setNotifyModalFor(undefined)} - /> - -
- - -
-
- {userType !== "Staff" ? ( - setNotifyModalFor(facility.id)} - > - - Notify - - ) : ( - <> - )} + +
+ +
+
+
+ {userType !== "Staff" ? ( - - - {t("view_faciliy")} - - - setNotifyModalFor(facility.id)} > - - {t("view_patients")} + + Notify -
+ ) : ( + <> + )} + + + + {t("view_faciliy")} + + + + + {t("view_patients")} + + {/*
*/}
diff --git a/src/Components/Facility/FacilityHome.tsx b/src/Components/Facility/FacilityHome.tsx index 405ba236f05..f14057d4a91 100644 --- a/src/Components/Facility/FacilityHome.tsx +++ b/src/Components/Facility/FacilityHome.tsx @@ -370,11 +370,8 @@ export const FacilityHome = (props: any) => { /> {hasCoverImage ? (
- hasPermissionToEditCoverImage && setEditCoverImage(true) + className={ + "group relative h-48 w-full text-clip rounded-t bg-gray-200 opacity-100 transition-all duration-200 ease-in-out md:h-0 md:opacity-0" } > diff --git a/src/Components/Form/FormFields/NumericWithUnitsFormField.tsx b/src/Components/Form/FormFields/NumericWithUnitsFormField.tsx index 02aa03fdf71..02f98a7ba17 100644 --- a/src/Components/Form/FormFields/NumericWithUnitsFormField.tsx +++ b/src/Components/Form/FormFields/NumericWithUnitsFormField.tsx @@ -35,7 +35,9 @@ export default function NumericWithUnitsFormField(props: Props) { autoComplete={props.autoComplete} required={field.required} value={numValue} - onChange={(e) => field.handleChange(e.target.value + " " + unitValue)} + onChange={(e) => + field.handleChange(Number(e.target.value) + " " + unitValue) + } />