Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Scroll Issue with Pressure Sores Popup #8400

Merged
merged 3 commits into from
Aug 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 42 additions & 18 deletions src/CAREUI/display/PopupModal.tsx
Original file line number Diff line number Diff line change
@@ -9,10 +9,17 @@ type Props = {
show: boolean;
onHide: () => void;
children: ReactNode;
anchorRef: React.RefObject<HTMLElement>;
className?: string;
onSubmit?: () => void;
};

type Position =
| { left: number; top: number }
| { right: number; bottom: number }
| { left: number; bottom: number }
| { right: number; top: number };

export default function PopupModal(props: Props) {
const { t } = useTranslation();
const isMobile = useBreakpoints({ default: true, lg: false });
@@ -43,7 +50,7 @@ export default function PopupModal(props: Props) {

const DesktopView = (props: Props) => {
const { t } = useTranslation();
const [position, setPosition] = useState({ x: 0, y: 0 });
const [position, setPosition] = useState<Position>({ left: 0, top: 0 });
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const modal = useRef<HTMLDivElement>(null);
const [children, setChildren] = useState(props.children);
@@ -68,25 +75,38 @@ const DesktopView = (props: Props) => {
const currentMousePosition = mousePosition;
const modalHeight = modal.current?.clientHeight || 0;
const modalWidth = modal.current?.clientWidth || 0;
const xRelative = currentMousePosition.x;
const yRelative = currentMousePosition.y;
const containerHeight = window.innerHeight;
const containerWidth = window.innerWidth;
const top =
yRelative + modalHeight > containerHeight
? yRelative - modalHeight
: yRelative;
const left =
xRelative + modalWidth > containerWidth
? xRelative - modalWidth
: xRelative;
setPosition({ x: left, y: top });
const clickX = currentMousePosition.x;
const clickY = currentMousePosition.y;
const windowHeight = window.innerHeight;
const windowWidth = window.innerWidth;

const anchorPosition = props.anchorRef.current?.getBoundingClientRect();
const anchorX = anchorPosition?.x || 0;
const anchorY = anchorPosition?.y || 0;
const verticalCenter = windowHeight / 2;
const horizontalCenter = windowWidth / 2;
const mountLeft = clickX - anchorX;
const mountTop = clickY - anchorY;

let position;
if (clickX > horizontalCenter) {
position = { left: mountLeft - modalWidth };
} else {
position = { left: mountLeft };
}
if (clickY > verticalCenter) {
position = { ...position, top: mountTop - modalHeight };
} else {
position = { ...position, top: mountTop };
}
setPosition(position);
}

document.addEventListener("mousedown", handleOutsideClick);
return () => {
document.removeEventListener("mousedown", handleOutsideClick);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.show]);

useEffect(() => {
@@ -99,13 +119,17 @@ const DesktopView = (props: Props) => {
};
}, []);

const positionAttributes = Object.entries(position).reduce(
(acc, [key, value]) => {
return { ...acc, [key]: `${value}px` };
},
{},
);

return (
<div
ref={modal}
style={{
top: position.y + "px",
left: position.x + "px",
}}
style={positionAttributes}
className={classNames(
"absolute z-10 rounded-lg border border-secondary-400 bg-white text-black shadow-lg transition-all",
props.show ? "visible opacity-100" : "invisible opacity-0",
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import PopupModal from "../../../../CAREUI/display/PopupModal";
import HumanBodyChart from "../../../../CAREUI/interactive/HumanChart";
import { SelectFormField } from "../../../Form/FormFields/SelectFormField";
@@ -17,6 +17,7 @@ import { calculatePushScore } from "./utils";

const PressureSore = ({ log, onChange, readonly }: LogUpdateSectionProps) => {
const value = log.pressure_sore ?? [];
const containerRef = useRef<HTMLDivElement>(null);
const [current, setCurrent] = useState<IPressureSore>();

const regionPushScore = (region: IPressureSore["region"]) => {
@@ -33,11 +34,11 @@ const PressureSore = ({ log, onChange, readonly }: LogUpdateSectionProps) => {
}
};

// TODO: wrap with a div with relative class so that the editor sticks on scroll.
return (
<>
<div className="relative" ref={containerRef}>
<RegionEditor
show={!!current}
anchorRef={containerRef}
value={current ?? getRegionInitialData("AnteriorAbdomen")}
onCancel={() => setCurrent(undefined)}
onSave={
@@ -74,7 +75,7 @@ const PressureSore = ({ log, onChange, readonly }: LogUpdateSectionProps) => {
}
regionText={(r) => regionPushScore(r)?.toString() ?? ""}
/>
</>
</div>
);
};

@@ -88,6 +89,7 @@ export default PressureSore;
type RegionEditorProps = {
show: boolean;
value: IPressureSore;
anchorRef: React.RefObject<HTMLElement>;
onCancel: () => void;
onSave?: (value: IPressureSore) => void;
};
@@ -106,6 +108,7 @@ const RegionEditor = (props: RegionEditorProps) => {
<PopupModal
show={props.show}
onHide={props.onCancel}
anchorRef={props.anchorRef}
className="flex w-72 flex-col items-center gap-4"
onSubmit={
props.onSave
10 changes: 7 additions & 3 deletions src/Components/LogUpdate/components/PainChart.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { IPainScale } from "../../Patient/models";
import RangeFormField from "../../Form/FormFields/RangeFormField";
import HumanBodyChart from "../../../CAREUI/interactive/HumanChart";
@@ -15,6 +15,7 @@ type Props = {

export default function PainChart({ pain, onChange }: Props) {
const [current, setCurrent] = useState<IPainScale>();
const containerRef = useRef<HTMLDivElement>(null);

const valueDescription = (region: IPainScale["region"]) => {
const scale = pain.find((obj) => obj.region === region)?.scale;
@@ -24,10 +25,11 @@ export default function PainChart({ pain, onChange }: Props) {
};

return (
<>
<div className="relative" ref={containerRef}>
<RegionEditor
show={!!current}
value={current ?? getInitialData("AnteriorAbdomen")}
anchorRef={containerRef}
onCancel={() => setCurrent(undefined)}
onSave={
onChange
@@ -60,13 +62,14 @@ export default function PainChart({ pain, onChange }: Props) {
pain.find((p) => p.region === region)?.scale.toString() ?? ""
}
/>
</>
</div>
);
}

type RegionEditorProps = {
show: boolean;
value: IPainScale;
anchorRef: React.RefObject<HTMLElement>;
onCancel: () => void;
onSave?: (value: IPainScale) => void;
};
@@ -85,6 +88,7 @@ const RegionEditor = (props: RegionEditorProps) => {
<PopupModal
show={props.show}
onHide={props.onCancel}
anchorRef={props.anchorRef}
className="flex flex-col items-center gap-4"
onSubmit={
props.onSave
Loading