From 385e9fc399ab3182b85f6dc507720b3bd3a3f07e Mon Sep 17 00:00:00 2001 From: VincentXu <90778107+vincentxuu@users.noreply.github.com> Date: Mon, 7 Oct 2024 07:43:11 +0800 Subject: [PATCH 01/12] fix:adjust value of options (#86) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修正以下: 1.刪除高中以下學歷選項 2.刪除交友相關字眼,並新增選項 3.調整揪團教育階段敘述 4.調整學歷敘述 5.調整性別敘述 --- components/Group/Form/index.jsx | 4 +- components/Group/Form/useGroupForm.jsx | 4 +- .../SearchField/SelectedEducationStep.jsx | 2 +- constants/member.js | 82 +++++++++---------- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/components/Group/Form/index.jsx b/components/Group/Form/index.jsx index 5364eaed..63061b0f 100644 --- a/components/Group/Form/index.jsx +++ b/components/Group/Form/index.jsx @@ -100,12 +100,12 @@ export default function GroupForm({ placeholder="想找什麼類型的夥伴?" /> !['master', 'doctor', 'other'].includes(edu.value), ); -_eduOptions.push({ key: 'noLimit', value: 'noLimit', label: '不限' }); +_eduOptions.push({ key: 'noLimit', value: 'noLimit', label: '終生學習' }); export const categoriesOptions = CATEGORIES; export const areasOptions = AREAS.filter((area) => area.label !== '線上'); @@ -47,7 +47,7 @@ const rules = { partnerStyle: z.string().max(50, '請勿輸入超過 50 字'), partnerEducationStep: z .array(z.enum(eduOptions.map(({ label }) => label))) - .min(1, '請選擇教育階段'), + .min(1, '請選擇的學習階段'), description: z .string() .min(1, '請輸入揪團描述') diff --git a/components/Group/SearchField/SelectedEducationStep.jsx b/components/Group/SearchField/SelectedEducationStep.jsx index b415449b..25caaff4 100644 --- a/components/Group/SearchField/SelectedEducationStep.jsx +++ b/components/Group/SearchField/SelectedEducationStep.jsx @@ -19,7 +19,7 @@ export default function SelectedEducationStep() { itemLabel="label" itemValue="label" renderValue={(selected) => - selected.length === 0 ? '適合的教育階段' : selected.join('、') + selected.length === 0 ? '適合的學習階段' : selected.join('、') } sx={{ '@media (max-width: 767px)': { diff --git a/constants/member.js b/constants/member.js index 6c2ca210..00e7dee6 100644 --- a/constants/member.js +++ b/constants/member.js @@ -8,7 +8,7 @@ export const GENDER = [ value: 'female', }, { - label: '其他', + label: '保持神秘', value: 'other', }, ]; @@ -46,7 +46,7 @@ export const ROLE = [ image: 'https://i.imgur.com/cXZXfBL.png', }, { - label: '其他', + label: '終生學習', key: 'other', value: 'other', image: 'https://i.imgur.com/Z7oGEnb.png', @@ -54,38 +54,38 @@ export const ROLE = [ ]; export const EDUCATION_STEP = [ - { - label: '學齡前', - key: 'preschool', - value: 'preschool', - }, - { - label: '國小低年級', - key: 'elementary-junior', - value: 'elementary-junior', - }, - { - label: '國小中年級', - key: 'elementary-middle', - value: 'elementary-middle', - }, - { - label: '國小高年級', - key: 'elementary-senior', - value: 'elementary-senior', - }, - { - label: '國中', - key: 'junior-high', - value: 'junior-high', - }, + // { + // label: '學齡前', + // key: 'preschool', + // value: 'preschool', + // }, + // { + // label: '國小低年級', + // key: 'elementary-junior', + // value: 'elementary-junior', + // }, + // { + // label: '國小中年級', + // key: 'elementary-middle', + // value: 'elementary-middle', + // }, + // { + // label: '國小高年級', + // key: 'elementary-senior', + // value: 'elementary-senior', + // }, + // { + // label: '國中', + // key: 'junior-high', + // value: 'junior-high', + // }, { label: '高中', key: 'high', value: 'high', }, { - label: '大學', + label: '大學以上', key: 'university', value: 'university', }, @@ -100,7 +100,7 @@ export const EDUCATION_STEP = [ value: 'doctor', }, { - label: '其他', + label: '終生學習', key: 'other', value: 'other', }, @@ -111,30 +111,30 @@ export const EDUCATION_STAGE = EDUCATION_STEP.filter( ); export const WANT_TO_DO_WITH_PARTNER = [ - { - label: '交朋友', - key: 'make-friends', - value: 'make-friends', - }, { label: '學習交流', key: 'interaction', value: 'interaction', }, { - label: '找老師', - key: 'find-teacher', - value: 'find-teacher', + label: '做專案/競賽', + key: 'do-project', + value: 'do-project', }, { - label: '揪團組課', + label: '自組課程', key: 'make-group-class', value: 'make-group-class', }, { - label: '做專案/競賽', - key: 'do-project', - value: 'do-project', + label: '找揪團', + key: 'find-group', + value: 'find-group', + }, + { + label: '找老師', + key: 'find-teacher', + value: 'find-teacher', }, { label: '找學生', From 8ea069188da363ed795f65155e45284ddb6c483e Mon Sep 17 00:00:00 2001 From: VincentXu <90778107+vincentxuu@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:45:27 +0800 Subject: [PATCH 02/12] Fix/adjust options (#89) * fix:adjust value of options * fix:adjust value of rule --- components/Group/Form/useGroupForm.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Group/Form/useGroupForm.jsx b/components/Group/Form/useGroupForm.jsx index fd2bc815..f18a272c 100644 --- a/components/Group/Form/useGroupForm.jsx +++ b/components/Group/Form/useGroupForm.jsx @@ -47,7 +47,7 @@ const rules = { partnerStyle: z.string().max(50, '請勿輸入超過 50 字'), partnerEducationStep: z .array(z.enum(eduOptions.map(({ label }) => label))) - .min(1, '請選擇的學習階段'), + .min(1, '請選擇適合的學習階段'), description: z .string() .min(1, '請輸入揪團描述') 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 03/12] 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 ( + <> +