Skip to content

Commit 5660b9f

Browse files
committed
update the pdf reader
1 parent 5f47eb7 commit 5660b9f

File tree

4 files changed

+73
-74
lines changed

4 files changed

+73
-74
lines changed

frontend/src/pages/DrugSummary/DrugSummaryForm.tsx

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ const DrugSummaryForm = () => {
2727
const { search } = useLocation();
2828
const params = new URLSearchParams(search);
2929
const guid = params.get("guid") || "";
30-
const pageParam = params.get("page");
3130
const textareaRef = useRef<HTMLTextAreaElement>(null);
3231

3332
useEffect(() => {
@@ -49,17 +48,6 @@ const DrugSummaryForm = () => {
4948

5049
useEffect(() => setHasPDF(!!guid), [guid]);
5150

52-
useEffect(() => {
53-
if (pageParam && hasPDF) {
54-
const page = parseInt(pageParam, 10);
55-
if (!isNaN(page) && page > 0) {
56-
window.dispatchEvent(
57-
new CustomEvent("navigateToPdfPage", { detail: { pageNumber: page } })
58-
);
59-
}
60-
}
61-
}, [pageParam, hasPDF]);
62-
6351
useEffect(() => {
6452
if (!isStreaming && !isLoading && textareaRef.current) {
6553
textareaRef.current.focus();
@@ -184,7 +172,7 @@ const DrugSummaryForm = () => {
184172
<div className="flex h-full w-full justify-center">
185173
{hasPDF && (
186174
<div className={`${panelWidthClass} h-full`}>
187-
<PDFViewer />
175+
<PDFViewer key={guid} />
188176
</div>
189177
)}
190178
<div className={`${panelWidthClass} h-full flex flex-col p-2`}>

frontend/src/pages/DrugSummary/PDFViewer.tsx

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ interface DocumentLoadSuccess {
2020
numPages: number;
2121
}
2222

23-
const PAGE_INIT_DELAY = 800;
24-
2523
const PDFViewer = () => {
2624
const [numPages, setNumPages] = useState<number | null>(null);
2725
const [pageNumber, setPageNumber] = useState(1);
@@ -45,13 +43,13 @@ const PDFViewer = () => {
4543
const pageRefs = useRef<Record<number, HTMLDivElement | null>>({});
4644
const prevGuidRef = useRef<string | null>(null);
4745
const isFetchingRef = useRef(false);
46+
const isAutoScrollingRef = useRef(false);
4847

4948
const location = useLocation();
5049
const navigate = useNavigate();
5150
const params = new URLSearchParams(location.search);
5251
const guid = params.get("guid");
5352
const pageParam = params.get("page");
54-
5553
const baseURL = import.meta.env.VITE_API_BASE_URL as string | undefined;
5654

5755
const pdfUrl = useMemo(() => {
@@ -65,28 +63,45 @@ const PDFViewer = () => {
6563
const guidChanged = guid !== prevGuidRef.current;
6664

6765
if (guidChanged) {
68-
pageRefs.current = {};
6966
setIsDocumentLoaded(false);
7067
setNumPages(null);
7168
setPdfData(null);
72-
setPageNumber(1);
69+
setTargetPageAfterLoad(null);
70+
const validPage = !isNaN(nextPage) && nextPage > 0 ? nextPage : 1;
71+
setPageNumber(validPage);
72+
setTargetPageAfterLoad(validPage);
73+
prevGuidRef.current = guid;
74+
return;
75+
}
76+
77+
const desired = !isNaN(nextPage) && nextPage > 0 ? nextPage : 1;
78+
if (pageNumber !== desired) {
79+
if (isDocumentLoaded && numPages) {
80+
const clampedPage = Math.max(1, Math.min(desired, numPages));
81+
setPageNumber(clampedPage);
82+
scrollToPage(clampedPage);
83+
} else {
84+
setPageNumber(desired);
85+
setTargetPageAfterLoad(desired);
86+
}
7387
}
7488

75-
setTargetPageAfterLoad(!isNaN(nextPage) && nextPage > 0 ? nextPage : 1);
7689
prevGuidRef.current = guid;
77-
}, [guid, pageParam, location.pathname, location.search]);
90+
}, [guid, pageParam, pageNumber, isDocumentLoaded, numPages]);
7891

7992
const updateCurrentPageFromScroll = useCallback(() => {
8093
if (!numPages || !contentRef.current) return;
8194

95+
if (isAutoScrollingRef.current) return;
96+
8297
const container = contentRef.current;
8398
const containerRectTop = container.getBoundingClientRect().top;
8499
const containerCenter = containerRectTop + container.clientHeight / 2;
85100

86101
let bestPage = 1;
87102
let bestDist = Infinity;
88103

89-
for (let i = 1; i <= (numPages ?? 0); i++) {
104+
for (let i = 1; i <= numPages; i++) {
90105
const el = pageRefs.current[i];
91106
if (!el) continue;
92107
const r = el.getBoundingClientRect();
@@ -99,6 +114,9 @@ const PDFViewer = () => {
99114
}
100115

101116
if (bestPage !== pageNumber) {
117+
console.log(
118+
`Scroll detected: updating page from ${pageNumber} to ${bestPage}`
119+
);
102120
setPageNumber(bestPage);
103121
const newParams = new URLSearchParams(location.search);
104122
newParams.set("page", String(bestPage));
@@ -126,16 +144,6 @@ const PDFViewer = () => {
126144
return () => container.removeEventListener("scroll", onScroll);
127145
}, [updateCurrentPageFromScroll]);
128146

129-
useEffect(() => {
130-
updateCurrentPageFromScroll();
131-
}, [
132-
numPages,
133-
deferredScale,
134-
containerSize.width,
135-
containerSize.height,
136-
updateCurrentPageFromScroll,
137-
]);
138-
139147
const scrollToPage = useCallback(
140148
(page: number) => {
141149
if (!numPages || page < 1 || page > numPages) return;
@@ -146,35 +154,47 @@ const PDFViewer = () => {
146154
return;
147155
}
148156

157+
isAutoScrollingRef.current = true;
149158
targetRef.scrollIntoView({
150159
behavior: "smooth",
151160
block: "start",
152161
inline: "nearest",
153162
});
154163

155164
const newParams = new URLSearchParams(location.search);
156-
const oldPage = newParams.get("page");
157-
if (oldPage !== String(page)) {
165+
if (newParams.get("page") !== String(page)) {
158166
newParams.set("page", String(page));
159167
navigate(`${location.pathname}?${newParams.toString()}`, {
160168
replace: true,
161169
});
162170
}
163171

164-
setPageNumber(page);
172+
setTimeout(() => {
173+
isAutoScrollingRef.current = false;
174+
updateCurrentPageFromScroll();
175+
}, 500);
165176
},
166-
[numPages, location.pathname, location.search, navigate]
177+
[
178+
numPages,
179+
location.pathname,
180+
location.search,
181+
navigate,
182+
updateCurrentPageFromScroll,
183+
]
167184
);
168185

169186
const goToPage = useCallback(
170187
(page: number) => {
171188
if (typeof page !== "number" || isNaN(page)) return;
172189

173190
const clamped = Math.max(1, numPages ? Math.min(page, numPages) : page);
191+
174192
if (!isDocumentLoaded || !numPages) {
175193
setTargetPageAfterLoad(clamped);
194+
setPageNumber(clamped);
176195
return;
177196
}
197+
178198
if (clamped === pageNumber) return;
179199

180200
setPageNumber(clamped);
@@ -197,16 +217,19 @@ const PDFViewer = () => {
197217
}, [goToPage]);
198218

199219
useEffect(() => {
200-
if (isDocumentLoaded && numPages && targetPageAfterLoad) {
201-
const validPage = Math.min(Math.max(1, targetPageAfterLoad), numPages);
202-
setPageNumber(validPage);
220+
if (isDocumentLoaded && numPages && targetPageAfterLoad !== null) {
221+
const validPage = Math.max(1, Math.min(targetPageAfterLoad, numPages));
203222

204-
const timer = setTimeout(() => {
223+
console.log(`Navigating to page ${validPage} after document load`);
224+
const timeoutId = setTimeout(() => {
205225
scrollToPage(validPage);
206-
setTargetPageAfterLoad(null);
207-
}, PAGE_INIT_DELAY);
208226

209-
return () => clearTimeout(timer);
227+
setTimeout(() => {
228+
setTargetPageAfterLoad(null);
229+
}, 600);
230+
}, 100);
231+
232+
return () => clearTimeout(timeoutId);
210233
}
211234
}, [isDocumentLoaded, numPages, targetPageAfterLoad, scrollToPage]);
212235

@@ -301,6 +324,7 @@ const PDFViewer = () => {
301324

302325
const onDocumentLoadSuccess = useCallback(
303326
({ numPages }: DocumentLoadSuccess) => {
327+
console.log(`Document loaded with ${numPages} pages`);
304328
setNumPages(numPages);
305329
setError(null);
306330
setIsDocumentLoaded(true);
@@ -441,7 +465,7 @@ const PDFViewer = () => {
441465
data-page={pageNum}
442466
>
443467
<Page
444-
key={`${guid}-${pageNum}`}
468+
key={pageNum}
445469
pageNumber={pageNum}
446470
width={baseWidth}
447471
scale={deferredScale}

frontend/src/pages/PatientManager/PatientSummary.tsx

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,10 @@ type MedicationWithSource = {
4242

4343
const truncate = (s = "", n = 220) =>
4444
s.length > n ? s.slice(0, n).trim() + "…" : s;
45-
const badge = (label: string) => (
46-
<span className="ml-2 inline-flex items-center rounded-md bg-indigo-50 px-2 py-0.5 text-xs font-medium text-indigo-700">
47-
{label}
48-
</span>
49-
);
45+
5046
const MedicationItem = ({
5147
medication,
52-
source,
48+
5349
isClicked,
5450
riskData,
5551
loading,
@@ -79,10 +75,7 @@ const MedicationItem = ({
7975
<li className="flex items-center justify-between py-4 pl-4 pr-5 text-sm leading-4 hover:bg-indigo-100">
8076
<div className="flex items-center flex-1 w-0">
8177
<div className="flex flex-1 min-w-0 gap-2 ml-4">
82-
<span className="font-medium truncate">
83-
{medication}
84-
<span className="ml-2 text-xs text-gray-400">({source})</span>
85-
</span>
78+
<span className="font-medium truncate">{medication}</span>
8679
{loading && isClicked && (
8780
<div className="flex items-start max-w-sm mt-0 ml-3 text-white">
8881
<TypingAnimation />
@@ -144,17 +137,11 @@ const MedicationItem = ({
144137
<div className="mt-6">
145138
<div className="flex items-center">
146139
<h4 className="text-sm font-medium text-indigo-600">Sources</h4>
147-
{riskData.source && badge(riskData.source.toUpperCase())}
148140
</div>
149141

150142
<ul className="mt-3 divide-y divide-gray-200 rounded-md border border-gray-200 bg-white">
151143
{riskData.sources.map((s, idx) => (
152144
<li key={idx} className="px-4 py-3">
153-
<div className="flex flex-wrap items-center gap-2">
154-
{s.rule_type && badge(s.rule_type)}
155-
{s.history_type && badge(s.history_type)}
156-
</div>
157-
158145
<div className="mt-1 text-sm font-medium text-gray-900 flex items-center justify-between">
159146
<span>{s.title || "Untitled source"}</span>
160147

@@ -217,23 +204,23 @@ const MedicationTier = ({
217204
<dt className="flex ml-2 text-sm font-medium leading-6 text-gray-900">
218205
{title}:
219206
</dt>
220-
{ medications.length ?
207+
{medications.length ? (
221208
<ul className="border border-gray-200 divide-y divide-gray-100 rounded-md">
222209
{medications.map((medicationObj) => (
223-
<MedicationItem
224-
key={medicationObj.name}
225-
medication={medicationObj.name}
226-
source={medicationObj.source}
227-
isClicked={medicationObj.name === clickedMedication}
228-
riskData={riskData}
229-
loading={loading}
230-
onClick={() => onMedicationClick(medicationObj)}
231-
/>
232-
))
233-
}
234-
</ul> :
210+
<MedicationItem
211+
key={medicationObj.name}
212+
medication={medicationObj.name}
213+
source={medicationObj.source}
214+
isClicked={medicationObj.name === clickedMedication}
215+
riskData={riskData}
216+
loading={loading}
217+
onClick={() => onMedicationClick(medicationObj)}
218+
/>
219+
))}
220+
</ul>
221+
) : (
235222
<em className="ml-2">{`Patient's other health concerns may contraindicate typical ${tier} line options.`}</em>
236-
}
223+
)}
237224
</>
238225
);
239226

server/Dockerfile.prod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# pull official base image
2-
FROM python:3.11.4-slim-buster
2+
FROM python:3.11.4-slim-bullseye
33

44

55
# set work directory

0 commit comments

Comments
 (0)