diff --git a/front/src/assets/integrations/cover/ewelink_logo.png b/front/src/assets/integrations/cover/ewelink_logo.png new file mode 100644 index 0000000000..15c5376474 Binary files /dev/null and b/front/src/assets/integrations/cover/ewelink_logo.png differ diff --git a/front/src/components/app.jsx b/front/src/components/app.jsx index 73d834c571..392a85376b 100644 --- a/front/src/components/app.jsx +++ b/front/src/components/app.jsx @@ -129,6 +129,7 @@ import EweLinkPage from '../routes/integration/all/ewelink/device-page'; import EweLinkEditPage from '../routes/integration/all/ewelink/edit-page'; import EweLinkDiscoverPage from '../routes/integration/all/ewelink/discover-page'; import EweLinkSetupPage from '../routes/integration/all/ewelink/setup-page'; +import EweLinkSetupLoginPage from '../routes/integration/all/ewelink/setup-page/login'; // OpenAI integration import OpenAIPage from '../routes/integration/all/openai/index'; @@ -271,6 +272,7 @@ const AppRouter = connect( + diff --git a/front/src/components/header/index.jsx b/front/src/components/header/index.jsx index 7203c8aefc..188c744441 100644 --- a/front/src/components/header/index.jsx +++ b/front/src/components/header/index.jsx @@ -22,7 +22,8 @@ const PAGES_WITHOUT_HEADER = [ '/confirm-email', '/dashboard/integration/device/google-home/authorize', '/dashboard/integration/device/alexa/authorize', - '/locked' + '/locked', + '/dashboard/integration/device/ewelink/setup/login' ]; const Header = ({ ...props }) => { diff --git a/front/src/config/demo.js b/front/src/config/demo.js index 90399ebb1e..cddd840338 100644 --- a/front/src/config/demo.js +++ b/front/src/config/demo.js @@ -3132,6 +3132,21 @@ const data = { ] } ], + 'get /api/v1/service/ewelink/status': { + configured: true, + connected: true + }, + 'get /api/v1/service/ewelink/config': { + application_id: 'ewelink_APPID', + application_secret: 'ewelink_APP_SECRET', + application_region: 'eu' + }, + 'post /api/v1/service/ewelink/config': { + application_id: 'ewelink_APPID', + application_secret: 'ewelink_APP_SECRET', + application_region: 'eu' + }, + 'post /api/v1/service/ewelink/token': {}, 'get /api/v1/service/tp-link': { id: 'c9fe2705-35dc-417b-b6fc-c4bbb9c69886', pod_id: null, diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index dd82e2472f..3184a0c7b6 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -14,6 +14,8 @@ "degreeValue": "{{value}}°", "workInProgress": "Work in progress...", "save": "Save", + "edit": "Edit", + "cancel": "Cancel", "celsius": "C", "fahrenheit": "F", "metersPerSec": "m/s", @@ -1430,15 +1432,27 @@ "setup": { "title": "eWeLink configuration", "eweLinkDescription": "You can connect Gladys to your eWeLink cloud account to command the associated devices.", - "userLabel": "Username", - "userPlaceholder": "Enter eWeLink username", - "passwordLabel": "Password", - "passwordPlaceholder": "Enter eWeLink password", - "saveLabel": "Save configuration", - "error": "An error occured while saving configuration.", - "connecting": "Configuration saved. Now connecting to your eWeLink cloud account...", - "connected": "Connected to the eWeLink cloud account with success !", - "connectionError": "Error while connecting, please check your configuration." + "applicationSetupLabel": "eWeLink application setup", + "applicationIdLabel": "Application Identifier (APPID)", + "applicationIdPlaceholder": "Enter APPID value", + "applicationSecretLabel": "Application Secret (APP SECRET)", + "applicationSecretPlaceholder": "Enter APP SECRET value", + "applicationRegionLabel": "Region", + "userConnectedLabel": "Connected", + "userNotConnectedLabel": "No user connected", + "connectLabel": "Connect", + "disconnectLabel": "Disconnect", + "loadStatusError": "An error occured while fetching eWeLink integration status. Gladys may be not reachable.", + "saveConfigError": "Unable to save eWeLink application configuration. Gladys may be not reachable.", + "loginRedirectError": "An error occured while connecting to eWeLink, please contact Gladys community.", + "exchangeTokenError": "An error occured while connecting to exchanging eWeLink user token, please contact Gladys community.", + "exchangeTokenSuccess": "Authentication succeed, current tab can be closed.", + "regions": { + "cn": "Mainland China", + "as": "Asia", + "us": "Americas", + "eu": "Europe" + } }, "error": { "defaultError": "There was an error saving the device.", diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index da7fb53ef8..ee89851f5b 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -14,6 +14,8 @@ "degreeValue": "{{value}}°", "workInProgress": "Travail en cours...", "save": "Enregistrer", + "edit": "Modifier", + "cancel": "Annuler", "celsius": "C", "fahrenheit": "F", "metersPerSec": "m/s", @@ -1432,15 +1434,27 @@ "setup": { "title": "Configuration eWeLink", "eweLinkDescription": "Vous pouvez connecter Gladys à votre compte cloud eWeLink pour commander les appareils associés.", - "userLabel": "Nom d'utilisateur", - "userPlaceholder": "Entrez le nom d'utilisateur eWeLink", - "passwordLabel": "Mot de passe", - "passwordPlaceholder": "Entrez le mot de passe utilisateur eWeLink", - "saveLabel": "Enregistrer la configuration", - "error": "Une erreur s'est produite lors de la sauvegarde de la configuration.", - "connecting": "Configuration sauvegardée. Connexion à votre compte cloud eWeLink...", - "connected": "Connexion réussie au compte cloud eWeLink !", - "connectionError": "Erreur lors de la connexion, veuillez vérifier votre configuration." + "applicationSetupLabel": "Configurationde l'application eWeLink", + "applicationIdLabel": "Identifiant de l'application (APPID)", + "applicationIdPlaceholder": "Entrez la valeur de APPID", + "applicationSecretLabel": "Secret de l'application (APP SECRET)", + "applicationSecretPlaceholder": "Entrez la valeur de APP SECRET", + "applicationRegionLabel": "Region", + "userConnectedLabel": "Connecté", + "userNotConnectedLabel": "Aucun utilisateur connecté", + "connectLabel": "Connexion", + "disconnectLabel": "Déconnexion", + "loadStatusError": "Impossible de remonter les informations sur l'état de l'intégration eWeLink. Gladys ne semble pas joignable.", + "saveConfigError": "Impossible d'enregistrer la configuration de l'application eWeLink. Gladys ne semble pas joignable.", + "loginRedirectError": "Une erreur est survenue lors de la connexion à eWeLink, merci de contacter la communauté.", + "exchangeTokenError": "Une erreur est survenue lors de la génération du jeton utilisateur eWeLink, merci de contacter la communauté.", + "exchangeTokenSuccess": "L'authentification est un succès, cette page peut être fermée.", + "regions": { + "cn": "Chine", + "as": "Asie", + "us": "Ameriques", + "eu": "Europe" + } }, "error": { "defaultError": "Une erreur s'est produite lors de l'enregistrement de l'appareil.", diff --git a/front/src/routes/integration/all/ewelink/setup-page/ApplicationSetup.jsx b/front/src/routes/integration/all/ewelink/setup-page/ApplicationSetup.jsx new file mode 100644 index 0000000000..6ab6aeb749 --- /dev/null +++ b/front/src/routes/integration/all/ewelink/setup-page/ApplicationSetup.jsx @@ -0,0 +1,192 @@ +import { Component } from 'preact'; +import { Localizer, Text } from 'preact-i18n'; +import cx from 'classnames'; + +import { REGIONS } from './constants'; + +class ApplicationSetup extends Component { + showPasswordTimer = null; + + updateApplicationId = event => { + const { value: applicationId } = event.target; + this.setState({ applicationId }); + }; + + updateApplicationSecret = event => { + const { value: applicationSecret } = event.target; + this.setState({ applicationSecret }); + }; + + updateApplicationRegion = event => { + const { value: applicationRegion } = event.target; + this.setState({ applicationRegion }); + }; + + saveConfiguration = async event => { + event.preventDefault(); + const { applicationId, applicationSecret, applicationRegion } = this.state; + const configuration = { applicationId, applicationSecret, applicationRegion }; + this.props.saveConfiguration(configuration); + }; + + resetConfiguration = event => { + event.preventDefault(); + const { ewelinkConfig = {} } = this.props; + const { applicationId = '', applicationSecret = '', applicationRegion } = ewelinkConfig; + this.setState({ applicationId, applicationSecret, applicationRegion }); + this.props.resetConfiguration(); + }; + + togglePassword = () => { + const { showPassword } = this.state; + + if (this.showPasswordTimer) { + clearTimeout(this.showPasswordTimer); + this.showPasswordTimer = null; + } + + this.setState({ showPassword: !showPassword }); + + if (!showPassword) { + this.showPasswordTimer = setTimeout(() => this.setState({ showPassword: false }), 5000); + } + }; + + constructor(props) { + super(props); + + const { ewelinkConfig = {} } = props; + const { applicationId = '', applicationSecret = '', applicationRegion } = ewelinkConfig; + this.state = { + applicationId, + applicationSecret, + applicationRegion + }; + } + + componentWillUnmount() { + if (this.showPasswordTimer) { + clearTimeout(this.showPasswordTimer); + this.showPasswordTimer = null; + } + } + + componentWillReceiveProps(nextProps) { + const { ewelinkConfig = {} } = nextProps; + const { applicationId = '', applicationSecret = '', applicationRegion } = ewelinkConfig; + const { + applicationId: currentApplicationId, + applicationSecret: currentApplicationSecret, + applicationRegion: currentApplicationRegion + } = this.state; + + if ( + applicationId !== currentApplicationId || + applicationSecret !== currentApplicationSecret || + applicationRegion !== currentApplicationRegion + ) { + this.setState({ applicationId, applicationSecret, applicationRegion }); + } + } + + render({ disabled }, { applicationId, applicationSecret, applicationRegion, showPassword }) { + const saveDisabled = applicationId === '' || applicationSecret === '' || !applicationRegion; + return ( +
+
+ + + } + value={applicationId} + onInput={this.updateApplicationId} + disabled={disabled} + autocomplete="off" + required + data-cy="ewelink-application-setup-app-id" + /> + +
+
+ +
+ + } + value={applicationSecret} + onInput={this.updateApplicationSecret} + disabled={disabled} + autocomplete="off" + required + data-cy="ewelink-application-setup-app-secret" + /> + + + + +
+
+
+ +
+ + + +
+
+
+ + +
+ + ); + } +} + +export default ApplicationSetup; diff --git a/front/src/routes/integration/all/ewelink/setup-page/SetupSummary.jsx b/front/src/routes/integration/all/ewelink/setup-page/SetupSummary.jsx new file mode 100644 index 0000000000..3efc2d4337 --- /dev/null +++ b/front/src/routes/integration/all/ewelink/setup-page/SetupSummary.jsx @@ -0,0 +1,75 @@ +import { Fragment } from 'preact'; +import { Text } from 'preact-i18n'; +import cx from 'classnames'; + +const SetupSummary = ({ ewelinkStatus = {}, enableEditionMode, disabled, connectUser, disconnectUser }) => { + const { configured, connected } = ewelinkStatus; + + return ( +
+
+
+ +
+ + +
+
+
+ +
+ {connected && ( + + + + + )} + {!connected && ( + + +
+ {configured && ( + + )} +
+
+ )} +
+
+ ); +}; + +export default SetupSummary; diff --git a/front/src/routes/integration/all/ewelink/setup-page/SetupTab.jsx b/front/src/routes/integration/all/ewelink/setup-page/SetupTab.jsx index 9f0b2f4546..ebb641fa73 100644 --- a/front/src/routes/integration/all/ewelink/setup-page/SetupTab.jsx +++ b/front/src/routes/integration/all/ewelink/setup-page/SetupTab.jsx @@ -1,93 +1,115 @@ -import { Text, Localizer, MarkupText } from 'preact-i18n'; +import { Component } from 'preact'; +import { Text } from 'preact-i18n'; import cx from 'classnames'; import { RequestStatus } from '../../../../../utils/consts'; -const SetupTab = ({ children, ...props }) => { - return ( -
-
-

- -

-
-
-
-
-
-

- -

- {props.connectEweLinkStatus === RequestStatus.Error && !props.eweLinkConnectionError && ( -

- -

- )} - {props.connectEweLinkStatus === RequestStatus.Success && !props.eweLinkConnected && ( -

- -

- )} - {props.eweLinkConnected && ( -

- -

- )} - {props.eweLinkConnectionError && ( -

- -

- )} +import ApplicationSetup from './ApplicationSetup'; +import SetupSummary from './SetupSummary'; + +class SetupTab extends Component { + enableEditionMode = () => { + this.setState({ editionMode: true }); + }; + + resetConfiguration = () => { + const { ewelinkStatus = {} } = this.props; + const { configured = false } = ewelinkStatus; + this.setState({ + editionMode: !configured + }); + }; + + constructor(props) { + super(props); -
-
- - - } - value={props.eweLinkUsername} - class="form-control" - onInput={props.updateConfigration} - /> - -
+ const { ewelinkStatus = {} } = props; + const { configured = false } = ewelinkStatus; + this.state = { + editionMode: !configured + }; + } -
- - - } - value={props.eweLinkPassword} - class="form-control" - onInput={props.updateConfigration} - /> - -
+ componentWillReceiveProps(nextProps) { + const { ewelinkStatus = {} } = nextProps; -
-
- -
-
-
+ if (ewelinkStatus.configured && this.state.editionMode) { + this.setState({ editionMode: false }); + } + } + + render( + { + ewelinkStatus, + loadEwelinkStatus = RequestStatus.Getting, + ewelinkConfig, + loadEwelinkConfig = RequestStatus.Getting, + saveEwelinkConfig, + saveConfiguration, + connectUser, + loadConnectUser, + disconnectUser, + loadDisconnectUser + }, + { editionMode } + ) { + const formDisabled = + saveEwelinkConfig === RequestStatus.Getting || + loadConnectUser === RequestStatus.Getting || + loadDisconnectUser === RequestStatus.Getting; + + return ( +
+
+

+ +

+
+
+

+ +

+
+
+
+ {loadEwelinkStatus === RequestStatus.Error && ( +

+ +

+ )} + {saveEwelinkConfig === RequestStatus.Error && ( +

+ +

+ )} + {editionMode && ( + + )} + {!editionMode && ( + + )} +
-
- ); -}; + ); + } +} export default SetupTab; diff --git a/front/src/routes/integration/all/ewelink/setup-page/constants.js b/front/src/routes/integration/all/ewelink/setup-page/constants.js new file mode 100644 index 0000000000..2a7afd0984 --- /dev/null +++ b/front/src/routes/integration/all/ewelink/setup-page/constants.js @@ -0,0 +1,4 @@ +const REGIONS = ['eu', 'us', 'as', 'cn']; +const DEFAULT_REGION = REGIONS[0]; + +export { REGIONS, DEFAULT_REGION }; diff --git a/front/src/routes/integration/all/ewelink/setup-page/index.js b/front/src/routes/integration/all/ewelink/setup-page/index.js index 483106a333..23ddf18ba3 100644 --- a/front/src/routes/integration/all/ewelink/setup-page/index.js +++ b/front/src/routes/integration/all/ewelink/setup-page/index.js @@ -1,39 +1,170 @@ import { Component } from 'preact'; import { connect } from 'unistore/preact'; -import actions from '../actions'; + import EweLinkPage from '../EweLinkPage'; import SetupTab from './SetupTab'; +import { DEFAULT_REGION } from './constants'; + import { WEBSOCKET_MESSAGE_TYPES } from '../../../../../../../server/utils/constants'; +import { RequestStatus } from '../../../../../utils/consts'; class EweLinkSetupPage extends Component { - componentWillMount() { - this.props.getIntegrationByName('ewelink'); - this.props.loadProps(); - this.props.session.dispatcher.addListener( - WEBSOCKET_MESSAGE_TYPES.EWELINK.CONNECTED, - this.props.displayConnectedMessage - ); - this.props.session.dispatcher.addListener(WEBSOCKET_MESSAGE_TYPES.EWELINK.ERROR, this.props.displayEweLinkError); + loadEwelinkStatus = async () => { + this.setState({ + loadEwelinkStatus: RequestStatus.Getting + }); + try { + const { configured, connected } = await this.props.httpClient.get('/api/v1/service/ewelink/status'); + const ewelinkStatus = { configured, connected }; + this.setState({ + ewelinkStatus, + loadEwelinkStatus: RequestStatus.Success + }); + } catch (e) { + console.error('eWeLink error loading status', e); + this.setState({ + loadEwelinkStatus: RequestStatus.Error + }); + } + }; + + loadEwelinkConfig = async () => { + this.setState({ + loadEwelinkConfig: RequestStatus.Getting + }); + try { + const { + application_id: applicationId, + application_secret: applicationSecret, + application_region: applicationRegion = DEFAULT_REGION + } = await this.props.httpClient.get('/api/v1/service/ewelink/config'); + this.setState({ + ewelinkConfig: { applicationId, applicationSecret, applicationRegion }, + loadEwelinkConfig: RequestStatus.Success + }); + } catch (e) { + console.error('eWeLink error loading config', e); + this.setState({ + loadEwelinkConfig: RequestStatus.Error + }); + } + }; + + saveEwelinkConfig = async config => { + this.setState({ + saveEwelinkConfig: RequestStatus.Getting + }); + try { + const { applicationId, applicationSecret, applicationRegion } = config; + const savedConfig = await this.props.httpClient.post('/api/v1/service/ewelink/config', { + application_id: applicationId, + application_secret: applicationSecret, + application_region: applicationRegion + }); + const ewelinkConfig = { + applicationId: savedConfig.application_id, + applicationSecret: savedConfig.application_secret, + applicationRegion: savedConfig.application_secret + }; + this.setState({ + ewelinkConfig, + saveEwelinkConfig: RequestStatus.Success + }); + } catch (e) { + console.error('eWeLink error saving config', e); + this.setState({ + saveEwelinkConfig: RequestStatus.Error + }); + } + }; + + connectUser = async () => { + this.setState({ loadConnectUser: RequestStatus.Getting }); + + const { origin, pathname } = window.location; + try { + const { loginUrl } = await this.props.httpClient.get('/api/v1/service/ewelink/loginUrl', { + redirect_url: `${origin}${pathname}/login` + }); + const loginPopup = window.open(loginUrl, 'ewelinkLogin'); + this.setState({ loadConnectUser: RequestStatus.Success, loginPopup }); + } catch (e) { + console.error(e); + this.setState({ loadConnectUser: RequestStatus.Error }); + } + }; + + disconnectUser = async () => { + this.setState({ loadDisconnectUser: RequestStatus.Getting }); + + try { + await this.props.httpClient.delete('/api/v1/service/ewelink/token'); + this.setState({ loadDisconnectUser: RequestStatus.Success }); + } catch (e) { + console.error(e); + this.setState({ loadDisconnectUser: RequestStatus.Error }); + } + }; + + updateStatus = payload => { + const { configured, connected } = payload; + const ewelinkStatus = { configured, connected }; + + const { loginPopup, ewelinkStatus: currentStatus = {} } = this.state; + if (!currentStatus.connected && connected && loginPopup && !loginPopup.closed) { + loginPopup.close(); + } + + this.setState({ ewelinkStatus }); + }; + + constructor(props) { + super(props); + + this.state = { + loadEwelinkStatus: RequestStatus.Getting + }; + } + + componentDidMount() { + this.props.session.dispatcher.addListener(WEBSOCKET_MESSAGE_TYPES.EWELINK.STATUS, this.updateStatus); + this.loadEwelinkStatus(); + this.loadEwelinkConfig(); } componentWillUnmount() { - this.props.session.dispatcher.removeListener( - WEBSOCKET_MESSAGE_TYPES.EWELINK.CONNECTED, - this.props.displayConnectedMessage - ); - this.props.session.dispatcher.removeListener(WEBSOCKET_MESSAGE_TYPES.EWELINK.ERROR, this.props.displayEweLinkError); + this.props.session.dispatcher.removeListener(WEBSOCKET_MESSAGE_TYPES.EWELINK.STATUS, this.updateStatus); } - render(props, {}) { + render( + {}, + { + loadEwelinkStatus, + ewelinkStatus, + loadEwelinkConfig, + ewelinkConfig, + saveEwelinkConfig, + loadDisconnectUser, + loadConnectUser + } + ) { return ( - + ); } } -export default connect( - 'user,session,eweLinkUsername,eweLinkPassword,connectEweLinkStatus,eweLinkConnected,eweLinkConnectionError', - actions -)(EweLinkSetupPage); +export default connect('user,session,httpClient')(EweLinkSetupPage); diff --git a/front/src/routes/integration/all/ewelink/setup-page/login/ErrorPage.jsx b/front/src/routes/integration/all/ewelink/setup-page/login/ErrorPage.jsx new file mode 100644 index 0000000000..97698bc65a --- /dev/null +++ b/front/src/routes/integration/all/ewelink/setup-page/login/ErrorPage.jsx @@ -0,0 +1,10 @@ +const ErrorPage = ({ children }) => ( +
+
+ +
+ {children} +
+); + +export default ErrorPage; diff --git a/front/src/routes/integration/all/ewelink/setup-page/login/ExchangeTokenPage.jsx b/front/src/routes/integration/all/ewelink/setup-page/login/ExchangeTokenPage.jsx new file mode 100644 index 0000000000..20ebf4aa91 --- /dev/null +++ b/front/src/routes/integration/all/ewelink/setup-page/login/ExchangeTokenPage.jsx @@ -0,0 +1,75 @@ +import { Component } from 'preact'; +import cx from 'classnames'; + +import { RequestStatus } from '../../../../../../utils/consts'; +import { Text } from 'preact-i18n'; +import ErrorPage from './ErrorPage'; + +class ExchangeTokenPage extends Component { + exchangeToken = async () => { + this.setState({ + exchangeTokenStatus: RequestStatus.Getting, + exchangeTokenError: null + }); + + try { + const { code, region, redirectUrl, state } = this.props; + + await this.props.httpClient.post('/api/v1/service/ewelink/token', { + code, + region, + redirect_url: redirectUrl, + state + }); + this.setState({ + exchangeTokenStatus: RequestStatus.Success + }); + } catch (e) { + console.error(e); + console.error(e.response); + this.setState({ + exchangeTokenStatus: RequestStatus.Error, + exchangeTokenError: e + }); + } + }; + + componentDidMount() { + this.exchangeToken(); + } + + render({}, { exchangeTokenStatus = RequestStatus.Getting, exchangeTokenError }) { + const { response = {} } = exchangeTokenError || {}; + const { data = {} } = response; + const { message } = data; + + return ( +
+
+
+ {exchangeTokenStatus === RequestStatus.Error && ( + +
+ +
+ {message ? message : exchangeTokenError} +
+
+ )} + {exchangeTokenStatus === RequestStatus.Success && ( +
+ +
+ )} +
+
+ ); + } +} + +export default ExchangeTokenPage; diff --git a/front/src/routes/integration/all/ewelink/setup-page/login/index.js b/front/src/routes/integration/all/ewelink/setup-page/login/index.js new file mode 100644 index 0000000000..98d9379c82 --- /dev/null +++ b/front/src/routes/integration/all/ewelink/setup-page/login/index.js @@ -0,0 +1,109 @@ +import { Component } from 'preact'; +import { connect } from 'unistore/preact'; +import { Localizer, Text } from 'preact-i18n'; + +import { RequestStatus } from '../../../../../../utils/consts'; +import ErrorPage from './ErrorPage'; +import ExchangeTokenPage from './ExchangeTokenPage'; + +class EweLinkSetupLoginPage extends Component { + exchangeToken = async config => { + this.setState({ + saveEwelinkConfig: RequestStatus.Getting + }); + try { + const { applicationId, applicationSecret, applicationRegion } = config; + const savedConfig = await this.props.httpClient.post('/api/v1/service/ewelink/token', { + application_id: applicationId, + application_secret: applicationSecret, + application_region: applicationRegion + }); + const ewelinkConfig = { + applicationId: savedConfig.application_id, + applicationSecret: savedConfig.application_secret, + applicationRegion: savedConfig.application_secret + }; + this.setState({ + ewelinkConfig, + saveEwelinkConfig: RequestStatus.Success + }); + } catch (e) { + console.error('eWeLink error saving config', e); + this.setState({ + saveEwelinkConfig: RequestStatus.Error + }); + } + }; + + constructor(props) { + super(props); + + const { search: queryString, origin, pathname } = window.location; + const queryParams = new URLSearchParams(queryString); + + // Map query params to JSON Object + const params = {}; + for (const [key, value] of queryParams.entries()) { + params[key] = value; + } + + this.state = { + params, + redirectUrl: `${origin}${pathname}` + }; + } + + render({ httpClient }, { params, redirectUrl }) { + const { code, region, state } = params; + const success = code && region && state; + + return ( +
+
+
+
+
+
+
+
+
+
+

+ + {<Text} + /> + + +

+
+ {success && ( + + )} + {!success && ( + + + + )} +
+
+
+
+
+
+
+
+
+ ); + } +} + +export default connect('user,session,httpClient')(EweLinkSetupLoginPage); diff --git a/server/utils/constants.js b/server/utils/constants.js index 4f4d4a8d70..e7b8f71294 100644 --- a/server/utils/constants.js +++ b/server/utils/constants.js @@ -917,7 +917,7 @@ const WEBSOCKET_MESSAGE_TYPES = { DISCOVER: 'bluetooth.discover', }, EWELINK: { - CONNECTED: 'ewelink.connected', + STATUS: 'ewelink.status', NEW_DEVICE: 'ewelink.new-device', ERROR: 'ewelink.error', },