diff --git a/app/components/EmissionListItem/EmissionListItem.tsx b/app/components/EmissionListItem/EmissionListItem.tsx index c9b175e6..df653f2b 100644 --- a/app/components/EmissionListItem/EmissionListItem.tsx +++ b/app/components/EmissionListItem/EmissionListItem.tsx @@ -1,9 +1,12 @@ import React from "react"; import { View, TouchableOpacity } from "react-native"; +import { useSelector } from "react-redux"; import { Ionicons } from "@expo/vector-icons"; import { FormattedNumber } from "react-native-globalize"; import { Colors } from "style"; +import { userPreferences } from "ducks"; +import { calculation } from "utils"; import { RecurringEmission, Emission, EmissionType } from "interfaces"; import Text from "../Text"; @@ -30,38 +33,49 @@ const EmissionListItem: React.FC = ({ title = "", co2value = 0, onPress, -}) => ( - - - +}) => { + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + + const displayValue: number = getDisplayUnitsValue(co2value, useMetricUnits); + + return ( + + + + + + + {name.length ? name : title} + + + = 1 ? 2 : 4} + value={displayValue} + /> + {" " + getDisplayUnits(co2value, useMetricUnits)}CO2eq + + {isMitigated && ( + <> + {" • "} + {"Offset"} + + )} + + - - - {name.length ? name : title} - - - = 1 ? 2 : 4} value={co2value} /> kgCO2 - - {isMitigated && ( - <> - {" • "} - {"Offset"} - - )} - - - - -); - + + ); +}; export { EmissionListItem, EmissionListItemProps }; diff --git a/app/components/EmissionListItem/__tests__/EmissionListItem.test.tsx b/app/components/EmissionListItem/__tests__/EmissionListItem.test.tsx index 40317ae1..981f55c6 100644 --- a/app/components/EmissionListItem/__tests__/EmissionListItem.test.tsx +++ b/app/components/EmissionListItem/__tests__/EmissionListItem.test.tsx @@ -1,6 +1,7 @@ import React from "react"; import { create } from "react-test-renderer"; import { GlobalizeProvider } from "react-native-globalize"; +import * as reactRedux from "react-redux"; import { FoodType, TransportType, @@ -11,6 +12,7 @@ import { MealType, } from "carbon-footprint"; +import { userPreferences } from "ducks"; import { ui } from "utils"; import { EmissionModelType } from "interfaces"; @@ -29,6 +31,12 @@ const props = { }, }; +const useSelectorMock = jest.spyOn(reactRedux, "useSelector"); + +beforeEach(() => { + useSelectorMock.mockImplementation(userPreferences.selectors.getUseMetricUnits); +}); + it("EmissionListItem renders correctly if mitigated", () => { const tree = create( diff --git a/app/components/EmissionListItem/__tests__/__snapshots__/EmissionListItem.test.tsx.snap b/app/components/EmissionListItem/__tests__/__snapshots__/EmissionListItem.test.tsx.snap index ebcd5345..4ab4453e 100644 --- a/app/components/EmissionListItem/__tests__/__snapshots__/EmissionListItem.test.tsx.snap +++ b/app/components/EmissionListItem/__tests__/__snapshots__/EmissionListItem.test.tsx.snap @@ -78,7 +78,8 @@ exports[`EmissionListItem renders correctly if mitigated 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq - kgCO2 + kg + CO2eq @@ -280,7 +282,8 @@ exports[`EmissionListItem renders correctly with boat icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -376,7 +379,8 @@ exports[`EmissionListItem renders correctly with bus icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -472,7 +476,8 @@ exports[`EmissionListItem renders correctly with car icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -568,7 +573,8 @@ exports[`EmissionListItem renders correctly with card icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -664,7 +670,8 @@ exports[`EmissionListItem renders correctly with chocolate icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -760,7 +767,8 @@ exports[`EmissionListItem renders correctly with coffee icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -856,7 +864,8 @@ exports[`EmissionListItem renders correctly with electricity icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -952,7 +961,8 @@ exports[`EmissionListItem renders correctly with fish icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -1048,7 +1058,8 @@ exports[`EmissionListItem renders correctly with full hd video icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -1144,7 +1155,8 @@ exports[`EmissionListItem renders correctly with hd video icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -1240,7 +1252,8 @@ exports[`EmissionListItem renders correctly with longHaulFlight icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -1336,7 +1349,8 @@ exports[`EmissionListItem renders correctly with meal icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -1432,7 +1446,8 @@ exports[`EmissionListItem renders correctly with mediumHaulFlight icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -1528,7 +1543,8 @@ exports[`EmissionListItem renders correctly with motorbike icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -1624,7 +1640,8 @@ exports[`EmissionListItem renders correctly with redMeat icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -1720,7 +1737,8 @@ exports[`EmissionListItem renders correctly with shirt icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -1816,7 +1834,8 @@ exports[`EmissionListItem renders correctly with shortHaulFlight icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -1912,7 +1931,8 @@ exports[`EmissionListItem renders correctly with train icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -2008,7 +2028,8 @@ exports[`EmissionListItem renders correctly with ultra hd video icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq @@ -2104,7 +2125,8 @@ exports[`EmissionListItem renders correctly with whiteMeat icon 1`] = ` maximumFractionDigits={2} value={2.1} /> - kgCO2 + kg + CO2eq diff --git a/app/components/ListItemSwitch/ListItemSwitch.styles.ts b/app/components/ListItemSwitch/ListItemSwitch.styles.ts new file mode 100644 index 00000000..b412184b --- /dev/null +++ b/app/components/ListItemSwitch/ListItemSwitch.styles.ts @@ -0,0 +1,23 @@ +import { StyleSheet } from "react-native"; + +import { Colors } from "style"; + +export default StyleSheet.create({ + container: { + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + flex: 1, + }, + text: { + paddingVertical: 18, + }, + topLine: { + borderTopColor: Colors.grey10, + borderTopWidth: 1.6, + }, + bottomLine: { + borderBottomColor: Colors.grey10, + borderBottomWidth: 1.6, + }, +}); diff --git a/app/components/ListItemSwitch/ListItemSwitch.tsx b/app/components/ListItemSwitch/ListItemSwitch.tsx new file mode 100644 index 00000000..d32c8e6c --- /dev/null +++ b/app/components/ListItemSwitch/ListItemSwitch.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import { View, ViewStyle, StyleProp } from "react-native"; +import { Switch } from "react-native-gesture-handler"; + +import styles from "./ListItemSwitch.styles"; +import Text from "../Text"; + +interface Props { + title: string; + value: boolean; + onChange: () => void; + showTopLine?: boolean; + showBottomLine?: boolean; +} + +const ListItemSwitch: React.FC = ({ + title, + value, + onChange, + showTopLine, + showBottomLine, +}) => { + const containerStyle: StyleProp = [styles.container]; + if (showTopLine) { + containerStyle.push(styles.topLine); + } + + if (showBottomLine) { + containerStyle.push(styles.bottomLine); + } + + return ( + + {title} + + + ); +}; + +export default ListItemSwitch; diff --git a/app/components/ListItemSwitch/__tests__/ListItemSwitch.test.tsx b/app/components/ListItemSwitch/__tests__/ListItemSwitch.test.tsx new file mode 100644 index 00000000..48be2ab1 --- /dev/null +++ b/app/components/ListItemSwitch/__tests__/ListItemSwitch.test.tsx @@ -0,0 +1,35 @@ +import "react-native"; +import React from "react"; +import { create } from "react-test-renderer"; + +import ListItemSwitch from "../ListItemSwitch"; + +describe("", () => { + const props = { + title: "Germany", + value: true, + onChange: () => { + // do nothing. + }, + }; + const wrapper = create(); + + test("render", () => { + expect(wrapper).toMatchSnapshot(); + }); + + test("ListItem renders correctly with topLine", () => { + const tree = create().toJSON(); + expect(tree).toMatchSnapshot(); + }); + + test("ListItem renders correctly with bottomLine", () => { + const tree = create().toJSON(); + expect(tree).toMatchSnapshot(); + }); + + test("ListItem renders correctly with both topLine and bottomLine", () => { + const tree = create().toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/app/components/ListItemSwitch/__tests__/__snapshots__/ListItemSwitch.test.tsx.snap b/app/components/ListItemSwitch/__tests__/__snapshots__/ListItemSwitch.test.tsx.snap new file mode 100644 index 00000000..c1e44e56 --- /dev/null +++ b/app/components/ListItemSwitch/__tests__/__snapshots__/ListItemSwitch.test.tsx.snap @@ -0,0 +1,189 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` ListItem renders correctly with both topLine and bottomLine 1`] = ` + + + Germany + + + +`; + +exports[` ListItem renders correctly with bottomLine 1`] = ` + + + Germany + + + +`; + +exports[` ListItem renders correctly with topLine 1`] = ` + + + Germany + + + +`; + +exports[` render 1`] = ` + + + Germany + + + +`; diff --git a/app/components/ListItemSwitch/index.ts b/app/components/ListItemSwitch/index.ts new file mode 100644 index 00000000..a30aad38 --- /dev/null +++ b/app/components/ListItemSwitch/index.ts @@ -0,0 +1 @@ +export { default } from "./ListItemSwitch"; diff --git a/app/components/ListItemSwitch/stories/ListItemSwitch.story.tsx b/app/components/ListItemSwitch/stories/ListItemSwitch.story.tsx new file mode 100644 index 00000000..37e229c6 --- /dev/null +++ b/app/components/ListItemSwitch/stories/ListItemSwitch.story.tsx @@ -0,0 +1,15 @@ +// import React from "react"; +// import { storiesOf } from "@storybook/react-native"; +// import { text } from "@storybook/addon-knobs"; + +// import ListItemSwitch from ".."; + +// storiesOf("ListItemSwitch", module).add("switch list item", () => ( +// { +// // do nothing. +// }} +// /> +// )); diff --git a/app/components/index.ts b/app/components/index.ts index 5009974d..8c3f8625 100644 --- a/app/components/index.ts +++ b/app/components/index.ts @@ -7,6 +7,7 @@ import TextInput from "./TextInput"; import StickersImage from "./StickersImage"; import SelectableListItem from "./SelectableListItem"; import ListItem from "./ListItem"; +import ListItemSwitch from "./ListItemSwitch" import HTMLImage from "./HTMLImage"; import InfoButton from "./InfoButton"; import NoEmission from "./NoEmission"; @@ -21,6 +22,7 @@ export { EmissionListItemProps, HTMLImage, ListItem, + ListItemSwitch, SelectableListItem, StickersImage, SocialMedia, diff --git a/app/ducks/userPreferences/__tests__/__snapshots__/userPreferences.actions.test.ts.snap b/app/ducks/userPreferences/__tests__/__snapshots__/userPreferences.actions.test.ts.snap index bacf47c0..2cb64b99 100644 --- a/app/ducks/userPreferences/__tests__/__snapshots__/userPreferences.actions.test.ts.snap +++ b/app/ducks/userPreferences/__tests__/__snapshots__/userPreferences.actions.test.ts.snap @@ -6,6 +6,7 @@ Object { "changeLanguage": [Function], "incrementTimesStarted": [Function], "toggleNotifications": [Function], + "toggleUnits": [Function], "updateLocation": [Function], } `; diff --git a/app/ducks/userPreferences/__tests__/userPreferences.actions.test.ts b/app/ducks/userPreferences/__tests__/userPreferences.actions.test.ts index beab68ac..734e464b 100644 --- a/app/ducks/userPreferences/__tests__/userPreferences.actions.test.ts +++ b/app/ducks/userPreferences/__tests__/userPreferences.actions.test.ts @@ -39,4 +39,12 @@ describe("userPreferences actions should", () => { }; expect(userPreferences.actions.incrementTimesStarted()).toEqual(expectedAction); }); + + it("be able to toggle units", () => { + const expectedAction = { + type: userPreferences.actions.toggleUnits.toString(), + payload: false, + }; + expect(userPreferences.actions.toggleUnits(false)).toEqual(expectedAction); + }) }); diff --git a/app/ducks/userPreferences/__tests__/userPreferences.reducer.test.ts b/app/ducks/userPreferences/__tests__/userPreferences.reducer.test.ts index f7dc85ce..43b2b157 100644 --- a/app/ducks/userPreferences/__tests__/userPreferences.reducer.test.ts +++ b/app/ducks/userPreferences/__tests__/userPreferences.reducer.test.ts @@ -14,6 +14,7 @@ describe("userPreferences reducer should", () => { location: ElectricityType.world, language: currentLanguage, timesStarted: 0, + useMetricUnits: true, }); }); @@ -31,6 +32,7 @@ describe("userPreferences reducer should", () => { location: ElectricityType.world, language: currentLanguage, timesStarted: 0, + useMetricUnits: true, }); }); @@ -46,6 +48,7 @@ describe("userPreferences reducer should", () => { location: ElectricityType.belgium, language: currentLanguage, timesStarted: 0, + useMetricUnits: true, }); }); @@ -61,6 +64,7 @@ describe("userPreferences reducer should", () => { location: ElectricityType.world, language: currentLanguage, timesStarted: 0, + useMetricUnits: true, }); }); @@ -76,6 +80,7 @@ describe("userPreferences reducer should", () => { location: ElectricityType.world, language: "fr", timesStarted: 0, + useMetricUnits: true, }); }); @@ -90,6 +95,23 @@ describe("userPreferences reducer should", () => { location: ElectricityType.world, language: currentLanguage, timesStarted: 1, + useMetricUnits: true, }); }); + + it("handle units change", () => { + const expectedAction = { + type: userPreferences.actions.toggleUnits.toString(), + payload: false + }; + + expect(userPreferences.reducer(undefined, expectedAction)).toEqual({ + acceptedTermsOfUseVersion: 0, + activatedNotifications: false, + location: ElectricityType.world, + language: currentLanguage, + timesStarted: 0, + useMetricUnits: false, + }); + }) }); diff --git a/app/ducks/userPreferences/__tests__/userPreferences.selectors.test.ts b/app/ducks/userPreferences/__tests__/userPreferences.selectors.test.ts index 9292c3ea..833eacd0 100644 --- a/app/ducks/userPreferences/__tests__/userPreferences.selectors.test.ts +++ b/app/ducks/userPreferences/__tests__/userPreferences.selectors.test.ts @@ -12,6 +12,7 @@ const initialState = { location: ElectricityType.world, language: supportedLanguages.en, timesStarted: 4, + useMetricUnits: true, }; describe("userPreferences selector should", () => { @@ -39,4 +40,9 @@ describe("userPreferences selector should", () => { test("return current timesStarted", () => expect(userPreferences.selectors.getTimesStarted(state)).toEqual(initialState.timesStarted)); + + test("return current units", () => + expect(userPreferences.selectors.getUseMetricUnits(state)).toEqual( + initialState.useMetricUnits + )); }); diff --git a/app/ducks/userPreferences/userPreferences.selectors.ts b/app/ducks/userPreferences/userPreferences.selectors.ts index e0aee2e7..50521bfc 100644 --- a/app/ducks/userPreferences/userPreferences.selectors.ts +++ b/app/ducks/userPreferences/userPreferences.selectors.ts @@ -18,10 +18,13 @@ const getLanguage = (state) => pathOr(currentLanguage, [namespace, "language"], const getTimesStarted = (state) => pathOr(0, [namespace, "timesStarted"], state); +const getUseMetricUnits = (state) => pathOr(true, [namespace, "useMetricUnits"], state); + export default { getAcceptedTermsOfUseVersion, getActivateNotifications, getLocation, getLanguage, getTimesStarted, + getUseMetricUnits, }; diff --git a/app/ducks/userPreferences/userPreferences.slice.ts b/app/ducks/userPreferences/userPreferences.slice.ts index db07bab3..59c1d3ff 100644 --- a/app/ducks/userPreferences/userPreferences.slice.ts +++ b/app/ducks/userPreferences/userPreferences.slice.ts @@ -9,6 +9,7 @@ const initialState = { location: ElectricityType.world, language: currentLanguage, timesStarted: 0, + useMetricUnits: true, }; const userPreferences = createSlice({ @@ -30,6 +31,9 @@ const userPreferences = createSlice({ incrementTimesStarted(state) { state.timesStarted += 1; }, + toggleUnits(state, action: PayloadAction) { + state.useMetricUnits = action.payload; + }, }, }); @@ -39,6 +43,7 @@ const { toggleNotifications, changeLanguage, incrementTimesStarted, + toggleUnits, } = userPreferences.actions; export const actions = { @@ -47,6 +52,7 @@ export const actions = { toggleNotifications, changeLanguage, incrementTimesStarted, + toggleUnits, }; export const namespace = userPreferences.name; diff --git a/app/screens/AddEmission/components/Custom/Custom.tsx b/app/screens/AddEmission/components/Custom/Custom.tsx index ac96b94e..2713f884 100644 --- a/app/screens/AddEmission/components/Custom/Custom.tsx +++ b/app/screens/AddEmission/components/Custom/Custom.tsx @@ -1,9 +1,11 @@ import React, { useState } from "react"; +import { useSelector } from "react-redux"; import { View } from "react-native"; import Slider from "@react-native-community/slider"; import { Text } from "components"; -import { t } from "utils"; +import { userPreferences } from "ducks"; +import { t, calculation } from "utils"; import { Colors } from "style"; import styles from "./Custom.styles"; @@ -18,7 +20,15 @@ interface Props { const Custom: React.FC = ({ setCo2eqKilograms, defaultValueSlider }) => { const [sliderValue, setSliderValue] = useState(defaultValueSlider); - setCo2eqKilograms(sliderValue); + + const onSliderValueChange = (value: number) => { + setSliderValue(value); + setCo2eqKilograms(value); + }; + + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; return ( <> @@ -26,8 +36,10 @@ const Custom: React.FC = ({ setCo2eqKilograms, defaultValueSlider }) => { {t("ADD_EMISSION_SCREEN_QUANTITY_OF_EMISSION")} - {Math.round(sliderValue)} - {" kgCO2eq"} + {Math.round(getDisplayUnitsValue(sliderValue, useMetricUnits))} + + {" " + getDisplayUnits(sliderValue, useMetricUnits) + "CO2eq"} + @@ -39,7 +51,7 @@ const Custom: React.FC = ({ setCo2eqKilograms, defaultValueSlider }) => { maximumValue={MAX_SLIDER_VALUE} minimumValue={MIN_SLIDER_VALUE} value={sliderValue} - onSlidingComplete={setSliderValue} + onSlidingComplete={onSliderValueChange} /> ); diff --git a/app/screens/AddEmission/components/Electricity/Electricity.tsx b/app/screens/AddEmission/components/Electricity/Electricity.tsx index 4b9b8ab5..1f52b68a 100644 --- a/app/screens/AddEmission/components/Electricity/Electricity.tsx +++ b/app/screens/AddEmission/components/Electricity/Electricity.tsx @@ -1,12 +1,14 @@ import React, { useState } from "react"; import { toUpper } from "ramda"; +import { useSelector } from "react-redux"; import { View } from "react-native"; import Slider from "@react-native-community/slider"; import { FormattedNumber } from "react-native-globalize"; import { electricity, ElectricityType } from "carbon-footprint"; import { Text } from "components"; -import { t } from "utils"; +import { userPreferences } from "ducks"; +import { t, calculation } from "utils"; import { Colors } from "style"; import styles from "./Electricity.styles"; @@ -26,7 +28,16 @@ const Electricity: React.FC = ({ defaultValueSlider, }) => { const [sliderValue, setSliderValue] = useState(defaultValueSlider); - setElectricityConsumption(sliderValue); + + const onSliderValueChange = (value: number) => { + const val = Math.round(value); + setSliderValue(val); + setElectricityConsumption(val); + }; + + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; return ( <> @@ -50,16 +61,22 @@ const Electricity: React.FC = ({ maximumValue={MAX_SLIDER_VALUE} minimumValue={MIN_SLIDER_VALUE} value={sliderValue} - onSlidingComplete={setSliderValue} + onSlidingComplete={onSliderValueChange} /> {t("ADD_EMISSION_SCREEN_TOTAL")} {" "} - kgCO2eq + + {getDisplayUnits(sliderValue * electricity[electricityCountry], useMetricUnits) + + "CO2eq"} + diff --git a/app/screens/AddEmission/components/Fashion/Fashion.tsx b/app/screens/AddEmission/components/Fashion/Fashion.tsx index 3572307e..d826dad6 100644 --- a/app/screens/AddEmission/components/Fashion/Fashion.tsx +++ b/app/screens/AddEmission/components/Fashion/Fashion.tsx @@ -1,11 +1,13 @@ import React, { useState } from "react"; +import { useSelector } from "react-redux"; import { View } from "react-native"; import Slider from "@react-native-community/slider"; import { FormattedNumber } from "react-native-globalize"; import { fashion } from "carbon-footprint"; import { Text } from "components"; -import { t } from "utils"; +import { userPreferences } from "ducks"; +import { t, calculation } from "utils"; import { Colors } from "style"; import styles from "./Fashion.styles"; @@ -28,6 +30,10 @@ const Fashion: React.FC = ({ emissionModelType, setQuantity, defaultValue setQuantity(val); }; + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + return ( <> @@ -48,10 +54,12 @@ const Fashion: React.FC = ({ emissionModelType, setQuantity, defaultValue {t("ADD_EMISSION_SCREEN_TOTAL")} {" "} - kgCO2eq + + {getDisplayUnits(sliderValue * fashion[emissionModelType], useMetricUnits) + "CO2eq"} + diff --git a/app/screens/AddEmission/components/Food/Food.tsx b/app/screens/AddEmission/components/Food/Food.tsx index 6af5a2f3..a0ea4cd9 100644 --- a/app/screens/AddEmission/components/Food/Food.tsx +++ b/app/screens/AddEmission/components/Food/Food.tsx @@ -1,11 +1,13 @@ import React, { useState } from "react"; +import { useSelector } from "react-redux"; import { View } from "react-native"; import Slider from "@react-native-community/slider"; import { FormattedNumber } from "react-native-globalize"; import { food } from "carbon-footprint"; import { Text } from "components"; -import { t } from "utils"; +import { userPreferences } from "ducks"; +import { t, calculation } from "utils"; import { Colors } from "style"; import styles from "./Food.styles"; @@ -29,11 +31,21 @@ const Food: React.FC = ({ emissionModelType, setQuantity, defaultValueSli setQuantity(val / 1000); }; + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + return ( <> {t("ADD_EMISSION_SCREEN_QUANTITY")} - {Math.round(sliderValue) + " grams"} + + {(useMetricUnits + ? getDisplayUnitsValue(sliderValue / 1000, useMetricUnits) + : getDisplayUnitsValue(sliderValue / 1000, useMetricUnits).toFixed(1)) + + " " + + getDisplayUnits(sliderValue / 1000, useMetricUnits)} + = ({ emissionModelType, setQuantity, defaultValueSli {t("ADD_EMISSION_SCREEN_TOTAL")} {" "} - kgCO2eq + + {getDisplayUnits((sliderValue / 1000) * food[emissionModelType], useMetricUnits) + + "CO2eq"} + diff --git a/app/screens/AddEmission/components/Meal/Meal.tsx b/app/screens/AddEmission/components/Meal/Meal.tsx index 801a3084..9bf33600 100644 --- a/app/screens/AddEmission/components/Meal/Meal.tsx +++ b/app/screens/AddEmission/components/Meal/Meal.tsx @@ -1,11 +1,13 @@ import React, { useState } from "react"; +import { useSelector } from "react-redux"; import { View } from "react-native"; import Slider from "@react-native-community/slider"; import { FormattedNumber } from "react-native-globalize"; import { meal } from "carbon-footprint"; import { Text } from "components"; -import { t } from "utils"; +import { userPreferences } from "ducks"; +import { t, calculation } from "utils"; import { Colors } from "style"; import styles from "./Meal.styles"; @@ -28,6 +30,10 @@ const Meal: React.FC = ({ emissionModelType, setQuantity, defaultValueSli setQuantity(val); }; + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + return ( <> @@ -48,10 +54,12 @@ const Meal: React.FC = ({ emissionModelType, setQuantity, defaultValueSli {t("ADD_EMISSION_SCREEN_TOTAL")} {" "} - kgCO2eq + + {getDisplayUnits(sliderValue * meal[emissionModelType], useMetricUnits) + "CO2eq"} + diff --git a/app/screens/AddEmission/components/ProductScanned/ProductScanned.tsx b/app/screens/AddEmission/components/ProductScanned/ProductScanned.tsx index 356246cc..272c2a16 100644 --- a/app/screens/AddEmission/components/ProductScanned/ProductScanned.tsx +++ b/app/screens/AddEmission/components/ProductScanned/ProductScanned.tsx @@ -1,9 +1,12 @@ import React, { useState } from "react"; +import { useSelector } from "react-redux"; import { View } from "react-native"; import Slider from "@react-native-community/slider"; +import { FormattedNumber } from "react-native-globalize"; import { Text } from "components"; -import { t } from "utils"; +import { userPreferences } from "ducks"; +import { t, calculation } from "utils"; import { Colors } from "style"; import styles from "./ProductScanned.styles"; @@ -18,12 +21,20 @@ interface Props { const ProductScanned: React.FC = ({ setCo2eqKilograms, productCarbonFootprint }) => { const [sliderValue, setSliderValue] = useState(1.4); + const emissionAmount = productCarbonFootprint < 1 ? Math.round(Math.round(sliderValue) * productCarbonFootprint * 1000) / 1000 : Math.round(Math.round(sliderValue) * productCarbonFootprint * 10) / 10; - setCo2eqKilograms(emissionAmount); + const onSliderValueChange = (value: number) => { + setSliderValue(value); + setCo2eqKilograms(emissionAmount); + }; + + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; if (!productCarbonFootprint) { return; @@ -38,10 +49,12 @@ const ProductScanned: React.FC = ({ setCo2eqKilograms, productCarbonFootp {Math.round(sliderValue) + " "} {t("ADD_EMISSION_SCREEN_ITEMS") + " - "} - - {emissionAmount} - {" kgCO2eq"} + {" "} + {getDisplayUnits(emissionAmount, useMetricUnits) + "CO2eq"} @@ -53,7 +66,7 @@ const ProductScanned: React.FC = ({ setCo2eqKilograms, productCarbonFootp maximumValue={MAX_SLIDER_VALUE} minimumValue={MIN_SLIDER_VALUE} value={sliderValue} - onSlidingComplete={setSliderValue} + onSlidingComplete={onSliderValueChange} /> ); diff --git a/app/screens/AddEmission/components/Purchase/Purchase.tsx b/app/screens/AddEmission/components/Purchase/Purchase.tsx index fa61d9ed..648122b2 100644 --- a/app/screens/AddEmission/components/Purchase/Purchase.tsx +++ b/app/screens/AddEmission/components/Purchase/Purchase.tsx @@ -1,11 +1,13 @@ import React, { useState } from "react"; +import { useSelector } from "react-redux"; import { View } from "react-native"; import Slider from "@react-native-community/slider"; import { FormattedNumber } from "react-native-globalize"; import { purchase } from "carbon-footprint"; import { Text } from "components"; -import { t } from "utils"; +import { userPreferences } from "ducks"; +import { t, calculation } from "utils"; import { Colors } from "style"; import styles from "./Purchase.styles"; @@ -28,6 +30,10 @@ const Purchase: React.FC = ({ emissionModelType, setQuantity, defaultValu setQuantity(val); }; + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + return ( <> @@ -48,10 +54,12 @@ const Purchase: React.FC = ({ emissionModelType, setQuantity, defaultValu {t("ADD_EMISSION_SCREEN_TOTAL")} {" "} - kgCO2eq + + {getDisplayUnits(sliderValue * purchase[emissionModelType], useMetricUnits) + "CO2eq"} + diff --git a/app/screens/AddEmission/components/Streaming/Streaming.tsx b/app/screens/AddEmission/components/Streaming/Streaming.tsx index ae0be1fa..2b8f057e 100644 --- a/app/screens/AddEmission/components/Streaming/Streaming.tsx +++ b/app/screens/AddEmission/components/Streaming/Streaming.tsx @@ -1,11 +1,13 @@ import React, { useState } from "react"; +import { useSelector } from "react-redux"; import { View } from "react-native"; import Slider from "@react-native-community/slider"; import { FormattedNumber } from "react-native-globalize"; import { streaming, getInternetUsageCarbonImpact, ElectricityType } from "carbon-footprint"; import { Text } from "components"; -import { t, time } from "utils"; +import { userPreferences } from "ducks"; +import { t, time, calculation } from "utils"; import { Colors } from "style"; import styles from "./Streaming.styles"; @@ -40,6 +42,10 @@ const Streaming: React.FC = ({ electricityCountry ); + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + return ( <> @@ -60,10 +66,10 @@ const Streaming: React.FC = ({ {t("ADD_EMISSION_SCREEN_TOTAL")} 1 ? carbonValue : carbonValue * 1000} + value={getDisplayUnitsValue(carbonValue, useMetricUnits)} maximumFractionDigits={2} />{" "} - {carbonValue > 1 ? "kgCO2eq" : "gCO2eq"} + {getDisplayUnits(carbonValue, useMetricUnits) + "CO2eq"} diff --git a/app/screens/AddEmission/components/Transport/Transport.tsx b/app/screens/AddEmission/components/Transport/Transport.tsx index 8ae8128a..3d252f06 100644 --- a/app/screens/AddEmission/components/Transport/Transport.tsx +++ b/app/screens/AddEmission/components/Transport/Transport.tsx @@ -1,14 +1,17 @@ import React, { useState } from "react"; +import { useSelector } from "react-redux"; import { View } from "react-native"; import Slider from "@react-native-community/slider"; import { FormattedNumber } from "react-native-globalize"; import { transport, TransportType } from "carbon-footprint"; import { Text } from "components"; +import { userPreferences } from "ducks"; import { t, time, calculation } from "utils"; import { Colors } from "style"; import styles from "./Transport.styles"; +import { MeasureType } from "../../../../types/measureType"; const MIN_SLIDER_VALUE = 2; const MAX_SLIDER_VALUE = 1000; @@ -39,6 +42,11 @@ const Transport: React.FC = ({ setDurationMinutes(val); }; + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getImperialMetricValue = calculation.getImperialMetricValue; + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + const renderDuration = () => { const { hours, minutes } = time.convertMinutesToHoursAnMinutes(sliderValue); @@ -54,7 +62,10 @@ const Transport: React.FC = ({ return ( {t("ADD_EMISSION_SCREEN_DISTANCE")} - {Math.round(sliderValue) + " kilometer(s)"} + + {Math.round(getImperialMetricValue(sliderValue, useMetricUnits, MeasureType.length)) + + (useMetricUnits ? " kilometer(s)" : " mile(s)")} + ); }; @@ -80,15 +91,24 @@ const Transport: React.FC = ({ {t("ADD_EMISSION_SCREEN_TOTAL")} {" "} - kgCO2eq + + {getDisplayUnits( + emissionModelType === TransportType.plane + ? calculation.getFlightEmissionValue(sliderValue) * + transport[calculation.getFlightType(sliderValue)] + : sliderValue * 1000 * transport[emissionModelType], + useMetricUnits + ) + "CO2eq"} + diff --git a/app/screens/Budget/components/ProgressChart/components/LegendItem/LegendItem.tsx b/app/screens/Budget/components/ProgressChart/components/LegendItem/LegendItem.tsx index 3f8a8a3b..0d9ad493 100644 --- a/app/screens/Budget/components/ProgressChart/components/LegendItem/LegendItem.tsx +++ b/app/screens/Budget/components/ProgressChart/components/LegendItem/LegendItem.tsx @@ -1,7 +1,11 @@ import React from "react"; import { View } from "react-native"; +import { useSelector } from "react-redux"; +import { FormattedNumber } from "react-native-globalize"; import { Text } from "components"; +import { userPreferences } from "ducks"; +import { calculation } from "utils"; import styles from "./LegendItem.styles"; @@ -12,24 +16,34 @@ interface Props { } const LegendItem: React.FC = ({ name = "", amount = 0, totalAmount = 0 }) => { + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + if (amount === 0 || totalAmount === 0) { return null; } let showPercentage = true; - let unitAmount = " kg - "; + let unitAmount = ` ${getDisplayUnits(amount, useMetricUnits)} - `; const percentage = Math.round((amount / totalAmount) * 100); if (totalAmount == amount || !percentage) { showPercentage = false; - unitAmount = " kg"; + unitAmount = ` ${getDisplayUnits(amount, useMetricUnits)}`; } return ( {name + " : "} - {amount + unitAmount} + + {" "} + {unitAmount} + {showPercentage && {percentage + " %"}} ); diff --git a/app/screens/Budget/components/ProgressChart/components/LegendItem/__tests__/LegendItem.test.tsx b/app/screens/Budget/components/ProgressChart/components/LegendItem/__tests__/LegendItem.test.tsx index 155c0b75..d555dafa 100644 --- a/app/screens/Budget/components/ProgressChart/components/LegendItem/__tests__/LegendItem.test.tsx +++ b/app/screens/Budget/components/ProgressChart/components/LegendItem/__tests__/LegendItem.test.tsx @@ -1,5 +1,8 @@ import React from "react"; import { create } from "react-test-renderer"; +import * as reactRedux from "react-redux"; + +import { userPreferences } from "ducks"; import LegendItem from "../LegendItem"; @@ -11,6 +14,12 @@ const props = { jest.unmock("../LegendItem"); +const useSelectorMock = jest.spyOn(reactRedux, "useSelector"); + +beforeEach(() => { + useSelectorMock.mockImplementation(userPreferences.selectors.getUseMetricUnits); +}); + it("LegendItem renders correctly", () => { const tree = create().toJSON(); expect(tree).toMatchSnapshot(); diff --git a/app/screens/Budget/components/ProgressChart/components/LegendItem/__tests__/__snapshots__/LegendItem.test.tsx.snap b/app/screens/Budget/components/ProgressChart/components/LegendItem/__tests__/__snapshots__/LegendItem.test.tsx.snap index ebe335e3..75f6ccad 100644 --- a/app/screens/Budget/components/ProgressChart/components/LegendItem/__tests__/__snapshots__/LegendItem.test.tsx.snap +++ b/app/screens/Budget/components/ProgressChart/components/LegendItem/__tests__/__snapshots__/LegendItem.test.tsx.snap @@ -16,7 +16,12 @@ exports[`LegendItem renders correctly 1`] = ` - 60 kg - + + + kg - - 0.01 kg + + + g `; diff --git a/app/screens/Budget/components/ProgressChart/components/PeriodBudget/PeriodBudget.tsx b/app/screens/Budget/components/ProgressChart/components/PeriodBudget/PeriodBudget.tsx index 4131360a..0a8c1666 100644 --- a/app/screens/Budget/components/ProgressChart/components/PeriodBudget/PeriodBudget.tsx +++ b/app/screens/Budget/components/ProgressChart/components/PeriodBudget/PeriodBudget.tsx @@ -1,8 +1,11 @@ import React from "react"; import { View } from "react-native"; +import { useSelector } from "react-redux"; +import { FormattedNumber } from "react-native-globalize"; import { Text } from "components"; -import { t } from "utils"; +import { userPreferences } from "ducks"; +import { calculation, t } from "utils"; import styles from "./PeriodBudget.styles"; @@ -12,12 +15,9 @@ interface Props { } const PeriodBudget: React.FC = ({ periodEmissionsBudget = 0, period = "" }) => { - let budget = periodEmissionsBudget.toString(); - let units = " kg"; - if (periodEmissionsBudget > 999) { - budget = (periodEmissionsBudget / 1000).toFixed(2); - units = " ton(s)"; - } + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; return ( @@ -26,7 +26,15 @@ const PeriodBudget: React.FC = ({ periodEmissionsBudget = 0, period = "" {period} {" : "} - {budget + units} + 1000 && useMetricUnits ? 2 : 0} + value={getDisplayUnitsValue(periodEmissionsBudget, useMetricUnits)} + />{" "} + {getDisplayUnits( + periodEmissionsBudget, + useMetricUnits, + !(periodEmissionsBudget > 1000 && useMetricUnits) + )} diff --git a/app/screens/Budget/components/ProgressChart/components/PeriodBudget/__tests__/PeriodBudget.test.tsx b/app/screens/Budget/components/ProgressChart/components/PeriodBudget/__tests__/PeriodBudget.test.tsx index 05d627f6..b2ee9735 100644 --- a/app/screens/Budget/components/ProgressChart/components/PeriodBudget/__tests__/PeriodBudget.test.tsx +++ b/app/screens/Budget/components/ProgressChart/components/PeriodBudget/__tests__/PeriodBudget.test.tsx @@ -1,5 +1,8 @@ import React from "react"; import { create } from "react-test-renderer"; +import * as reactRedux from "react-redux"; + +import { userPreferences } from "ducks"; import PeriodBudget from "../PeriodBudget"; @@ -10,6 +13,12 @@ const props = { jest.unmock("../PeriodBudget"); +const useSelectorMock = jest.spyOn(reactRedux, "useSelector"); + +beforeEach(() => { + useSelectorMock.mockImplementation(userPreferences.selectors.getUseMetricUnits); +}); + it("PeriodBudget renders correctly", () => { const tree = create().toJSON(); expect(tree).toMatchSnapshot(); diff --git a/app/screens/Budget/components/ProgressChart/components/PeriodBudget/__tests__/__snapshots__/PeriodBudget.test.tsx.snap b/app/screens/Budget/components/ProgressChart/components/PeriodBudget/__tests__/__snapshots__/PeriodBudget.test.tsx.snap index f49c73e0..f27ee433 100644 --- a/app/screens/Budget/components/ProgressChart/components/PeriodBudget/__tests__/__snapshots__/PeriodBudget.test.tsx.snap +++ b/app/screens/Budget/components/ProgressChart/components/PeriodBudget/__tests__/__snapshots__/PeriodBudget.test.tsx.snap @@ -21,7 +21,12 @@ exports[`PeriodBudget renders correctly 1`] = ` center={true} lightGray={true} > - 760 kg + + + kg @@ -48,7 +53,12 @@ exports[`PeriodBudget renders correctly if tons 1`] = ` center={true} lightGray={true} > - 760 kg + + + kg diff --git a/app/screens/EmissionItem/EmissionItemScreen.tsx b/app/screens/EmissionItem/EmissionItemScreen.tsx index 04c47f12..488b2ab4 100644 --- a/app/screens/EmissionItem/EmissionItemScreen.tsx +++ b/app/screens/EmissionItem/EmissionItemScreen.tsx @@ -8,7 +8,7 @@ import { FormattedNumber } from "react-native-globalize"; import { useNavigation, useRoute } from "@react-navigation/native"; import { Text, Button } from "components"; -import { emissions, recurringEmissions } from "ducks"; +import { emissions, recurringEmissions, userPreferences } from "ducks"; import { calculation, ui, @@ -33,6 +33,10 @@ const EmissionItemScreen = ({ language = "" }: LocalizationContextProps) => { const dispatch = useDispatch(); + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + let emission = useSelector((state) => emissions.selectors.getEmissionById(state, emissionId)); const recurringEmission = useSelector((state) => @@ -110,9 +114,9 @@ const EmissionItemScreen = ({ language = "" }: LocalizationContextProps) => { 1 ? co2Emission : co2Emission * 1000} + value={getDisplayUnitsValue(co2Emission, useMetricUnits)} />{" "} - {co2Emission > 1 ? " kgC02eq" : " gC02eq"} + {`${getDisplayUnits(co2Emission, useMetricUnits)}C02eq`} {!isRecurringEmission && ( diff --git a/app/screens/EmissionItem/__tests__/EmissionItemScreen.test.tsx b/app/screens/EmissionItem/__tests__/EmissionItemScreen.test.tsx index 07c1afca..b0555a1d 100644 --- a/app/screens/EmissionItem/__tests__/EmissionItemScreen.test.tsx +++ b/app/screens/EmissionItem/__tests__/EmissionItemScreen.test.tsx @@ -1,9 +1,18 @@ import React from "react"; import MockDate from "mockdate"; import { create } from "react-test-renderer"; +import * as reactRedux from "react-redux"; + +import { userPreferences } from "ducks"; import EmissionItemScreen from "../EmissionItemScreen"; +const useSelectorMock = jest.spyOn(reactRedux, "useSelector"); + +beforeEach(() => { + useSelectorMock.mockImplementationOnce(userPreferences.selectors.getUseMetricUnits); +}); + it("EmissionsScreen renders correctly", () => { const nowString = "2021-02-21T21:21:21"; MockDate.set(nowString); diff --git a/app/screens/EmissionItem/__tests__/__snapshots__/EmissionItemScreen.test.tsx.snap b/app/screens/EmissionItem/__tests__/__snapshots__/EmissionItemScreen.test.tsx.snap index 1d8eafa9..027544a0 100644 --- a/app/screens/EmissionItem/__tests__/__snapshots__/EmissionItemScreen.test.tsx.snap +++ b/app/screens/EmissionItem/__tests__/__snapshots__/EmissionItemScreen.test.tsx.snap @@ -46,7 +46,7 @@ exports[`EmissionsScreen renders correctly 1`] = ` value={NaN} /> - gC02eq + tC02eq Mitigation diff --git a/app/screens/MonthlyBudget/MonthlyBudgetScreen.tsx b/app/screens/MonthlyBudget/MonthlyBudgetScreen.tsx index 12601770..f52e17a8 100644 --- a/app/screens/MonthlyBudget/MonthlyBudgetScreen.tsx +++ b/app/screens/MonthlyBudget/MonthlyBudgetScreen.tsx @@ -5,10 +5,11 @@ import Slider from "@react-native-community/slider"; import { Ionicons } from "@expo/vector-icons"; import * as WebBrowser from "expo-web-browser"; import { useDispatch, useSelector } from "react-redux"; +import { FormattedNumber } from "react-native-globalize"; import { Text, Button } from "components"; -import { budget } from "ducks"; -import { t } from "utils"; +import { budget, userPreferences } from "ducks"; +import { t, calculation } from "utils"; import { Colors } from "style"; import { navigate } from "navigation"; import { NavStatelessComponent } from "interfaces"; @@ -19,23 +20,34 @@ import navigationOptions from "./MonthlyBudgetScreen.navigationOptions"; const MIN_MONTHLY_CARBON_BUDGET = 10; const MAX_MONTHLY_CARBON_BUDGET = 1000; -const translationMontlyBudgetCountries = [ - "MONTHLY_BUDGET_SCREEN_LUXEMBOURG", - "MONTHLY_BUDGET_SCREEN_UNITED_STATES", - "MONTHLY_BUDGET_SCREEN_JAPAN", - "MONTHLY_BUDGET_SCREEN_SWEDEN", - "MONTHLY_BUDGET_SCREEN_FRANCE", - "MONTHLY_BUDGET_SCREEN_CHINA", - "MONTHLY_BUDGET_SCREEN_BRAZIL", - "MONTHLY_BUDGET_SCREEN_INDIA", - "MONTHLY_BUDGET_SCREEN_ETHIOPIA", +const translationMonthlyBudgetCountries = [ + ["MONTHLY_BUDGET_SCREEN_LUXEMBOURG", 3500], + ["MONTHLY_BUDGET_SCREEN_UNITED_STATES", 1500], + ["MONTHLY_BUDGET_SCREEN_JAPAN", 900], + ["MONTHLY_BUDGET_SCREEN_SWEDEN", 595], + ["MONTHLY_BUDGET_SCREEN_FRANCE", 575], + ["MONTHLY_BUDGET_SCREEN_CHINA", 522], + ["MONTHLY_BUDGET_SCREEN_BRAZIL", 208], + ["MONTHLY_BUDGET_SCREEN_INDIA", 139], + ["MONTHLY_BUDGET_SCREEN_ETHIOPIA", 8.3], ]; -const CountryExample = (translation, index) => ( - - {t(translation)} - -); +const CountryExample = (translation, kgCarbonValue, index) => { + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + + return ( + + {t(translation)} + {" "} + {getDisplayUnits(kgCarbonValue, useMetricUnits)} + {"CO2eq"} + + ); +}; const onPressInfoWorldEmission = () => WebBrowser.openBrowserAsync( @@ -57,6 +69,10 @@ const MonthlyBudgetScreen: NavStatelessComponent = () => { navigator.goBack(); }; + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + return ( @@ -73,7 +89,11 @@ const MonthlyBudgetScreen: NavStatelessComponent = () => { value={sliderValue} onSlidingComplete={setSliderValue} /> - {Math.round(sliderValue) + " kg CO2eq"} + + {" "} + {getDisplayUnits(sliderValue, useMetricUnits)} + {"CO2eq"} + @@ -86,10 +106,14 @@ const MonthlyBudgetScreen: NavStatelessComponent = () => { /> - {translationMontlyBudgetCountries.map(CountryExample)} + {translationMonthlyBudgetCountries.map((countryArr, idx) => + CountryExample(countryArr[0], countryArr[1], idx) + )} - {t("MONTHLY_BUDGET_SCREEN_PARIS_AGREEMENT")} + {t("MONTHLY_BUDGET_SCREEN_PARIS_AGREEMENT")}{" "} + {Math.round(getDisplayUnitsValue(167, useMetricUnits))}{" "} + {getDisplayUnits(167, useMetricUnits) + "CO2eq"} - NaN kg CO2eq + + + lb + CO2eq - Luxembourg : 3.5 tons + Luxembourg : + + + lb + CO2eq - United States : 1.5 tons + United States : + + + lb + CO2eq - Japan : 900 kg + Japan : + + + lb + CO2eq - Sweden : 595 kg + Sweden : + + + lb + CO2eq - France : 575 kg + France : + + + lb + CO2eq - China : 522 kg + China : + + + lb + CO2eq - Brazil : 208 kg + Brazil : + + + lb + CO2eq - India : 139 kg + India : + + + lb + CO2eq - Ethiopia : 8.3 kg + Ethiopia : + + + lb + CO2eq - If you wish to respect the Paris agreement (to keep the rise in global average temperature below 2 degrees), set your monthly budget at 167 kgCO2eq + If you wish to respect the Paris agreement (to keep the rise in global average temperature below 2 degrees), set your monthly budget at + + 368 + + lbCO2eq { } } + const useMetricUnits = useSelector(userPreferences.selectors.getUseMetricUnits); + const getDisplayUnitsValue = calculation.getDisplayUnitsValue; + const getDisplayUnits = calculation.getDisplayUnits; + const renderHeader = () => ( - {`${co2value.toFixed(2)} kgCO2eq`} + {`${getDisplayUnitsValue(co2value, useMetricUnits).toFixed(2)} ${getDisplayUnits( + co2value, + useMetricUnits + )}CO2eq`} {percentageBudget && ( 100} green={percentageBudget < 100}> diff --git a/app/screens/MonthlyEmissions/__tests__/MonthlyEmissionsScreen.test.tsx b/app/screens/MonthlyEmissions/__tests__/MonthlyEmissionsScreen.test.tsx index a454a343..27f83ac7 100644 --- a/app/screens/MonthlyEmissions/__tests__/MonthlyEmissionsScreen.test.tsx +++ b/app/screens/MonthlyEmissions/__tests__/MonthlyEmissionsScreen.test.tsx @@ -4,7 +4,7 @@ import { create } from "react-test-renderer"; import { FoodType, TransportType } from "carbon-footprint"; import * as reactRedux from "react-redux"; -import { emissions } from "ducks"; +import { emissions, userPreferences } from "ducks"; import { Emission, EmissionType } from "interfaces"; import { selectors } from "../ducks"; @@ -46,6 +46,7 @@ describe("", () => { beforeEach(() => { useSelectorMock.mockClear(); + useSelectorMock.mockImplementation(userPreferences.selectors.getUseMetricUnits); }); test("render", () => { diff --git a/app/screens/Settings/SettingsScreen.tsx b/app/screens/Settings/SettingsScreen.tsx index 5f70764d..15f68e2b 100644 --- a/app/screens/Settings/SettingsScreen.tsx +++ b/app/screens/Settings/SettingsScreen.tsx @@ -4,28 +4,43 @@ import { useNavigation } from "@react-navigation/native"; import ExpoConstants from "expo-constants"; import * as WebBrowser from "expo-web-browser"; import * as Linking from "expo-linking"; +import { useDispatch , useSelector } from "react-redux"; import { ImagesAssets } from "constant"; -import { Button, Text, SocialMedia, ListItem } from "components"; +import { Button, Text, SocialMedia, ListItem, ListItemSwitch } from "components"; import { t, platform } from "utils"; import { navigate } from "navigation"; import { NavStatelessComponent } from "interfaces"; +import { userPreferences } from "ducks"; import styles from "./SettingsScreen.styles"; import navigationOptions from "./SettingsScreen.navigationOptions"; import quotes from "../../../assets/quotes/quotes.json"; + + + const quoteIndex = Math.floor(Math.random() * Math.floor(quotes.length)); const SettingsScreen: NavStatelessComponent = () => { const navigation = useNavigation(); const navigator = navigate(navigation); + const dispatch = useDispatch(); + const rowItems = [ { title: t("SETTINGS_SCREEN_ABOUT"), onPress: navigator.openAbout, }, + { + isSwitchItem: true, + title: t("SETTINGS_SCREEN_UNITS"), + value: useSelector(userPreferences.selectors.getUseMetricUnits), + get onChange() {return () => { + dispatch(userPreferences.actions.toggleUnits(!this.value)) + }} + }, { title: t("SETTINGS_SCREEN_IMPORT_SAVE_DELETE_DATA"), onPress: navigator.openMyData, @@ -80,18 +95,28 @@ const SettingsScreen: NavStatelessComponent = () => { const [steps, setSteps] = useState(0); const { version, ios, android } = ExpoConstants.manifest; - const buildNumber = platform.isIOS ? ios.buildNumber : android.versionCode; + const buildNumber = platform.isIOS ? ios.buildNumber : android.versionCode; return ( - {rowItems.map((item, index) => ( - item.onPress()} - title={item.title} - /> - ))} + {rowItems.map((item, index) => { + if (item.isSwitchItem) { + return + } else { + return item.onPress()} + title={item.title} + /> + } + })} setSteps(steps + 1)}> diff --git a/app/screens/Settings/__tests__/__snapshots__/SettingsScreen.test.tsx.snap b/app/screens/Settings/__tests__/__snapshots__/SettingsScreen.test.tsx.snap index b7e2fed3..59e5677b 100644 --- a/app/screens/Settings/__tests__/__snapshots__/SettingsScreen.test.tsx.snap +++ b/app/screens/Settings/__tests__/__snapshots__/SettingsScreen.test.tsx.snap @@ -11,350 +11,71 @@ exports[`SettingsScreen renders correctly 1`] = ` } > - - - About - - - - + + - - My data - - - - + - - Notifications - - - - + - - My Location - - - - + - - Support us! - - - - + - - FAQ - - - - + - - NMF.earth - - - - + - - Roadmap - - - - + - - Help translation - - - - + - - Feedback - - - - + - - Terms of use - - - - + - - Languages - - - + showBottomLine={false} + title="Languages" + /> { it("food emission", () => { expect(calculation.getC02ValueFromEmission(emissionFood)).toEqual( @@ -190,3 +222,96 @@ describe("getCarbonIntensityInGramPerKWHromKgPerJoules should convert data from ); }); }); + +describe("getImperialMetricValue should return the correct measurement value", () => { + for (const value of imperialMetricBaseline) { + it("for a mass value in metric", () => { + expect(calculation.getImperialMetricValue(value, true, MeasureType.mass)).toEqual(value); + }); + + it("for a length value in metric", () => { + expect(calculation.getImperialMetricValue(value, true, MeasureType.length)).toEqual(value); + }); + + it("for a mass value in Imperial", () => { + expect(calculation.getImperialMetricValue(value, false, MeasureType.mass)).toEqual( + value * 2.205 + ); + }); + + it("for a length value in Imperial", () => { + expect(calculation.getImperialMetricValue(value, false, MeasureType.length)).toEqual( + value / 1.609 + ); + }); + } +}); + +describe("getDisplayUnitsValue should convert the given kilogram value to", () => { + it("grams", () => { + for (const kgValue of unitsBasline.toGrams) { + expect(calculation.getDisplayUnitsValue(kgValue, true)).toEqual(kgValue * 1000); + } + }); + + it("kilograms", () => { + for (const kgValue of unitsBasline.toKilograms) { + expect(calculation.getDisplayUnitsValue(kgValue, true)).toEqual(kgValue); + } + }); + + it("tonnes", () => { + for (const kgValue of unitsBasline.toTonnes) { + expect(calculation.getDisplayUnitsValue(kgValue, true)).toEqual(kgValue / 1000); + } + }); + + it("ounces", () => { + for (const kgValue of unitsBasline.toOunces) { + expect(calculation.getDisplayUnitsValue(kgValue, false)).toEqual(kgValue * 2.205 * 16); + } + }); + + it("pounds", () => { + for (const kgValue of unitsBasline.toPounds) { + expect(calculation.getDisplayUnitsValue(kgValue, false)).toEqual(kgValue * 2.205); + } + }); +}); + +describe("getDisplayUnits should return the correct units given a kilogram value that should be converted to", () => { + it("grams", () => { + for (const kgValue of unitsBasline.toGrams) { + expect(calculation.getDisplayUnits(kgValue, true)).toEqual(t("GRAMS_SYMBOL")); + expect(calculation.getDisplayUnits(kgValue, true, false)).toEqual(t("GRAMS_FULL")); + } + }); + + it("kilograms", () => { + for (const kgValue of unitsBasline.toKilograms) { + expect(calculation.getDisplayUnits(kgValue, true)).toEqual(t("KILOGRAMS_SYMBOL")); + expect(calculation.getDisplayUnits(kgValue, true, false)).toEqual(t("KILOGRAMS_FULL")); + } + }); + + it("tonnes", () => { + for (const kgValue of unitsBasline.toTonnes) { + expect(calculation.getDisplayUnits(kgValue, true)).toEqual(t("TONNES_SYMBOL")); + expect(calculation.getDisplayUnits(kgValue, true, false)).toEqual(t("TONNES_FULL")); + } + }); + + it("ounces", () => { + for (const kgValue of unitsBasline.toOunces) { + expect(calculation.getDisplayUnits(kgValue, false)).toEqual(t("OUNCES_SYMBOL")); + expect(calculation.getDisplayUnits(kgValue, false, false)).toEqual(t("OUNCES_FULL")); + } + }); + + it("pounds", () => { + for (const kgValue of unitsBasline.toPounds) { + expect(calculation.getDisplayUnits(kgValue, false)).toEqual(t("POUNDS_SYMBOL")); + expect(calculation.getDisplayUnits(kgValue, false, false)).toEqual(t("POUNDS_FULL")); + } + }); +}); diff --git a/app/utils/calculation/calculation.ts b/app/utils/calculation/calculation.ts index 7e560930..c35eee1e 100644 --- a/app/utils/calculation/calculation.ts +++ b/app/utils/calculation/calculation.ts @@ -16,6 +16,7 @@ import { EmissionType, Emission, RecurringEmission, PeriodicityType, WeekDays } import { WEEK_DAYS } from "constant/weekDays"; import { t } from "../translations"; +import { MeasureType } from "../../types/measureType"; const isNilOrEmpty = either(isNil, isEmpty); @@ -136,6 +137,63 @@ const getPeriodicityText = ({ return periodicityText; }; +const getImperialMetricValue = ( + metricValue: number, + useMetricUnits: boolean, + measureType: MeasureType +): number => { + if (useMetricUnits) { + return metricValue; + } else { + if (measureType === MeasureType.mass) { + /* kg -> lbs */ + return metricValue * 2.205; + } else if (measureType === MeasureType.length) { + /* km -> miles + note: deviates from NMF.earth's standard of using meters as a reference */ + return metricValue / 1.609; + } + } +}; + +const getDisplayUnitsValue = (kgValue: number, useMetricUnits: boolean): number => { + if (useMetricUnits) { + if (kgValue <= 1) { + return kgValue * 1000; + } else if (kgValue > 1 && kgValue <= 1000) { + return kgValue; + } else { + return kgValue / 1000; + } + } else { + if (kgValue <= 0.454) { + return getImperialMetricValue(kgValue, useMetricUnits, MeasureType.mass) * 16; + } else { + return getImperialMetricValue(kgValue, useMetricUnits, MeasureType.mass); + } + } +}; + +const getDisplayUnits = (kgValue: number, useMetricUnits: boolean, useSymbol = true): string => { + const suffix = useSymbol ? "_SYMBOL" : "_FULL"; + + if (useMetricUnits) { + if (kgValue <= 1) { + return t(`GRAMS${suffix}`); + } else if (kgValue > 1 && kgValue <= 1000) { + return t(`KILOGRAMS${suffix}`); + } else { + return t(`TONNES${suffix}`); + } + } else { + if (kgValue <= 0.454) { + return t(`OUNCES${suffix}`); + } else { + return t(`POUNDS${suffix}`); + } + } +}; + export default { getLatestEmission, getC02ValueFromEmission, @@ -143,4 +201,7 @@ export default { getFlightEmissionValue, getCarbonIntensityInGramPerKWHromKgPerJoules, getPeriodicityText, + getImperialMetricValue, + getDisplayUnitsValue, + getDisplayUnits, }; diff --git a/app/utils/calculation/translations/da.json b/app/utils/calculation/translations/da.json new file mode 100644 index 00000000..2dd6dfd5 --- /dev/null +++ b/app/utils/calculation/translations/da.json @@ -0,0 +1,16 @@ +{ + "GRAMS_SYMBOL": "g", + "GRAMS_FULL": "gram", + "KILOGRAMS_SYMBOL": "kg", + "KILOGRAMS_FULL": "kilogram", + "TONNES_SYMBOL": "t", + "TONNES_FULL": "ton(s)", + "OUNCES_SYMBOL": "oz", + "OUNCES_FULL": "ounce(s)", + "POUNDS_SYMBOL": "lb", + "POUNDS_FULL": "pund", + "KILOMETERS_SYMBOL": "km", + "KILOMETERS_FULL": "kilometer", + "MILES_SYMBOL": "mi", + "MILES_FULL": "mil(es)" +} \ No newline at end of file diff --git a/app/utils/calculation/translations/de.json b/app/utils/calculation/translations/de.json new file mode 100644 index 00000000..8e3f7efb --- /dev/null +++ b/app/utils/calculation/translations/de.json @@ -0,0 +1,16 @@ +{ + "GRAMS_SYMBOL": "g", + "GRAMS_FULL": "Gramm", + "KILOGRAMS_SYMBOL": "kg", + "KILOGRAMS_FULL": "Kilogramm", + "TONNES_SYMBOL": "t", + "TONNES_FULL": "Tonne", + "OUNCES_SYMBOL": "oz", + "OUNCES_FULL": "Unze", + "POUNDS_SYMBOL": "lb", + "POUNDS_FULL": "Pfund", + "KILOMETERS_SYMBOL": "km", + "KILOMETERS_FULL": "Kilometer", + "MILES_SYMBOL": "mi", + "MILES_FULL": "Meile(n)" +} \ No newline at end of file diff --git a/app/utils/calculation/translations/en.json b/app/utils/calculation/translations/en.json new file mode 100644 index 00000000..a2ee26be --- /dev/null +++ b/app/utils/calculation/translations/en.json @@ -0,0 +1,16 @@ +{ + "GRAMS_SYMBOL": "g", + "GRAMS_FULL": "gram(s)", + "KILOGRAMS_SYMBOL": "kg", + "KILOGRAMS_FULL": "kilogram(s)", + "TONNES_SYMBOL": "t", + "TONNES_FULL": "ton(s)", + "OUNCES_SYMBOL": "oz", + "OUNCES_FULL": "ounce(s)", + "POUNDS_SYMBOL": "lb", + "POUNDS_FULL": "pound(s)", + "KILOMETERS_SYMBOL": "km", + "KILOMETERS_FULL": "kilometer(s)", + "MILES_SYMBOL": "mi", + "MILES_FULL": "mile(s)" +} \ No newline at end of file diff --git a/app/utils/calculation/translations/es.json b/app/utils/calculation/translations/es.json new file mode 100644 index 00000000..d53de8af --- /dev/null +++ b/app/utils/calculation/translations/es.json @@ -0,0 +1,16 @@ +{ + "GRAMS_SYMBOL": "g", + "GRAMS_FULL": "gramo(s)", + "KILOGRAMS_SYMBOL": "kg", + "KILOGRAMS_FULL": "kilogramo(s)", + "TONNES_SYMBOL": "t", + "TONNES_FULL": "tonelada(s)", + "OUNCES_SYMBOL": "onz", + "OUNCES_FULL": "onza(s)", + "POUNDS_SYMBOL": "lb", + "POUNDS_FULL": "libra(s)", + "KILOMETERS_SYMBOL": "km", + "KILOMETERS_FULL": "kilómetro(s)", + "MILES_SYMBOL": "mi", + "MILES_FULL": "milla(s)" +} \ No newline at end of file diff --git a/app/utils/calculation/translations/fr.json b/app/utils/calculation/translations/fr.json new file mode 100644 index 00000000..f0d28e83 --- /dev/null +++ b/app/utils/calculation/translations/fr.json @@ -0,0 +1,16 @@ +{ + "GRAMS_SYMBOL": "g", + "GRAMS_FULL": "gramme(s)", + "KILOGRAMS_SYMBOL": "kg", + "KILOGRAMS_FULL": "kilogramme(s)", + "TONNES_SYMBOL": "t", + "TONNES_FULL": "tonne(s)", + "OUNCES_SYMBOL": "oz", + "OUNCES_FULL": "once(s)", + "POUNDS_SYMBOL": "lb", + "POUNDS_FULL": "livre(s)", + "KILOMETERS_SYMBOL": "km", + "KILOMETERS_FULL": "kilomètre(s)", + "MILES_SYMBOL": "mi", + "MILES_FULL": "mille(s)" +} \ No newline at end of file diff --git a/app/utils/calculation/translations/index.ts b/app/utils/calculation/translations/index.ts new file mode 100644 index 00000000..f4032c4a --- /dev/null +++ b/app/utils/calculation/translations/index.ts @@ -0,0 +1,30 @@ +import en from "./en.json"; +import fr from "./fr.json"; +import de from "./de.json"; +import sv from "./sv.json"; +import es from "./es.json"; +import pt from "./pt.json"; +import da from "./da.json"; +import ru from "./ru.json"; +import pl from "./pl.json"; +import zh from "./zh.json"; +import ms from "./ms.json"; + +interface TranslationKeys { + GRAMS_SYMBOL: string; + GRAMS_FULL: string; + KILOGRAMS_SYMBOL: string; + KILOGRAMS_FULL: string; + TONNES_SYMBOL: string; + TONNES_FULL: string; + OUNCES_SYMBOL: string; + OUNCES_FULL: string; + POUNDS_SYMBOL: string; + POUNDS_FULL: string; + KILOMETERS_SYMBOL: string; + KILOMETERS_FULL: string; + MILES_SYMBOL: string; + MILES_FULL: string; +} + +export { en, fr, de, sv, es, pt, da, ru, pl, zh, ms, TranslationKeys }; diff --git a/app/utils/calculation/translations/ms.json b/app/utils/calculation/translations/ms.json new file mode 100644 index 00000000..8945e7c3 --- /dev/null +++ b/app/utils/calculation/translations/ms.json @@ -0,0 +1,16 @@ +{ + "GRAMS_SYMBOL": "g", + "GRAMS_FULL": "gram", + "KILOGRAMS_SYMBOL": "kg", + "KILOGRAMS_FULL": "kilogram", + "TONNES_SYMBOL": "t", + "TONNES_FULL": "ton", + "OUNCES_SYMBOL": "oz", + "OUNCES_FULL": "ons", + "POUNDS_SYMBOL": "lb", + "POUNDS_FULL": "pon", + "KILOMETERS_SYMBOL": "km", + "KILOMETERS_FULL": "kilometer(s)", + "MILES_SYMBOL": "mi", + "MILES_FULL": "mil" +} \ No newline at end of file diff --git a/app/utils/calculation/translations/pl.json b/app/utils/calculation/translations/pl.json new file mode 100644 index 00000000..be0b1ebe --- /dev/null +++ b/app/utils/calculation/translations/pl.json @@ -0,0 +1,16 @@ +{ + "GRAMS_SYMBOL": "g", + "GRAMS_FULL": "gram(y)", + "KILOGRAMS_SYMBOL": "kg", + "KILOGRAMS_FULL": "kilogram(y)", + "TONNES_SYMBOL": "t", + "TONNES_FULL": "tona/y", + "OUNCES_SYMBOL": "oz", + "OUNCES_FULL": "uncja/e", + "POUNDS_SYMBOL": "lb", + "POUNDS_FULL": "funt(y)", + "KILOMETERS_SYMBOL": "km", + "KILOMETERS_FULL": "kilometr(y)", + "MILES_SYMBOL": "mi", + "MILES_FULL": "mila/e" +} \ No newline at end of file diff --git a/app/utils/calculation/translations/pt.json b/app/utils/calculation/translations/pt.json new file mode 100644 index 00000000..8d41062a --- /dev/null +++ b/app/utils/calculation/translations/pt.json @@ -0,0 +1,16 @@ +{ + "GRAMS_SYMBOL": "g", + "GRAMS_FULL": "grama(s)", + "KILOGRAMS_SYMBOL": "kg", + "KILOGRAMS_FULL": "quilograma(s)", + "TONNES_SYMBOL": "t", + "TONNES_FULL": "tonelada(s)", + "OUNCES_SYMBOL": "oz", + "OUNCES_FULL": "onça(s)", + "POUNDS_SYMBOL": "lb", + "POUNDS_FULL": "libra(s)", + "KILOMETERS_SYMBOL": "km", + "KILOMETERS_FULL": "quilômetro(s)", + "MILES_SYMBOL": "mi", + "MILES_FULL": "milha(s)" +} \ No newline at end of file diff --git a/app/utils/calculation/translations/ru.json b/app/utils/calculation/translations/ru.json new file mode 100644 index 00000000..c4061b13 --- /dev/null +++ b/app/utils/calculation/translations/ru.json @@ -0,0 +1,16 @@ +{ + "GRAMS_SYMBOL": "г", + "GRAMS_FULL": "грамм(а)", + "KILOGRAMS_SYMBOL": "кг", + "KILOGRAMS_FULL": "килограмм(а)", + "TONNES_SYMBOL": "т", + "TONNES_FULL": "тонна/ы", + "OUNCES_SYMBOL": "oz", + "OUNCES_FULL": "унция/и", + "POUNDS_SYMBOL": "фунт", + "POUNDS_FULL": "фунт", + "KILOMETERS_SYMBOL": "км", + "KILOMETERS_FULL": "километр(а)", + "MILES_SYMBOL": "ми", + "MILES_FULL": "миля/и" +} \ No newline at end of file diff --git a/app/utils/calculation/translations/sv.json b/app/utils/calculation/translations/sv.json new file mode 100644 index 00000000..9ef62148 --- /dev/null +++ b/app/utils/calculation/translations/sv.json @@ -0,0 +1,16 @@ +{ + "GRAMS_SYMBOL": "g", + "GRAMS_FULL": "gram", + "KILOGRAMS_SYMBOL": "kg", + "KILOGRAMS_FULL": "kilogram", + "TONNES_SYMBOL": "t", + "TONNES_FULL": "ton", + "OUNCES_SYMBOL": "oz", + "OUNCES_FULL": "uns", + "POUNDS_SYMBOL": "lb", + "POUNDS_FULL": "pund", + "KILOMETERS_SYMBOL": "km", + "KILOMETERS_FULL": "kilometer", + "MILES_SYMBOL": "mi", + "MILES_FULL": "mil" +} \ No newline at end of file diff --git a/app/utils/calculation/translations/zh.json b/app/utils/calculation/translations/zh.json new file mode 100644 index 00000000..e68e9f83 --- /dev/null +++ b/app/utils/calculation/translations/zh.json @@ -0,0 +1,16 @@ +{ + "GRAMS_SYMBOL": "克", + "GRAMS_FULL": "克", + "KILOGRAMS_SYMBOL": "公斤", + "KILOGRAMS_FULL": "公斤", + "TONNES_SYMBOL": "吨", + "TONNES_FULL": "吨", + "OUNCES_SYMBOL": "盎司", + "OUNCES_FULL": "盎司", + "POUNDS_SYMBOL": "磅", + "POUNDS_FULL": "磅", + "KILOMETERS_SYMBOL": "公里", + "KILOMETERS_FULL": "公里", + "MILES_SYMBOL": "英里", + "MILES_FULL": "英里" +} \ No newline at end of file diff --git a/app/utils/translations/resources.ts b/app/utils/translations/resources.ts index e0cc0104..bd245d34 100644 --- a/app/utils/translations/resources.ts +++ b/app/utils/translations/resources.ts @@ -32,6 +32,7 @@ import * as OpenFoodFacts from "components/OpenFoodFacts/translations"; /* UTILS */ import * as UI from "utils/ui/translations"; +import * as Calculation from "utils/calculation/translations"; const en = { ...Act.en, @@ -62,10 +63,12 @@ const en = { ...OpenFoodFacts.en, ...Periodicity.en, ...UI.en, + ...Calculation.en, }; const de = { ...UI.de, + ...Calculation.de, ...About.de, ...MonthlyBudget.de, ...NoEmission.de, @@ -97,6 +100,7 @@ const de = { const fr = { ...UI.fr, + ...Calculation.fr, ...About.fr, ...Notifications.fr, ...MonthlyBudget.fr, @@ -128,6 +132,7 @@ const fr = { const sv = { ...UI.sv, + ...Calculation.sv, ...About.sv, ...Notifications.sv, ...MonthlyBudget.sv, @@ -159,6 +164,7 @@ const sv = { const pt = { ...UI.pt, + ...Calculation.pt, ...About.pt, ...Notifications.pt, ...MonthlyBudget.pt, @@ -190,6 +196,7 @@ const pt = { const es = { ...UI.es, + ...Calculation.es, ...About.es, ...Notifications.es, ...MonthlyBudget.es, @@ -221,6 +228,7 @@ const es = { const ru = { ...UI.ru, + ...Calculation.ru, ...About.ru, ...Notifications.ru, ...MonthlyBudget.ru, @@ -252,6 +260,7 @@ const ru = { const pl = { ...UI.pl, + ...Calculation.pl, ...About.pl, ...Notifications.pl, ...MonthlyBudget.pl, @@ -283,6 +292,7 @@ const pl = { const da = { ...UI.da, + ...Calculation.da, ...About.da, ...Notifications.da, ...MonthlyBudget.da, @@ -314,6 +324,7 @@ const da = { const zh = { ...UI.zh, + ...Calculation.zh, ...About.zh, ...Notifications.zh, ...MonthlyBudget.zh, @@ -345,6 +356,7 @@ const zh = { const ms = { ...UI.ms, + ...Calculation.ms, ...About.ms, ...Notifications.ms, ...MonthlyBudget.ms, @@ -376,6 +388,7 @@ const ms = { export interface TranslationKeys extends UI.TranslationKeys, + Calculation.TranslationKeys, MonthlyBudget.TranslationKeys, NoEmission.TranslationKeys, PermissionsRequest.TranslationKeys, diff --git a/jest/mock/components/index.js b/jest/mock/components/index.js index 19a4f72d..d4a4dbb0 100644 --- a/jest/mock/components/index.js +++ b/jest/mock/components/index.js @@ -21,6 +21,8 @@ jest.mock( jest.mock("../../../app/screens/Emissions/components/SectionHeader", () => "SectionHeader"); /* Shared Components */ +jest.mock("../../../app/components/ListItem", () => "ListItem"); +jest.mock("../../../app/components/ListItemSwitch", () => "ListItemSwitch"); jest.mock("../../../app/components/PermissionsRequest", () => "PermissionsRequest"); jest.mock("../../../app/components/StickersImage", () => "StickersImage"); jest.mock("../../../app/components/TextInput", () => "TextInput"); diff --git a/storybook/storyLoader.js b/storybook/storyLoader.js index b77d4ae5..6cf7b360 100644 --- a/storybook/storyLoader.js +++ b/storybook/storyLoader.js @@ -9,6 +9,7 @@ // require("../app/components/ClickableTag/stories/ClickableTag.story"); // require("../app/components/EmissionListItem/stories/EmissionListItem.story"); // require("../app/components/ListItem/stories/ListItem.story"); +// require("../app/components/ListItemSwitch/stories/ListItemSwitch.story"); // require("../app/components/NoEmission/stories/NoEmission.story"); // require("../app/components/SelectableListItem/stories/SelectableListItem.story"); // require("../app/components/SocialMedia/stories/SocialMedia.story"); @@ -23,6 +24,7 @@ // "../app/components/ClickableTag/stories/ClickableTag.story", // "../app/components/EmissionListItem/stories/EmissionListItem.story", // "../app/components/ListItem/stories/ListItem.story", +// "../app/components/ListItemSwitch/stories/ListItemSwitch.story", // "../app/components/NoEmission/stories/NoEmission.story", // "../app/components/SelectableListItem/stories/SelectableListItem.story", // "../app/components/SocialMedia/stories/SocialMedia.story",