diff --git a/.gitignore b/.gitignore index 9ea09a3..167b5d2 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ dist/ # Intellij integration *.iml +*.idea/ # ignores for Yarn v3 w/o PNP .pnp.* diff --git a/src/laboratory.component.tsx b/src/laboratory.component.tsx index cf3aa8f..96ef690 100644 --- a/src/laboratory.component.tsx +++ b/src/laboratory.component.tsx @@ -1,7 +1,7 @@ import React from "react"; import { LaboratoryHeader } from "./header/laboratory-header.component"; import LaboratorySummaryTiles from "./summary-tiles/laboratory-summary-tiles.component"; -import LaboratoryQueueList from "./queue-list/laboratory-queue.component"; +import LaboratoryQueueList from "./queue-list/laboratory-tabs.component"; const Laboratory: React.FC = () => { return ( diff --git a/src/queue-list/laboratory-patient-list.component.tsx b/src/queue-list/laboratory-patient-list.component.tsx index 87d6ded..894f7cc 100644 --- a/src/queue-list/laboratory-patient-list.component.tsx +++ b/src/queue-list/laboratory-patient-list.component.tsx @@ -1,6 +1,7 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { DataTable, + DataTableHeader, DataTableSkeleton, Pagination, Table, @@ -13,111 +14,222 @@ import { TableHeader, TableRow, TabPanel, + TableToolbar, + TableToolbarContent, + TableToolbarSearch, + Layer, + Tag, } from "@carbon/react"; import { useTranslation } from "react-i18next"; -import { formatDatetime, parseDate } from "@openmrs/esm-framework"; +import { + age, + formatDate, + formatDatetime, + parseDate, + usePagination, + useSession, +} from "@openmrs/esm-framework"; import styles from "./laboratory-queue.scss"; +import { usePatientQueuesList } from "./laboratory-patient-list.resource"; +import { + formatWaitTime, + getTagColor, + trimVisitNumber, +} from "../utils/functions"; + +// type FilterProps = { +// rowIds: Array; +// headers: Array; +// cellsById: any; +// inputValue: string; +// getCellId: (row, key) => string; +// }; -interface LaboratoryPatientListProps { - searchTerm: string; - location: string; - status: string; -} +interface LaboratoryPatientListProps {} -const LaboratoryPatientList: React.FC = ({ - searchTerm, - location, - status, -}) => { +const LaboratoryPatientList: React.FC = () => { const { t } = useTranslation(); + const session = useSession(); + + const { patientQueueEntries, isLoading } = usePatientQueuesList( + session?.sessionLocation?.uuid, + status + ); + + const pageSizes = [10, 20, 30, 40, 50]; const [page, setPage] = useState(1); - const [pageSize, setPageSize] = useState(10); + const [currentPageSize, setPageSize] = useState(10); const [nextOffSet, setNextOffSet] = useState(0); - const [laboratoryQueue, setLaboratoryQueue] = useState([]); - const totalOrders = 0; + + const { + goTo, + results: paginatedQueueEntries, + currentPage, + } = usePagination(patientQueueEntries, currentPageSize); let columns = [ - { header: t("visitId", "Visit ID"), key: "visitId" }, - { header: t("names", "Names"), key: "names" }, - { header: t("age", "Age"), key: "age" }, - { header: t("orderedFrom", "Ordered from"), key: "orderedFrom" }, - { header: t("waitingTime", "Waiting time"), key: "waitingTime" }, - { header: t("testsOrdered", "Tests ordered"), key: "testsOrdered" }, + { id: 0, header: t("visitId", "Visit ID"), key: "visitId" }, + { id: 1, header: t("names", "Names"), key: "names" }, + { id: 2, header: t("age", "Age"), key: "age" }, + { id: 3, header: t("orderedFrom", "Ordered from"), key: "orderedFrom" }, + { id: 4, header: t("waitingTime", "Waiting time"), key: "waitingTime" }, ]; - useEffect(() => { - setPage(1); - setNextOffSet(0); - }, [searchTerm]); + const tableRows = useMemo(() => { + return paginatedQueueEntries?.map((entry) => ({ + ...entry, + visitId: { + content: {trimVisitNumber(entry.visitNumber)}, + }, + names: { + content: {entry.name}, + }, + age: { + content: {age(entry.patientDob)}, + }, + orderedFrom: { + content: {entry.locationFromName}, + }, + waitingTime: { + content: ( + + + {formatWaitTime(entry.waitTime, t)} + + + ), + }, + })); + }, [paginatedQueueEntries, t]); + + // const handleFilter = ({ + // rowIds, + // headers, + // cellsById, + // inputValue, + // getCellId, + // }: FilterProps): Array => { + // return rowIds.filter((rowId) => + // headers.some(({ key }) => { + // const cellId = getCellId(rowId, key); + // const filterableValue = cellsById[cellId].value; + // const filterTerm = inputValue.toLowerCase(); - return ( - -
- {/* {isLoading && } */} - {/* {error &&

Error

} */} - {laboratoryQueue && ( - <> - - {({ - rows, - headers, - getHeaderProps, - getRowProps, - getTableProps, - }) => ( - - - - - - {headers.map((header) => ( - - {header.header} - - ))} - - - - {rows.map((row) => ( - - - {row.cells.map((cell) => ( - - {cell.id.endsWith("created") - ? formatDatetime(parseDate(cell.value)) - : cell.id.endsWith("patient") - ? cell.value.name - : cell.id.endsWith("status") - ? t(cell.value) - : cell.value} - - ))} - - - ))} - -
-
- )} -
-
+ // if (typeof filterableValue === "boolean") { + // return false; + // } + // if (filterableValue.hasOwnProperty("content")) { + // if (Array.isArray(filterableValue.content.props.children)) { + // return ( + // "" + filterableValue.content.props.children[1].props.children + // ) + // .toLowerCase() + // .includes(filterTerm); + // } + // if (typeof filterableValue.content.props.children === "object") { + // return ("" + filterableValue.content.props.children.props.children) + // .toLowerCase() + // .includes(filterTerm); + // } + // return ("" + filterableValue.content.props.children) + // .toLowerCase() + // .includes(filterTerm); + // } + // return ("" + filterableValue).toLowerCase().includes(filterTerm); + // }) + // ); + // }; + if (isLoading) { + return ; + } + if (patientQueueEntries?.length) { + return ( +
+
+ + {({ + rows, + headers, + getHeaderProps, + getTableProps, + getRowProps, + onInputChange, + }) => ( + + + + + + + + + + + + + {headers.map((header) => ( + + {header.header} + + ))} + + + + {rows.map((row, index) => { + return ( + + + {row.cells.map((cell) => ( + + {cell.value?.content ?? cell.value} + + ))} + + + ); + })} + +
{ - setPage(page); - setNextOffSet((page - 1) * pageSize); - setPageSize(pageSize); + forwardText="Next page" + backwardText="Previous page" + page={currentPage} + pageSize={currentPageSize} + pageSizes={pageSizes} + totalItems={patientQueueEntries?.length} + className={styles.pagination} + onChange={({ pageSize, page }) => { + if (pageSize !== currentPageSize) { + setPageSize(pageSize); + } + if (page !== currentPage) { + goTo(page); + } }} /> -
- - )} + + )} +
- - ); + ); + } }; export default LaboratoryPatientList; diff --git a/src/queue-list/laboratory-patient-list.resource.ts b/src/queue-list/laboratory-patient-list.resource.ts new file mode 100644 index 0000000..5adbfad --- /dev/null +++ b/src/queue-list/laboratory-patient-list.resource.ts @@ -0,0 +1,64 @@ +import { PatientQueue } from "../types/patient-queues"; +import dayjs from "dayjs"; +import useSWR from "swr"; + +import { formatDate, openmrsFetch, parseDate } from "@openmrs/esm-framework"; + +export function usePatientQueuesList( + currentQueueRoomLocationUuid: string, + status: string +) { + const apiUrl = `/ws/rest/v1/patientqueue?v=full&room=${currentQueueRoomLocationUuid}&status=${status}`; + return usePatientQueueRequest(apiUrl); +} + +export function usePatientQueueRequest(apiUrl: string) { + const { data, error, isLoading, isValidating, mutate } = useSWR< + { data: { results: Array } }, + Error + >(apiUrl, openmrsFetch, { refreshInterval: 3000 }); + + const mapppedQueues = data?.data?.results.map((queue: PatientQueue) => { + return { + ...queue, + id: queue.uuid, + name: queue.patient?.person.display, + patientUuid: queue.patient?.uuid, + priorityComment: queue.priorityComment, + priority: + queue.priorityComment === "Urgent" ? "Priority" : queue.priorityComment, + priorityLevel: queue.priority, + waitTime: queue.dateCreated + ? `${dayjs().diff(dayjs(queue.dateCreated), "minutes")}` + : "--", + status: queue.status, + patientAge: queue.patient?.person?.age, + patientSex: queue.patient?.person?.gender === "M" ? "MALE" : "FEMALE", + patientDob: queue.patient?.person?.birthdate + ? formatDate(parseDate(queue.patient.person.birthdate), { time: false }) + : "--", + identifiers: queue.patient?.identifiers, + locationFrom: queue.locationFrom?.uuid, + locationFromName: queue.locationFrom?.name, + locationTo: queue.locationTo?.uuid, + locationToName: queue.locationTo?.name, + queueRoom: queue.locationTo?.display, + visitNumber: queue.visitNumber, + dateCreated: queue.dateCreated + ? formatDate(parseDate(queue.dateCreated), { time: false }) + : "--", + creatorUuid: queue.creator?.uuid, + creatorUsername: queue.creator?.username, + creatorDisplay: queue.creator?.display, + }; + }); + + return { + patientQueueEntries: mapppedQueues || [], + patientQueueCount: mapppedQueues?.length, + isLoading, + isError: error, + isValidating, + mutate, + }; +} diff --git a/src/queue-list/laboratory-queue.component.tsx b/src/queue-list/laboratory-queue.component.tsx deleted file mode 100644 index 53919d9..0000000 --- a/src/queue-list/laboratory-queue.component.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { Tab, Tabs, TabList, TabPanels, Search } from "@carbon/react"; -import { useTranslation } from "react-i18next"; -import styles from "./laboratory-queue.scss"; -import LaboratoryPatientList from "./laboratory-patient-list.component"; - -enum TabTypes { - STARRED, - SYSTEM, - USER, - ALL, -} - -const LaboratoryQueueList: React.FC = () => { - const { t } = useTranslation(); - const [selectedTab, setSelectedTab] = useState(TabTypes.STARRED); - const [searchTermUserInput, setSearchTermUserInput] = useState(""); - const [searchTerm, setSearchTerm] = useState(""); - const [location, setLocation] = useState(""); - - const tabs = [ - { - key: "testedOrders", - header: t("testedOrders", "Tests ordered"), - status: "ACTIVE", - }, - { - key: "worklist", - header: t("worklist", "Worklist"), - status: "", - }, - { - key: "referredTests", - header: t("referredTests", "Referred tests"), - status: "", - }, - { - key: "completedTests", - header: t("completedTests", "Completed tests"), - status: "", - }, - ]; - - useEffect(() => { - const debounceFn = setTimeout(() => { - setSearchTerm(searchTermUserInput); - }, 500); - - return () => clearTimeout(debounceFn); - }, [searchTermUserInput]); - - return ( -
-
- - - {tabs.map((tab, index) => { - return ( - - {t(tab.header)} - - ); - })} - -
- { - e.preventDefault(); - setSearchTermUserInput(e.target.value); - }} - size="md" - className={styles.patientSearch} - /> -
- - {tabs.map((tab, index) => { - return ( - - ); - })} - -
-
-
- ); -}; - -export default LaboratoryQueueList; diff --git a/src/queue-list/laboratory-queue.scss b/src/queue-list/laboratory-queue.scss index bb4675e..50eebb4 100644 --- a/src/queue-list/laboratory-queue.scss +++ b/src/queue-list/laboratory-queue.scss @@ -94,6 +94,40 @@ title { } } +.tableContainer { + background-color: $ui-01; + margin: 0 spacing.$spacing-05; + padding: 0; + + a { + text-decoration: none; + } + + th { + color: $text-02; + } + + :global(.cds--data-table) { + background-color: $ui-03; + } + + .toolbarContent { + height: spacing.$spacing-07; + margin-bottom: spacing.$spacing-02; + } +} + +.activePatientsTable tr:last-of-type { + td { + border-bottom: none; + } +} +.headerBtnContainer { + background-color: $ui-background; + padding: spacing.$spacing-05; + text-align: right; +} + .searchContainer { display: flex; align-items: center; @@ -131,3 +165,7 @@ title { background-color: $ui-02; border-bottom-color: $ui-03; } + +.container { + background-color: $ui-01; +} \ No newline at end of file diff --git a/src/queue-list/laboratory-tabs.component.tsx b/src/queue-list/laboratory-tabs.component.tsx new file mode 100644 index 0000000..20892a0 --- /dev/null +++ b/src/queue-list/laboratory-tabs.component.tsx @@ -0,0 +1,74 @@ +import React, { useEffect, useState } from "react"; +import { Tab, Tabs, TabList, TabPanels, TabPanel, Search } from "@carbon/react"; +import { useTranslation } from "react-i18next"; +import styles from "./laboratory-queue.scss"; +import LaboratoryPatientList from "./laboratory-patient-list.component"; +import { EmptyState } from "@openmrs/esm-patient-common-lib"; + +enum TabTypes { + STARRED, + SYSTEM, + USER, + ALL, +} + +const LaboratoryQueueTabs: React.FC = () => { + const { t } = useTranslation(); + const [selectedTab, setSelectedTab] = useState(0); + return ( +
+
+ setSelectedTab(selectedIndex)} + className={styles.tabs} + > + + {t("testedOrders", "Tests ordered")} + {t("worklist", "Worklist")} + {t("referredTests", "Referred tests")} + {t("completedTests", "Completed tests")} + + + + + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ ); +}; + +export default LaboratoryQueueTabs; diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..ebeb23e --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,412 @@ +import { OpenmrsResource } from "@openmrs/esm-framework"; + +export enum SearchTypes { + BASIC = "basic", + ADVANCED = "advanced", + SEARCH_RESULTS = "search_results", + SCHEDULED_VISITS = "scheduled-visits", + VISIT_FORM = "visit_form", + QUEUE_SERVICE_FORM = "queue_service_form", + QUEUE_ROOM_FORM = "queue_room_form", +} + +export interface Patient { + uuid: string; + display: string; + identifiers: Array; + person: Person; +} + +export interface Attribute { + attributeType: OpenmrsResource; + display: string; + uuid: string; + value: string | number; +} + +export interface Person { + age: number; + attributes: Array; + birthDate: string; + gender: string; + display: string; + preferredAddress: OpenmrsResource; + uuid: string; +} + +export interface ServiceTypes { + duration: number; + name: string; + uuid: string; +} + +export interface AppointmentService { + appointmentServiceId: number; + color: string; + creatorName: string; + description: string; + durationMins: string; + endTime: string; + initialAppointmentStatus: string; + location: OpenmrsResource; + maxAppointmentsLimit: number | null; + name: string; + speciality: OpenmrsResource; + startTime: string; + uuid: string; + serviceTypes: Array; +} + +export interface Note { + concept: OpenmrsResource; + note: string; + provider: { + name: string; + role: string; + }; + time: string; +} +export interface Order { + uuid: string; + dateActivated: string; + dateStopped?: Date | null; + dose: number; + dosingInstructions: string | null; + dosingType?: + | "org.openmrs.FreeTextDosingInstructions" + | "org.openmrs.SimpleDosingInstructions"; + doseUnits: { + uuid: string; + display: string; + }; + drug: { + uuid: string; + name: string; + strength: string; + }; + duration: number; + durationUnits: { + uuid: string; + display: string; + }; + frequency: { + uuid: string; + display: string; + }; + numRefills: number; + orderNumber: string; + orderReason: string | null; + orderReasonNonCoded: string | null; + orderer: { + uuid: string; + person: { + uuid: string; + display: string; + }; + }; + orderType: { + uuid: string; + display: string; + }; + route: { + uuid: string; + display: string; + }; + quantity: number; + quantityUnits: OpenmrsResource; +} + +export interface OrderItem { + order: Order; + provider: { + name: string; + role: string; + }; + time: string; +} + +export interface DiagnosisItem { + diagnosis: string; +} + +export interface Encounter { + uuid: string; + encounterDatetime: string; + encounterProviders: Array<{ + uuid: string; + display: string; + encounterRole: { + uuid: string; + display: string; + }; + provider: { + uuid: string; + person: { + uuid: string; + display: string; + }; + }; + }>; + encounterType: { + uuid: string; + display: string; + }; + obs: Array; + form: OpenmrsResource; + patient: OpenmrsResource; + orders: Array; +} + +export interface Observation { + uuid: string; + concept: { + uuid: string; + display: string; + conceptClass: { + uuid: string; + display: string; + }; + }; + display: string; + groupMembers: null | Array<{ + uuid: string; + concept: { + uuid: string; + display: string; + }; + value: { + uuid: string; + display: string; + }; + }>; + value: any; + obsDatetime: string; +} + +export interface PatientVitals { + systolic?: number; + diastolic?: number; + pulse?: number; + temperature?: number; + oxygenSaturation?: number; + height?: number; + weight?: number; + bmi?: number | null; + respiratoryRate?: number; + muac?: number; + provider?: { + name: string; + role: string; + }; + time?: string; +} + +export interface MappedEncounter { + id: string; + datetime: string; + encounterType: string; + form: OpenmrsResource; + obs: Array; + provider: string; + visitUuid?: string; +} + +export interface FormattedEncounter { + id: string; + datetime: string; + encounterType: string; + form: OpenmrsResource; + obs: Array; + provider: string; +} + +export interface ObsMetaInfo { + [_: string]: any; + assessValue?: (value: number) => OBSERVATION_INTERPRETATION; +} + +export type OBSERVATION_INTERPRETATION = + | "NORMAL" + | "HIGH" + | "CRITICALLY_HIGH" + | "OFF_SCALE_HIGH" + | "LOW" + | "CRITICALLY_LOW" + | "OFF_SCALE_LOW" + | "--"; +export interface PatientProgram { + uuid: string; + display: string; + patient: OpenmrsResource; + program: OpenmrsResource; + dateEnrolled: string; + dateCompleted: string; + location: OpenmrsResource; +} + +export interface AppointmentCountMap { + allAppointmentsCount: number; + missedAppointmentsCount; + appointmentDate: number; + appointmentServiceUuid: string; +} + +export interface AppointmentSummary { + appointmentService: { name: string }; + appointmentCountMap: Record; +} +export interface QueueEntryPayload { + visit: { uuid: string }; + queueEntry: { + status: { uuid: string }; + priority: { uuid: string }; + queue: { uuid: string }; + patient: { uuid: string }; + startedAt: Date; + sortWeight: number; + }; +} + +export interface QueueServiceInfo { + uuid: string; + display: string; + name: string; + description: string; +} + +export interface MappedServiceQueueEntry { + id: string; + name: string; + age: string; + gender: string; + phoneNumber: string; + visitType: string; + returnDate: string; + patientUuid: string; +} + +export enum FilterTypes { + SHOW, + HIDE, +} +export interface Provider { + uuid: string; + display: string; + comments: string; + response?: string; + person: OpenmrsResource; + location: string; + serviceType: string; +} + +export interface MappedQueueEntry { + id: string; + name: string; + patientAge: string; + patientSex: string; + patientDob: string; + patientUuid: string; + priority: string; + priorityComment: string; + priorityUuid: string; + service: string; + status: string; + statusUuid: string; + visitStartDateTime: string; + visitType: string; + visitUuid: string; + waitTime: string; + queueUuid: string; + queueEntryUuid: string; + queueLocation: string; + sortWeight: string; + visitNumber: string; + dateCreated: string; +} + +export interface EndVisitPayload { + location: string; + startDatetime: Date; + visitType: string; + stopDatetime: Date; +} + +export interface LocationResponse { + type: string; + total: number; + resourceType: string; + meta: { + lastUpdated: string; + }; + link: Array<{ + relation: string; + url: string; + }>; + id: string; + entry: Array; +} + +export interface LocationEntry { + resource: Resource; +} +export interface Resource { + id: string; + name: string; + resourceType: string; + status: "active" | "inactive"; + meta?: { + tag?: Array<{ + code: string; + display: string; + system: string; + }>; + }; +} + +export interface Identifer { + identifier: string; + display: string; + uuid: string; + identifierType: { + uuid: string; + display: string; + }; +} + +export interface NewVisitPayload { + uuid?: string; + location: string; + patient?: string; + startDatetime: Date; + visitType: string; + stopDatetime?: Date; + attributes?: Array<{ + attributeType: string; + value: string; + }>; +} + +export interface QueueRoom { + uuid: string; + display: string; + name: string; + description: string; +} + +export interface ProvidersQueueRoom { + uuid: string; + provider: { + uuid: string; + display: string; + }; + queueRoom: { + uuid: string; + name: string; + display: string; + }; +} + +export interface WaitTime { + metric: string; + averageWaitTime: string; +} diff --git a/src/types/patient-queues.ts b/src/types/patient-queues.ts new file mode 100644 index 0000000..8a74b2a --- /dev/null +++ b/src/types/patient-queues.ts @@ -0,0 +1,115 @@ +export interface PatientQueue { + uuid: string; + creator: { + uuid: string; + display: string; + username: string; + systemId: string; + person: UuidDisplay; + privileges: []; + roles: Array; + retired: boolean; + }; + dateCreated: string; + changedBy?: string; + dateChanged?: string; + voided: boolean; + dateVoided: string; + voidedBy: string; + patient: { + uuid: string; + display: string; + identifiers: Array; + person: { + uuid: string; + display: string; + gender: string; + age: number; + birthdate: string; + birthdateEstimated: boolean; + dead: boolean; + deathDate?: string; + causeOfDeath?: string; + preferredName: UuidDisplay; + preferredAddress: UuidDisplay; + attributes: []; + voided: boolean; + birthtime?: string; + deathdateEstimated: boolean; + }; + voided: boolean; + }; + provider: { + uuid: string; + display: string; + person: UuidDisplay; + identifier: string; + attributes: []; + retired: boolean; + }; + locationFrom: QueueLocation; + locationTo: QueueLocation; + // encounter: string; // TODO add encounter type + status: string; // TODO add status enum + priority: number; // TODO add priority enum + priorityComment: string; + visitNumber: string; + comment: string; + queueRoom: QueueRoom; + datePicked: string; + dateCompleted: string; +} + +export interface QueueLocation { + uuid: string; + display: string; + name: string; + description: string; + address1?: string; + address2?: string; + cityVillage?: string; + stateProvince?: string; + country: string; + postalCode?: string; + latitude?: string; + longitude?: string; + countyDistrict?: string; + address3?: string; + address4?: string; + address5?: string; + address6?: string; + tags: Array; + parentLocation: UuidDisplay; + childLocations: Array; + retired: boolean; + attributes: []; +} + +export interface QueueRoom { + uuid: string; + display: string; + name: string; + description: string; + address1?: string; + address2?: string; + cityVillage?: string; + stateProvince?: string; + country?: string; + postalCode?: string; + latitude?: string; + longitude?: string; + countyDistrict?: string; + address3?: string; + address4?: string; + address5?: string; + address6?: string; + tags: Array; + parentLocation: UuidDisplay; + childLocations: Array; + retired: boolean; +} + +export interface UuidDisplay { + uuid: string; + display: string; +} diff --git a/src/utils/functions.ts b/src/utils/functions.ts new file mode 100644 index 0000000..067e49d --- /dev/null +++ b/src/utils/functions.ts @@ -0,0 +1,37 @@ +export const trimVisitNumber = (visitNumber: string) => { + if (!visitNumber) { + return; + } + return visitNumber.substring(15); +}; + +export const formatWaitTime = (waitTime: string, t) => { + const num = parseInt(waitTime); + const hours = num / 60; + const rhours = Math.floor(hours); + const minutes = (hours - rhours) * 60; + const rminutes = Math.round(minutes); + if (rhours > 0) { + return ( + rhours + + " " + + `${t("hoursAnd", "hours and ")}` + + rminutes + + " " + + `${t("minutes", "minutes")}` + ); + } else { + return rminutes + " " + `${t("minutes", "minutes")}`; + } +}; + +export const getTagColor = (waitTime: string) => { + const num = parseInt(waitTime); + if (num <= 30) { + return "green"; + } else if (num > 30 && num <= 45) { + return "orange"; + } else { + return "red"; + } +};