diff --git a/src/common/NavBar/NavMenu/NavMenu.js b/src/common/NavBar/NavMenu/NavMenu.js index b8126116a..329e93dfb 100644 --- a/src/common/NavBar/NavMenu/NavMenu.js +++ b/src/common/NavBar/NavMenu/NavMenu.js @@ -2,14 +2,16 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); +const { useServices } = require('stremio/services'); const Button = require('stremio/common/Button'); const Popup = require('stremio/common/Popup'); const useBinaryState = require('stremio/common/useBinaryState'); const useFullscreen = require('stremio/common/useFullscreen'); -const useUser = require('./useUser'); +const useUser = require('stremio/common/useUser'); const styles = require('./styles'); const NavMenu = ({ className }) => { + const { core } = useServices(); const [menuOpen, openMenu, closeMenu, toggleMenu] = useBinaryState(false); const [fullscreen, requestFullscreen, exitFullscreen] = useFullscreen(); const user = useUser(); @@ -21,6 +23,14 @@ const NavMenu = ({ className }) => { const popupMenuOnClick = React.useCallback((event) => { event.nativeEvent.togglePopupPrevented = true; }, []); + const logoutButtonOnClick = React.useCallback(() => { + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'Logout' + } + }); + }, []); return ( {
-
{user.anonymous ? 'Anonymous user' : user.email}
+
{!user ? 'Anonymous user' : user.email}
-
diff --git a/src/common/useUser.js b/src/common/useUser.js index 0c5391b26..cb92a36b6 100644 --- a/src/common/useUser.js +++ b/src/common/useUser.js @@ -3,14 +3,18 @@ const { useServices } = require('stremio/services'); const useUser = () => { const { core } = useServices(); - const [user, setUser] = React.useState(state.ctx.auth ? state.ctx.auth.user : null); + const [user, setUser] = React.useState(() => { + const state = core.getState(); + return state.ctx.content.auth ? state.ctx.content.auth.user : null; + }); React.useEffect(() => { - const onNewModel = () => { - setUser(state.ctx.auth ? state.ctx.auth.user : null); + const onNewState = () => { + const state = core.getState(); + setUser(state.ctx.content.auth ? state.ctx.content.auth.user : null); }; - core.on('NewModel', onNewModel); + core.on('NewModel', onNewState); return () => { - core.off('NewModel', onNewModel); + core.off('NewModel', onNewState); }; }, []); return user; diff --git a/src/index.html b/src/index.html index 55a8694ad..919a94851 100755 --- a/src/index.html +++ b/src/index.html @@ -12,6 +12,17 @@
+ + diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index 9f1ad474f..beb35e26d 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -3,14 +3,15 @@ const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const { useRouteFocused } = require('stremio-router'); const { Button } = require('stremio/common'); +const { useServices } = require('stremio/services'); const CredentialsTextInput = require('./CredentialsTextInput'); const ConsentCheckbox = require('./ConsentCheckbox'); const styles = require('./styles'); -const LOGIN_FORM = 'LOGIN_FORM'; -const SIGNUP_FORM = 'SIGNUP_FORM'; +const SIGNUP_FORM = 'signup'; -const Intro = () => { +const Intro = ({ queryParams }) => { + const { core } = useServices(); const routeFocused = useRouteFocused(); const emailRef = React.useRef(); const passwordRef = React.useRef(); @@ -22,17 +23,20 @@ const Intro = () => { const [state, dispatch] = React.useReducer( (state, action) => { switch (action.type) { - case 'switch-form': - return { - form: state.form === SIGNUP_FORM ? LOGIN_FORM : SIGNUP_FORM, - email: '', - password: '', - confirmPassword: '', - termsAccepted: false, - privacyPolicyAccepted: false, - marketingAccepted: false, - error: '' - }; + case 'set-form': + if (state.form !== action.form) { + return { + form: action.form, + email: '', + password: '', + confirmPassword: '', + termsAccepted: false, + privacyPolicyAccepted: false, + marketingAccepted: false, + error: '' + }; + } + return state; case 'change-credentials': return { ...state, @@ -55,7 +59,7 @@ const Intro = () => { } }, { - form: SIGNUP_FORM, + form: queryParams.get('form'), email: '', password: '', confirmPassword: '', @@ -65,27 +69,115 @@ const Intro = () => { error: '' } ); - const loginWithFacebook = React.useCallback(() => { - alert('TODO: Facebook login'); + React.useEffect(() => { + const onEvent = ({ event, args }) => { + if (event === 'CtxActionErr') { + dispatch({ type: 'error', error: args[1].args.message }); + } + if (event === 'CtxChanged') { + const state = core.getState(); + if (state.ctx.content.auth !== null) { + window.location.replace('/'); + } + } + }; + core.on('Event', onEvent); + return () => { + core.off('Event', onEvent); + }; }, []); + const loginWithFacebook = React.useCallback(() => { + FB.login((response) => { + if (response.status === 'connected') { + fetch('https://www.strem.io/fb-login-with-token/' + encodeURIComponent(response.authResponse.accessToken), { timeout: 10 * 1000 }) + .then((resp) => { + if (resp.status < 200 || resp.status >= 300) { + throw new Error('Login failed at getting token from Stremio with status ' + resp.status); + } else { + return resp.json(); + } + }) + .then(() => { + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'Login', + args: { + email: state.email, + password: response.authResponse.accessToken + } + } + }); + }) + .catch((err) => { + console.error(err); + }); + } + }); + }, [state.email, state.password]); const loginWithEmail = React.useCallback(() => { if (typeof state.email !== 'string' || state.email.length === 0) { dispatch({ type: 'error', error: 'Invalid email' }); return; } - - alert('TODO: Login'); + if (state.password.length === 0) { + dispatch({ type: 'error', error: 'Invalid password' }); + return; + } + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'Login', + args: { + email: state.email, + password: state.password + } + } + }); }, [state.email, state.password]); const loginAsGuest = React.useCallback(() => { if (!state.termsAccepted) { dispatch({ type: 'error', error: 'You must accept the Terms of Service' }); return; } - - alert('TODO: Guest login'); - }, [state.termsAccepted, state.privacyPolicyAccepted, state.marketingAccepted]); + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'Logout' + } + }); + location = '#/'; + }, [state.termsAccepted]); const signup = React.useCallback(() => { - alert('TODO: Signup'); + if (!state.termsAccepted) { + dispatch({ type: 'error', error: 'You must accept the Terms of Service' }); + return; + } + if (!state.privacyPolicyAccepted) { + dispatch({ type: 'error', error: 'You must accept the Privacy Policy' }); + return; + } + if (state.password !== state.confirmPassword) { + dispatch({ type: 'error', error: 'Passwords do not match' }); + return; + } + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'Register', + args: { + email: state.email, + password: state.password, + gdpr_consent: { + tos: state.termsAccepted, + privacy: state.privacyPolicyAccepted, + marketing: state.marketingAccepted, + time: new Date(), + from: 'web' + } + } + } + }); }, [state.email, state.password, state.confirmPassword, state.termsAccepted, state.privacyPolicyAccepted, state.marketingAccepted]); const emailOnChange = React.useCallback((event) => { dispatch({ @@ -130,9 +222,9 @@ const Intro = () => { const toggleMarketingAccepted = React.useCallback(() => { dispatch({ type: 'toggle-checkbox', name: 'marketingAccepted' }); }, []); - const switchForm = React.useCallback(() => { - dispatch({ type: 'switch-form' }); - }, []); + React.useEffect(() => { + dispatch({ type: 'set-form', form: queryParams.get('form') }); + }, [queryParams]); React.useEffect(() => { if (typeof state.error === 'string' && state.error.length > 0) { errorRef.current.scrollIntoView(); @@ -229,7 +321,7 @@ const Intro = () => { : null } -