Skip to content

Commit

Permalink
Merge branch 'coronasafe:develop' into Fix-ohcnetwork#6944
Browse files Browse the repository at this point in the history
  • Loading branch information
AshrafMd-1 authored Jun 6, 2024
2 parents e7297f1 + db8b1f4 commit e129388
Show file tree
Hide file tree
Showing 35 changed files with 468 additions and 222 deletions.
2 changes: 1 addition & 1 deletion cypress/pageobject/Patient/PatientInvestigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class PatientInvestigation {
}

selectInvestigation(investigation: string) {
cy.get("#search-patient-investigation").click();
cy.get("#search-patient-investigation").type(investigation);
cy.verifyAndClickElement("#investigation-group", investigation);
cy.verifyAndClickElement("#investigation", "Investigation No. 1");
}
Expand Down
8 changes: 7 additions & 1 deletion src/CAREUI/display/NetworkSignal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function NetworkSignal({ strength, children }: Props) {
return (
<div
className={classNames(
"flex items-center", // Strength colors
"relative flex items-center", // Strength colors
strength === 0 && "text-danger-500",
strength === 1 && "text-danger-500",
strength === 2 && "text-warning-500",
Expand Down Expand Up @@ -50,6 +50,12 @@ export default function NetworkSignal({ strength, children }: Props) {
/>
))
)}
{!!strength && strength < 2 && (
<CareIcon
icon="l-exclamation-circle"
className="absolute left-0.5 top-0 animate-pulse text-sm text-danger-500"
/>
)}
</div>
{children}
</div>
Expand Down
8 changes: 4 additions & 4 deletions src/CAREUI/display/RecordMeta.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import CareIcon from "../icons/CareIcon";
import {
formatDate,
formatDateTime,
formatName,
formatTime,
isUserOnline,
relativeTime,
} from "../../Utils/utils";
Expand Down Expand Up @@ -39,8 +38,9 @@ const RecordMeta = ({
<div className="tooltip">
<span className="underline">{relativeTime(time)}</span>
<span className="tooltip-text tooltip-bottom flex -translate-x-1/2 gap-1 text-xs font-medium tracking-wider">
{formatTime(time)} <br />
{formatDate(time)}
<span className="whitespace-break-spaces">
{formatDateTime(time).replace(";", "")}
</span>
{user && !inlineUser && (
<span className="flex items-center gap-1">
by
Expand Down
2 changes: 1 addition & 1 deletion src/CAREUI/interactive/FiltersSlideover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const AdvancedFilterButton = ({ onClick }: { onClick: () => void }) => {
<ButtonV2
ghost
border
className="w-full bg-white sm:w-auto"
className="w-full bg-white md:w-auto"
onClick={onClick}
id="advanced-filter"
>
Expand Down
15 changes: 12 additions & 3 deletions src/CAREUI/misc/Fullscreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ interface Props {
fullscreenClassName?: string;
children: React.ReactNode;
fullscreen: boolean;
onExit: () => void;
onExit: (reason?: "DEVICE_UNSUPPORTED") => void;
}

export default function Fullscreen(props: Props) {
const ref = useRef<HTMLDivElement>(null);

useEffect(() => {
if (!ref.current) {
return;
}

if (props.fullscreen) {
ref.current?.requestFullscreen();
if (ref.current.requestFullscreen) {
ref.current.requestFullscreen();
} else {
props.onExit("DEVICE_UNSUPPORTED");
}
} else {
document.exitFullscreen();
document.exitFullscreen?.();
}
}, [props.fullscreen]);

Expand All @@ -27,6 +35,7 @@ export default function Fullscreen(props: Props) {
};

document.addEventListener("fullscreenchange", listener);

return () => {
document.removeEventListener("fullscreenchange", listener);
};
Expand Down
4 changes: 2 additions & 2 deletions src/Common/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,10 @@ export const SAMPLE_TEST_RESULT = [
export const CONSULTATION_SUGGESTION = [
{ id: "HI", text: "Home Isolation", deprecated: true }, // # Deprecated. Preserving option for backward compatibility (use only for readonly operations)
{ id: "A", text: "Admission" },
{ id: "R", text: "Refer to another Hospital" },
{ id: "R", text: "Refer to another Hospital", editDisabled: true },
{ id: "OP", text: "OP Consultation" },
{ id: "DC", text: "Domiciliary Care" },
{ id: "DD", text: "Declare Death" },
{ id: "DD", text: "Declare Death", editDisabled: true },
] as const;

export type ConsultationSuggestionValue =
Expand Down
74 changes: 48 additions & 26 deletions src/Components/Assets/AssetsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,40 +105,63 @@ const AssetsList = () => {
prefetch: !!(qParams.facility && qParams.location),
});

const getAssetIdFromQR = async (assetUrl: string) => {
function isValidURL(url: string) {
try {
new URL(url);
return true;
} catch (_) {
return false;
}
}

const accessAssetIdFromQR = async (assetURL: string) => {
try {
setIsLoading(true);
setIsScannerActive(false);
const params = parseQueryParams(assetUrl);
if (!isValidURL(assetURL)) {
setIsLoading(false);
Notification.Error({
msg: "Invalid QR code scanned !!!",
});
return;
}
const params = parseQueryParams(assetURL);
// QR Maybe searchParams "asset" or "assetQR"
// If no params found, then use assetText
const assetId = params.asset || params.assetQR;

if (assetId) {
const { data } = await request(routes.listAssets, {
query: { qr_code_id: assetId },
const { data } = await request(routes.listAssetQR, {
pathParams: { qr_code_id: assetId },
});
if (!data) {
setIsLoading(false);
Notification.Error({
msg: "Invalid QR code scanned !!!",
});
return;
}
const { data: assetData } = await request(routes.listAssets, {
query: { qr_code_id: assetId, limit: 1 },
});
if (assetData?.results.length === 1) {
navigate(
`/facility/${assetData.results[0].location_object.facility?.id}/assets/${assetData.results[0].id}`,
);
} else {
setIsLoading(false);
Notification.Error({
msg: "Asset not found !!!",
});
}
} else {
setIsLoading(false);
Notification.Error({
msg: "Invalid QR code scanned !!!",
});
return data?.results[0].id;
}
} catch (err) {
console.log(err);
}
};

const checkValidAssetId = async (assetId: string) => {
const { data: assetData } = await request(routes.getAsset, {
pathParams: { external_id: assetId },
});
try {
if (assetData) {
navigate(
`/facility/${assetData.location_object.facility?.id}/assets/${assetId}`,
);
}
} catch (err) {
console.log(err);
setIsLoading(false);
Notification.Error({
msg: "Invalid QR code scanned !!!",
});
}
};

Expand All @@ -159,8 +182,7 @@ const AssetsList = () => {
<Scanner
onResult={async (text) => {
if (text) {
const assetId = await getAssetIdFromQR(text);
checkValidAssetId(assetId ?? text);
await accessAssetIdFromQR(text);
}
}}
onError={(e) => {
Expand Down
9 changes: 8 additions & 1 deletion src/Components/Assets/configure/CameraConfigure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getCameraConfig } from "../../../Utils/transformUtils";
import { Submit } from "../../Common/components/ButtonV2";
import TextFormField from "../../Form/FormFields/TextFormField";
import Card from "../../../CAREUI/display/Card";
import { FieldErrorText } from "../../Form/FormFields/FormField";

interface CameraConfigureProps {
asset: AssetData;
Expand Down Expand Up @@ -59,8 +60,14 @@ export default function CameraConfigure(props: CameraConfigureProps) {
value={newPreset}
className="mt-1"
onChange={(e) => setNewPreset(e.value)}
error=""
errorClassName="hidden"
/>
{newPreset.length > 12 && (
<FieldErrorText
error="It is advisable to keep preset name below 12 characters"
className="!text-warning-500"
/>
)}
</div>
</div>
<div className="mt-4 flex justify-end">
Expand Down
57 changes: 37 additions & 20 deletions src/Components/CameraFeed/AssetBedSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,56 +15,73 @@ export default function CameraPresetSelect(props: Props) {
const label = props.label ?? defaultLabel;
return (
<>
<div className="hidden gap-2 whitespace-nowrap pr-2 md:flex">
<div className="hidden gap-4 whitespace-nowrap pr-2 lg:flex lg:gap-2">
{/* Desktop View */}
{props.options
.slice(0, props.options.length > 5 ? 4 : 5)
.map((option) => (
<button
className={classNames(
"rounded-xl border px-2 py-0.5 text-xs transition-all duration-200 ease-in-out hover:bg-zinc-600",
"min-w-16 max-w-40 overflow-hidden text-ellipsis whitespace-nowrap rounded-lg border-2 px-2 py-0.5 text-base transition-all duration-200 ease-in-out hover:bg-zinc-600",
props.value?.id === option.id
? "border-white bg-zinc-100 font-bold text-black"
: "border-white/50 text-zinc-100",
: "border-zinc-700 font-medium text-zinc-300",
)}
onClick={() => props.onChange?.(option)}
>
{label(option)}
</button>
))}
{props.options.length > 5 && (
<CameraPresetDropdown {...props} options={props.options.slice(4)} />
<CameraPresetDropdown
{...props}
placeholder="More preset"
options={props.options.slice(4)}
value={props.options.slice(4).find((o) => o.id === props.value?.id)}
/>
)}
</div>
<div className="md:hidden">
<div className="w-full lg:hidden">
{/* Mobile View */}
<CameraPresetDropdown {...props} />
<CameraPresetDropdown {...props} placeholder="Select preset" />
</div>
</>
);
}

export const CameraPresetDropdown = (props: Props) => {
export const CameraPresetDropdown = (
props: Props & { placeholder: string },
) => {
const selected = props.value;

const options = props.options.filter(({ meta }) => meta.type !== "boundary");

const label = props.label ?? defaultLabel;

return (
<Listbox value={selected} onChange={props.onChange}>
<Listbox
value={selected}
onChange={props.onChange}
disabled={options.length === 0}
>
<div className="relative flex-1">
<Listbox.Button className="relative w-full cursor-default pr-6 text-left text-xs text-white focus:outline-none disabled:cursor-not-allowed disabled:bg-transparent disabled:text-zinc-700 sm:text-sm md:pl-2">
<span
className={classNames(
"block truncate",
!selected && "text-gray-500",
)}
>
{selected ? label(selected) : "Select preset"}
<Listbox.Button
className={classNames(
"relative min-w-32 max-w-40 overflow-hidden text-ellipsis whitespace-nowrap rounded-lg border-2 px-2 py-0.5 pr-8 text-left text-base transition-all duration-200 ease-in-out hover:bg-zinc-600 focus:outline-none disabled:cursor-not-allowed disabled:bg-transparent disabled:text-zinc-700",
selected
? "border-white bg-zinc-100 font-bold text-black"
: "border-zinc-700 font-medium text-zinc-300",
)}
>
<span className="block truncate">
{options.length === 0
? "No presets"
: selected
? label(selected)
: props.placeholder}
</span>
<span className="pointer-events-none absolute inset-y-0 right-0 mt-1 flex items-center">
<CareIcon icon="l-angle-down" className="text-lg text-zinc-500" />
<span className="pointer-events-none absolute inset-y-0 right-0 mr-1 mt-1 flex items-center">
<CareIcon icon="l-angle-down" className="text-xl text-zinc-400" />
</span>
</Listbox.Button>
<Transition
Expand All @@ -73,7 +90,7 @@ export const CameraPresetDropdown = (props: Props) => {
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="absolute z-20 mt-1 max-h-48 w-full overflow-auto rounded-b-lg bg-zinc-900/75 py-1 text-base shadow-lg ring-1 ring-white/5 backdrop-blur-sm focus:outline-none sm:text-sm md:max-h-60">
<Listbox.Options className="absolute z-20 mt-1 max-h-48 w-full overflow-auto rounded-b-lg bg-zinc-900/75 py-1 text-base shadow-lg ring-1 ring-white/5 backdrop-blur-sm focus:outline-none md:max-h-60">
{options?.map((obj) => (
<Listbox.Option
key={obj.id}
Expand All @@ -87,7 +104,7 @@ export const CameraPresetDropdown = (props: Props) => {
{({ selected }) => (
<>
<span
className={`block truncate text-xs md:text-sm ${
className={`block truncate text-sm md:text-base ${
selected ? "font-bold text-white" : "font-normal"
}`}
>
Expand Down
Loading

0 comments on commit e129388

Please sign in to comment.