From 7e7394acb0578e1a6125efa4f99a33754571aef7 Mon Sep 17 00:00:00 2001 From: Johnson Mao <86179381+JohnsonMao@users.noreply.github.com> Date: Mon, 7 Oct 2024 20:48:34 +0800 Subject: [PATCH] feat: optimize login flow (#91) --- components/Group/Form/index.jsx | 15 +- components/Group/Form/useGroupForm.jsx | 9 +- components/Group/detail/Contact/index.jsx | 14 +- pages/_app.jsx | 27 ++- pages/index.jsx | 15 +- pages/login/index.jsx | 32 ++-- pages/login/popup/index.jsx | 158 ++++++++++++++++++ .../MainNav/Hamberger/MenuList.jsx | 8 +- .../Navigation_v2/MainNav/SubList/index.jsx | 6 +- shared/components/Navigation_v2/index.jsx | 2 +- utils/openLoginWindow.js | 15 ++ utils/share.js | 2 +- utils/storage.js | 19 +++ 13 files changed, 273 insertions(+), 49 deletions(-) create mode 100644 pages/login/popup/index.jsx create mode 100644 utils/openLoginWindow.js create mode 100644 utils/storage.js diff --git a/components/Group/Form/index.jsx b/components/Group/Form/index.jsx index 63061b0f..ab635d72 100644 --- a/components/Group/Form/index.jsx +++ b/components/Group/Form/index.jsx @@ -24,8 +24,15 @@ export default function GroupForm({ isLoading, onSubmit, }) { - const { control, values, errors, isDirty, setValues, handleSubmit } = - useGroupForm(); + const { + notLogin, + control, + values, + errors, + isDirty, + setValues, + handleSubmit, + } = useGroupForm(); const isCreateMode = mode === 'create'; useEffect(() => { @@ -36,6 +43,10 @@ export default function GroupForm({ }); }, [defaultValues]); + if (notLogin) { + return ; + } + return ( diff --git a/components/Group/Form/useGroupForm.jsx b/components/Group/Form/useGroupForm.jsx index f18a272c..502ae9f1 100644 --- a/components/Group/Form/useGroupForm.jsx +++ b/components/Group/Form/useGroupForm.jsx @@ -1,11 +1,11 @@ import { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; -import { useRouter } from 'next/router'; import { ZodType, z } from 'zod'; import { CATEGORIES } from '@/constants/category'; import { AREAS } from '@/constants/areas'; import { EDUCATION_STEP } from '@/constants/member'; import { BASE_URL } from '@/constants/common'; +import openLoginWindow from '@/utils/openLoginWindow'; const _eduOptions = EDUCATION_STEP.filter( (edu) => !['master', 'doctor', 'other'].includes(edu.value), @@ -57,9 +57,9 @@ const rules = { }; export default function useGroupForm() { - const router = useRouter(); const [isDirty, setIsDirty] = useState(false); const me = useSelector((state) => state.user); + const notLogin = !me?._id; const [values, setValues] = useState({ ...DEFAULT_VALUES, userId: me?._id, @@ -143,10 +143,11 @@ export default function useGroupForm() { }; useEffect(() => { - if (!me?._id) router.push('/login'); - }, [me, router]); + if (notLogin) openLoginWindow('/login'); + }, [notLogin]); return { + notLogin, control, errors, values, diff --git a/components/Group/detail/Contact/index.jsx b/components/Group/detail/Contact/index.jsx index 69e35242..5d8934ab 100644 --- a/components/Group/detail/Contact/index.jsx +++ b/components/Group/detail/Contact/index.jsx @@ -1,7 +1,6 @@ import { useId, useState, forwardRef, useEffect } from 'react'; import { useRouter } from 'next/router'; import { useSelector } from 'react-redux'; -import Link from 'next/link'; import styled from '@emotion/styled'; import { Avatar, @@ -20,6 +19,7 @@ import { ROLE } from '@/constants/member'; import chatSvg from '@/public/assets/icons/chat.svg'; import useMutation from '@/hooks/useMutation'; import { mapToTable } from '@/utils/helper'; +import openLoginWindow from '@/utils/openLoginWindow'; import Feedback from './Feedback'; const ROLELIST = mapToTable(ROLE); @@ -55,17 +55,18 @@ const StyledTextArea = styled(TextareaAutosize)` width: 100%; min-height: 128px; `; -const StyledLink = styled(Link)` +const StyledText = styled.div` margin-top: 6px; margin-left: 6px; display: block; color: black; font-size: 12px; `; -const StyledSpan = styled.span` +const StyledLink = styled.span` padding: 0 2px; color: #16b9b3; text-decoration: underline; + cursor: pointer; `; const Transition = forwardRef((props, ref) => { @@ -152,10 +153,11 @@ function ContactButton({ {label} {!isLogin && ( - - 註冊登入 + + router.push('/login')}>註冊或 + openLoginWindow()}>登入 即可聯繫主揪! - + )} { const ThemeComponentWrap = ({ pageProps, Component }) => { const dispatch = useDispatch(); - const firebaseApp = initializeApp(firebaseConfig); const mode = useSelector((state) => state?.theme?.mode ?? 'light'); const theme = useMemo(() => themeFactory(mode), [mode]); const isEnv = useMemo(() => process.env.NODE_ENV === 'development', []); + const router = useRouter(); useEffect(() => { dispatch(checkLoginValidity()); }, []); + useEffect(() => { + const receiveMessage = (e) => { + if (e.origin !== window.location.origin) return; + if (e.data.isLogin) { + const { token, id } = e.data; + const redirectionStorage = getRedirectionStorage(); + const redirection = redirectionStorage.get(); + dispatch(fetchUserById(id, token)); + if (redirection) { + redirectionStorage.remove(); + router.push(redirection); + } + } + }; + window.addEventListener('message', receiveMessage, false); + + return () => { + window.removeEventListener('message', receiveMessage, false); + }; + }, []); + return ( {/* mui normalize css */} diff --git a/pages/index.jsx b/pages/index.jsx index b132474b..2e3f97d6 100644 --- a/pages/index.jsx +++ b/pages/index.jsx @@ -1,8 +1,6 @@ import React, { useMemo, useEffect } from 'react'; import styled from '@emotion/styled'; import { useRouter } from 'next/router'; -import { useDispatch, useSelector } from 'react-redux'; -import { fetchUserById } from '@/redux/actions/user'; import SEOConfig from '../shared/components/SEO'; import Home from '../components/Home'; import Navigation from '../shared/components/Navigation_v2'; @@ -47,14 +45,15 @@ const HomePage = () => { [router?.asPath], ); - // fetch signin userData with token and id from query String - - const dispatch = useDispatch(); const { token, id } = router.query; + useEffect(() => { - if (token) { - dispatch(fetchUserById(id, token)); - router.push('/'); + if (id && token) { + window.opener?.postMessage( + { isLogin: true, id, token }, + window.location.origin, + ); + window.close(); } }, [id, token]); diff --git a/pages/login/index.jsx b/pages/login/index.jsx index b2350063..45f8e3cd 100644 --- a/pages/login/index.jsx +++ b/pages/login/index.jsx @@ -1,7 +1,6 @@ import React, { useMemo } from 'react'; import styled from '@emotion/styled'; import { useRouter } from 'next/router'; -import Link from '@mui/material/Link'; import Script from 'next/script'; import { Box, Typography, Button, Skeleton } from '@mui/material'; import { LazyLoadImage } from 'react-lazy-load-image-component'; @@ -9,6 +8,7 @@ import SEOConfig from '@/shared/components/SEO'; import Navigation from '@/shared/components/Navigation_v2'; import Footer from '@/shared/components/Footer_v2'; import { BASE_URL } from '@/constants/common'; +import openLoginWindow from '@/utils/openLoginWindow'; // import sendDataToChromeExtension from '../../utils/sendDataToChromeExtension'; const HomePageWrapper = styled.div` @@ -38,7 +38,7 @@ const ContentWrapper = styled.div` `; const LoginPage = () => { - const LOGINPATH = `${BASE_URL}/auth/google`; + const LOGIN_PATH = `${BASE_URL}/auth/google`; const router = useRouter(); const SEOData = useMemo( @@ -101,21 +101,19 @@ const LoginPage = () => { /> } /> - - - + {`註冊即代表您同意島島阿學的 `} diff --git a/pages/login/popup/index.jsx b/pages/login/popup/index.jsx new file mode 100644 index 00000000..c1a5786c --- /dev/null +++ b/pages/login/popup/index.jsx @@ -0,0 +1,158 @@ +import React, { useMemo } from 'react'; +import styled from '@emotion/styled'; +import { useRouter } from 'next/router'; +import Link from '@mui/material/Link'; +import Script from 'next/script'; +import { Box, Typography, Button, Skeleton } from '@mui/material'; +import { LazyLoadImage } from 'react-lazy-load-image-component'; +import SEOConfig from '@/shared/components/SEO'; +import { NavigationWrapper } from '@/shared/components/Navigation_v2'; +import { BASE_URL } from '@/constants/common'; +import Logo from '@/shared/components/Navigation_v2/MainNav/Logo'; + +const HomePageWrapper = styled.div` + --section-height: calc(100vh - 80px); + --section-height-offset: 80px; + background: linear-gradient(0deg, #f3fcfc, #f3fcfc), #f7f8fa; +`; + +const ContentWrapper = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + background-color: #fff; + border-radius: 8px; + margin: 60px auto; + padding: 40px 40px; + max-width: 440px; + width: 100%; + @media (max-width: 767px) { + width: 90%; + .title { + text-overflow: ellipsis; + width: 100%; + } + } +`; + +const LoginPage = () => { + const LOGINPATH = `${BASE_URL}/auth/google`; + const router = useRouter(); + + const SEOData = useMemo( + () => ({ + title: '登入島島|島島阿學', + description: + '「島島阿學」盼能透過建立多元的學習資源網絡,讓自主學習者能找到合適的成長方法,進一步成為自己想成為的人,從中培養共好精神。目前正積極打造「可共編的學習資源平台」。', + keywords: '島島阿學', + author: '島島阿學', + copyright: '島島阿學', + imgLink: 'https://www.daoedu.tw/preview.webp', + link: `${process.env.HOSTNAME}${router?.asPath}`, + }), + [router?.asPath], + ); + + return ( + <> +