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

PDF Export #90

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
282e66d
install react-pdf packages
purav-parekh Oct 24, 2024
d362dc2
add pdf boilerplate
purav-parekh Oct 24, 2024
72574aa
add pdf components
purav-parekh Oct 29, 2024
babd10d
pdf w gen-info
purav-parekh Oct 31, 2024
c2891d1
add alternative summary + modularize code
purav-parekh Nov 1, 2024
f832578
separate all cost inputs for pdf
purav-parekh Nov 22, 2024
24162a6
refactor all input costs
purav-parekh Dec 5, 2024
8650b7d
pdf results pt1
purav-parekh Dec 19, 2024
8be8a64
Merge branch 'main' into pdf-export
purav-parekh Dec 19, 2024
854ce67
update pdf packages
purav-parekh Dec 19, 2024
7583783
add result summary tables
purav-parekh Dec 24, 2024
414d520
add annual alternative tables
purav-parekh Dec 25, 2024
8e95e9c
stylings, types, polishing pt1 result tables
purav-parekh Dec 27, 2024
f8da067
display 1 graph for test
purav-parekh Jan 16, 2025
7ee3659
add html-to-image package
purav-parekh Jan 16, 2025
451a58b
Merge branch 'main' into pdf-export
purav-parekh Jan 16, 2025
c6758b9
add resultstreams file
purav-parekh Jan 16, 2025
8a9e36f
Merge pull request #107 from usnistgov/result-streams
purav-parekh Jan 16, 2025
1dc0aaf
Merge branch 'main' into pdf-export
purav-parekh Jan 16, 2025
9269cdd
add new class name to result graph
purav-parekh Jan 23, 2025
305f0dc
delete extra resultStream file
purav-parekh Jan 23, 2025
2ad097f
Merge branch 'main' of https://github.com/usnistgov/blcc
purav-parekh Jan 24, 2025
f434765
Merge branch 'main' of https://github.com/usnistgov/blcc
purav-parekh Jan 28, 2025
5ecd2f4
Merge branch 'main' into pdf-export
purav-parekh Jan 28, 2025
76dc327
adding pdf-renderer and html-to-image npm packages
purav-parekh Jan 28, 2025
8ccf92d
pdf working with pulling data from db
purav-parekh Jan 28, 2025
bbbea8f
fix csv to work with data from db
purav-parekh Jan 28, 2025
0f08e8f
round all result values to 2 decimal places
purav-parekh Jan 28, 2025
4865aaa
fix type errors pt1
purav-parekh Jan 28, 2025
f98a3d5
fix - displays all alternatives
purav-parekh Jan 28, 2025
ee4a0cd
fixing type errors pt1
purav-parekh Jan 29, 2025
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
5,926 changes: 4,685 additions & 1,241 deletions frontend/package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@lrd/e3-sdk": "^1.0.11",
"@mdi/js": "^7.4.47",
"@mdi/react": "^1.6.1",
"@react-pdf/renderer": "^4.1.6",
"@react-rxjs/core": "^0.10.7",
"@react-rxjs/utils": "^0.9.7",
"antd": "^5.18.0",
Expand All @@ -30,6 +31,7 @@
"effect": "^3.12.1",
"fast-xml-parser": "4.4.1",
"framer-motion": "^11.2.10",
"html-to-image": "^1.11.11",
"html-to-react": "^1.7.0",
"monocle-ts": "^2.3.13",
"object-hash": "^3.0.0",
Expand All @@ -38,6 +40,7 @@
"react-csv": "^2.2.2",
"react-data-grid": "7.0.0-beta.43",
"react-dom": "^18.3.1",
"react-pdf": "^9.1.1",
"react-router-dom": "^6.23.1",
"rxjs": "^7.8.1",
"ts-pattern": "^5.1.2",
Expand Down
Binary file added frontend/public/645px-nist_logo-svg_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 20 additions & 9 deletions frontend/src/components/CSVDownload.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Alternative, Project } from "blcc-format/Format";
import { Project } from "blcc-format/Format";
import { db } from "model/db";
import { lccRow } from "./allResultStreams";

type lccBaselineRow = {
Expand Down Expand Up @@ -86,13 +87,23 @@ type altResults = {
resourceUsage: resourceUsageRow[][];
};

const CSVDownload = (
project: Project,
alternatives: Alternative[],
summary: summary,
annual: annual,
altResults: altResults
) => {
const fetchData = async () => {
try {
const result = await db.alternatives.toArray();
if (!result || result.length === 0) {
console.log("No alternatives found.");
return [];
}
return result;
} catch (error) {
console.error("Error fetching data:", error);
return [];
}
};

const alternatives = await fetchData();

const CSVDownload = (project: Project[] | undefined, summary: summary, annual: annual, altResults: altResults) => {
let altNames: string[] = alternatives?.map((alt) => alt?.name);
console.log(summary, annual, altResults);

Expand Down Expand Up @@ -285,7 +296,7 @@ const CSVDownload = (
[new Date().toLocaleTimeString()],
[],
["BLCC Project Results"],
[project?.name],
[project?.[0]?.name],
[],
["Summary"],
[],
Expand Down
86 changes: 86 additions & 0 deletions frontend/src/components/Pdf.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { Document, Image, Page, Text, View } from "@react-pdf/renderer";
import { Project } from "blcc-format/Format";

import { db } from "model/db";
import { altResults, annual, summary } from "./allResultStreams";
import Alternatives from "./pdf-components/Alternatives";
import GeneralInformation from "./pdf-components/GeneralInformation";
import NISTHeader from "./pdf-components/NISTHeader";
import PageNumber from "./pdf-components/PageNumber";
import PdfDisclaimer from "./pdf-components/PdfDisclaimer";
import { styles } from "./pdf-components/pdfStyles";
import Results from "./pdf-components/Results";

const fetchData = async () => {
try {
const [alternatives, costs] = await Promise.all([
db.alternatives.toArray().then((result) => {
if (result === undefined || result.length === 0) {
console.log("No alternatives found.");
return [];
}
return result;
}),
db.costs.toArray().then((result) => {
if (result === undefined || result.length === 0) {
console.log("No costs found.");
return [];
}
return result;
})
]);
return [alternatives, costs];
} catch (error) {
console.error("Error fetching data:", error);
return [[], []];
}
};

const [alternatives, costs] = await fetchData();

const Pdf = (props: {
project: Project[];
summary: summary;
annual: annual;
altResults: altResults;
graphSources: string[];
}) => {
const { project, summary, annual, altResults, graphSources } = props;

console.log(project, alternatives, costs);

return (
<Document>
<Page style={styles.page} size="LETTER">
<NISTHeader />
<View style={styles.blccHeader}>
<Image style={styles.logo} src="../public/logo.png" />
<Text style={styles.date}>
Report Generated: {`${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`}
</Text>
</View>
<GeneralInformation project={project} />
<PageNumber />
</Page>
<Page size="LETTER">
<NISTHeader />
<Alternatives alternatives={alternatives} costs={costs} releaseYear={project[0]?.releaseYear} />
<PageNumber />
</Page>
<Page size="LETTER">
<NISTHeader />
<Results
alternatives={alternatives}
summary={summary}
annual={annual}
altResults={altResults}
graphs={graphSources}
/>
<PdfDisclaimer />
<PageNumber />
</Page>
</Document>
);
};

export default Pdf;
117 changes: 105 additions & 12 deletions frontend/src/components/ResultsAppBar.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,38 @@
import { mdiArrowLeft, mdiContentSave, mdiFileDownload, mdiLoading, mdiPlay, mdiTableArrowDown } from "@mdi/js";
import Icon from "@mdi/react";
import type { Alternative, Cost, Project } from "blcc-format/Format";
import { pdf } from "@react-pdf/renderer";
import type { Project } from "blcc-format/Format";
import AppBar from "components/AppBar";
import ButtonBar from "components/ButtonBar";
import HelpButtons from "components/HelpButtons";
import { Button, ButtonType } from "components/input/Button";
import { useSubscribe } from "hooks/UseSubscribe";
import * as htmlToImage from "html-to-image";
import { db } from "model/db";
import { Model, costs$, useAlternatives, useProject } from "model/Model";
import { ResultModel } from "model/ResultModel";
import React from "react";
import { useCallback } from "react";
import { useNavigate } from "react-router-dom";
import { Subject, withLatestFrom } from "rxjs";
import { download } from "util/DownloadFile";
import Pdf from "./Pdf";

import {
altNPV,
altNpvRow,
annualNPVComparisonRow,
lccBaseline,
lccBaselineRow,
lccResourceRow,
lccResourceRows,
lccRow,
lccRows,
npvAll,
npvAllRow,
npvComparison,
npvCosts,
resourceUsage
resourceUsage,
resourceUsageRow
} from "./allResultStreams";
import CSVDownload from "./CSVDownload";

Expand All @@ -31,14 +42,96 @@ const csvClick$ = new Subject<void>();

export default function ResultsAppBar() {
const navigate = useNavigate();
const project: Project = useProject();
const alternatives: Alternative[] = useAlternatives();
let costs: Cost[] = [];
costs$.subscribe((data) => {
costs = data;
});

useSubscribe(pdfClick$, () => {}); //TODO Create and download PDF
// need to handle error properly - discuss with Luke for Modal
const fetchProject = async () => {
try {
const result = await db.projects.where("id").equals(1).toArray(); // Assuming you want the result as an array

if (result === undefined || result.length === 0) {
console.log("No project found.");
} else {
return result; // Process the result
}
} catch (error) {
console.error("Error fetching project:", error);
}
};

let project: Project[] | undefined;
fetchProject().then((p) => (project = p));

const generatePdf = useCallback(
(
_: undefined,
lccRows: lccRow[],
lccBaseline: lccBaselineRow[],
npvCosts: { [key: string]: string }[],
lccResourceRows: lccResourceRow[],
npvComparison: annualNPVComparisonRow[],
altNPV: altNpvRow[][],
resourceUsage: resourceUsageRow[][],
npvAll: npvAllRow[][]
) => {
const pdfGraphs = document.getElementsByClassName("result-graph");
// if (pdfGraphs.length === 0) return;

const promises = [...pdfGraphs].map((graph) =>
htmlToImage.toPng(graph as HTMLElement).then((graphSrc) => graphSrc)
);

Promise.all(promises).then((graphSources) => {
console.log(graphSources);
const blob = pdf(
<Pdf
project={project}
summary={{ lccRows, lccBaseline, npvCosts, lccResourceRows }}
annual={{ npvComparison, npvAll }}
altResults={{ altNPV, resourceUsage }}
graphSources={(graphSources as string[]) || []}
/>
).toBlob();

blob.then((blob: Blob | MediaSource) => {
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `${project?.[0]?.name}.pdf`;
link.click();
});
});
},
[project]
);

useSubscribe(
pdfClick$.pipe(
withLatestFrom(
lccRows,
lccBaseline,
npvCosts,
lccResourceRows,
npvComparison,
altNPV,
resourceUsage,
npvAll
)
),
([_, lccRows, lccBaseline, npvCosts, lccResourceRows, npvComparison, altNPV, resourceUsage, npvAll]) => {
console.log("clicked");
generatePdf(
_,
lccRows,
lccBaseline,
npvCosts,
lccResourceRows,
npvComparison,
altNPV,
resourceUsage,
npvAll
);
}
); //TODO Create and download PDF
useSubscribe(
csvClick$.pipe(
withLatestFrom(
Expand All @@ -58,11 +151,11 @@ export default function ResultsAppBar() {
const altResults = { altNPV, resourceUsage };
// Trigger CSV download
const link = document.createElement("a");
const csvData = CSVDownload(project, alternatives, summary, annual, altResults);
const csvData = CSVDownload(project, summary, annual, altResults);
const csvBlob = new Blob([csvData.join("\n")], { type: "text/csv" });
const url = window.URL.createObjectURL(csvBlob);
link.href = url;
link.download = `${project.name}.csv`; // Set the desired file name
link.download = `${project?.[0]?.name}.csv`; // Set the desired file name
link.click();
window.URL.revokeObjectURL(url); // Clean up the URL object
}
Expand Down
Loading