mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-21 11:42:05 +00:00
Merge pull request #698 from Stremio/refactor/facebook-login-shell
refactor(Intro): make fb login compatible with shell
This commit is contained in:
commit
251878bb69
6 changed files with 128 additions and 62 deletions
17
package-lock.json
generated
17
package-lock.json
generated
|
|
@ -21,7 +21,7 @@
|
||||||
"classnames": "2.3.1",
|
"classnames": "2.3.1",
|
||||||
"eventemitter3": "4.0.7",
|
"eventemitter3": "4.0.7",
|
||||||
"filter-invalid-dom-props": "2.1.0",
|
"filter-invalid-dom-props": "2.1.0",
|
||||||
"hat": "0.0.3",
|
"hat": "^0.0.3",
|
||||||
"i18next": "^22.4.3",
|
"i18next": "^22.4.3",
|
||||||
"langs": "^2.0.0",
|
"langs": "^2.0.0",
|
||||||
"lodash.debounce": "4.0.8",
|
"lodash.debounce": "4.0.8",
|
||||||
|
|
@ -46,6 +46,7 @@
|
||||||
"@babel/plugin-proposal-object-rest-spread": "7.16.0",
|
"@babel/plugin-proposal-object-rest-spread": "7.16.0",
|
||||||
"@babel/preset-env": "7.16.0",
|
"@babel/preset-env": "7.16.0",
|
||||||
"@babel/preset-react": "7.16.0",
|
"@babel/preset-react": "7.16.0",
|
||||||
|
"@types/hat": "^0.0.4",
|
||||||
"@types/react": "^18.2.9",
|
"@types/react": "^18.2.9",
|
||||||
"babel-loader": "8.2.3",
|
"babel-loader": "8.2.3",
|
||||||
"clean-webpack-plugin": "4.0.0",
|
"clean-webpack-plugin": "4.0.0",
|
||||||
|
|
@ -3181,6 +3182,13 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/hat": {
|
||||||
|
"version": "0.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hat/-/hat-0.0.4.tgz",
|
||||||
|
"integrity": "sha512-HsNPoA1/v8x1d1jztZNI/RJNv7gvFsy2QVx9TEJyZ7S2aqJEDyRPiEYjr246tujQ6Br5ouH1VWIv8tXHYKlZUw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/html-minifier-terser": {
|
"node_modules/@types/html-minifier-terser": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
|
@ -6887,7 +6895,12 @@
|
||||||
},
|
},
|
||||||
"node_modules/hat": {
|
"node_modules/hat": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"license": "MIT/X11"
|
"resolved": "https://registry.npmjs.org/hat/-/hat-0.0.3.tgz",
|
||||||
|
"integrity": "sha512-zpImx2GoKXy42fVDSEad2BPKuSQdLcqsCYa48K3zHSzM/ugWuYjLDr8IXxpVuL7uCLHw56eaiLxCRthhOzf5ug==",
|
||||||
|
"license": "MIT/X11",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/he": {
|
"node_modules/he": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
"classnames": "2.3.1",
|
"classnames": "2.3.1",
|
||||||
"eventemitter3": "4.0.7",
|
"eventemitter3": "4.0.7",
|
||||||
"filter-invalid-dom-props": "2.1.0",
|
"filter-invalid-dom-props": "2.1.0",
|
||||||
"hat": "0.0.3",
|
"hat": "^0.0.3",
|
||||||
"i18next": "^22.4.3",
|
"i18next": "^22.4.3",
|
||||||
"langs": "^2.0.0",
|
"langs": "^2.0.0",
|
||||||
"lodash.debounce": "4.0.8",
|
"lodash.debounce": "4.0.8",
|
||||||
|
|
@ -50,6 +50,7 @@
|
||||||
"@babel/plugin-proposal-object-rest-spread": "7.16.0",
|
"@babel/plugin-proposal-object-rest-spread": "7.16.0",
|
||||||
"@babel/preset-env": "7.16.0",
|
"@babel/preset-env": "7.16.0",
|
||||||
"@babel/preset-react": "7.16.0",
|
"@babel/preset-react": "7.16.0",
|
||||||
|
"@types/hat": "^0.0.4",
|
||||||
"@types/react": "^18.2.9",
|
"@types/react": "^18.2.9",
|
||||||
"babel-loader": "8.2.3",
|
"babel-loader": "8.2.3",
|
||||||
"clean-webpack-plugin": "4.0.0",
|
"clean-webpack-plugin": "4.0.0",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (C) 2017-2023 Smart code 203358507
|
// Copyright (C) 2017-2023 Smart code 203358507
|
||||||
|
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
|
const { useTranslation } = require('react-i18next');
|
||||||
const PropTypes = require('prop-types');
|
const PropTypes = require('prop-types');
|
||||||
const classnames = require('classnames');
|
const classnames = require('classnames');
|
||||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||||
|
|
@ -10,7 +11,7 @@ const { Button, Image, useBinaryState } = require('stremio/common');
|
||||||
const CredentialsTextInput = require('./CredentialsTextInput');
|
const CredentialsTextInput = require('./CredentialsTextInput');
|
||||||
const ConsentCheckbox = require('./ConsentCheckbox');
|
const ConsentCheckbox = require('./ConsentCheckbox');
|
||||||
const PasswordResetModal = require('./PasswordResetModal');
|
const PasswordResetModal = require('./PasswordResetModal');
|
||||||
const useFacebookToken = require('./useFacebookToken');
|
const useFacebookLogin = require('./useFacebookLogin');
|
||||||
const styles = require('./styles');
|
const styles = require('./styles');
|
||||||
|
|
||||||
const SIGNUP_FORM = 'signup';
|
const SIGNUP_FORM = 'signup';
|
||||||
|
|
@ -18,8 +19,9 @@ const LOGIN_FORM = 'login';
|
||||||
|
|
||||||
const Intro = ({ queryParams }) => {
|
const Intro = ({ queryParams }) => {
|
||||||
const { core } = useServices();
|
const { core } = useServices();
|
||||||
|
const { t } = useTranslation();
|
||||||
const routeFocused = useRouteFocused();
|
const routeFocused = useRouteFocused();
|
||||||
const getFacebookToken = useFacebookToken();
|
const [startFacebookLogin, stopFacebookLogin] = useFacebookLogin();
|
||||||
const emailRef = React.useRef(null);
|
const emailRef = React.useRef(null);
|
||||||
const passwordRef = React.useRef(null);
|
const passwordRef = React.useRef(null);
|
||||||
const confirmPasswordRef = React.useRef(null);
|
const confirmPasswordRef = React.useRef(null);
|
||||||
|
|
@ -80,15 +82,17 @@ const Intro = ({ queryParams }) => {
|
||||||
);
|
);
|
||||||
const loginWithFacebook = React.useCallback(() => {
|
const loginWithFacebook = React.useCallback(() => {
|
||||||
openLoaderModal();
|
openLoaderModal();
|
||||||
getFacebookToken()
|
startFacebookLogin()
|
||||||
.then((accessToken) => {
|
.then(({ email, password }) => {
|
||||||
core.transport.dispatch({
|
core.transport.dispatch({
|
||||||
action: 'Ctx',
|
action: 'Ctx',
|
||||||
args: {
|
args: {
|
||||||
action: 'Authenticate',
|
action: 'Authenticate',
|
||||||
args: {
|
args: {
|
||||||
type: 'Facebook',
|
type: 'Login',
|
||||||
token: accessToken,
|
email,
|
||||||
|
password,
|
||||||
|
facebook: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -98,6 +102,10 @@ const Intro = ({ queryParams }) => {
|
||||||
dispatch({ type: 'error', error: error.message });
|
dispatch({ type: 'error', error: error.message });
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
const cancelLoginWithFacebook = React.useCallback(() => {
|
||||||
|
stopFacebookLogin();
|
||||||
|
closeLoaderModal();
|
||||||
|
}, []);
|
||||||
const loginWithEmail = React.useCallback(() => {
|
const loginWithEmail = React.useCallback(() => {
|
||||||
if (typeof state.email !== 'string' || state.email.length === 0 || !emailRef.current.validity.valid) {
|
if (typeof state.email !== 'string' || state.email.length === 0 || !emailRef.current.validity.valid) {
|
||||||
dispatch({ type: 'error', error: 'Invalid email' });
|
dispatch({ type: 'error', error: 'Invalid email' });
|
||||||
|
|
@ -383,6 +391,9 @@ const Intro = ({ queryParams }) => {
|
||||||
<div className={styles['loader-container']}>
|
<div className={styles['loader-container']}>
|
||||||
<Icon className={styles['icon']} name={'person'} />
|
<Icon className={styles['icon']} name={'person'} />
|
||||||
<div className={styles['label']}>Authenticating...</div>
|
<div className={styles['label']}>Authenticating...</div>
|
||||||
|
<Button className={styles['button']} onClick={cancelLoginWithFacebook}>
|
||||||
|
{t('BUTTON_CANCEL')}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
:
|
:
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,8 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 2rem;
|
gap: 1rem;
|
||||||
|
padding: 2.5rem;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
background-color: var(--modal-background-color);
|
background-color: var(--modal-background-color);
|
||||||
|
|
||||||
|
|
@ -218,7 +219,6 @@
|
||||||
flex: none;
|
flex: none;
|
||||||
width: 5rem;
|
width: 5rem;
|
||||||
height: 5rem;
|
height: 5rem;
|
||||||
margin-bottom: 1rem;
|
|
||||||
color: var(--primary-foreground-color);
|
color: var(--primary-foreground-color);
|
||||||
animation: 1s linear infinite alternate flash;
|
animation: 1s linear infinite alternate flash;
|
||||||
}
|
}
|
||||||
|
|
@ -228,6 +228,27 @@
|
||||||
color: var(--primary-foreground-color);
|
color: var(--primary-foreground-color);
|
||||||
animation: 1s linear infinite alternate flash;
|
animation: 1s linear infinite alternate flash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 3.5rem;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 3.5rem;
|
||||||
|
padding: 0 1rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--primary-foreground-color);
|
||||||
|
outline: var(--focus-outline-size) solid var(--primary-foreground-color);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--secondary-foreground-color);
|
||||||
|
background-color: var(--primary-foreground-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
71
src/routes/Intro/useFacebookLogin.ts
Normal file
71
src/routes/Intro/useFacebookLogin.ts
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
// Copyright (C) 2017-2023 Smart code 203358507
|
||||||
|
|
||||||
|
import { useCallback, useEffect, useRef } from 'react';
|
||||||
|
import hat from 'hat';
|
||||||
|
import { usePlatform } from 'stremio/common';
|
||||||
|
|
||||||
|
const STREMIO_URL = 'https://www.strem.io';
|
||||||
|
const MAX_TRIES = 25;
|
||||||
|
|
||||||
|
const getCredentials = async (state: string) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${STREMIO_URL}/login-fb-get-acc/${state}`);
|
||||||
|
const { user } = await response.json();
|
||||||
|
|
||||||
|
return Promise.resolve({
|
||||||
|
email: user.email,
|
||||||
|
password: user.fbLoginToken,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to get credentials from facebook auth', e);
|
||||||
|
return Promise.reject(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const useFacebookLogin = () => {
|
||||||
|
const platform = usePlatform();
|
||||||
|
const started = useRef(false);
|
||||||
|
const timeout = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
|
const start = useCallback(() => new Promise((resolve, reject) => {
|
||||||
|
started.current = true;
|
||||||
|
const state = hat(128);
|
||||||
|
let tries = 0;
|
||||||
|
|
||||||
|
platform.openExternal(`${STREMIO_URL}/login-fb/${state}`);
|
||||||
|
|
||||||
|
const waitForCredentials = () => {
|
||||||
|
if (started.current) {
|
||||||
|
timeout.current && clearTimeout(timeout.current);
|
||||||
|
timeout.current = setTimeout(() => {
|
||||||
|
if (tries >= MAX_TRIES)
|
||||||
|
return reject(new Error('Failed to authenticate with facebook'));
|
||||||
|
|
||||||
|
tries++;
|
||||||
|
|
||||||
|
getCredentials(state)
|
||||||
|
.then(resolve)
|
||||||
|
.catch(waitForCredentials);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
waitForCredentials();
|
||||||
|
}), []);
|
||||||
|
|
||||||
|
const stop = useCallback(() => {
|
||||||
|
started.current = false;
|
||||||
|
timeout.current && clearTimeout(timeout.current);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => stop();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return [
|
||||||
|
start,
|
||||||
|
stop,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = useFacebookLogin;
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
// Copyright (C) 2017-2023 Smart code 203358507
|
|
||||||
|
|
||||||
const React = require('react');
|
|
||||||
|
|
||||||
const useFacebookToken = () => {
|
|
||||||
const getToken = React.useCallback(() => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (typeof FB === 'undefined') {
|
|
||||||
reject(new Error('Failed to connect to Facebook'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FB.getLoginStatus((resp) => {
|
|
||||||
if (resp && resp.authResponse && typeof resp.authResponse.accessToken === 'string') {
|
|
||||||
resolve(resp.authResponse.accessToken);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FB.login((resp) => {
|
|
||||||
if (!resp || !resp.authResponse || typeof resp.authResponse.accessToken !== 'string') {
|
|
||||||
reject(new Error('Failed to get token from Facebook'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(resp.authResponse.accessToken);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
React.useEffect(() => {
|
|
||||||
window.fbAsyncInit = function() {
|
|
||||||
FB.init({
|
|
||||||
appId: '1537119779906825',
|
|
||||||
status: true,
|
|
||||||
xfbml: false,
|
|
||||||
version: 'v2.7'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const sdkScriptElement = document.createElement('script');
|
|
||||||
sdkScriptElement.src = 'https://connect.facebook.net/en_US/sdk.js';
|
|
||||||
sdkScriptElement.async = true;
|
|
||||||
sdkScriptElement.defer = true;
|
|
||||||
document.body.appendChild(sdkScriptElement);
|
|
||||||
return () => {
|
|
||||||
document.body.removeChild(sdkScriptElement);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
return getToken;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = useFacebookToken;
|
|
||||||
Loading…
Reference in a new issue