Skip to content

Commit

Permalink
Merge pull request #247 from ORNL-AMO/issue-123-b
Browse files Browse the repository at this point in the history
Issue 123 - Add End of Game report
  • Loading branch information
rhernandez-intertech authored Mar 12, 2024
2 parents 7e33d33 + 07a3cdf commit 3254ead
Show file tree
Hide file tree
Showing 16 changed files with 5,299 additions and 129 deletions.
4,467 changes: 4,361 additions & 106 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@emotion/styled": "^11.9.3",
"@fontsource/roboto": "^4.5.7",
"@mui/material": "^5.8.7",
"@react-pdf/renderer": "^3.3.8",
"@react-spring/web": "^9.5.0",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
Expand All @@ -27,8 +28,10 @@
"electron-log": "^4.4.8",
"env-cmd": "^10.1.0",
"mui-image": "^1.0.7",
"plotly.js": "^2.29.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-plotly.js": "^2.6.0",
"react-scripts": "5.0.1",
"typescript": "^4.7.4",
"wait-on": "^7.0.1",
Expand Down
2 changes: 2 additions & 0 deletions src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ $doe-green: #007a3e;
$mui-success: #2e7d32;
$blur-radius: 5px;

$landfill-gasses: #f06807;


.bp-font-color {
color: $better-plants-blue
Expand Down
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ export class App extends React.PureComponent<unknown, AppState> {
<ThemeProvider theme={theme}>
<Container maxWidth='xl'>
<Box className='row' sx={{ bgcolor: '#ffffff80', minHeight: '100vh' }}>
{this.state.currentPage == Pages.yearRecap || this.state.showDashboard ?
{this.state.currentPage == Pages.yearRecap || this.state.currentPage == Pages.endGameReport || this.state.showDashboard ?
<>
<Box sx={{ flexGrow: 1 }}>
<AppBar position='relative'
Expand Down
14 changes: 12 additions & 2 deletions src/PageControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import { Box } from '@mui/system';
import { backButton, continueButton, selectButton, infoButtonWithPopup } from './components/Buttons';
import Pages from './Pages';
import { newStartPageControl } from './components/StartPage';
import { newYearRecapControl } from './components/YearRecap';
import { newGroupedChoicesControl } from './components/GroupedChoices';
import { newSelectGameSettingsControl } from './components/SelectGameSettings';
import { newAppPageDialogControl } from './components/Dialogs/InfoDialog';
import Projects from './Projects';
import { newYearRecapControl } from './components/YearRecap';
import { newEndGameReportPageControl } from './components/EndGameReport/EndGameReportPage';
declare interface PageControls {
[key: symbol]: PageControl;
}
Expand Down Expand Up @@ -60,6 +61,14 @@ PageControls[Pages.winScreen] = newAppPageDialogControl({
text: (state) => `You succeeded at the goal! \n You managed to decarbonize {${state.companyName}} by {${(state.trackedStats.carbonSavingsPercent * 100).toFixed(1)}%} in 10 years or less! \n You reduced CO<sub>2</sub>e Emissions by a total of {${state.trackedStats.carbonSavingsPerKg.toLocaleString(undefined, { maximumFractionDigits: 0 })} kg CO<sub>2</sub>e}! \n You saved a total of {$${state.trackedStats.costPerCarbonSavings.toFixed(2)}/kg CO<sub>2</sub>e}! \n You spent a total of {$${state.trackedStats.yearEndTotalSpending.toLocaleString()}} and completed {${state.completedProjects.length}} projects!`,
img: 'images/confetti.png',
buttons: [
{
text: 'View Report',
variant: 'text',
size: 'large',
onClick: function () {
return Pages.endGameReport;
}
},
{
text: 'Play again',
variant: 'text',
Expand Down Expand Up @@ -224,7 +233,8 @@ PageControls[Pages.scope2Projects] = newGroupedChoicesControl({
hideDashboard: false,
}, Pages.selectScope);

PageControls[Pages.yearRecap] = newYearRecapControl({}, Pages.selectScope);
PageControls[Pages.yearRecap] = newYearRecapControl(Pages.selectScope);
PageControls[Pages.endGameReport] = newEndGameReportPageControl();


// todo: investigate whether making this a callback improves page load time (by not resolving all the react components at the start)
Expand Down
1 change: 1 addition & 0 deletions src/Pages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const Pages = {
yearRecap: Symbol('year-recap'),
winScreen: Symbol('win-screen'),
loseScreen: Symbol('lose-screen'),
endGameReport: Symbol('end-game-report'),
// below: scope 1 projects
wasteHeatRecovery: Symbol('waste-heat-recovery'),
wasteHeatRecoveryRebate: Symbol('waste-heat-recovery-rebate'),
Expand Down
9 changes: 5 additions & 4 deletions src/ProjectControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export class ProjectControl implements ProjectControlParams {
statsRecapAppliers?: TrackedStatsApplier;
title: string;
shortTitle: string;
shortTitleRawText: string;
choiceInfoText: string | string[];
choiceInfoImg?: string;
choiceInfoImgAlt?: string;
Expand Down Expand Up @@ -74,6 +75,7 @@ export class ProjectControl implements ProjectControlParams {
this.customBudgetType = params.customBudgetType,
this.title = params.title;
this.shortTitle = params.shortTitle;
this.shortTitleRawText = params.shortTitleRawText;
this.choiceInfoText = params.choiceInfoText;
this.choiceInfoImg = params.choiceInfoImg;
this.choiceInfoImgAlt = params.choiceInfoImgAlt;
Expand Down Expand Up @@ -832,7 +834,7 @@ export const Scope2Projects = [

export declare interface CaseStudy {
title: string;
text: string | string[];
text: string;
url: string;
}

Expand Down Expand Up @@ -873,7 +875,6 @@ export interface SelectedProject extends Project {

/**
* Project that must be renewed each year
* @param gameYearsImplemented - which game years was the project implemented
*/
export interface RenewableProject extends ImplementedProject {
yearlyFinancialSavings?: {
Expand All @@ -891,7 +892,6 @@ export interface ImplementedProject extends Project {
// todo 200 just get from gameYearsImpelmented?
yearStarted?: number;
financingOption?: FinancingOption;

}

export interface Project {
Expand Down Expand Up @@ -925,7 +925,8 @@ declare interface ProjectControlParams {
customBudgetType?: FinancingType;
isSinglePaymentRenewable?: boolean;
isPPA?: boolean;
financingOptions?: FinancingOption[]
financingOptions?: FinancingOption[];
shortTitleRawText?: string,
/**
* Project that only gets energy $ savings for 1 year
*/
Expand Down
7 changes: 7 additions & 0 deletions src/Projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ Projects[Pages.solarPanelsCarPort] = new ProjectControl({
}],
title: 'Small Carport Solar Installation',
shortTitle: 'Install solar panels on new facility carport. {THIS PROJECT WILL BE RENEWED ANNUALLY}.',
shortTitleRawText: 'Install solar panels on new facility carport. THIS PROJECT WILL BE RENEWED ANNUALLY.',
choiceInfoText: [
`You decided to look into installing a small covered carport with a solar electricity generation system.
Given the sizing of your parking lot and available room, you decide on a {0.25 MW system} and use parking in the carport as an incentive to well-performing or energy-saving employees.
Expand Down Expand Up @@ -1096,6 +1097,7 @@ Projects[Pages.smallVPPA] = new ProjectControl({
},
title: 'Invest in wind VPPA',
shortTitle: 'Invest in wind VPPA to offset {10%} of your electricity emissions. {THIS PROJECT WILL BE RENEWED ANNUALLY}.',
shortTitleRawText: 'Invest in wind VPPA to offset 10% of your electricity emissions. THIS PROJECT WILL BE RENEWED ANNUALLY.',
choiceInfoText: ['You decided to look into entering a virtual power purchase agreement for a wind farm a few states away. You can pay $0.05/kWh to offset your electricity emissions, this project costs offsetting {10%} of your electricity emissions. Working with upper management, you work out a deal where {half of the project costs} come from your budget and the other half from a corporate budget. {THIS PROJECT WILL BE RENEWED ANNUALLY}.'],
choiceInfoImg: 'images/wind-mills.jpg',
choiceInfoImgAlt: 'wind mills in a field',
Expand Down Expand Up @@ -1128,6 +1130,7 @@ Projects[Pages.midVPPA] = new ProjectControl({
},
title: 'Invest in wind VPPA',
shortTitle: 'Invest in wind VPPA to offset {20%} of your electricity emissions. {THIS PROJECT WILL BE RENEWED ANNUALLY}.',
shortTitleRawText: 'Invest in wind VPPA to offset 20% of your electricity emissions. THIS PROJECT WILL BE RENEWED ANNUALLY.',
choiceInfoText: ['You decided to look into entering a virtual power purchase agreement for a wind farm a few states away. You can pay $0.05/kWh to offset your electricity emissions, this project costs offsetting {20%} of your electricity emissions. Working with upper management, you work out a deal where {half of the project costs} come from your budget and the other half from a corporate budget. {THIS PROJECT WILL BE RENEWED ANNUALLY}.'],
choiceInfoImg: 'images/wind-mills.jpg',
choiceInfoImgAlt: 'wind mills in a field',
Expand Down Expand Up @@ -1160,6 +1163,7 @@ Projects[Pages.largeVPPA] = new ProjectControl({
},
title: 'Invest in wind VPPA',
shortTitle: 'Invest in wind VPPA to offset {30%} of your electricity emissions. {THIS PROJECT WILL BE RENEWED ANNUALLY}.',
shortTitleRawText: 'Invest in wind VPPA to offset 30% of your electricity emissions. THIS PROJECT WILL BE RENEWED ANNUALLY.',
choiceInfoText: ['You decided to look into entering a virtual power purchase agreement for a wind farm a few states away. You can pay $0.05/kWh to offset your electricity emissions, this project costs offsetting {30%} of your electricity emissions. Working with upper management, you work out a deal where {half of the project costs} come from your budget and the other half from a corporate budget. {THIS PROJECT WILL BE RENEWED ANNUALLY}.'],
choiceInfoImg: 'images/wind-mills.jpg',
choiceInfoImgAlt: 'wind mills in a field',
Expand Down Expand Up @@ -1195,6 +1199,7 @@ Projects[Pages.midSolar] = new ProjectControl({
},
title: 'Mid-sized Solar PPPA',
shortTitle: 'Enter a PPPA with your local utility to build a 2MW solar array. {THIS PROJECT WILL BE RENEWED ANNUALLY}.',
shortTitleRawText: 'Enter a PPPA with your local utility to build a 2MW solar array. THIS PROJECT WILL BE RENEWED ANNUALLY.',
choiceInfoText: [
`To meet aggressive decarbonization goals, you have looked into leasing some neighboring land to your utility for solar panels and receiving the electricity as a physical power purchase agreement (PPPA).
You will continue paying your utility provider for electricity, at a higher rate than previously, but not be responsible for the capital investment or maintenance of the system.
Expand Down Expand Up @@ -1238,6 +1243,7 @@ Projects[Pages.largeWind] = new ProjectControl({
},
title: 'Utility-PPPA Wind Project',
shortTitle: 'Enter a PPPA with a local wind farm to help them expand into a neighboring field. {THIS PROJECT WILL BE RENEWED ANNUALLY}.',
shortTitleRawText: 'Enter a PPPA with a local wind farm to help them expand into a neighboring field. THIS PROJECT WILL BE RENEWED ANNUALLY.',
choiceInfoText: [
`To meet aggressive decarbonization goals, you have looked into selling an empty field next to your facility to a local wind farm company and receiving the electricity as
part of a 15-year contract to source a large portion of your electricity use. You will continue paying your utility provider for electricity, at a higher rate than previously,
Expand Down Expand Up @@ -1280,6 +1286,7 @@ Projects[Pages.communityWindProject] = new ProjectControl({
},
title: 'Community Wind Project',
shortTitle: 'Invest in community wind project. {THIS PROJECT WILL BE RENEWED ANNUALLY}.',
shortTitleRawText: 'Invest in community wind project. THIS PROJECT WILL BE RENEWED ANNUALLY.',
choiceInfoText: [
`To meet aggressive decarbonization goals, you have looked into working with a local wind farm company and investing in a portion of the generation.
You can use Green Bonds to pay for project and you will then own a portion of the generation. The utility is planning to install a {10MW system} on the site, and you will invest in 4MW.
Expand Down
18 changes: 17 additions & 1 deletion src/components/CurrentPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { Fragment } from 'react';
import type { ImplementedProject, RenewableProject} from '../ProjectControl';
import type { CompletedProject, SelectedProject} from '../ProjectControl';
import { PureComponentIgnoreFuncs } from '../functions-and-types';
Expand All @@ -11,6 +11,7 @@ import type { StartPageProps } from './StartPage';
import { YearRecap } from './YearRecap';
import type { PageControlProps, ControlCallbacks } from './controls';
import { CapitalFundingState } from '../Financing';
import EndGameReport from './EndGameReport/EndGameReportPage';


interface CurrentPageProps extends ControlCallbacks, PageControlProps {
Expand Down Expand Up @@ -84,6 +85,21 @@ export class CurrentPage extends PureComponentIgnoreFuncs<CurrentPageProps> {
yearRangeInitialStats={this.props.yearRangeInitialStats}
handleNewYearSetup={this.props.handleNewYearSetupOnProceed}
/>;
case EndGameReport:
return (
<Fragment>
<EndGameReport
{...controlCallbacks}
{...this.props.gameSettings}
trackedStats={this.props.trackedStats}
capitalFundingState={this.props.capitalFundingState}
implementedRenewableProjects={this.props.implementedRenewableProjects}
implementedFinancedProjects={this.props.implementedFinancedProjects}
completedProjects={this.props.completedProjects}
yearRangeInitialStats={this.props.yearRangeInitialStats}
/>
</Fragment>
);
default:
return <></>;
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ export class Dashboard extends PureComponentIgnoreFuncs<DashboardProps> {
text={hydrogenFormatted}
label='Landfill Gas (MMBTU)'
textFontSize={0.85}
color1={theme.palette.primary.light}
color1={'#f06807'}
ticks={[{
value: .5,
label: shortenNumber(statsGaugeProperties.hydrogenMMBTU.maxValue * 0.5),
Expand Down
154 changes: 154 additions & 0 deletions src/components/EndGameReport/DownloadPDF.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { Fragment } from "react";
import { CompletedProject, ProjectControl } from "../../ProjectControl";
import Projects from "../../Projects";
import { truncate } from "../../functions-and-types";
import { TrackedStats } from "../../trackedStats";
import * as ReactPDF from '@react-pdf/renderer';
import { Button, Tooltip, TooltipProps, Typography, styled, tooltipClasses } from "@mui/material";
import React from "react";

export interface ReportPDFProps {
yearRangeInitialStats: TrackedStats[], completedProjects: CompletedProject[]
}

export default function DownloadPDF(props: ReportPDFProps) {
const [pdfInstance, setPdfInstance] = ReactPDF.usePDF({
document:
<EndGameReportPDF
yearRangeInitialStats={props.yearRangeInitialStats}
completedProjects={props.completedProjects}
/>
});

const downloadPDF = () => {
const link = document.createElement("a");
link.download = `CYOS-End-of-Game.pdf`;
link.href = pdfInstance.url;
link.click();
}

return (

<Fragment>
{pdfInstance.loading && <div>Loading ...</div>}
{pdfInstance.error && <div>Error generating document: {pdfInstance.error}</div>}

<HtmlTooltip
title={
<Fragment>
<Typography color="inherit">{"Get list of implemented projects with links to real-world "}<u>{'case studies'}</u></Typography>
</Fragment>
}
>
<Button
size='medium'
variant='contained'
onClick={downloadPDF}
style={{ margin: '10px', marginLeft: '2rem' }}>
Download Projects PDF
</Button>
</HtmlTooltip>
</Fragment>
)
}


function EndGameReportPDF(props: ReportPDFProps): JSX.Element {
let projectPDFLinks: any[] = [];
props.completedProjects.forEach(project => {
let implementedProject: ProjectControl = Projects[project.page];
projectPDFLinks.push(
<div key={implementedProject.pageId.toString()}>
{implementedProject.caseStudy ?
<div>
<ReactPDF.Text style={styles.textTitle}>{implementedProject.title}
</ReactPDF.Text>
<ReactPDF.Text style={styles.textDesc}>{implementedProject.shortTitleRawText} </ReactPDF.Text>
<ReactPDF.Link style={styles.link} src={implementedProject.caseStudy.url}>Case Study - {truncate(implementedProject.caseStudy.text)}</ReactPDF.Link>
</div>
:
<div>
<ReactPDF.Text style={styles.textTitle}>{implementedProject.title}</ReactPDF.Text>
<ReactPDF.Text style={styles.textDesc}>{implementedProject.shortTitleRawText} </ReactPDF.Text>
<ReactPDF.Text style={styles.textDesc}>No case study available </ReactPDF.Text>
</div>
}
<br />
</div>
)
});


return (
<ReactPDF.Document>
<ReactPDF.Page style={styles.body}>
<ReactPDF.Link style={styles.header} src={'https://cyos.ornl.gov'} fixed>cyos.ornl.gov</ReactPDF.Link>
<ReactPDF.Text style={styles.title}>Choose Your Own Solution</ReactPDF.Text>
<ReactPDF.Text style={styles.subtitle}>Energy Project Case Studies</ReactPDF.Text>
{projectPDFLinks.map(projects => {
return projects;
})}
</ReactPDF.Page>
</ReactPDF.Document>

);
}

const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => (
<Tooltip {...props} classes={{ popper: className }} />
))(({ theme }) => ({
[`& .${tooltipClasses.tooltip}`]: {
backgroundColor: '#f5f5f9',
color: 'rgba(0, 0, 0, 0.87)',
maxWidth: 220,
fontSize: theme.typography.pxToRem(12),
border: '1px solid #dadde9',
},
}));

const styles = ReactPDF.StyleSheet.create({
body: {
paddingTop: 35,
paddingBottom: 65,
paddingHorizontal: 35,
},
title: {
fontSize: 24,
textAlign: 'center',
fontFamily: 'Times-Roman'
},
subtitle: {
fontSize: 12,
textAlign: 'center',
marginBottom: 40,
},
textTitle: {
margin: 12,
marginBottom: 2,
fontSize: 16,
textAlign: 'left',
fontFamily: 'Times-Roman'
},
textDesc: {
margin: 2,
marginBottom: 2,
marginLeft: 24,
fontSize: 12,
textAlign: 'left',
fontFamily: 'Times-Roman'
},
link: {
margin: 2,
marginBottom: 16,
marginLeft: 24,
fontSize: 14,
textAlign: 'left',
fontFamily: 'Times-Roman'
},
header: {
fontSize: 12,
marginBottom: 20,
textAlign: 'center',
color: 'grey',
},
});
Loading

0 comments on commit 3254ead

Please sign in to comment.