diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml index 002e3deec..9a9630909 100644 --- a/android/app/src/main/res/values/colors.xml +++ b/android/app/src/main/res/values/colors.xml @@ -3,6 +3,7 @@ #0a6ed1 #262626 #00376C + #262626 #E7E7E7 #FFF diff --git a/src/App.tsx b/src/App.tsx index 8135a83d0..ca444f42c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,7 +9,6 @@ import { StatusBar } from 'react-native'; import { RootSiblingParent } from 'react-native-root-siblings'; import { scale } from 'react-native-size-matters'; -import computeStyleSheet from './AppStyles'; import DeepLinkingManager from './deeplinking/DeepLinkingManager'; import I18nManager from './I18n/I18nManager'; import LocationManager from './location/LocationManager'; @@ -171,7 +170,9 @@ function createChargingStationDetailsTabsNavigator(props: BaseProps) { inactiveColor={commonColor.topTabBarActiveTextColor} barStyle={barStyle} labeled - backBehavior="none"> + shifting={true} + backBehavior="history" + > + shifting={true} + backBehavior="history" + > + backBehavior="history" + > createTabBarIcon(iconProps, 'AntDesign', 'linechart') + tabBarIcon: (iconProps) => createTabBarIcon(iconProps, 'MaterialCommunityIcons', 'chart-line') }} /> @@ -273,11 +277,31 @@ function createTransactionDetailsTabsNavigator(props: BaseProps) { function createSitesNavigator(props: BaseProps) { return ( - - - + + + + + @@ -291,7 +315,11 @@ function createSitesNavigator(props: BaseProps) { component={createTransactionDetailsTabsNavigator} initialParams={props?.route?.params?.params} /> - + ); } @@ -299,7 +327,11 @@ function createSitesNavigator(props: BaseProps) { function createChargingStationsNavigator(props: BaseProps) { return ( - + - + - + ); } @@ -352,11 +388,6 @@ function createTransactionInProgressNavigator(props: BaseProps) { component={TransactionsInProgress} initialParams={props?.route?.params?.params} /> - - + }> - + - - + + - + ); } @@ -559,7 +577,6 @@ export default class App extends React.Component { public render() { const { showAppUpdateDialog } = this.state; - const commonColors = Utils.getCurrentCommonColor(); return ( this.state.isNavigationStateLoaded && ( diff --git a/src/components/modal/ModalSelect.tsx b/src/components/modal/ModalSelect.tsx index 05934c658..97761c9bf 100644 --- a/src/components/modal/ModalSelect.tsx +++ b/src/components/modal/ModalSelect.tsx @@ -69,6 +69,9 @@ export default class ModalSelect extends React.Component this.setState({ isVisible: false })} + // Modal component registers the given method for hardwareBackPress event and unregisters it when the modal inner content unmounts. + // Inner component list also unsubscribe on unmount, allowing the last subscriber to choose back implementation. + // Here the last subscriber is the parent component onBackButtonPress={() => this.setState({ isVisible: false })} onBackdropPress={() => this.setState({ isVisible: false })} hideModalContentWhileAnimating={true}> diff --git a/src/components/transaction/header/TransactionHeaderComponent.tsx b/src/components/transaction/header/TransactionHeaderComponent.tsx index a61e78649..7e8299be4 100644 --- a/src/components/transaction/header/TransactionHeaderComponent.tsx +++ b/src/components/transaction/header/TransactionHeaderComponent.tsx @@ -2,7 +2,6 @@ import { Text, View } from 'native-base'; import React from 'react'; import I18nManager from '../../../I18n/I18nManager'; -import BaseScreen from '../../../screens/base-screen/BaseScreen'; import BaseProps from '../../../types/BaseProps'; import Transaction from '../../../types/Transaction'; import Utils from '../../../utils/Utils'; @@ -16,7 +15,7 @@ export interface Props extends BaseProps { } interface State {} -export default class TransactionHeaderComponent extends BaseScreen { +export default class TransactionHeaderComponent extends React.Component { public state: State; public props: Props; diff --git a/src/provider/CentralServerProvider.tsx b/src/provider/CentralServerProvider.tsx index c5100147d..f2264bf47 100644 --- a/src/provider/CentralServerProvider.tsx +++ b/src/provider/CentralServerProvider.tsx @@ -152,7 +152,7 @@ export default class CentralServerProvider { let tenantLogo = this.tenantLogosCache.get(tenant.subdomain); if (!tenantLogo) { // Call backend - const result = await this.axiosInstance.get(`${this.buildCentralRestServerServiceUtilURL(tenant)}/${ServerAction.TENANT_LOGO}`, { + const result = await this.axiosInstance.get(this.buildUtilRestEndpointUrl(ServerRoute.REST_TENANT_LOGO), { headers: this.buildHeaders(), responseType: 'arraybuffer', params: { @@ -542,7 +542,7 @@ export default class CentralServerProvider { // Build Sorting this.buildSorting(sorting, params); // Call - const result = await this.axiosInstance.get(`${this.buildCentralRestServerServiceSecuredURL()}/${ServerAction.SITES}`, { + const result = await this.axiosInstance.get(this.buildRestEndpointUrl(ServerRoute.REST_SITES), { headers: this.buildSecuredHeaders(), params }); @@ -878,11 +878,10 @@ export default class CentralServerProvider { let foundSiteImage = this.siteImagesCache.get(id); if (!foundSiteImage) { // Call backend - const result = await this.axiosInstance.get(`${this.buildCentralRestServerServiceUtilURL(this.tenant)}/${ServerAction.SITE_IMAGE}`, { + const result = await this.axiosInstance.get(this.buildUtilRestEndpointUrl(ServerRoute.REST_SITE_IMAGE, { id }), { headers: this.buildHeaders(), responseType: 'arraybuffer', params: { - ID: id, TenantID: this.decodedToken?.tenantID } }); diff --git a/src/screens/auth/AuthHeader.tsx b/src/screens/auth/AuthHeader.tsx index 7572e6cb6..7315209df 100644 --- a/src/screens/auth/AuthHeader.tsx +++ b/src/screens/auth/AuthHeader.tsx @@ -5,7 +5,6 @@ import { Image, ImageStyle } from 'react-native'; import DeviceInfo from 'react-native-device-info'; import BaseProps from '../../types/BaseProps'; -import BaseScreen from '../base-screen/BaseScreen'; import computeStyleSheet from './AuthStyles'; export interface Props extends BaseProps { @@ -15,15 +14,10 @@ export interface Props extends BaseProps { interface State {} -export default class AuthHeader extends BaseScreen { +export default class AuthHeader extends React.Component{ public state: State; public props: Props; - // eslint-disable-next-line no-useless-constructor - public constructor(props: Props) { - super(props); - } - public setState = ( state: State | ((prevState: Readonly, props: Readonly) => State | Pick) | Pick, callback?: () => void diff --git a/src/screens/auth/eula/Eula.tsx b/src/screens/auth/eula/Eula.tsx index 4e76b38c0..f32862dc6 100644 --- a/src/screens/auth/eula/Eula.tsx +++ b/src/screens/auth/eula/Eula.tsx @@ -61,13 +61,6 @@ export default class Eula extends BaseScreen { } }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.navigate('Login'); - // Do not bubble up - return true; - }; - public render() { const style = computeStyleSheet(); const { eulaTextHtml, loading } = this.state; diff --git a/src/screens/auth/login/Login.tsx b/src/screens/auth/login/Login.tsx index c12c51c24..f528d5082 100644 --- a/src/screens/auth/login/Login.tsx +++ b/src/screens/auth/login/Login.tsx @@ -1,16 +1,7 @@ import I18n from 'i18n-js'; import { Button, CheckBox, Form, Icon, Item, Spinner, Text, View } from 'native-base'; import React from 'react'; -import { - BackHandler, - Keyboard, - KeyboardAvoidingView, - NativeEventSubscription, - ScrollView, - TextInput, - TouchableOpacity -} from 'react-native'; - +import { BackHandler, Keyboard, KeyboardAvoidingView, ScrollView, TextInput, TouchableOpacity } from 'react-native'; import DialogModal from '../../../components/modal/DialogModal'; import ExitAppDialog from '../../../components/modal/exit-app/ExitAppDialog'; import computeModalCommonStyle from '../../../components/modal/ModalCommonStyle'; @@ -53,7 +44,6 @@ export default class Login extends BaseScreen { public props: Props; private tenants: TenantConnection[] = []; private passwordInput: TextInput; - private backHandler: NativeEventSubscription; private formValidationDef = { tenantSubDomain: { presence: { @@ -114,8 +104,6 @@ export default class Login extends BaseScreen { public async componentDidMount() { await super.componentDidMount(); - // Bind the back button to the onBack method (Android) - this.backHandler = BackHandler.addEventListener('hardwareBackPress', this.onBack.bind(this)); let email = (this.state.email = ''); let password = (this.state.password = ''); let tenant: TenantConnection; @@ -174,10 +162,8 @@ export default class Login extends BaseScreen { public async componentDidFocus() { super.componentDidFocus(); - // Bind the back button to the onBack method (Android) - this.backHandler = BackHandler.addEventListener('hardwareBackPress', this.onBack.bind(this)); const tenantSubDomain = Utils.getParamFromNavigation(this.props.route, 'tenantSubDomain', this.state.tenantSubDomain); - // Check if current Tenant selection is still valid (handle delete tenant usee case) + // Check if current Tenant selection is still valid (handle delete tenant use case) if (tenantSubDomain) { // Get the current Tenant const tenant = await this.centralServerProvider.getTenant(tenantSubDomain.toString()); @@ -202,18 +188,6 @@ export default class Login extends BaseScreen { } } - public componentWillUnmount() { - super.componentWillUnmount(); - // Unbind the back button and reset its default behavior (Android) - this.backHandler.remove(); - } - - public componentDidBlur() { - super.componentDidBlur(); - // Unbind the back button and reset its default behavior (Android) - this.backHandler.remove(); - } - public async checkAutoLogin(tenant: TenantConnection, email: string, password: string) { // Check if user can be logged if ( diff --git a/src/screens/auth/reset-password/ResetPassword.tsx b/src/screens/auth/reset-password/ResetPassword.tsx index 275191ec3..47dbee20b 100644 --- a/src/screens/auth/reset-password/ResetPassword.tsx +++ b/src/screens/auth/reset-password/ResetPassword.tsx @@ -92,10 +92,6 @@ export default class ResetPassword extends BaseScreen { this.centralServerProvider.setAutoLoginDisabled(true); } - public recaptchaResponseToken = (captcha: string) => { - this.setState({ captcha }); - }; - public resetPassword = async () => { // Check field const formIsValid = Utils.validateInput(this, this.formValidationDef); @@ -148,13 +144,6 @@ export default class ResetPassword extends BaseScreen { } }; - public onBack = (): boolean => { - // Back mobile button: Force navigation - this.props.navigation.navigate('Login'); - // Do not bubble up - return true; - }; - public render() { const style = computeStyleSheet(); const formStyle = computeFormStyleSheet(); diff --git a/src/screens/auth/retrieve-password/RetrievePassword.tsx b/src/screens/auth/retrieve-password/RetrievePassword.tsx index 77122af66..03446958c 100644 --- a/src/screens/auth/retrieve-password/RetrievePassword.tsx +++ b/src/screens/auth/retrieve-password/RetrievePassword.tsx @@ -134,13 +134,6 @@ export default class RetrievePassword extends BaseScreen { } }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.navigate('Login'); - // Do not bubble up - return true; - }; - public render() { const style = computeStyleSheet(); const formStyle = computeFormStyleSheet(); diff --git a/src/screens/auth/sign-up/SignUp.tsx b/src/screens/auth/sign-up/SignUp.tsx index 0af690f4c..f193ef328 100644 --- a/src/screens/auth/sign-up/SignUp.tsx +++ b/src/screens/auth/sign-up/SignUp.tsx @@ -214,7 +214,7 @@ export default class SignUp extends BaseScreen { } }; - public onBack = (): boolean => { + public onBack(): boolean { // Back mobile button: Force navigation this.props.navigation.navigate('Login', { tenantSubDomain: this.state.tenantSubDomain diff --git a/src/screens/base-screen/BaseAutoRefreshScreen.tsx b/src/screens/base-screen/BaseAutoRefreshScreen.tsx index 84d30ef90..2db4d32b3 100644 --- a/src/screens/base-screen/BaseAutoRefreshScreen.tsx +++ b/src/screens/base-screen/BaseAutoRefreshScreen.tsx @@ -60,10 +60,6 @@ export default class BaseAutoRefreshScreen extends BaseScreen - // Not Handled: has to be taken in the sub-classes - false; - public setActive(active: boolean) { this.timerRefreshActive = active; } diff --git a/src/screens/base-screen/BaseScreen.tsx b/src/screens/base-screen/BaseScreen.tsx index a0fbc826c..e077353ce 100644 --- a/src/screens/base-screen/BaseScreen.tsx +++ b/src/screens/base-screen/BaseScreen.tsx @@ -6,6 +6,7 @@ import CentralServerProvider from '../../provider/CentralServerProvider'; import ProviderFactory from '../../provider/ProviderFactory'; import SecurityProvider from '../../provider/SecurityProvider'; import BaseProps from '../../types/BaseProps'; +import { AppStateStatus, BackHandler, NativeEventSubscription } from 'react-native'; export interface Props extends BaseProps {} @@ -19,6 +20,7 @@ export default class BaseScreen extends React.Component { private screenFilters: ScreenFilters; private componentFocusUnsubscribe: () => void; private componentBlurUnsubscribe: () => void; + backHandler: NativeEventSubscription; public constructor(props: Props) { super(props); @@ -30,12 +32,15 @@ export default class BaseScreen extends React.Component { } public async componentDidMount() { + const { navigation } = this.props; // Get providers this.centralServerProvider = await ProviderFactory.getProvider(); - this.securityProvider = this.centralServerProvider.getSecurityProvider(); + this.securityProvider = this.centralServerProvider?.getSecurityProvider(); // Add listeners - this.componentFocusUnsubscribe = this.props.navigation.addListener('focus', this.componentDidFocus.bind(this)); - this.componentBlurUnsubscribe = this.props.navigation.addListener('blur', this.componentDidBlur.bind(this)); + this.componentFocusUnsubscribe = navigation?.addListener('focus', () => this.componentDidFocus()); + this.componentBlurUnsubscribe = navigation?.addListener('blur', () => this.componentDidBlur()); + // Bind the back button to the onBack method (Android) + this.backHandler = BackHandler.addEventListener('hardwareBackPress', () => this.onBack()); // Ok this.mounted = true; } @@ -44,6 +49,8 @@ export default class BaseScreen extends React.Component { this.mounted = false; this.componentFocusUnsubscribe?.(); this.componentBlurUnsubscribe?.(); + // Unbind the back button and reset its default behavior (Android) + this.backHandler.remove(); } public setHeaderComponent(headerComponent: HeaderComponent) { @@ -75,11 +82,17 @@ export default class BaseScreen extends React.Component { } public onBack(): boolean { - // Not Handled: has to be taken in the sub-classes + this.props.navigation.goBack(); return true; } - public componentDidFocus(): void {} + public componentDidFocus(): void { + // Bind the back button to the onBack method (Android) + this.backHandler = BackHandler.addEventListener('hardwareBackPress', () => this.onBack()); + } - public componentDidBlur(): void {} + public componentDidBlur(): void { + // Unbind the back button and reset its default behavior (Android) + this.backHandler.remove(); + } } diff --git a/src/screens/cars/CarCatalogs.tsx b/src/screens/cars/CarCatalogs.tsx index e143d898a..41dbdc799 100644 --- a/src/screens/cars/CarCatalogs.tsx +++ b/src/screens/cars/CarCatalogs.tsx @@ -98,13 +98,6 @@ export default class CarCatalogs extends SelectableList { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public onEndScroll = async (): Promise => { const { count, skip, limit } = this.state; // No reached the end? diff --git a/src/screens/cars/Cars.tsx b/src/screens/cars/Cars.tsx index dfc3d4add..caa18b4e5 100644 --- a/src/screens/cars/Cars.tsx +++ b/src/screens/cars/Cars.tsx @@ -71,6 +71,7 @@ export default class Cars extends SelectableList { } public async componentDidFocus() { + super.componentDidFocus(); Orientation.lockToPortrait(); this.setState({ refreshing: true }); await this.refresh(); diff --git a/src/screens/charging-stations/actions/ChargingStationActions.tsx b/src/screens/charging-stations/actions/ChargingStationActions.tsx index 4cc8d245a..e1a65cbac 100644 --- a/src/screens/charging-stations/actions/ChargingStationActions.tsx +++ b/src/screens/charging-stations/actions/ChargingStationActions.tsx @@ -208,13 +208,6 @@ export default class ChargingStationActions extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public refresh = async () => { if (this.isMounted()) { const spinnerConnectors = new Map(); diff --git a/src/screens/charging-stations/list/ChargingStations.tsx b/src/screens/charging-stations/list/ChargingStations.tsx index 0001bf667..9e63c5e38 100644 --- a/src/screens/charging-stations/list/ChargingStations.tsx +++ b/src/screens/charging-stations/list/ChargingStations.tsx @@ -64,7 +64,6 @@ export default class ChargingStations extends BaseAutoRefreshScreen { + public onBack (): boolean { if (!this.state.showMap) { this.setState({ showMap: true }, () => this.refresh()); return true; diff --git a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx index 42c82df88..4f7f5b54d 100644 --- a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx +++ b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx @@ -115,13 +115,6 @@ export default class ChargingStationOcppParameters extends BaseScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public requestChargingStationOcppParametersConfirm() { const { chargingStation } = this.state; Alert.alert( diff --git a/src/screens/charging-stations/properties/ChargingStationProperties.tsx b/src/screens/charging-stations/properties/ChargingStationProperties.tsx index cb2e3deed..0d3f06d0c 100644 --- a/src/screens/charging-stations/properties/ChargingStationProperties.tsx +++ b/src/screens/charging-stations/properties/ChargingStationProperties.tsx @@ -1,4 +1,3 @@ -import { DrawerActions } from '@react-navigation/native'; import I18n from 'i18n-js'; import { Container, Spinner, Text, View } from 'native-base'; import React from 'react'; @@ -153,13 +152,6 @@ export default class ChargingStationProperties extends BaseScreen this.setState({ refreshing: false }); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/payment-methods/PaymentMethods.tsx b/src/screens/payment-methods/PaymentMethods.tsx index 66c59df47..f926a88cc 100644 --- a/src/screens/payment-methods/PaymentMethods.tsx +++ b/src/screens/payment-methods/PaymentMethods.tsx @@ -72,6 +72,7 @@ export default class PaymentMethods extends SelectableList } public async componentDidFocus() { + super.componentDidFocus(); this.setState({ refreshing: true }); await this.refresh(); } diff --git a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx index bbdcd9b52..70aba6213 100644 --- a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx +++ b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx @@ -2,8 +2,9 @@ import { CardField, CardFieldInput, initStripe, useConfirmSetupIntent } from '@s import I18n from 'i18n-js'; import { Button, CheckBox, Spinner, View } from 'native-base'; import React, { useEffect, useState } from 'react'; -import { Text, TouchableOpacity } from 'react-native'; +import { BackHandler, Text, TouchableOpacity } from 'react-native'; import { scale } from 'react-native-size-matters'; +import { useFocusEffect } from '@react-navigation/native'; import HeaderComponent from '../../../components/header/HeaderComponent'; import CentralServerProvider from '../../../provider/CentralServerProvider'; @@ -33,6 +34,17 @@ export default function StripePaymentMethodCreationForm(props: Props) { }); }); + useFocusEffect(React.useCallback(() => { + const backHandler = BackHandler.addEventListener('hardwareBackPress', () => onBack()); + return () => backHandler.remove(); + }, []) + ); + + function onBack(): boolean { + props.navigation.goBack(); + return true; + } + async function setUp(): Promise { const csProvider = await ProviderFactory.getProvider(); setProvider(csProvider); diff --git a/src/screens/sidebar/SideBar.tsx b/src/screens/sidebar/SideBar.tsx index 2bdf22239..9071fa606 100644 --- a/src/screens/sidebar/SideBar.tsx +++ b/src/screens/sidebar/SideBar.tsx @@ -13,8 +13,10 @@ import BaseProps from '../../types/BaseProps'; import User from '../../types/User'; import UserToken from '../../types/UserToken'; import Utils from '../../utils/Utils'; -import BaseScreen from '../base-screen/BaseScreen'; import computeStyleSheet from './SideBarStyles'; +import CentralServerProvider from '../../provider/CentralServerProvider'; +import ProviderFactory from '../../provider/ProviderFactory'; +import SecurityProvider from '../../provider/SecurityProvider'; export interface Props extends BaseProps {} @@ -27,12 +29,18 @@ interface State { appVersion?: CheckVersionResponse; } -export default class SideBar extends BaseScreen { +export default class SideBar extends React.Component { public state: State; public props: Props; + private centralServerProvider: CentralServerProvider; + private securityProvider: SecurityProvider; + private componentFocusUnsubscribe: () => void; + private componentBlurUnsubscribe: () => void; public constructor(props: Props) { super(props); + this.componentFocusUnsubscribe = this.props.navigation?.addListener('focus', () => this.componentDidFocus()); + this.componentBlurUnsubscribe = this.props.navigation?.addListener('blur', () => this.componentDidFocus()); this.state = { userToken: null, tenantName: '', @@ -50,13 +58,19 @@ export default class SideBar extends BaseScreen { super.setState(state, callback); }; - public async componentDidMount() { - await super.componentDidMount(); + public async componentDidFocus(): Promise { + this.centralServerProvider = await ProviderFactory.getProvider(); + this.securityProvider = this.centralServerProvider?.getSecurityProvider(); await this.getUpdateDate(); // Init User (delay it) this.refresh(); } + public componentWillUnmount() { + this.componentFocusUnsubscribe?.(); + this.componentBlurUnsubscribe?.(); + } + public refresh = async () => { await this.getUserInfo(); const appVersion = await checkVersion(); diff --git a/src/screens/site-areas/SiteAreas.tsx b/src/screens/site-areas/SiteAreas.tsx index c66c9f675..0f5967e47 100644 --- a/src/screens/site-areas/SiteAreas.tsx +++ b/src/screens/site-areas/SiteAreas.tsx @@ -120,15 +120,15 @@ export default class SiteAreas extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.siteAreas)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(siteAreas: SiteArea[]): Promise { diff --git a/src/screens/sites/Sites.tsx b/src/screens/sites/Sites.tsx index 8af840df1..ae6aa3a2e 100644 --- a/src/screens/sites/Sites.tsx +++ b/src/screens/sites/Sites.tsx @@ -118,15 +118,15 @@ export default class Sites extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.sites)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); + this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(sites: Site[]): Promise { diff --git a/src/screens/transactions/chart/TransactionChart.tsx b/src/screens/transactions/chart/TransactionChart.tsx index 19f009ef2..e44fdbb76 100644 --- a/src/screens/transactions/chart/TransactionChart.tsx +++ b/src/screens/transactions/chart/TransactionChart.tsx @@ -60,6 +60,10 @@ export default class TransactionChart extends BaseAutoRefreshScreen { + await super.componentDidMount(); + } + public setState = ( state: State | ((prevState: Readonly, props: Readonly) => State | Pick) | Pick, callback?: () => void @@ -346,13 +350,6 @@ export default class TransactionChart extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/transactions/details/TransactionDetails.tsx b/src/screens/transactions/details/TransactionDetails.tsx index 804742768..ab4872615 100644 --- a/src/screens/transactions/details/TransactionDetails.tsx +++ b/src/screens/transactions/details/TransactionDetails.tsx @@ -231,15 +231,7 @@ export default class TransactionDetails extends BaseScreen { ); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { - const { navigation } = this.props; const style = computeStyleSheet(); const { transaction } = this.state; const { loading, siteImage, isPricingActive } = this.state; diff --git a/src/screens/transactions/history/TransactionsHistory.tsx b/src/screens/transactions/history/TransactionsHistory.tsx index f42852b0a..f99835663 100644 --- a/src/screens/transactions/history/TransactionsHistory.tsx +++ b/src/screens/transactions/history/TransactionsHistory.tsx @@ -136,13 +136,6 @@ export default class TransactionsHistory extends BaseScreen { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); - // Do not bubble up - return true; - }; - public async refresh() { // Component Mounted? if (this.isMounted()) { diff --git a/src/types/Server.tsx b/src/types/Server.tsx index 01263e695..94658acf0 100644 --- a/src/types/Server.tsx +++ b/src/types/Server.tsx @@ -562,6 +562,7 @@ export enum ServerRoute { REST_TENANTS = 'tenants', REST_TENANT = 'tenants/:id', + REST_TENANT_LOGO = 'tenant/:id/logo', REST_COMPANIES = 'companies', REST_COMPANY = 'companies/:id', @@ -618,6 +619,15 @@ export enum ServerRoute { REST_SITE_AREA_ASSIGN_ASSETS = 'site-areas/:id/assets/assign', REST_SITE_AREA_REMOVE_ASSETS = 'site-areas/:id/assets/unassign', + REST_SITES = 'sites', + REST_SITE = 'sites/:id', + REST_SITE_USERS = 'sites/:id/users', + REST_SITE_ADD_USERS = 'sites/:id/users/assign', + REST_SITE_REMOVE_USERS = 'sites/:id/users/unassign', + REST_SITE_ADMIN = 'sites/:id/users/admin', + REST_SITE_OWNER = 'sites/:id/users/owner', + REST_SITE_IMAGE = 'sites/:id/image', + // BILLING URLs for CRUD operations on PAYMENT METHODS REST_BILLING_PAYMENT_METHODS = 'users/:userID/payment-methods', REST_BILLING_PAYMENT_METHOD = 'users/:userID/payment-methods/:paymentMethodID',
extends BaseScreen - // Not Handled: has to be taken in the sub-classes - false; - public setActive(active: boolean) { this.timerRefreshActive = active; } diff --git a/src/screens/base-screen/BaseScreen.tsx b/src/screens/base-screen/BaseScreen.tsx index a0fbc826c..e077353ce 100644 --- a/src/screens/base-screen/BaseScreen.tsx +++ b/src/screens/base-screen/BaseScreen.tsx @@ -6,6 +6,7 @@ import CentralServerProvider from '../../provider/CentralServerProvider'; import ProviderFactory from '../../provider/ProviderFactory'; import SecurityProvider from '../../provider/SecurityProvider'; import BaseProps from '../../types/BaseProps'; +import { AppStateStatus, BackHandler, NativeEventSubscription } from 'react-native'; export interface Props extends BaseProps {} @@ -19,6 +20,7 @@ export default class BaseScreen extends React.Component { private screenFilters: ScreenFilters; private componentFocusUnsubscribe: () => void; private componentBlurUnsubscribe: () => void; + backHandler: NativeEventSubscription; public constructor(props: Props) { super(props); @@ -30,12 +32,15 @@ export default class BaseScreen extends React.Component { } public async componentDidMount() { + const { navigation } = this.props; // Get providers this.centralServerProvider = await ProviderFactory.getProvider(); - this.securityProvider = this.centralServerProvider.getSecurityProvider(); + this.securityProvider = this.centralServerProvider?.getSecurityProvider(); // Add listeners - this.componentFocusUnsubscribe = this.props.navigation.addListener('focus', this.componentDidFocus.bind(this)); - this.componentBlurUnsubscribe = this.props.navigation.addListener('blur', this.componentDidBlur.bind(this)); + this.componentFocusUnsubscribe = navigation?.addListener('focus', () => this.componentDidFocus()); + this.componentBlurUnsubscribe = navigation?.addListener('blur', () => this.componentDidBlur()); + // Bind the back button to the onBack method (Android) + this.backHandler = BackHandler.addEventListener('hardwareBackPress', () => this.onBack()); // Ok this.mounted = true; } @@ -44,6 +49,8 @@ export default class BaseScreen extends React.Component { this.mounted = false; this.componentFocusUnsubscribe?.(); this.componentBlurUnsubscribe?.(); + // Unbind the back button and reset its default behavior (Android) + this.backHandler.remove(); } public setHeaderComponent(headerComponent: HeaderComponent) { @@ -75,11 +82,17 @@ export default class BaseScreen extends React.Component { } public onBack(): boolean { - // Not Handled: has to be taken in the sub-classes + this.props.navigation.goBack(); return true; } - public componentDidFocus(): void {} + public componentDidFocus(): void { + // Bind the back button to the onBack method (Android) + this.backHandler = BackHandler.addEventListener('hardwareBackPress', () => this.onBack()); + } - public componentDidBlur(): void {} + public componentDidBlur(): void { + // Unbind the back button and reset its default behavior (Android) + this.backHandler.remove(); + } } diff --git a/src/screens/cars/CarCatalogs.tsx b/src/screens/cars/CarCatalogs.tsx index e143d898a..41dbdc799 100644 --- a/src/screens/cars/CarCatalogs.tsx +++ b/src/screens/cars/CarCatalogs.tsx @@ -98,13 +98,6 @@ export default class CarCatalogs extends SelectableList { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public onEndScroll = async (): Promise => { const { count, skip, limit } = this.state; // No reached the end? diff --git a/src/screens/cars/Cars.tsx b/src/screens/cars/Cars.tsx index dfc3d4add..caa18b4e5 100644 --- a/src/screens/cars/Cars.tsx +++ b/src/screens/cars/Cars.tsx @@ -71,6 +71,7 @@ export default class Cars extends SelectableList { } public async componentDidFocus() { + super.componentDidFocus(); Orientation.lockToPortrait(); this.setState({ refreshing: true }); await this.refresh(); diff --git a/src/screens/charging-stations/actions/ChargingStationActions.tsx b/src/screens/charging-stations/actions/ChargingStationActions.tsx index 4cc8d245a..e1a65cbac 100644 --- a/src/screens/charging-stations/actions/ChargingStationActions.tsx +++ b/src/screens/charging-stations/actions/ChargingStationActions.tsx @@ -208,13 +208,6 @@ export default class ChargingStationActions extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public refresh = async () => { if (this.isMounted()) { const spinnerConnectors = new Map(); diff --git a/src/screens/charging-stations/list/ChargingStations.tsx b/src/screens/charging-stations/list/ChargingStations.tsx index 0001bf667..9e63c5e38 100644 --- a/src/screens/charging-stations/list/ChargingStations.tsx +++ b/src/screens/charging-stations/list/ChargingStations.tsx @@ -64,7 +64,6 @@ export default class ChargingStations extends BaseAutoRefreshScreen { + public onBack (): boolean { if (!this.state.showMap) { this.setState({ showMap: true }, () => this.refresh()); return true; diff --git a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx index 42c82df88..4f7f5b54d 100644 --- a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx +++ b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx @@ -115,13 +115,6 @@ export default class ChargingStationOcppParameters extends BaseScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public requestChargingStationOcppParametersConfirm() { const { chargingStation } = this.state; Alert.alert( diff --git a/src/screens/charging-stations/properties/ChargingStationProperties.tsx b/src/screens/charging-stations/properties/ChargingStationProperties.tsx index cb2e3deed..0d3f06d0c 100644 --- a/src/screens/charging-stations/properties/ChargingStationProperties.tsx +++ b/src/screens/charging-stations/properties/ChargingStationProperties.tsx @@ -1,4 +1,3 @@ -import { DrawerActions } from '@react-navigation/native'; import I18n from 'i18n-js'; import { Container, Spinner, Text, View } from 'native-base'; import React from 'react'; @@ -153,13 +152,6 @@ export default class ChargingStationProperties extends BaseScreen this.setState({ refreshing: false }); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/payment-methods/PaymentMethods.tsx b/src/screens/payment-methods/PaymentMethods.tsx index 66c59df47..f926a88cc 100644 --- a/src/screens/payment-methods/PaymentMethods.tsx +++ b/src/screens/payment-methods/PaymentMethods.tsx @@ -72,6 +72,7 @@ export default class PaymentMethods extends SelectableList } public async componentDidFocus() { + super.componentDidFocus(); this.setState({ refreshing: true }); await this.refresh(); } diff --git a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx index bbdcd9b52..70aba6213 100644 --- a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx +++ b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx @@ -2,8 +2,9 @@ import { CardField, CardFieldInput, initStripe, useConfirmSetupIntent } from '@s import I18n from 'i18n-js'; import { Button, CheckBox, Spinner, View } from 'native-base'; import React, { useEffect, useState } from 'react'; -import { Text, TouchableOpacity } from 'react-native'; +import { BackHandler, Text, TouchableOpacity } from 'react-native'; import { scale } from 'react-native-size-matters'; +import { useFocusEffect } from '@react-navigation/native'; import HeaderComponent from '../../../components/header/HeaderComponent'; import CentralServerProvider from '../../../provider/CentralServerProvider'; @@ -33,6 +34,17 @@ export default function StripePaymentMethodCreationForm(props: Props) { }); }); + useFocusEffect(React.useCallback(() => { + const backHandler = BackHandler.addEventListener('hardwareBackPress', () => onBack()); + return () => backHandler.remove(); + }, []) + ); + + function onBack(): boolean { + props.navigation.goBack(); + return true; + } + async function setUp(): Promise { const csProvider = await ProviderFactory.getProvider(); setProvider(csProvider); diff --git a/src/screens/sidebar/SideBar.tsx b/src/screens/sidebar/SideBar.tsx index 2bdf22239..9071fa606 100644 --- a/src/screens/sidebar/SideBar.tsx +++ b/src/screens/sidebar/SideBar.tsx @@ -13,8 +13,10 @@ import BaseProps from '../../types/BaseProps'; import User from '../../types/User'; import UserToken from '../../types/UserToken'; import Utils from '../../utils/Utils'; -import BaseScreen from '../base-screen/BaseScreen'; import computeStyleSheet from './SideBarStyles'; +import CentralServerProvider from '../../provider/CentralServerProvider'; +import ProviderFactory from '../../provider/ProviderFactory'; +import SecurityProvider from '../../provider/SecurityProvider'; export interface Props extends BaseProps {} @@ -27,12 +29,18 @@ interface State { appVersion?: CheckVersionResponse; } -export default class SideBar extends BaseScreen { +export default class SideBar extends React.Component { public state: State; public props: Props; + private centralServerProvider: CentralServerProvider; + private securityProvider: SecurityProvider; + private componentFocusUnsubscribe: () => void; + private componentBlurUnsubscribe: () => void; public constructor(props: Props) { super(props); + this.componentFocusUnsubscribe = this.props.navigation?.addListener('focus', () => this.componentDidFocus()); + this.componentBlurUnsubscribe = this.props.navigation?.addListener('blur', () => this.componentDidFocus()); this.state = { userToken: null, tenantName: '', @@ -50,13 +58,19 @@ export default class SideBar extends BaseScreen { super.setState(state, callback); }; - public async componentDidMount() { - await super.componentDidMount(); + public async componentDidFocus(): Promise { + this.centralServerProvider = await ProviderFactory.getProvider(); + this.securityProvider = this.centralServerProvider?.getSecurityProvider(); await this.getUpdateDate(); // Init User (delay it) this.refresh(); } + public componentWillUnmount() { + this.componentFocusUnsubscribe?.(); + this.componentBlurUnsubscribe?.(); + } + public refresh = async () => { await this.getUserInfo(); const appVersion = await checkVersion(); diff --git a/src/screens/site-areas/SiteAreas.tsx b/src/screens/site-areas/SiteAreas.tsx index c66c9f675..0f5967e47 100644 --- a/src/screens/site-areas/SiteAreas.tsx +++ b/src/screens/site-areas/SiteAreas.tsx @@ -120,15 +120,15 @@ export default class SiteAreas extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.siteAreas)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(siteAreas: SiteArea[]): Promise { diff --git a/src/screens/sites/Sites.tsx b/src/screens/sites/Sites.tsx index 8af840df1..ae6aa3a2e 100644 --- a/src/screens/sites/Sites.tsx +++ b/src/screens/sites/Sites.tsx @@ -118,15 +118,15 @@ export default class Sites extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.sites)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); + this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(sites: Site[]): Promise { diff --git a/src/screens/transactions/chart/TransactionChart.tsx b/src/screens/transactions/chart/TransactionChart.tsx index 19f009ef2..e44fdbb76 100644 --- a/src/screens/transactions/chart/TransactionChart.tsx +++ b/src/screens/transactions/chart/TransactionChart.tsx @@ -60,6 +60,10 @@ export default class TransactionChart extends BaseAutoRefreshScreen { + await super.componentDidMount(); + } + public setState = ( state: State | ((prevState: Readonly, props: Readonly) => State | Pick) | Pick, callback?: () => void @@ -346,13 +350,6 @@ export default class TransactionChart extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/transactions/details/TransactionDetails.tsx b/src/screens/transactions/details/TransactionDetails.tsx index 804742768..ab4872615 100644 --- a/src/screens/transactions/details/TransactionDetails.tsx +++ b/src/screens/transactions/details/TransactionDetails.tsx @@ -231,15 +231,7 @@ export default class TransactionDetails extends BaseScreen { ); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { - const { navigation } = this.props; const style = computeStyleSheet(); const { transaction } = this.state; const { loading, siteImage, isPricingActive } = this.state; diff --git a/src/screens/transactions/history/TransactionsHistory.tsx b/src/screens/transactions/history/TransactionsHistory.tsx index f42852b0a..f99835663 100644 --- a/src/screens/transactions/history/TransactionsHistory.tsx +++ b/src/screens/transactions/history/TransactionsHistory.tsx @@ -136,13 +136,6 @@ export default class TransactionsHistory extends BaseScreen { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); - // Do not bubble up - return true; - }; - public async refresh() { // Component Mounted? if (this.isMounted()) { diff --git a/src/types/Server.tsx b/src/types/Server.tsx index 01263e695..94658acf0 100644 --- a/src/types/Server.tsx +++ b/src/types/Server.tsx @@ -562,6 +562,7 @@ export enum ServerRoute { REST_TENANTS = 'tenants', REST_TENANT = 'tenants/:id', + REST_TENANT_LOGO = 'tenant/:id/logo', REST_COMPANIES = 'companies', REST_COMPANY = 'companies/:id', @@ -618,6 +619,15 @@ export enum ServerRoute { REST_SITE_AREA_ASSIGN_ASSETS = 'site-areas/:id/assets/assign', REST_SITE_AREA_REMOVE_ASSETS = 'site-areas/:id/assets/unassign', + REST_SITES = 'sites', + REST_SITE = 'sites/:id', + REST_SITE_USERS = 'sites/:id/users', + REST_SITE_ADD_USERS = 'sites/:id/users/assign', + REST_SITE_REMOVE_USERS = 'sites/:id/users/unassign', + REST_SITE_ADMIN = 'sites/:id/users/admin', + REST_SITE_OWNER = 'sites/:id/users/owner', + REST_SITE_IMAGE = 'sites/:id/image', + // BILLING URLs for CRUD operations on PAYMENT METHODS REST_BILLING_PAYMENT_METHODS = 'users/:userID/payment-methods', REST_BILLING_PAYMENT_METHOD = 'users/:userID/payment-methods/:paymentMethodID',
extends React.Component { private screenFilters: ScreenFilters; private componentFocusUnsubscribe: () => void; private componentBlurUnsubscribe: () => void; + backHandler: NativeEventSubscription; public constructor(props: Props) { super(props); @@ -30,12 +32,15 @@ export default class BaseScreen extends React.Component { } public async componentDidMount() { + const { navigation } = this.props; // Get providers this.centralServerProvider = await ProviderFactory.getProvider(); - this.securityProvider = this.centralServerProvider.getSecurityProvider(); + this.securityProvider = this.centralServerProvider?.getSecurityProvider(); // Add listeners - this.componentFocusUnsubscribe = this.props.navigation.addListener('focus', this.componentDidFocus.bind(this)); - this.componentBlurUnsubscribe = this.props.navigation.addListener('blur', this.componentDidBlur.bind(this)); + this.componentFocusUnsubscribe = navigation?.addListener('focus', () => this.componentDidFocus()); + this.componentBlurUnsubscribe = navigation?.addListener('blur', () => this.componentDidBlur()); + // Bind the back button to the onBack method (Android) + this.backHandler = BackHandler.addEventListener('hardwareBackPress', () => this.onBack()); // Ok this.mounted = true; } @@ -44,6 +49,8 @@ export default class BaseScreen extends React.Component { this.mounted = false; this.componentFocusUnsubscribe?.(); this.componentBlurUnsubscribe?.(); + // Unbind the back button and reset its default behavior (Android) + this.backHandler.remove(); } public setHeaderComponent(headerComponent: HeaderComponent) { @@ -75,11 +82,17 @@ export default class BaseScreen extends React.Component { } public onBack(): boolean { - // Not Handled: has to be taken in the sub-classes + this.props.navigation.goBack(); return true; } - public componentDidFocus(): void {} + public componentDidFocus(): void { + // Bind the back button to the onBack method (Android) + this.backHandler = BackHandler.addEventListener('hardwareBackPress', () => this.onBack()); + } - public componentDidBlur(): void {} + public componentDidBlur(): void { + // Unbind the back button and reset its default behavior (Android) + this.backHandler.remove(); + } } diff --git a/src/screens/cars/CarCatalogs.tsx b/src/screens/cars/CarCatalogs.tsx index e143d898a..41dbdc799 100644 --- a/src/screens/cars/CarCatalogs.tsx +++ b/src/screens/cars/CarCatalogs.tsx @@ -98,13 +98,6 @@ export default class CarCatalogs extends SelectableList { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public onEndScroll = async (): Promise => { const { count, skip, limit } = this.state; // No reached the end? diff --git a/src/screens/cars/Cars.tsx b/src/screens/cars/Cars.tsx index dfc3d4add..caa18b4e5 100644 --- a/src/screens/cars/Cars.tsx +++ b/src/screens/cars/Cars.tsx @@ -71,6 +71,7 @@ export default class Cars extends SelectableList { } public async componentDidFocus() { + super.componentDidFocus(); Orientation.lockToPortrait(); this.setState({ refreshing: true }); await this.refresh(); diff --git a/src/screens/charging-stations/actions/ChargingStationActions.tsx b/src/screens/charging-stations/actions/ChargingStationActions.tsx index 4cc8d245a..e1a65cbac 100644 --- a/src/screens/charging-stations/actions/ChargingStationActions.tsx +++ b/src/screens/charging-stations/actions/ChargingStationActions.tsx @@ -208,13 +208,6 @@ export default class ChargingStationActions extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public refresh = async () => { if (this.isMounted()) { const spinnerConnectors = new Map(); diff --git a/src/screens/charging-stations/list/ChargingStations.tsx b/src/screens/charging-stations/list/ChargingStations.tsx index 0001bf667..9e63c5e38 100644 --- a/src/screens/charging-stations/list/ChargingStations.tsx +++ b/src/screens/charging-stations/list/ChargingStations.tsx @@ -64,7 +64,6 @@ export default class ChargingStations extends BaseAutoRefreshScreen { + public onBack (): boolean { if (!this.state.showMap) { this.setState({ showMap: true }, () => this.refresh()); return true; diff --git a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx index 42c82df88..4f7f5b54d 100644 --- a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx +++ b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx @@ -115,13 +115,6 @@ export default class ChargingStationOcppParameters extends BaseScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public requestChargingStationOcppParametersConfirm() { const { chargingStation } = this.state; Alert.alert( diff --git a/src/screens/charging-stations/properties/ChargingStationProperties.tsx b/src/screens/charging-stations/properties/ChargingStationProperties.tsx index cb2e3deed..0d3f06d0c 100644 --- a/src/screens/charging-stations/properties/ChargingStationProperties.tsx +++ b/src/screens/charging-stations/properties/ChargingStationProperties.tsx @@ -1,4 +1,3 @@ -import { DrawerActions } from '@react-navigation/native'; import I18n from 'i18n-js'; import { Container, Spinner, Text, View } from 'native-base'; import React from 'react'; @@ -153,13 +152,6 @@ export default class ChargingStationProperties extends BaseScreen this.setState({ refreshing: false }); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/payment-methods/PaymentMethods.tsx b/src/screens/payment-methods/PaymentMethods.tsx index 66c59df47..f926a88cc 100644 --- a/src/screens/payment-methods/PaymentMethods.tsx +++ b/src/screens/payment-methods/PaymentMethods.tsx @@ -72,6 +72,7 @@ export default class PaymentMethods extends SelectableList } public async componentDidFocus() { + super.componentDidFocus(); this.setState({ refreshing: true }); await this.refresh(); } diff --git a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx index bbdcd9b52..70aba6213 100644 --- a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx +++ b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx @@ -2,8 +2,9 @@ import { CardField, CardFieldInput, initStripe, useConfirmSetupIntent } from '@s import I18n from 'i18n-js'; import { Button, CheckBox, Spinner, View } from 'native-base'; import React, { useEffect, useState } from 'react'; -import { Text, TouchableOpacity } from 'react-native'; +import { BackHandler, Text, TouchableOpacity } from 'react-native'; import { scale } from 'react-native-size-matters'; +import { useFocusEffect } from '@react-navigation/native'; import HeaderComponent from '../../../components/header/HeaderComponent'; import CentralServerProvider from '../../../provider/CentralServerProvider'; @@ -33,6 +34,17 @@ export default function StripePaymentMethodCreationForm(props: Props) { }); }); + useFocusEffect(React.useCallback(() => { + const backHandler = BackHandler.addEventListener('hardwareBackPress', () => onBack()); + return () => backHandler.remove(); + }, []) + ); + + function onBack(): boolean { + props.navigation.goBack(); + return true; + } + async function setUp(): Promise { const csProvider = await ProviderFactory.getProvider(); setProvider(csProvider); diff --git a/src/screens/sidebar/SideBar.tsx b/src/screens/sidebar/SideBar.tsx index 2bdf22239..9071fa606 100644 --- a/src/screens/sidebar/SideBar.tsx +++ b/src/screens/sidebar/SideBar.tsx @@ -13,8 +13,10 @@ import BaseProps from '../../types/BaseProps'; import User from '../../types/User'; import UserToken from '../../types/UserToken'; import Utils from '../../utils/Utils'; -import BaseScreen from '../base-screen/BaseScreen'; import computeStyleSheet from './SideBarStyles'; +import CentralServerProvider from '../../provider/CentralServerProvider'; +import ProviderFactory from '../../provider/ProviderFactory'; +import SecurityProvider from '../../provider/SecurityProvider'; export interface Props extends BaseProps {} @@ -27,12 +29,18 @@ interface State { appVersion?: CheckVersionResponse; } -export default class SideBar extends BaseScreen { +export default class SideBar extends React.Component { public state: State; public props: Props; + private centralServerProvider: CentralServerProvider; + private securityProvider: SecurityProvider; + private componentFocusUnsubscribe: () => void; + private componentBlurUnsubscribe: () => void; public constructor(props: Props) { super(props); + this.componentFocusUnsubscribe = this.props.navigation?.addListener('focus', () => this.componentDidFocus()); + this.componentBlurUnsubscribe = this.props.navigation?.addListener('blur', () => this.componentDidFocus()); this.state = { userToken: null, tenantName: '', @@ -50,13 +58,19 @@ export default class SideBar extends BaseScreen { super.setState(state, callback); }; - public async componentDidMount() { - await super.componentDidMount(); + public async componentDidFocus(): Promise { + this.centralServerProvider = await ProviderFactory.getProvider(); + this.securityProvider = this.centralServerProvider?.getSecurityProvider(); await this.getUpdateDate(); // Init User (delay it) this.refresh(); } + public componentWillUnmount() { + this.componentFocusUnsubscribe?.(); + this.componentBlurUnsubscribe?.(); + } + public refresh = async () => { await this.getUserInfo(); const appVersion = await checkVersion(); diff --git a/src/screens/site-areas/SiteAreas.tsx b/src/screens/site-areas/SiteAreas.tsx index c66c9f675..0f5967e47 100644 --- a/src/screens/site-areas/SiteAreas.tsx +++ b/src/screens/site-areas/SiteAreas.tsx @@ -120,15 +120,15 @@ export default class SiteAreas extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.siteAreas)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(siteAreas: SiteArea[]): Promise { diff --git a/src/screens/sites/Sites.tsx b/src/screens/sites/Sites.tsx index 8af840df1..ae6aa3a2e 100644 --- a/src/screens/sites/Sites.tsx +++ b/src/screens/sites/Sites.tsx @@ -118,15 +118,15 @@ export default class Sites extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.sites)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); + this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(sites: Site[]): Promise { diff --git a/src/screens/transactions/chart/TransactionChart.tsx b/src/screens/transactions/chart/TransactionChart.tsx index 19f009ef2..e44fdbb76 100644 --- a/src/screens/transactions/chart/TransactionChart.tsx +++ b/src/screens/transactions/chart/TransactionChart.tsx @@ -60,6 +60,10 @@ export default class TransactionChart extends BaseAutoRefreshScreen { + await super.componentDidMount(); + } + public setState = ( state: State | ((prevState: Readonly, props: Readonly) => State | Pick) | Pick, callback?: () => void @@ -346,13 +350,6 @@ export default class TransactionChart extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/transactions/details/TransactionDetails.tsx b/src/screens/transactions/details/TransactionDetails.tsx index 804742768..ab4872615 100644 --- a/src/screens/transactions/details/TransactionDetails.tsx +++ b/src/screens/transactions/details/TransactionDetails.tsx @@ -231,15 +231,7 @@ export default class TransactionDetails extends BaseScreen { ); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { - const { navigation } = this.props; const style = computeStyleSheet(); const { transaction } = this.state; const { loading, siteImage, isPricingActive } = this.state; diff --git a/src/screens/transactions/history/TransactionsHistory.tsx b/src/screens/transactions/history/TransactionsHistory.tsx index f42852b0a..f99835663 100644 --- a/src/screens/transactions/history/TransactionsHistory.tsx +++ b/src/screens/transactions/history/TransactionsHistory.tsx @@ -136,13 +136,6 @@ export default class TransactionsHistory extends BaseScreen { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); - // Do not bubble up - return true; - }; - public async refresh() { // Component Mounted? if (this.isMounted()) { diff --git a/src/types/Server.tsx b/src/types/Server.tsx index 01263e695..94658acf0 100644 --- a/src/types/Server.tsx +++ b/src/types/Server.tsx @@ -562,6 +562,7 @@ export enum ServerRoute { REST_TENANTS = 'tenants', REST_TENANT = 'tenants/:id', + REST_TENANT_LOGO = 'tenant/:id/logo', REST_COMPANIES = 'companies', REST_COMPANY = 'companies/:id', @@ -618,6 +619,15 @@ export enum ServerRoute { REST_SITE_AREA_ASSIGN_ASSETS = 'site-areas/:id/assets/assign', REST_SITE_AREA_REMOVE_ASSETS = 'site-areas/:id/assets/unassign', + REST_SITES = 'sites', + REST_SITE = 'sites/:id', + REST_SITE_USERS = 'sites/:id/users', + REST_SITE_ADD_USERS = 'sites/:id/users/assign', + REST_SITE_REMOVE_USERS = 'sites/:id/users/unassign', + REST_SITE_ADMIN = 'sites/:id/users/admin', + REST_SITE_OWNER = 'sites/:id/users/owner', + REST_SITE_IMAGE = 'sites/:id/image', + // BILLING URLs for CRUD operations on PAYMENT METHODS REST_BILLING_PAYMENT_METHODS = 'users/:userID/payment-methods', REST_BILLING_PAYMENT_METHOD = 'users/:userID/payment-methods/:paymentMethodID',
extends React.Component { } public async componentDidMount() { + const { navigation } = this.props; // Get providers this.centralServerProvider = await ProviderFactory.getProvider(); - this.securityProvider = this.centralServerProvider.getSecurityProvider(); + this.securityProvider = this.centralServerProvider?.getSecurityProvider(); // Add listeners - this.componentFocusUnsubscribe = this.props.navigation.addListener('focus', this.componentDidFocus.bind(this)); - this.componentBlurUnsubscribe = this.props.navigation.addListener('blur', this.componentDidBlur.bind(this)); + this.componentFocusUnsubscribe = navigation?.addListener('focus', () => this.componentDidFocus()); + this.componentBlurUnsubscribe = navigation?.addListener('blur', () => this.componentDidBlur()); + // Bind the back button to the onBack method (Android) + this.backHandler = BackHandler.addEventListener('hardwareBackPress', () => this.onBack()); // Ok this.mounted = true; } @@ -44,6 +49,8 @@ export default class BaseScreen extends React.Component { this.mounted = false; this.componentFocusUnsubscribe?.(); this.componentBlurUnsubscribe?.(); + // Unbind the back button and reset its default behavior (Android) + this.backHandler.remove(); } public setHeaderComponent(headerComponent: HeaderComponent) { @@ -75,11 +82,17 @@ export default class BaseScreen extends React.Component { } public onBack(): boolean { - // Not Handled: has to be taken in the sub-classes + this.props.navigation.goBack(); return true; } - public componentDidFocus(): void {} + public componentDidFocus(): void { + // Bind the back button to the onBack method (Android) + this.backHandler = BackHandler.addEventListener('hardwareBackPress', () => this.onBack()); + } - public componentDidBlur(): void {} + public componentDidBlur(): void { + // Unbind the back button and reset its default behavior (Android) + this.backHandler.remove(); + } } diff --git a/src/screens/cars/CarCatalogs.tsx b/src/screens/cars/CarCatalogs.tsx index e143d898a..41dbdc799 100644 --- a/src/screens/cars/CarCatalogs.tsx +++ b/src/screens/cars/CarCatalogs.tsx @@ -98,13 +98,6 @@ export default class CarCatalogs extends SelectableList { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public onEndScroll = async (): Promise => { const { count, skip, limit } = this.state; // No reached the end? diff --git a/src/screens/cars/Cars.tsx b/src/screens/cars/Cars.tsx index dfc3d4add..caa18b4e5 100644 --- a/src/screens/cars/Cars.tsx +++ b/src/screens/cars/Cars.tsx @@ -71,6 +71,7 @@ export default class Cars extends SelectableList { } public async componentDidFocus() { + super.componentDidFocus(); Orientation.lockToPortrait(); this.setState({ refreshing: true }); await this.refresh(); diff --git a/src/screens/charging-stations/actions/ChargingStationActions.tsx b/src/screens/charging-stations/actions/ChargingStationActions.tsx index 4cc8d245a..e1a65cbac 100644 --- a/src/screens/charging-stations/actions/ChargingStationActions.tsx +++ b/src/screens/charging-stations/actions/ChargingStationActions.tsx @@ -208,13 +208,6 @@ export default class ChargingStationActions extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public refresh = async () => { if (this.isMounted()) { const spinnerConnectors = new Map(); diff --git a/src/screens/charging-stations/list/ChargingStations.tsx b/src/screens/charging-stations/list/ChargingStations.tsx index 0001bf667..9e63c5e38 100644 --- a/src/screens/charging-stations/list/ChargingStations.tsx +++ b/src/screens/charging-stations/list/ChargingStations.tsx @@ -64,7 +64,6 @@ export default class ChargingStations extends BaseAutoRefreshScreen { + public onBack (): boolean { if (!this.state.showMap) { this.setState({ showMap: true }, () => this.refresh()); return true; diff --git a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx index 42c82df88..4f7f5b54d 100644 --- a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx +++ b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx @@ -115,13 +115,6 @@ export default class ChargingStationOcppParameters extends BaseScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public requestChargingStationOcppParametersConfirm() { const { chargingStation } = this.state; Alert.alert( diff --git a/src/screens/charging-stations/properties/ChargingStationProperties.tsx b/src/screens/charging-stations/properties/ChargingStationProperties.tsx index cb2e3deed..0d3f06d0c 100644 --- a/src/screens/charging-stations/properties/ChargingStationProperties.tsx +++ b/src/screens/charging-stations/properties/ChargingStationProperties.tsx @@ -1,4 +1,3 @@ -import { DrawerActions } from '@react-navigation/native'; import I18n from 'i18n-js'; import { Container, Spinner, Text, View } from 'native-base'; import React from 'react'; @@ -153,13 +152,6 @@ export default class ChargingStationProperties extends BaseScreen this.setState({ refreshing: false }); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/payment-methods/PaymentMethods.tsx b/src/screens/payment-methods/PaymentMethods.tsx index 66c59df47..f926a88cc 100644 --- a/src/screens/payment-methods/PaymentMethods.tsx +++ b/src/screens/payment-methods/PaymentMethods.tsx @@ -72,6 +72,7 @@ export default class PaymentMethods extends SelectableList } public async componentDidFocus() { + super.componentDidFocus(); this.setState({ refreshing: true }); await this.refresh(); } diff --git a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx index bbdcd9b52..70aba6213 100644 --- a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx +++ b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx @@ -2,8 +2,9 @@ import { CardField, CardFieldInput, initStripe, useConfirmSetupIntent } from '@s import I18n from 'i18n-js'; import { Button, CheckBox, Spinner, View } from 'native-base'; import React, { useEffect, useState } from 'react'; -import { Text, TouchableOpacity } from 'react-native'; +import { BackHandler, Text, TouchableOpacity } from 'react-native'; import { scale } from 'react-native-size-matters'; +import { useFocusEffect } from '@react-navigation/native'; import HeaderComponent from '../../../components/header/HeaderComponent'; import CentralServerProvider from '../../../provider/CentralServerProvider'; @@ -33,6 +34,17 @@ export default function StripePaymentMethodCreationForm(props: Props) { }); }); + useFocusEffect(React.useCallback(() => { + const backHandler = BackHandler.addEventListener('hardwareBackPress', () => onBack()); + return () => backHandler.remove(); + }, []) + ); + + function onBack(): boolean { + props.navigation.goBack(); + return true; + } + async function setUp(): Promise { const csProvider = await ProviderFactory.getProvider(); setProvider(csProvider); diff --git a/src/screens/sidebar/SideBar.tsx b/src/screens/sidebar/SideBar.tsx index 2bdf22239..9071fa606 100644 --- a/src/screens/sidebar/SideBar.tsx +++ b/src/screens/sidebar/SideBar.tsx @@ -13,8 +13,10 @@ import BaseProps from '../../types/BaseProps'; import User from '../../types/User'; import UserToken from '../../types/UserToken'; import Utils from '../../utils/Utils'; -import BaseScreen from '../base-screen/BaseScreen'; import computeStyleSheet from './SideBarStyles'; +import CentralServerProvider from '../../provider/CentralServerProvider'; +import ProviderFactory from '../../provider/ProviderFactory'; +import SecurityProvider from '../../provider/SecurityProvider'; export interface Props extends BaseProps {} @@ -27,12 +29,18 @@ interface State { appVersion?: CheckVersionResponse; } -export default class SideBar extends BaseScreen { +export default class SideBar extends React.Component { public state: State; public props: Props; + private centralServerProvider: CentralServerProvider; + private securityProvider: SecurityProvider; + private componentFocusUnsubscribe: () => void; + private componentBlurUnsubscribe: () => void; public constructor(props: Props) { super(props); + this.componentFocusUnsubscribe = this.props.navigation?.addListener('focus', () => this.componentDidFocus()); + this.componentBlurUnsubscribe = this.props.navigation?.addListener('blur', () => this.componentDidFocus()); this.state = { userToken: null, tenantName: '', @@ -50,13 +58,19 @@ export default class SideBar extends BaseScreen { super.setState(state, callback); }; - public async componentDidMount() { - await super.componentDidMount(); + public async componentDidFocus(): Promise { + this.centralServerProvider = await ProviderFactory.getProvider(); + this.securityProvider = this.centralServerProvider?.getSecurityProvider(); await this.getUpdateDate(); // Init User (delay it) this.refresh(); } + public componentWillUnmount() { + this.componentFocusUnsubscribe?.(); + this.componentBlurUnsubscribe?.(); + } + public refresh = async () => { await this.getUserInfo(); const appVersion = await checkVersion(); diff --git a/src/screens/site-areas/SiteAreas.tsx b/src/screens/site-areas/SiteAreas.tsx index c66c9f675..0f5967e47 100644 --- a/src/screens/site-areas/SiteAreas.tsx +++ b/src/screens/site-areas/SiteAreas.tsx @@ -120,15 +120,15 @@ export default class SiteAreas extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.siteAreas)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(siteAreas: SiteArea[]): Promise { diff --git a/src/screens/sites/Sites.tsx b/src/screens/sites/Sites.tsx index 8af840df1..ae6aa3a2e 100644 --- a/src/screens/sites/Sites.tsx +++ b/src/screens/sites/Sites.tsx @@ -118,15 +118,15 @@ export default class Sites extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.sites)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); + this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(sites: Site[]): Promise { diff --git a/src/screens/transactions/chart/TransactionChart.tsx b/src/screens/transactions/chart/TransactionChart.tsx index 19f009ef2..e44fdbb76 100644 --- a/src/screens/transactions/chart/TransactionChart.tsx +++ b/src/screens/transactions/chart/TransactionChart.tsx @@ -60,6 +60,10 @@ export default class TransactionChart extends BaseAutoRefreshScreen { + await super.componentDidMount(); + } + public setState = ( state: State | ((prevState: Readonly, props: Readonly) => State | Pick) | Pick, callback?: () => void @@ -346,13 +350,6 @@ export default class TransactionChart extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/transactions/details/TransactionDetails.tsx b/src/screens/transactions/details/TransactionDetails.tsx index 804742768..ab4872615 100644 --- a/src/screens/transactions/details/TransactionDetails.tsx +++ b/src/screens/transactions/details/TransactionDetails.tsx @@ -231,15 +231,7 @@ export default class TransactionDetails extends BaseScreen { ); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { - const { navigation } = this.props; const style = computeStyleSheet(); const { transaction } = this.state; const { loading, siteImage, isPricingActive } = this.state; diff --git a/src/screens/transactions/history/TransactionsHistory.tsx b/src/screens/transactions/history/TransactionsHistory.tsx index f42852b0a..f99835663 100644 --- a/src/screens/transactions/history/TransactionsHistory.tsx +++ b/src/screens/transactions/history/TransactionsHistory.tsx @@ -136,13 +136,6 @@ export default class TransactionsHistory extends BaseScreen { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); - // Do not bubble up - return true; - }; - public async refresh() { // Component Mounted? if (this.isMounted()) { diff --git a/src/types/Server.tsx b/src/types/Server.tsx index 01263e695..94658acf0 100644 --- a/src/types/Server.tsx +++ b/src/types/Server.tsx @@ -562,6 +562,7 @@ export enum ServerRoute { REST_TENANTS = 'tenants', REST_TENANT = 'tenants/:id', + REST_TENANT_LOGO = 'tenant/:id/logo', REST_COMPANIES = 'companies', REST_COMPANY = 'companies/:id', @@ -618,6 +619,15 @@ export enum ServerRoute { REST_SITE_AREA_ASSIGN_ASSETS = 'site-areas/:id/assets/assign', REST_SITE_AREA_REMOVE_ASSETS = 'site-areas/:id/assets/unassign', + REST_SITES = 'sites', + REST_SITE = 'sites/:id', + REST_SITE_USERS = 'sites/:id/users', + REST_SITE_ADD_USERS = 'sites/:id/users/assign', + REST_SITE_REMOVE_USERS = 'sites/:id/users/unassign', + REST_SITE_ADMIN = 'sites/:id/users/admin', + REST_SITE_OWNER = 'sites/:id/users/owner', + REST_SITE_IMAGE = 'sites/:id/image', + // BILLING URLs for CRUD operations on PAYMENT METHODS REST_BILLING_PAYMENT_METHODS = 'users/:userID/payment-methods', REST_BILLING_PAYMENT_METHOD = 'users/:userID/payment-methods/:paymentMethodID',
extends React.Component { this.mounted = false; this.componentFocusUnsubscribe?.(); this.componentBlurUnsubscribe?.(); + // Unbind the back button and reset its default behavior (Android) + this.backHandler.remove(); } public setHeaderComponent(headerComponent: HeaderComponent) { @@ -75,11 +82,17 @@ export default class BaseScreen extends React.Component { } public onBack(): boolean { - // Not Handled: has to be taken in the sub-classes + this.props.navigation.goBack(); return true; } - public componentDidFocus(): void {} + public componentDidFocus(): void { + // Bind the back button to the onBack method (Android) + this.backHandler = BackHandler.addEventListener('hardwareBackPress', () => this.onBack()); + } - public componentDidBlur(): void {} + public componentDidBlur(): void { + // Unbind the back button and reset its default behavior (Android) + this.backHandler.remove(); + } } diff --git a/src/screens/cars/CarCatalogs.tsx b/src/screens/cars/CarCatalogs.tsx index e143d898a..41dbdc799 100644 --- a/src/screens/cars/CarCatalogs.tsx +++ b/src/screens/cars/CarCatalogs.tsx @@ -98,13 +98,6 @@ export default class CarCatalogs extends SelectableList { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public onEndScroll = async (): Promise => { const { count, skip, limit } = this.state; // No reached the end? diff --git a/src/screens/cars/Cars.tsx b/src/screens/cars/Cars.tsx index dfc3d4add..caa18b4e5 100644 --- a/src/screens/cars/Cars.tsx +++ b/src/screens/cars/Cars.tsx @@ -71,6 +71,7 @@ export default class Cars extends SelectableList { } public async componentDidFocus() { + super.componentDidFocus(); Orientation.lockToPortrait(); this.setState({ refreshing: true }); await this.refresh(); diff --git a/src/screens/charging-stations/actions/ChargingStationActions.tsx b/src/screens/charging-stations/actions/ChargingStationActions.tsx index 4cc8d245a..e1a65cbac 100644 --- a/src/screens/charging-stations/actions/ChargingStationActions.tsx +++ b/src/screens/charging-stations/actions/ChargingStationActions.tsx @@ -208,13 +208,6 @@ export default class ChargingStationActions extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public refresh = async () => { if (this.isMounted()) { const spinnerConnectors = new Map(); diff --git a/src/screens/charging-stations/list/ChargingStations.tsx b/src/screens/charging-stations/list/ChargingStations.tsx index 0001bf667..9e63c5e38 100644 --- a/src/screens/charging-stations/list/ChargingStations.tsx +++ b/src/screens/charging-stations/list/ChargingStations.tsx @@ -64,7 +64,6 @@ export default class ChargingStations extends BaseAutoRefreshScreen { + public onBack (): boolean { if (!this.state.showMap) { this.setState({ showMap: true }, () => this.refresh()); return true; diff --git a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx index 42c82df88..4f7f5b54d 100644 --- a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx +++ b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx @@ -115,13 +115,6 @@ export default class ChargingStationOcppParameters extends BaseScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public requestChargingStationOcppParametersConfirm() { const { chargingStation } = this.state; Alert.alert( diff --git a/src/screens/charging-stations/properties/ChargingStationProperties.tsx b/src/screens/charging-stations/properties/ChargingStationProperties.tsx index cb2e3deed..0d3f06d0c 100644 --- a/src/screens/charging-stations/properties/ChargingStationProperties.tsx +++ b/src/screens/charging-stations/properties/ChargingStationProperties.tsx @@ -1,4 +1,3 @@ -import { DrawerActions } from '@react-navigation/native'; import I18n from 'i18n-js'; import { Container, Spinner, Text, View } from 'native-base'; import React from 'react'; @@ -153,13 +152,6 @@ export default class ChargingStationProperties extends BaseScreen this.setState({ refreshing: false }); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/payment-methods/PaymentMethods.tsx b/src/screens/payment-methods/PaymentMethods.tsx index 66c59df47..f926a88cc 100644 --- a/src/screens/payment-methods/PaymentMethods.tsx +++ b/src/screens/payment-methods/PaymentMethods.tsx @@ -72,6 +72,7 @@ export default class PaymentMethods extends SelectableList } public async componentDidFocus() { + super.componentDidFocus(); this.setState({ refreshing: true }); await this.refresh(); } diff --git a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx index bbdcd9b52..70aba6213 100644 --- a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx +++ b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx @@ -2,8 +2,9 @@ import { CardField, CardFieldInput, initStripe, useConfirmSetupIntent } from '@s import I18n from 'i18n-js'; import { Button, CheckBox, Spinner, View } from 'native-base'; import React, { useEffect, useState } from 'react'; -import { Text, TouchableOpacity } from 'react-native'; +import { BackHandler, Text, TouchableOpacity } from 'react-native'; import { scale } from 'react-native-size-matters'; +import { useFocusEffect } from '@react-navigation/native'; import HeaderComponent from '../../../components/header/HeaderComponent'; import CentralServerProvider from '../../../provider/CentralServerProvider'; @@ -33,6 +34,17 @@ export default function StripePaymentMethodCreationForm(props: Props) { }); }); + useFocusEffect(React.useCallback(() => { + const backHandler = BackHandler.addEventListener('hardwareBackPress', () => onBack()); + return () => backHandler.remove(); + }, []) + ); + + function onBack(): boolean { + props.navigation.goBack(); + return true; + } + async function setUp(): Promise { const csProvider = await ProviderFactory.getProvider(); setProvider(csProvider); diff --git a/src/screens/sidebar/SideBar.tsx b/src/screens/sidebar/SideBar.tsx index 2bdf22239..9071fa606 100644 --- a/src/screens/sidebar/SideBar.tsx +++ b/src/screens/sidebar/SideBar.tsx @@ -13,8 +13,10 @@ import BaseProps from '../../types/BaseProps'; import User from '../../types/User'; import UserToken from '../../types/UserToken'; import Utils from '../../utils/Utils'; -import BaseScreen from '../base-screen/BaseScreen'; import computeStyleSheet from './SideBarStyles'; +import CentralServerProvider from '../../provider/CentralServerProvider'; +import ProviderFactory from '../../provider/ProviderFactory'; +import SecurityProvider from '../../provider/SecurityProvider'; export interface Props extends BaseProps {} @@ -27,12 +29,18 @@ interface State { appVersion?: CheckVersionResponse; } -export default class SideBar extends BaseScreen { +export default class SideBar extends React.Component { public state: State; public props: Props; + private centralServerProvider: CentralServerProvider; + private securityProvider: SecurityProvider; + private componentFocusUnsubscribe: () => void; + private componentBlurUnsubscribe: () => void; public constructor(props: Props) { super(props); + this.componentFocusUnsubscribe = this.props.navigation?.addListener('focus', () => this.componentDidFocus()); + this.componentBlurUnsubscribe = this.props.navigation?.addListener('blur', () => this.componentDidFocus()); this.state = { userToken: null, tenantName: '', @@ -50,13 +58,19 @@ export default class SideBar extends BaseScreen { super.setState(state, callback); }; - public async componentDidMount() { - await super.componentDidMount(); + public async componentDidFocus(): Promise { + this.centralServerProvider = await ProviderFactory.getProvider(); + this.securityProvider = this.centralServerProvider?.getSecurityProvider(); await this.getUpdateDate(); // Init User (delay it) this.refresh(); } + public componentWillUnmount() { + this.componentFocusUnsubscribe?.(); + this.componentBlurUnsubscribe?.(); + } + public refresh = async () => { await this.getUserInfo(); const appVersion = await checkVersion(); diff --git a/src/screens/site-areas/SiteAreas.tsx b/src/screens/site-areas/SiteAreas.tsx index c66c9f675..0f5967e47 100644 --- a/src/screens/site-areas/SiteAreas.tsx +++ b/src/screens/site-areas/SiteAreas.tsx @@ -120,15 +120,15 @@ export default class SiteAreas extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.siteAreas)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(siteAreas: SiteArea[]): Promise { diff --git a/src/screens/sites/Sites.tsx b/src/screens/sites/Sites.tsx index 8af840df1..ae6aa3a2e 100644 --- a/src/screens/sites/Sites.tsx +++ b/src/screens/sites/Sites.tsx @@ -118,15 +118,15 @@ export default class Sites extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.sites)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); + this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(sites: Site[]): Promise { diff --git a/src/screens/transactions/chart/TransactionChart.tsx b/src/screens/transactions/chart/TransactionChart.tsx index 19f009ef2..e44fdbb76 100644 --- a/src/screens/transactions/chart/TransactionChart.tsx +++ b/src/screens/transactions/chart/TransactionChart.tsx @@ -60,6 +60,10 @@ export default class TransactionChart extends BaseAutoRefreshScreen { + await super.componentDidMount(); + } + public setState = ( state: State | ((prevState: Readonly, props: Readonly) => State | Pick) | Pick, callback?: () => void @@ -346,13 +350,6 @@ export default class TransactionChart extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/transactions/details/TransactionDetails.tsx b/src/screens/transactions/details/TransactionDetails.tsx index 804742768..ab4872615 100644 --- a/src/screens/transactions/details/TransactionDetails.tsx +++ b/src/screens/transactions/details/TransactionDetails.tsx @@ -231,15 +231,7 @@ export default class TransactionDetails extends BaseScreen { ); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { - const { navigation } = this.props; const style = computeStyleSheet(); const { transaction } = this.state; const { loading, siteImage, isPricingActive } = this.state; diff --git a/src/screens/transactions/history/TransactionsHistory.tsx b/src/screens/transactions/history/TransactionsHistory.tsx index f42852b0a..f99835663 100644 --- a/src/screens/transactions/history/TransactionsHistory.tsx +++ b/src/screens/transactions/history/TransactionsHistory.tsx @@ -136,13 +136,6 @@ export default class TransactionsHistory extends BaseScreen { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); - // Do not bubble up - return true; - }; - public async refresh() { // Component Mounted? if (this.isMounted()) { diff --git a/src/types/Server.tsx b/src/types/Server.tsx index 01263e695..94658acf0 100644 --- a/src/types/Server.tsx +++ b/src/types/Server.tsx @@ -562,6 +562,7 @@ export enum ServerRoute { REST_TENANTS = 'tenants', REST_TENANT = 'tenants/:id', + REST_TENANT_LOGO = 'tenant/:id/logo', REST_COMPANIES = 'companies', REST_COMPANY = 'companies/:id', @@ -618,6 +619,15 @@ export enum ServerRoute { REST_SITE_AREA_ASSIGN_ASSETS = 'site-areas/:id/assets/assign', REST_SITE_AREA_REMOVE_ASSETS = 'site-areas/:id/assets/unassign', + REST_SITES = 'sites', + REST_SITE = 'sites/:id', + REST_SITE_USERS = 'sites/:id/users', + REST_SITE_ADD_USERS = 'sites/:id/users/assign', + REST_SITE_REMOVE_USERS = 'sites/:id/users/unassign', + REST_SITE_ADMIN = 'sites/:id/users/admin', + REST_SITE_OWNER = 'sites/:id/users/owner', + REST_SITE_IMAGE = 'sites/:id/image', + // BILLING URLs for CRUD operations on PAYMENT METHODS REST_BILLING_PAYMENT_METHODS = 'users/:userID/payment-methods', REST_BILLING_PAYMENT_METHOD = 'users/:userID/payment-methods/:paymentMethodID',
extends React.Component { } public onBack(): boolean { - // Not Handled: has to be taken in the sub-classes + this.props.navigation.goBack(); return true; } - public componentDidFocus(): void {} + public componentDidFocus(): void { + // Bind the back button to the onBack method (Android) + this.backHandler = BackHandler.addEventListener('hardwareBackPress', () => this.onBack()); + } - public componentDidBlur(): void {} + public componentDidBlur(): void { + // Unbind the back button and reset its default behavior (Android) + this.backHandler.remove(); + } } diff --git a/src/screens/cars/CarCatalogs.tsx b/src/screens/cars/CarCatalogs.tsx index e143d898a..41dbdc799 100644 --- a/src/screens/cars/CarCatalogs.tsx +++ b/src/screens/cars/CarCatalogs.tsx @@ -98,13 +98,6 @@ export default class CarCatalogs extends SelectableList { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public onEndScroll = async (): Promise => { const { count, skip, limit } = this.state; // No reached the end? diff --git a/src/screens/cars/Cars.tsx b/src/screens/cars/Cars.tsx index dfc3d4add..caa18b4e5 100644 --- a/src/screens/cars/Cars.tsx +++ b/src/screens/cars/Cars.tsx @@ -71,6 +71,7 @@ export default class Cars extends SelectableList { } public async componentDidFocus() { + super.componentDidFocus(); Orientation.lockToPortrait(); this.setState({ refreshing: true }); await this.refresh(); diff --git a/src/screens/charging-stations/actions/ChargingStationActions.tsx b/src/screens/charging-stations/actions/ChargingStationActions.tsx index 4cc8d245a..e1a65cbac 100644 --- a/src/screens/charging-stations/actions/ChargingStationActions.tsx +++ b/src/screens/charging-stations/actions/ChargingStationActions.tsx @@ -208,13 +208,6 @@ export default class ChargingStationActions extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public refresh = async () => { if (this.isMounted()) { const spinnerConnectors = new Map(); diff --git a/src/screens/charging-stations/list/ChargingStations.tsx b/src/screens/charging-stations/list/ChargingStations.tsx index 0001bf667..9e63c5e38 100644 --- a/src/screens/charging-stations/list/ChargingStations.tsx +++ b/src/screens/charging-stations/list/ChargingStations.tsx @@ -64,7 +64,6 @@ export default class ChargingStations extends BaseAutoRefreshScreen { + public onBack (): boolean { if (!this.state.showMap) { this.setState({ showMap: true }, () => this.refresh()); return true; diff --git a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx index 42c82df88..4f7f5b54d 100644 --- a/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx +++ b/src/screens/charging-stations/ocpp/ChargingStationOcppParameters.tsx @@ -115,13 +115,6 @@ export default class ChargingStationOcppParameters extends BaseScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public requestChargingStationOcppParametersConfirm() { const { chargingStation } = this.state; Alert.alert( diff --git a/src/screens/charging-stations/properties/ChargingStationProperties.tsx b/src/screens/charging-stations/properties/ChargingStationProperties.tsx index cb2e3deed..0d3f06d0c 100644 --- a/src/screens/charging-stations/properties/ChargingStationProperties.tsx +++ b/src/screens/charging-stations/properties/ChargingStationProperties.tsx @@ -1,4 +1,3 @@ -import { DrawerActions } from '@react-navigation/native'; import I18n from 'i18n-js'; import { Container, Spinner, Text, View } from 'native-base'; import React from 'react'; @@ -153,13 +152,6 @@ export default class ChargingStationProperties extends BaseScreen this.setState({ refreshing: false }); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/payment-methods/PaymentMethods.tsx b/src/screens/payment-methods/PaymentMethods.tsx index 66c59df47..f926a88cc 100644 --- a/src/screens/payment-methods/PaymentMethods.tsx +++ b/src/screens/payment-methods/PaymentMethods.tsx @@ -72,6 +72,7 @@ export default class PaymentMethods extends SelectableList } public async componentDidFocus() { + super.componentDidFocus(); this.setState({ refreshing: true }); await this.refresh(); } diff --git a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx index bbdcd9b52..70aba6213 100644 --- a/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx +++ b/src/screens/payment-methods/stripe/StripePaymentMethodCreationForm.tsx @@ -2,8 +2,9 @@ import { CardField, CardFieldInput, initStripe, useConfirmSetupIntent } from '@s import I18n from 'i18n-js'; import { Button, CheckBox, Spinner, View } from 'native-base'; import React, { useEffect, useState } from 'react'; -import { Text, TouchableOpacity } from 'react-native'; +import { BackHandler, Text, TouchableOpacity } from 'react-native'; import { scale } from 'react-native-size-matters'; +import { useFocusEffect } from '@react-navigation/native'; import HeaderComponent from '../../../components/header/HeaderComponent'; import CentralServerProvider from '../../../provider/CentralServerProvider'; @@ -33,6 +34,17 @@ export default function StripePaymentMethodCreationForm(props: Props) { }); }); + useFocusEffect(React.useCallback(() => { + const backHandler = BackHandler.addEventListener('hardwareBackPress', () => onBack()); + return () => backHandler.remove(); + }, []) + ); + + function onBack(): boolean { + props.navigation.goBack(); + return true; + } + async function setUp(): Promise { const csProvider = await ProviderFactory.getProvider(); setProvider(csProvider); diff --git a/src/screens/sidebar/SideBar.tsx b/src/screens/sidebar/SideBar.tsx index 2bdf22239..9071fa606 100644 --- a/src/screens/sidebar/SideBar.tsx +++ b/src/screens/sidebar/SideBar.tsx @@ -13,8 +13,10 @@ import BaseProps from '../../types/BaseProps'; import User from '../../types/User'; import UserToken from '../../types/UserToken'; import Utils from '../../utils/Utils'; -import BaseScreen from '../base-screen/BaseScreen'; import computeStyleSheet from './SideBarStyles'; +import CentralServerProvider from '../../provider/CentralServerProvider'; +import ProviderFactory from '../../provider/ProviderFactory'; +import SecurityProvider from '../../provider/SecurityProvider'; export interface Props extends BaseProps {} @@ -27,12 +29,18 @@ interface State { appVersion?: CheckVersionResponse; } -export default class SideBar extends BaseScreen { +export default class SideBar extends React.Component { public state: State; public props: Props; + private centralServerProvider: CentralServerProvider; + private securityProvider: SecurityProvider; + private componentFocusUnsubscribe: () => void; + private componentBlurUnsubscribe: () => void; public constructor(props: Props) { super(props); + this.componentFocusUnsubscribe = this.props.navigation?.addListener('focus', () => this.componentDidFocus()); + this.componentBlurUnsubscribe = this.props.navigation?.addListener('blur', () => this.componentDidFocus()); this.state = { userToken: null, tenantName: '', @@ -50,13 +58,19 @@ export default class SideBar extends BaseScreen { super.setState(state, callback); }; - public async componentDidMount() { - await super.componentDidMount(); + public async componentDidFocus(): Promise { + this.centralServerProvider = await ProviderFactory.getProvider(); + this.securityProvider = this.centralServerProvider?.getSecurityProvider(); await this.getUpdateDate(); // Init User (delay it) this.refresh(); } + public componentWillUnmount() { + this.componentFocusUnsubscribe?.(); + this.componentBlurUnsubscribe?.(); + } + public refresh = async () => { await this.getUserInfo(); const appVersion = await checkVersion(); diff --git a/src/screens/site-areas/SiteAreas.tsx b/src/screens/site-areas/SiteAreas.tsx index c66c9f675..0f5967e47 100644 --- a/src/screens/site-areas/SiteAreas.tsx +++ b/src/screens/site-areas/SiteAreas.tsx @@ -120,15 +120,15 @@ export default class SiteAreas extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.siteAreas)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(siteAreas: SiteArea[]): Promise { diff --git a/src/screens/sites/Sites.tsx b/src/screens/sites/Sites.tsx index 8af840df1..ae6aa3a2e 100644 --- a/src/screens/sites/Sites.tsx +++ b/src/screens/sites/Sites.tsx @@ -118,15 +118,15 @@ export default class Sites extends BaseAutoRefreshScreen { return null; }; - public onBack = () => { + public onBack () { // Back mobile button: Force navigation - if (this.state.showMap && !Utils.isEmptyArray(this.state.sites)) { + if (this.state.showMap) { this.setState({ showMap: false }); + return true; } else { - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); + this.props.navigation.goBack(); + return true; } - // Do not bubble up - return true; }; public async computeRegion(sites: Site[]): Promise { diff --git a/src/screens/transactions/chart/TransactionChart.tsx b/src/screens/transactions/chart/TransactionChart.tsx index 19f009ef2..e44fdbb76 100644 --- a/src/screens/transactions/chart/TransactionChart.tsx +++ b/src/screens/transactions/chart/TransactionChart.tsx @@ -60,6 +60,10 @@ export default class TransactionChart extends BaseAutoRefreshScreen { + await super.componentDidMount(); + } + public setState = ( state: State | ((prevState: Readonly, props: Readonly) => State | Pick) | Pick, callback?: () => void @@ -346,13 +350,6 @@ export default class TransactionChart extends BaseAutoRefreshScreen { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { const { navigation } = this.props; const style = computeStyleSheet(); diff --git a/src/screens/transactions/details/TransactionDetails.tsx b/src/screens/transactions/details/TransactionDetails.tsx index 804742768..ab4872615 100644 --- a/src/screens/transactions/details/TransactionDetails.tsx +++ b/src/screens/transactions/details/TransactionDetails.tsx @@ -231,15 +231,7 @@ export default class TransactionDetails extends BaseScreen { ); }; - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.goBack(); - // Do not bubble up - return true; - }; - public render() { - const { navigation } = this.props; const style = computeStyleSheet(); const { transaction } = this.state; const { loading, siteImage, isPricingActive } = this.state; diff --git a/src/screens/transactions/history/TransactionsHistory.tsx b/src/screens/transactions/history/TransactionsHistory.tsx index f42852b0a..f99835663 100644 --- a/src/screens/transactions/history/TransactionsHistory.tsx +++ b/src/screens/transactions/history/TransactionsHistory.tsx @@ -136,13 +136,6 @@ export default class TransactionsHistory extends BaseScreen { return null; } - public onBack = () => { - // Back mobile button: Force navigation - this.props.navigation.navigate('HomeNavigator', { screen: 'Home' }); - // Do not bubble up - return true; - }; - public async refresh() { // Component Mounted? if (this.isMounted()) { diff --git a/src/types/Server.tsx b/src/types/Server.tsx index 01263e695..94658acf0 100644 --- a/src/types/Server.tsx +++ b/src/types/Server.tsx @@ -562,6 +562,7 @@ export enum ServerRoute { REST_TENANTS = 'tenants', REST_TENANT = 'tenants/:id', + REST_TENANT_LOGO = 'tenant/:id/logo', REST_COMPANIES = 'companies', REST_COMPANY = 'companies/:id', @@ -618,6 +619,15 @@ export enum ServerRoute { REST_SITE_AREA_ASSIGN_ASSETS = 'site-areas/:id/assets/assign', REST_SITE_AREA_REMOVE_ASSETS = 'site-areas/:id/assets/unassign', + REST_SITES = 'sites', + REST_SITE = 'sites/:id', + REST_SITE_USERS = 'sites/:id/users', + REST_SITE_ADD_USERS = 'sites/:id/users/assign', + REST_SITE_REMOVE_USERS = 'sites/:id/users/unassign', + REST_SITE_ADMIN = 'sites/:id/users/admin', + REST_SITE_OWNER = 'sites/:id/users/owner', + REST_SITE_IMAGE = 'sites/:id/image', + // BILLING URLs for CRUD operations on PAYMENT METHODS REST_BILLING_PAYMENT_METHODS = 'users/:userID/payment-methods', REST_BILLING_PAYMENT_METHOD = 'users/:userID/payment-methods/:paymentMethodID',