@aclymatepackages/modules 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +43 -0
  2. package/babel.config.json +18 -0
  3. package/dist/components/CompaniesAutocomplete.js +126 -0
  4. package/dist/components/CompanyOnboardingInput.js +116 -0
  5. package/dist/components/ComparisonChart.js +200 -0
  6. package/dist/components/CustomTooltipDisplayRow.js +59 -0
  7. package/dist/components/EmissionsChart.js +467 -0
  8. package/dist/components/EmissionsCustomTooltip.js +181 -0
  9. package/dist/components/EmissionsPieChart.js +130 -0
  10. package/dist/components/EmissionsReductionGraph.js +118 -0
  11. package/dist/components/FootprintEquivalencies.js +181 -0
  12. package/dist/components/FootprintVideo.js +262 -0
  13. package/dist/components/FuelTypesSelect.js +36 -0
  14. package/dist/components/IndustryAutocomplete.js +58 -0
  15. package/dist/components/PlacesAutocomplete.js +173 -0
  16. package/dist/components/StripeElements.js +95 -0
  17. package/dist/components/YesNoQuestion.js +88 -0
  18. package/dist/components/stripeInput.js +293 -0
  19. package/dist/components/useChartWarningLabels.js +143 -0
  20. package/dist/index.js +118 -0
  21. package/package.json +74 -0
  22. package/public/favicon.ico +0 -0
  23. package/public/index.html +43 -0
  24. package/public/logo192.png +0 -0
  25. package/public/logo512.png +0 -0
  26. package/public/manifest.json +25 -0
  27. package/public/robots.txt +3 -0
  28. package/src/components/CompaniesAutocomplete.js +125 -0
  29. package/src/components/CompanyOnboardingInput.js +113 -0
  30. package/src/components/ComparisonChart.js +236 -0
  31. package/src/components/CustomTooltipDisplayRow.js +41 -0
  32. package/src/components/EmissionsChart.js +579 -0
  33. package/src/components/EmissionsCustomTooltip.js +146 -0
  34. package/src/components/EmissionsPieChart.js +120 -0
  35. package/src/components/EmissionsReductionGraph.js +107 -0
  36. package/src/components/FootprintEquivalencies.js +203 -0
  37. package/src/components/FootprintVideo.js +328 -0
  38. package/src/components/FuelTypesSelect.js +29 -0
  39. package/src/components/IndustryAutocomplete.js +56 -0
  40. package/src/components/PlacesAutocomplete.js +174 -0
  41. package/src/components/StripeElements.js +95 -0
  42. package/src/components/YesNoQuestion.js +68 -0
  43. package/src/components/stripeInput.js +288 -0
  44. package/src/components/useChartWarningLabels.js +139 -0
  45. package/src/index.js +35 -0
@@ -0,0 +1,120 @@
1
+ import React from "react";
2
+
3
+ import {
4
+ Tooltip as ChartTooltip,
5
+ ResponsiveContainer,
6
+ PieChart,
7
+ Pie,
8
+ Cell,
9
+ } from "recharts";
10
+
11
+ import { Typography, Grid, Avatar } from "@mui/material";
12
+
13
+ import { DefaultPaper } from "@aclymatepackages/atoms";
14
+ import { formatDecimal } from "@aclymatepackages/formatters";
15
+ import { sumTonsCo2e } from "@aclymatepackages/other-helpers";
16
+ import {
17
+ buildSubcategoriesArray,
18
+ buildScopesArray,
19
+ } from "@aclymatepackages/subcategories";
20
+
21
+ const PieChartCustomTooltip = ({ payload: passedPayload }) => {
22
+ const [payloadObj] = passedPayload;
23
+ const { payload = {} } = payloadObj || [{}];
24
+ const { name, emissionPercentage, color, icon, Icon } = payload;
25
+
26
+ return (
27
+ <DefaultPaper>
28
+ <Grid container spacing={2} alignItems="center">
29
+ <Grid item>
30
+ <Avatar style={{ backgroundColor: color, color: "white" }}>
31
+ {icon}
32
+ {Icon && <Icon style={{ color: "inherit" }} />}
33
+ </Avatar>
34
+ </Grid>
35
+ <Grid item>
36
+ <Typography variant="subtitle1" color="textPrimary">
37
+ {name}
38
+ </Typography>
39
+ <Typography variant="caption" color="textSecondary">{`${formatDecimal(
40
+ emissionPercentage
41
+ )}% of total emissions`}</Typography>
42
+ </Grid>
43
+ </Grid>
44
+ </DefaultPaper>
45
+ );
46
+ };
47
+
48
+ const EmissionsPieChart = ({
49
+ dataArray: emissions,
50
+ viewMode = "subcategories",
51
+ pieChartRef,
52
+ }) => {
53
+ const subcategoriesArray = buildSubcategoriesArray(emissions);
54
+ const scopesArray = buildScopesArray();
55
+
56
+ const emissionsSum = sumTonsCo2e(emissions);
57
+
58
+ const formatChartPieSlices = () => {
59
+ const filterFunction = (subcategory) => (emission) => {
60
+ if (viewMode === "subcategories") {
61
+ return emission.subcategory === subcategory;
62
+ }
63
+
64
+ const scopeNumber = Number(subcategory.charAt(subcategory.length - 1));
65
+ return emission.scope === scopeNumber;
66
+ };
67
+
68
+ const slicesArray =
69
+ viewMode === "subcategories" ? subcategoriesArray : scopesArray;
70
+
71
+ const unProjectedSlices = slicesArray.filter(({ subcategory }) => {
72
+ const projectedStringArray = subcategory.split("_");
73
+ return projectedStringArray.length === 1;
74
+ });
75
+
76
+ return unProjectedSlices.map((subcategoryObj) => {
77
+ const { subcategory } = subcategoryObj;
78
+ const emissionsWithThisCategory = emissions.filter(
79
+ filterFunction(subcategory)
80
+ );
81
+
82
+ const categoryEmissionsSum = sumTonsCo2e(emissionsWithThisCategory);
83
+
84
+ return {
85
+ ...subcategoryObj,
86
+ emissionPercentage: (categoryEmissionsSum / emissionsSum) * 100,
87
+ };
88
+ });
89
+ };
90
+
91
+ const pieSlicesWithPercentages = formatChartPieSlices();
92
+
93
+ return (
94
+ <ResponsiveContainer height="100%" aspect={1.5}>
95
+ <PieChart ref={pieChartRef}>
96
+ <Pie
97
+ data={pieSlicesWithPercentages}
98
+ outerRadius={"100%"}
99
+ fill="#8884d8"
100
+ dataKey="emissionPercentage"
101
+ cx="50%"
102
+ cy="50%"
103
+ >
104
+ {pieSlicesWithPercentages.map(({ category, name, color }) => (
105
+ <Cell
106
+ key={`emissions-pie-chart-cell-${category}`}
107
+ name={name}
108
+ fill={color}
109
+ />
110
+ ))}
111
+ </Pie>
112
+ <ChartTooltip
113
+ wrapperStyle={{ zIndex: 99 }}
114
+ content={<PieChartCustomTooltip />}
115
+ />
116
+ </PieChart>
117
+ </ResponsiveContainer>
118
+ );
119
+ };
120
+ export default EmissionsPieChart;
@@ -0,0 +1,107 @@
1
+ import React from "react";
2
+
3
+ import { Box, Typography } from "@mui/material";
4
+ import { useTheme } from "@mui/styles";
5
+ import {
6
+ ResponsiveContainer,
7
+ LineChart,
8
+ Line,
9
+ XAxis,
10
+ YAxis,
11
+ CartesianGrid,
12
+ Tooltip,
13
+ } from "recharts";
14
+
15
+ import { calculateEmissionsDecayRate } from "@aclymatepackages/other-helpers";
16
+
17
+ const CustomTooltip = ({ active, payload, label }) => {
18
+ if (active && payload && payload.length) {
19
+ const { remainingAmount } = payload[0].payload;
20
+ return (
21
+ <Box
22
+ style={{
23
+ background: "#fff",
24
+ border: "1px solid #ccc",
25
+ padding: "10px",
26
+ borderRadius: "5px",
27
+ boxShadow: "0 2px 5px rgba(0, 0, 0, 0.3)",
28
+ fontSize: "14px",
29
+ }}
30
+ >
31
+ <Typography
32
+ variant="body2"
33
+ style={{ marginBottom: "5px", fontWeight: "bold" }}
34
+ >
35
+ Year: {label}
36
+ </Typography>
37
+ <Typography variant="body2" style={{ marginBottom: "5px" }}>
38
+ Remaining Amount: {remainingAmount.toFixed(2)}
39
+ </Typography>
40
+ </Box>
41
+ );
42
+ }
43
+ return null;
44
+ };
45
+
46
+ const EmissionsReductionGraph = ({
47
+ initialEmissionAmount = 100,
48
+ desiredReductionPercentage = 0.5,
49
+ targetYear = 2030,
50
+ startYear = new Date().getFullYear(),
51
+ lineColor = null,
52
+ width = "100%",
53
+ height = 450,
54
+ carbonUnit = "lbs",
55
+ }) => {
56
+ const { palette } = useTheme();
57
+
58
+ const totalYears = targetYear - startYear;
59
+
60
+ const buildDecayLineArray = () => {
61
+ const decayRate = calculateEmissionsDecayRate(
62
+ desiredReductionPercentage,
63
+ totalYears
64
+ );
65
+
66
+ return [...new Array(totalYears + 1)].map((_, idx) => ({
67
+ year: startYear + idx,
68
+ remainingAmount: initialEmissionAmount * Math.exp(decayRate * idx),
69
+ decayRate,
70
+ }));
71
+ };
72
+
73
+ return (
74
+ <ResponsiveContainer width={width} height={height}>
75
+ <LineChart
76
+ data={buildDecayLineArray()}
77
+ margin={{ top: 20, right: 30, left: 10, bottom: 10 }}
78
+ >
79
+ <CartesianGrid strokeDasharray="3 3" stroke="#bbb" />
80
+ <XAxis
81
+ dataKey="year"
82
+ stroke="#333"
83
+ tick={{ fill: "#333", fontSize: 12 }}
84
+ />
85
+ <YAxis
86
+ tickFormatter={(value) => `${value} ${carbonUnit}`}
87
+ stroke="#333"
88
+ tick={{ fill: "#333", fontSize: 12 }}
89
+ />
90
+ <Tooltip content={<CustomTooltip />} />
91
+ <Line
92
+ type="monotone"
93
+ dataKey="remainingAmount"
94
+ stroke={lineColor || palette.error.main}
95
+ strokeWidth={2}
96
+ dot={{
97
+ stroke: lineColor || palette.error.main,
98
+ strokeWidth: 2,
99
+ r: 6,
100
+ }}
101
+ activeDot={{ r: 8 }}
102
+ />
103
+ </LineChart>
104
+ </ResponsiveContainer>
105
+ );
106
+ };
107
+ export default EmissionsReductionGraph;
@@ -0,0 +1,203 @@
1
+ import React, { useState } from "react";
2
+
3
+ import { Box, Grid, ButtonBase, Typography, Paper } from "@mui/material";
4
+ import { ThemeProvider } from "@mui/material/styles";
5
+
6
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
7
+ import {
8
+ faSteeringWheel,
9
+ faTrees,
10
+ faIcicles,
11
+ faHamburger,
12
+ faPiggyBank,
13
+ faMobile,
14
+ } from "@fortawesome/pro-solid-svg-icons";
15
+
16
+ import {
17
+ kgsToTons,
18
+ hexToRgba,
19
+ tonsToLbs,
20
+ convertFootprintToDriving,
21
+ convertFootprintToIce,
22
+ footprintToHamburgers,
23
+ } from "@aclymatepackages/converters";
24
+ import { formatDecimal } from "@aclymatepackages/formatters";
25
+ import { useLayoutHelpers, mergeDarkTheme } from "@aclymatepackages/themes";
26
+
27
+ //source: Google Drive: Aclymate Team\Climate Accounting\Data\Tree Carbon Calculator\CarbonCalculator31.xls
28
+ const convertFootprintToTreeYears = (footprintTons) => {
29
+ const treeYearsDecimal = footprintTons / kgsToTons(160.6);
30
+ return formatDecimal(treeYearsDecimal.toFixed(1));
31
+ };
32
+
33
+ //source: https://shrinkthatfootprint.com/carbon-targets-for-your-footprint/
34
+ const footprintToCarbonBudgetPercent = (footprintTons) =>
35
+ `${formatDecimal((footprintTons / 4.1) * 100)}%`;
36
+
37
+ //SOURCE: https://news.energysage.com/how-many-watts-does-a-phone-charger-use/
38
+ //US average carbon intensity comes from carbon intensity data in app backend
39
+ const footprintToCellphoneYears = (footprintTons) => {
40
+ const US_AVG_TONS_CO2E_PER_KWH = 0.00043222913699413057;
41
+ const CELLPHONE_KWH_PER_YEAR = 1.83;
42
+ const footprintYears =
43
+ footprintTons / US_AVG_TONS_CO2E_PER_KWH / CELLPHONE_KWH_PER_YEAR;
44
+
45
+ return formatDecimal(footprintYears.toFixed(1));
46
+ };
47
+
48
+ const FootprintEquivalencies = ({
49
+ footprintTons,
50
+ exclusionCategories = [],
51
+ }) => {
52
+ const { theme, isMobile, isMedium } = useLayoutHelpers();
53
+
54
+ const [selectedCategoryIdx, setSelectedCategoryIdx] = useState(0);
55
+
56
+ const footprintEquivalentsCategories = [
57
+ {
58
+ type: "driving-emissions",
59
+ icon: faSteeringWheel,
60
+ buildString: (carbon, equivalency) =>
61
+ `Your ${carbon} lbs. of carbon is like driving a car ${equivalency} miles.`,
62
+ equivalency: convertFootprintToDriving(footprintTons),
63
+ color: "vehicles",
64
+ backgroundOpacity: 0.5,
65
+ },
66
+ {
67
+ type: "tree-sequestration",
68
+ icon: faTrees,
69
+ buildString: (carbon, equivalency) =>
70
+ `It would take an average oak tree ${equivalency} years to absorb your ${carbon} lbs. of carbon`,
71
+ equivalency: convertFootprintToTreeYears(footprintTons),
72
+ color: "secondary",
73
+ backgroundOpacity: 0.3,
74
+ },
75
+ {
76
+ type: "melting-polar-bear",
77
+ icon: faIcicles,
78
+ buildString: (carbon, equivalency) =>
79
+ `Your ${carbon} lbs. of carbon is enough to permanently melt ${equivalency} square ${
80
+ equivalency === "1" ? "foot" : "feet"
81
+ } of Arctic sea ice`,
82
+ equivalency: formatDecimal(convertFootprintToIce(footprintTons)),
83
+ color: "travel",
84
+ backgroundOpacity: 0.3,
85
+ },
86
+ {
87
+ type: "eating-hamburgers",
88
+ icon: faHamburger,
89
+ buildString: (carbon, equivalency) =>
90
+ `Your ${carbon} lbs. of carbon is equivalent to the emissions of eating ${equivalency} hamburgers`,
91
+ equivalency: formatDecimal(footprintToHamburgers(footprintTons)),
92
+ color: "mileage",
93
+ backgroundOpacity: 0.4,
94
+ },
95
+ {
96
+ type: "carbon-budget",
97
+ icon: faPiggyBank,
98
+ buildString: (carbon, equivalency) =>
99
+ `Your ${carbon} lbs. of carbon is ${equivalency} of the annual carbon budget that we all need to achieve to reach our global climate goals.`,
100
+ equivalency: footprintToCarbonBudgetPercent(footprintTons),
101
+ color: "offices",
102
+ backgroundOpacity: 0.5,
103
+ },
104
+ {
105
+ type: "cell-phone-charging",
106
+ icon: faMobile,
107
+ buildString: (carbon, equivalency) =>
108
+ `Your ${carbon} lbs. of carbon is enough to keep your cellphone charged for ${equivalency} years`,
109
+ equivalency: footprintToCellphoneYears(footprintTons),
110
+ color: "rides",
111
+ backgroundOpacity: 0.5,
112
+ },
113
+ ];
114
+
115
+ const filteredEquivalentCategories = footprintEquivalentsCategories.filter(
116
+ ({ type }) => !exclusionCategories.includes(type)
117
+ );
118
+
119
+ const { type, color, buildString, equivalency } =
120
+ filteredEquivalentCategories[selectedCategoryIdx];
121
+
122
+ return (
123
+ <Grid container spacing={2} alignItems="stretch" justifyContent="center">
124
+ <Grid item lg={2} xs={12}>
125
+ <Grid
126
+ container
127
+ direction={isMedium ? "row" : "column"}
128
+ spacing={2}
129
+ justifyContent={isMedium ? "space-around" : "center"}
130
+ wrap="nowrap"
131
+ >
132
+ {filteredEquivalentCategories.map(({ icon, color }, idx) => (
133
+ <Grid item key={`grid-equivalency-carousel-icon-${idx}`}>
134
+ <ButtonBase onClick={() => setSelectedCategoryIdx(idx)}>
135
+ <Box
136
+ style={{
137
+ height: "50px",
138
+ width: "50px",
139
+ backgroundColor:
140
+ idx === selectedCategoryIdx
141
+ ? theme.palette[color].main
142
+ : "white",
143
+ borderRadius: "50%",
144
+ }}
145
+ display="flex"
146
+ alignItems="center"
147
+ justifyContent="center"
148
+ >
149
+ <FontAwesomeIcon
150
+ icon={icon}
151
+ size="2x"
152
+ style={{
153
+ color:
154
+ idx === selectedCategoryIdx
155
+ ? "white"
156
+ : theme.palette[color].main,
157
+ }}
158
+ />
159
+ </Box>
160
+ </ButtonBase>
161
+ </Grid>
162
+ ))}
163
+ </Grid>
164
+ </Grid>
165
+ <Grid item lg={6} xs={12}>
166
+ <Box display="flex" justifyContent="center">
167
+ <Box position="relative">
168
+ <img
169
+ alt={`${type}-image`}
170
+ src={`https://dashboard.aclymate.com/images/footprint-equivalencies/${type}.svg`}
171
+ style={{ width: "100%" }}
172
+ />
173
+ <Paper
174
+ style={{
175
+ backgroundColor: hexToRgba(theme.palette[color].main, 0.85),
176
+ position: "absolute",
177
+ bottom: 0,
178
+ left: 0,
179
+ right: 0,
180
+ }}
181
+ >
182
+ <Box p={isMobile ? 0.25 : 1}>
183
+ <ThemeProvider theme={mergeDarkTheme}>
184
+ <Typography
185
+ variant={isMobile ? "subtitle2" : "subtitle1"}
186
+ align="center"
187
+ color="textPrimary"
188
+ >
189
+ {buildString(
190
+ formatDecimal(tonsToLbs(footprintTons)),
191
+ equivalency
192
+ )}
193
+ </Typography>
194
+ </ThemeProvider>
195
+ </Box>
196
+ </Paper>
197
+ </Box>
198
+ </Box>
199
+ </Grid>
200
+ </Grid>
201
+ );
202
+ };
203
+ export default FootprintEquivalencies;