Closed kavimuru closed 2 months ago
:wave: Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
Triggered auto assignment to @anmurali (Bug
), see https://stackoverflow.com/c/expensify/questions/14418 for more details.
Triggered auto assignment to @deetergp (Engineering
), see https://stackoverflowteams.com/c/expensify/questions/9980/ for more details.
@anmurali FYI I haven't added the External label as I wasn't 100% sure about this issue. Please take a look and add the label if you agree it's a bug and can be handled by external contributors.
Is this our culprit PR? https://github.com/Expensify/App/pull/35255 (cc @eh2077 @s77rt @luacmartins)
We have just added support for PDF receipts, so I'm not sure this would qualify as a deploy blocker because we don't support PDF receipts in production right now.
Thanks @youssef-lr, that sounds reasonable. I'll remove the label and demote this back down to Daily.
@eh2077 Can you please take a quick look on this?
@s77rt Sure. I'm looking into it.
It seems not easy to avoid reloading PDF when going back and forth between 1:1 DM, IOU report and transaction thread. This is because the browser by default can't cache the canvas
of the PDFThumbnail but it's able to cache image
by default.
While checking this issue, I also found another flaw that's easier to avoid - PDF thumbnail reloads when hovering on it
https://github.com/Expensify/App/assets/117511920/df575660-eba5-4a00-9dc1-08f9e0fda1dd
I think the reloading issue when hovering is a legit regression. I can make a quick PR to fix it.
But the reloading issue when re-visiting different pages seems a tricky one. Can this be a followup improvement instead of a regression?
@s77rt @luacmartins What're your opinions?
@eh2077 Can you please raise a PR fixing the hover issue? I thought we fixed that here https://github.com/Expensify/App/pull/35255#discussion_r1469048195 Is this another case that we missed?
Yea, let's fix the hover issue and then investigate the reload one as a separate issue.
@deetergp Please assign me here
Reviewing
label has been removed, please complete the "BugZero Checklist".
The solution for this issue has been :rocket: deployed to production :rocket: in version 1.4.51-3 and is now subject to a 7-day regression period :calendar:. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2024-03-20. :confetti_ball:
For reference, here are some details about the assignees on this issue:
BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:
@luacmartins / @deetergp We still have the bug when switching reports; let's reopen this since we only fixed the hover case.
[Upwork Job]()
I think we should wait till the bug is fixed on switching reports as well before we pay this. Do you agree @s77rt ?
Yes. In fact we should reopen this. Can you or @deetergp add Help Wanted
label, remove Awaiting Payment
and update the title
Should be all set @s77rt.
Going to make this a weekly till we have some proposals.
Still waiting on proposals
PDF receipt preview loads each time visting DM, report and transaction thread.
The react-pdf document is loading url using the file prop. According to react-pdf,
({ url: 'http://example.com/document.pdf' }) === ({ url: 'http://example.com/document.pdf' })
false
When the expected would have been true.
react-pdf takes the file as referentially unequal each time the file prop is set to previewSourceURL and causes re-render. https://github.com/Expensify/App/blob/b9bd07fcbf13ad517a0b42b5a4dc4abafefb91f7/src/components/PDFThumbnail/index.tsx#L22
Since only the thumbnail preview of the first page is needed and image receipt previews are loading correctly. I suggest to convert the first page of the pdf receipt to image for previewing purposes and render the first page as image rather than rendering the first page as pdf. The pdf approach would be difficult given the contraints posed by react-pdf.
The approach uses helper method to get the first page of the pdf receipt and render to canvas element and then get the DataURL (img in base64 format). The base64 img is stored in localstorage and uses fileName as key to the base64 img.
The PDFThumbnail component would need fileName (previewSourceURL) of the pdf receipt for mapping in localStorage. Using URl.createObjectURL returns different url each time which causes re-render so need to map using fileName. https://github.com/Expensify/App/blob/b9bd07fcbf13ad517a0b42b5a4dc4abafefb91f7/src/components/PDFThumbnail/index.tsx#L15
const isImageLoadedRef = useRef(false);
const [imageUrl, setImageUrl] = useState<string>(null);
const data = localStorage.getItem(fileName);
if(data && !isImageLoadedRef.current)
{
isImageLoadedRef.current = true;
setImageUrl(data);
}
useEffect(() => {
if (data) {
return;
}
const canvas = document.createElement("canvas");
pdfjs.getDocument(url).promise.then((pdf) => {
for (let i = 0; i < 1; i++) {
pdf.getPage(i + 1).then((page) => {
const viewport = page.getViewport({ scale: 5 });
const context = canvas.getContext("2d");
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext).promise.then((e) => {
const data = canvas.toDataURL();
localStorage.setItem(fileName, data);
isImageLoadedRef.current = true;
setImageUrl(data);
canvas.remove();
});
})
}
});
}, [data])
In the PDFThumbnail component instead of loading react-pdf component load ReceiptImage component and pass the base64 imageURL. https://github.com/Expensify/App/blob/b9bd07fcbf13ad517a0b42b5a4dc4abafefb91f7/src/components/PDFThumbnail/index.tsx#L40
{imageUrl &&
<ReceiptImage
isThumbnail={false}
source={imageUrl}
// AuthToken is required when retrieving the image from the server
// but we don't need it to load the blob:// or file:// image when starting a money request / split bill
// So if we have a thumbnail, it means we're retrieving the image from the server
isAuthTokenRequired={isAuthTokenRequired}
/>
}
@jsdev2547 Thanks for the proposal. Regarding the RCA
The react-pdf document is loading url using the file prop. According to react-pdf,
({ url: 'http://example.com/document.pdf' }) === ({ url: 'http://example.com/document.pdf' }) false
Can you link to the relevant code? If the bug is in react-pdf then it should be fixed upstream
@s77rt I downgraded to react-pdf version 6.2.2 and the pdf thumbnail is still reloading when navigation from DM to report and transaction thread. I also checked if the route navigation was causing re-render when navigating from DM to report and transaction thread, but when image receipt is used even though the route navigates in reportPreview and MoneyRequestAction no reloading issue is observed, but the reloading issue is present when using pdf thumbnails. So the issue is definitely the third party lib react-pdf. But the important thing is not to try and solve the bug in third party lib but to correct approach of displaying pdf thumbnails.
Route navigation https://github.com/Expensify/App/blob/8f90c2567f020ed924a96593244727aace9a7d72/src/components/ReportActionItem/ReportPreview.tsx#L257
More so what I have observed is the correct approach to solving the issue of pdf thumbnails is to generate thumbnail of pdf by rendering the pdf page to canvas and then converting the canvas to image using toDataURL() for preview.
pdfjs in the provided example of pdf thumbnail has suggested to convert the canvas to image and then display the image, rather than displaying the pdf page directly.
https://github.com/mozilla/pdf.js/blob/master/web/pdf_thumbnail_view.js#L216
@jsdev2547 Let's fix the root cause. Rendering pdf then converting to image is more work than just rendering the pdf.
@s77rt The pdf would not be rendered, i.e. the react-pdf document component would not be used in pdf thumbnail. The poc is quite straight forward, get page 1 of pdf, render on canvas, get the image from canvas. The root cause would be to not to render pdf thumbnails as pdf but to render pdf thumbnails as image. I was trying to actually use pdfjs to render pdf thumbnail but then came across pdf_thumbnail example which suggests to convert pdf to thumbnail rather use pdf directly.
I have poc video of pdf image thumbnails in pdf receipts and how the functionality appears, or I can also provide branch, if needed.
@jsdev2547 I'm pretty sure our back end creates a thumbnail of these uploaded PDFs automagically. If you replace the .pdf
extension of the uploaded PDF with .jpg
there you should have a JPG rendering of the fist page of the PDF. And if you add .320.jpg
or .1024.jpg
on to that you'll have 320px & 1024px thumbnails.
You may not have access to actually view these but I guarantee you they are there: https://staging.expensify.com/receipts/w_edee87a4d07915c51e6b58ed256da890177f2a3c.pdf https://staging.expensify.com/receipts/w_edee87a4d07915c51e6b58ed256da890177f2a3c.jpg https://staging.expensify.com/receipts/w_edee87a4d07915c51e6b58ed256da890177f2a3c.jpg.320.jpg https://staging.expensify.com/receipts/w_edee87a4d07915c51e6b58ed256da890177f2a3c.jpg.1024.jpg
@jsdev2547
get page 1 of pdf, render on canvas, get the image from canvas
This is more work than what we have currently in place where we just render the pdf on canvas.
@deetergp When offline we don't have access to those urls. We render the pdf instead
@deetergp Interesting, then the conversion step is already done only the thumbnail needs displaying.
@s77rt the issue is regarding the thumbnail reloading not offline, so @deetergp might have point on using the urls provided by server. I need to look into and get back.
@deetergp @s77rt The urls become available after the scan request is complete and the urls are available offline and online. The issue is regarding reloading of the pdf which happens either online or offline while the user is waiting for the scan request to complete. Once the scan request is complete the backend sends the thumbnail of the first page of the pdf and the pdfthumbnail component is no longer used instead the pdf image thumbnail is rendered using thumbnail component. The isPDFThumbnail variable is also set to false for pdf receipts and shouldUseThumbnailImage is set to true.
The backend already has the correct approach of sending thumbnails of first page of pdf receipts after scan is complete, while the user is waiting for the scan to complete(online or offline), the front end should also correct the approach and generate image thumbnail of pdf. The thumbnail images generated on the front end would resolve the reloading issue and be available (online or offline) while the user is waiting for scan request to complete. Once the scan request is complete, the thumbnail would be served from the backend.
So what needs to be decided is to whether to push for and continue the use of pdfs in thumbnails while the user is waiting for the scan to complete, or whether the front end should be consistent with the backend and generate thumbnails for pdf while the scan is in progress. I vote for generating thumbnail of first page pdf on the front end because the effort is inlined with the backend and not hard to implement. I already having functional solution which solves the issue (I can provide video and branch for testing). Trying to get the pdf to directly render in thumbnail(also spending time to find bug in react-pdf) seems to be unnecessary effort when the server would eventually return thumbnails. I would have agreed more with the second approach if the backend was not sending thumbnails.
@jsdev2547 Thanks for looking into this. Generating an image has to pass via the pdf rendering phase. This is not giving us any advantage and it's only resulting in more work. We should just fix the pdf rendering phase to not re-render if the source is not changed.
Generating an image has to pass via the pdf rendering phase.
@s77rt The current implementation is going to load the pdf document anyways on first render, the entire image generation can be done in onLoadSuccess event and is not difficult to implement. Please take moment to review the implementation and test the provided branch.
https://github.com/jsdev2547/App/tree/generatePdfThumbnail
Also added poc video,
We should just fix the pdf rendering phase to not re-render if the source is not changed.
Typically the right approach would be to correct the useEffect to not re-render if the source has not changed, but in the given issue, the useEffect is in third party lib and also I have concerns the approach of rendering pdf directly for thumbnails is incorrect. react-pdf is using pdf.js and in the pdf.js example I mentioned is also converting first page to image thumbnail and also the backend is generating image thumbnail. Also I find little advantage in trying to display the pdf thumbnail when after the scan is complete the backend would be sending image thumbnails anyways. so the correct approach should be to simply display image thumbnails (online and offline) while the user is waiting for the scan to complete.
@deetergp perhaps internal engineer can be requested to get second opinion on whether pdf should be used for thumbnails while the user is waiting for scan to complete (online & offline) or whether front end should generate image thumbnails and after the scan is complete display the thumbnails sent by backend.
@jsdev2547
The current implementation is going to load the pdf document anyways on first render
Correct, and that should be all what we have to do here. No post-processing.
the entire image generation can be done in onLoadSuccess event and is not difficult to implement
This is workaround, we are doing more work just to avoid fixing the root cause. We should fix the root cause
but in the given issue, the useEffect is in third party lib
This is not a blocker. We should raise a PR in that library
Not overdue. Still looking for proposals
Same
Making weekly while await additional proposals.
Still looking for proposals
Same ^
MOTS
Still looking for proposals
Same ^
Job added to Upwork: https://www.upwork.com/jobs/~016df3671b30e63c80
Current assignee @s77rt is eligible for the External assigner, not assigning anyone new.
Still no proposals, but that may be because there wasn't an External label on this one. Added it now.
If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!
Version Number: 1.4.48-0 Reproducible in staging?: y Reproducible in production?: n If this was caught during regression testing, add the test name, ID and link from TestRail: Email or phone of affected tester (no customers): Logs: https://stackoverflow.com/c/expensify/questions/4856 Expensify/Expensify Issue URL: Issue reported by: Applause internal team Slack conversation:
Action Performed:
Expected Result:
The PDF receipt preview will not load each time going back and forth between 1:1 DM, IOU report and transaction thread.
Actual Result:
The PDF receipt preview loads each time going back and forth between 1:1 DM, IOU report and transaction thread. Sometimes it shows blue "loading page" briefly when the receipt is rendering.
Workaround:
unknown
Platforms:
Which of our officially supported platforms is this issue occurring on?
Screenshots/Videos
Add any screenshot/video evidence
https://github.com/Expensify/App/assets/43996225/885644dc-0d8b-43ab-86a3-b288dfe8d92d
View all open jobs on GitHub
Upwork Automation - Do Not Edit
Issue Owner
Current Issue Owner: @