Skip to content

Commit

Permalink
Merge branch 'develop' into issues/#8055/Facility_listing_occupancy
Browse files Browse the repository at this point in the history
  • Loading branch information
Fredrick2503 authored Aug 13, 2024
2 parents 838fa93 + e118453 commit 90b8f79
Show file tree
Hide file tree
Showing 51 changed files with 1,267 additions and 384 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ jobs:
stale-issue-message: "Hi, @coronasafe/care-frontend-maintainers, This issue has been automatically marked as stale because it has not had any recent activity."
stale-pr-message: "Hi, This pr has been automatically marked as stale because it has not had any recent activity. It will be automatically closed if no further activity occurs for 7 more days. Thank you for your contributions."
close-pr-message: "Hi, @coronasafe/care-frontend-maintainers, This PR has been automatically closed due to inactivity. Thank you for your contributions. Feel free to re-open the PR."
exempt-issue-labels: "blocked,waiting for related PR,waiting for back end,help wanted,work-in-progress,In Progress,wishlist,EPIC"
exempt-pr-labels: "tested,needs testing,need Review,waiting for related PR,waiting for back end,help wanted,blocked,work-in-progress,In Progress"
exempt-issue-labels: "blocked,waiting for related PR,waiting for back end,help wanted,work-in-progress,In Progress,wishlist,EPIC,backlog"
exempt-pr-labels: "tested,needs testing,need Review,waiting for related PR,waiting for back end,help wanted,blocked,work-in-progress,In Progress,backlog"
days-before-issue-stale: 14
days-before-pr-stale: 7
days-before-issue-close: -1
Expand Down
2 changes: 1 addition & 1 deletion cypress/pageobject/Patient/PatientLogupdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class PatientLogupdate {
}

selectPatientCategory(category: string) {
cy.clickAndSelectOption("#patient_category", category);
cy.clickAndSelectOption("#patientCategory", category);
}

typePhysicalExamination(examination: string) {
Expand Down
36 changes: 36 additions & 0 deletions src/CAREUI/misc/PrintPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { ReactNode } from "react";
import ButtonV2 from "../../Components/Common/components/ButtonV2";
import CareIcon from "../icons/CareIcon";
import { classNames } from "../../Utils/utils";
import Page from "../../Components/Common/components/Page";

type Props = {
children: ReactNode;
disabled?: boolean;
className?: string;
title: string;
};

export default function PrintPreview(props: Props) {
return (
<Page title={props.title}>
<div className="mx-auto my-8 w-[50rem]">
<div className="top-0 z-20 flex justify-end gap-2 bg-secondary-100 px-2 py-4 xl:absolute xl:right-6 xl:top-8">
<ButtonV2 disabled={props.disabled} onClick={() => window.print()}>
<CareIcon icon="l-print" className="text-lg" />
Print
</ButtonV2>
</div>

<div className="bg-white p-10 text-sm shadow-2xl transition-all duration-200 ease-in-out">
<div
id="section-to-print"
className={classNames("w-full", props.className)}
>
{props.children}
</div>
</div>
</div>
</Page>
);
}
7 changes: 7 additions & 0 deletions src/Common/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,13 @@ export const PATIENT_SORT_OPTIONS: SortOption[] = [
{ isAscending: false, value: "-name" },
];

export const EVENTS_SORT_OPTIONS: SortOption[] = [
{ isAscending: false, value: "-created_date" },
{ isAscending: true, value: "created_date" },
{ isAscending: false, value: "-taken_at" },
{ isAscending: true, value: "taken_at" },
];

export const DISCHARGED_PATIENT_SORT_OPTIONS: SortOption[] = [
{ isAscending: false, value: "-created_date" },
{ isAscending: true, value: "created_date" },
Expand Down
11 changes: 2 additions & 9 deletions src/Components/ABDM/ABDMFacilityRecords.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ export default function ABDMFacilityRecords({ facilityId }: IProps) {
consent.expiry,
) < new Date()
? "EXPIRED"
: consent.consent_artefacts?.[0]?.status ??
consent.status}
: (consent.consent_artefacts?.[0]?.status ??
consent.status)}
</td>

<td className="px-3 py-4 text-center text-sm">
Expand All @@ -102,13 +102,6 @@ export default function ABDMFacilityRecords({ facilityId }: IProps) {
: "-"}
</td>

{/* <td className="px-3 py-4 text-center text-sm">
{`${consent.requester?.first_name} ${consent.requester?.last_name}`.trim()}
<p className="text-secondary-600">
({consent.requester.username})
</p>
</td> */}

<td className="px-3 py-4 text-center text-sm">
{formatDateTime(
consent.consent_artefacts?.[0]?.from_time ??
Expand Down
4 changes: 2 additions & 2 deletions src/Components/ABDM/ABDMRecordsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import CareIcon from "../../CAREUI/icons/CareIcon";
import ButtonV2 from "../Common/components/ButtonV2";
import * as Notification from "../../Utils/Notifications.js";
import Loading from "../Common/Loading";
import { classNames } from "../../Utils/utils";
import { classNames, formatName } from "../../Utils/utils";
import { Link } from "raviger";
import routes from "../../Redux/api";
import request from "../../Utils/request/request";
Expand Down Expand Up @@ -75,7 +75,7 @@ function ConsentRequestCard({ consent }: IConsentRequestCardProps) {
}
</h5>
<h6 className="mt-1 leading-6 text-secondary-700">
{consent.requester.first_name} {consent.requester.last_name}
{formatName(consent.requester)}
</h6>
</div>
<div className="flex flex-col items-center">
Expand Down
5 changes: 2 additions & 3 deletions src/Components/Assets/AssetManage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Pagination from "../Common/Pagination";
import { navigate } from "raviger";
import QRCode from "qrcode.react";
import AssetWarrantyCard from "./AssetWarrantyCard";
import { formatDate, formatDateTime } from "../../Utils/utils";
import { formatDate, formatDateTime, formatName } from "../../Utils/utils";
import Chip from "../../CAREUI/display/Chip";
import CareIcon from "../../CAREUI/icons/CareIcon";
import ButtonV2 from "../Common/components/ButtonV2";
Expand Down Expand Up @@ -148,8 +148,7 @@ const AssetManage = (props: AssetManageProps) => {
</td>
<td className="whitespace-nowrap px-6 py-4 text-center text-sm leading-5 text-secondary-500">
<span className="font-medium text-secondary-900">
{transaction.performed_by.first_name}{" "}
{transaction.performed_by.last_name}
{formatName(transaction.performed_by)}
</span>
</td>
<td className="whitespace-nowrap px-6 py-4 text-right text-sm leading-5 text-secondary-500">
Expand Down
2 changes: 1 addition & 1 deletion src/Components/Common/DateInputV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ const DateInputV2: React.FC<Props> = ({
type="text"
readOnly
disabled={disabled}
className={`cui-input-base cursor-pointer !px-2 disabled:cursor-not-allowed ${className}`}
className={`cui-input-base cursor-pointer disabled:cursor-not-allowed ${className}`}
placeholder={placeholder ?? t("select_date")}
value={value && dayjs(value).format("DD/MM/YYYY")}
/>
Expand Down
4 changes: 2 additions & 2 deletions src/Components/Common/RelativeDateUserMention.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import CareIcon from "../../CAREUI/icons/CareIcon";
import { formatDateTime, relativeDate } from "../../Utils/utils";
import { formatDateTime, formatName, relativeDate } from "../../Utils/utils";
import { PerformedByModel } from "../HCX/misc";

function RelativeDateUserMention(props: {
Expand Down Expand Up @@ -28,7 +28,7 @@ function RelativeDateUserMention(props: {
}`}
>
<div className="flex flex-col whitespace-normal text-sm font-semibold leading-5 text-white">
<p className="flex justify-center">{`${props.user.first_name} ${props.user.last_name}`}</p>
<p className="flex justify-center">{formatName(props.user)}</p>
<p className="flex justify-center">{`@${props.user.username}`}</p>
<p className="flex justify-center">{props.user.user_type}</p>
</div>
Expand Down
210 changes: 128 additions & 82 deletions src/Components/Common/UserAutocompleteFormField.tsx
Original file line number Diff line number Diff line change
@@ -1,112 +1,158 @@
import { useAsyncOptions } from "../../Common/hooks/useAsyncOptions";
import { getFacilityUsers, getUserList } from "../../Redux/actions";
import { Autocomplete } from "../Form/FormFields/Autocomplete";
import FormField from "../Form/FormFields/FormField";
import {
FormFieldBaseProps,
useFormFieldPropsResolver,
} from "../Form/FormFields/Utils";
import { UserModel } from "../Users/models";
import { isUserOnline } from "../../Utils/utils";
import {
classNames,
formatName,
isUserOnline,
mergeQueryOptions,
} from "../../Utils/utils";
import { UserRole } from "../../Common/constants";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import useQuery from "../../Utils/request/useQuery";
import routes from "../../Redux/api";
import { UserBareMinimum } from "../Users/models";

type Props = FormFieldBaseProps<UserModel> & {
type BaseProps = FormFieldBaseProps<UserBareMinimum> & {
placeholder?: string;
facilityId?: string;
homeFacility?: string;
userType?: UserRole;
showActiveStatus?: boolean;
noResultsError?: string;
};

export default function UserAutocompleteFormField(props: Props) {
type LinkedFacilitySearchProps = BaseProps & {
facilityId: string;
homeFacility?: undefined;
};

type UserSearchProps = BaseProps & {
facilityId?: undefined;
homeFacility?: string;
};

export default function UserAutocomplete(props: UserSearchProps) {
const field = useFormFieldPropsResolver(props);
const { fetchOptions, isLoading, options } = useAsyncOptions<UserModel>(
"id",
{ queryResponseExtractor: (data) => data.results },
);
const [query, setQuery] = useState("");
const [disabled, setDisabled] = useState(false);

let search_filter: {
limit: number;
offset: number;
home_facility?: string;
user_type?: string;
search_text?: string;
} = { limit: 50, offset: 0 };
const { data, loading } = useQuery(routes.userList, {
query: {
home_facility: props.homeFacility,
user_type: props.userType,
search_text: query,
limit: 50,
offset: 0,
},
});

if (props.showActiveStatus && props.userType) {
search_filter = { ...search_filter, user_type: props.userType };
}
useEffect(() => {
if (
loading ||
query ||
!field.required ||
!props.noResultsError ||
!data?.results
) {
return;
}

if (props.homeFacility) {
search_filter = { ...search_filter, home_facility: props.homeFacility };
}
if (data.results.length === 0) {
setDisabled(true);
field.handleChange(undefined as unknown as UserBareMinimum);
}
}, [loading, query, field.required, data?.results, props.noResultsError]);

const getStatusIcon = (option: UserModel) => {
if (!props.showActiveStatus) return null;
return (
<FormField field={field}>
<Autocomplete
id={field.id}
disabled={field.disabled || disabled}
required={field.required as true}
placeholder={(disabled && props.noResultsError) || props.placeholder}
value={field.value}
onChange={field.handleChange}
options={mergeQueryOptions(
field.value ? [field.value] : [],
data?.results ?? [],
(obj) => obj.username,
)}
optionLabel={formatName}
optionIcon={userOnlineDot}
optionDescription={(option) =>
`${option.user_type} - ${option.username}`
}
optionValue={(option) => option}
onQuery={setQuery}
isLoading={loading}
/>
</FormField>
);
}

return (
<div className="mr-6 mt-[2px]">
<svg
className={`h-3 w-3 ${
isUserOnline(option) ? "text-green-500" : "text-secondary-400"
}`}
fill="currentColor"
viewBox="0 0 8 8"
>
<circle cx="4" cy="4" r="4" />
</svg>
</div>
);
};
export const LinkedFacilityUsers = (props: LinkedFacilitySearchProps) => {
const field = useFormFieldPropsResolver(props);

const items = options(field.value && [field.value]);
const [query, setQuery] = useState("");

useEffect(() => {
if (props.required && !isLoading && !items.length && props.noResultsError) {
field.handleChange(undefined as unknown as UserModel);
}
}, [isLoading, items, props.required]);
const { data, loading } = useQuery(routes.getFacilityUsers, {
pathParams: { facility_id: props.facilityId },
query: {
user_type: props.userType,
search_text: query,
limit: 50,
offset: 0,
},
});

const noResultError =
(props.required && !isLoading && !items.length && props.noResultsError) ||
(!query &&
!loading &&
field.required &&
!data?.results?.length &&
props.noResultsError) ||
undefined;

useEffect(() => {
if (noResultError) {
field.handleChange(undefined as unknown as UserBareMinimum);
}
}, [noResultError]);

return (
<FormField field={field}>
<div className="relative">
<Autocomplete
id={field.id}
disabled={field.disabled || !!noResultError}
// Voluntarily casting type as true to ignore type errors.
required={field.required as true}
placeholder={noResultError || props.placeholder}
value={field.value}
onChange={field.handleChange}
options={items}
optionLabel={getUserFullName}
optionIcon={getStatusIcon}
optionDescription={(option) => `${option.user_type}`}
optionValue={(option) => option}
onQuery={(query) =>
fetchOptions(
props.facilityId
? getFacilityUsers(props.facilityId, {
...search_filter,
search_text: query,
})
: getUserList({ ...search_filter, search_text: query }),
)
}
isLoading={isLoading}
/>
</div>
<Autocomplete
id={field.id}
disabled={field.disabled || !!noResultError}
// Voluntarily casting type as true to ignore type errors.
required={field.required as true}
placeholder={noResultError || props.placeholder}
value={field.value}
onChange={field.handleChange}
options={mergeQueryOptions(
field.value ? [field.value] : [],
data?.results ?? [],
(obj) => obj.username,
)}
optionLabel={formatName}
optionIcon={userOnlineDot}
optionDescription={(option) =>
`${option.user_type} - ${option.username}`
}
optionValue={(option) => option}
onQuery={setQuery}
isLoading={loading}
/>
</FormField>
);
}

const getUserFullName = (user: UserModel) => {
const personName = user.first_name + " " + user.last_name;
return personName.trim().length > 0 ? personName : user.username || "";
};

const userOnlineDot = (user: UserBareMinimum) => (
<div
className={classNames(
"mr-4 size-2.5 rounded-full ",
isUserOnline(user) ? "bg-primary-500" : "bg-secondary-400",
)}
/>
);
Loading

0 comments on commit 90b8f79

Please sign in to comment.