From d4b60bc5f17e04f184683d58017327471dc53717 Mon Sep 17 00:00:00 2001 From: ruby10127130 Date: Wed, 18 Dec 2024 20:45:20 +0800 Subject: [PATCH 01/32] styles: correct background-color typo --- components/Marathon/SignUp/EditSubMilestone.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Marathon/SignUp/EditSubMilestone.jsx b/components/Marathon/SignUp/EditSubMilestone.jsx index 87d02fd6..a0e218ee 100644 --- a/components/Marathon/SignUp/EditSubMilestone.jsx +++ b/components/Marathon/SignUp/EditSubMilestone.jsx @@ -40,10 +40,10 @@ const StyledContainer = styled(Box)` align-items: center; gap: 10px; width: 100%; - backgroundColor: #FFF; padding: 12px 16px; border-radius: 8px; border: 1px solid #DBDBDB; + background-color: #FFF; @media (max-width: 767px) { display: grid; From 21c6391d22da1264fff27ccbd4f8e7ff6c2104d4 Mon Sep 17 00:00:00 2001 From: ruby10127130 Date: Sat, 21 Dec 2024 15:40:41 +0800 Subject: [PATCH 02/32] feat: adjust new logo width to 152px --- shared/components/Navigation_v2/MainNav/Logo.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/components/Navigation_v2/MainNav/Logo.jsx b/shared/components/Navigation_v2/MainNav/Logo.jsx index a035a06f..1d444ca0 100644 --- a/shared/components/Navigation_v2/MainNav/Logo.jsx +++ b/shared/components/Navigation_v2/MainNav/Logo.jsx @@ -10,7 +10,7 @@ const Logo = () => { return ( - logo + logo ); From 99b74f1fe746741c79a14e0137e387c015c62446 Mon Sep 17 00:00:00 2001 From: ruby10127130 Date: Sat, 21 Dec 2024 15:50:56 +0800 Subject: [PATCH 03/32] feat: remove min-height and add @media hover on PromotionBar --- shared/components/Navigation_v2/PromotionBar.jsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/shared/components/Navigation_v2/PromotionBar.jsx b/shared/components/Navigation_v2/PromotionBar.jsx index 8d01a46e..8e5a7aaf 100644 --- a/shared/components/Navigation_v2/PromotionBar.jsx +++ b/shared/components/Navigation_v2/PromotionBar.jsx @@ -34,10 +34,12 @@ const PromotionBarWrapper = styled.div` justify-content: center; align-items: center; font-size: 16px; - min-height: 64px; - a:hover { - text-decoration: underline; - text-underline-offset: 3px; + + @media (hover: hover) { + a:hover { + text-decoration: underline; + text-underline-offset: 3px; + } } `; From e34a73556f35fe3d18d3f2096a26a9b58f31962f Mon Sep 17 00:00:00 2001 From: ruby10127130 Date: Sat, 21 Dec 2024 15:58:10 +0800 Subject: [PATCH 04/32] style: adjust learning-marathon/index sidebar font-size to 16px --- pages/learning-marathon/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/learning-marathon/index.jsx b/pages/learning-marathon/index.jsx index a1d0b5ff..b823d3d2 100644 --- a/pages/learning-marathon/index.jsx +++ b/pages/learning-marathon/index.jsx @@ -179,7 +179,7 @@ const Sidebar = ({ onClickSignupButton }) => { From 405fdd1d73bb1c5f5a8090892d99fd7a36086aef Mon Sep 17 00:00:00 2001 From: Johnson Mao <86179381+JohnsonMao@users.noreply.github.com> Date: Sat, 21 Dec 2024 18:40:03 +0800 Subject: [PATCH 05/32] fix(shared): modal component animation --- shared/components/Modal.tsx | 30 +++++++++++++++++++++++------- shared/components/Portal.tsx | 4 ++-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/shared/components/Modal.tsx b/shared/components/Modal.tsx index caabb755..1fb68ee5 100644 --- a/shared/components/Modal.tsx +++ b/shared/components/Modal.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useId } from "react"; import { cn } from "@/utils/cn"; import Portal from "./Portal"; @@ -6,6 +6,7 @@ interface ModalProps { isOpen: boolean; title: string; children: React.ReactNode; + describedby?: string; className?: string; keepMounted?: boolean; onClose: () => void; @@ -16,12 +17,16 @@ function Modal({ isOpen, title, children, + describedby, className, keepMounted = false, onClose, onRemovedDOM, }: ModalProps) { + const id = useId(); + const modalId = `modal-${id}`; const [removeDOM, setRemoveDOM] = useState(true); + const [isInitialized, setIsInitialized] = useState(false); const handleKeyUp: React.KeyboardEventHandler = (e) => { if (e.key === "Enter") { @@ -35,6 +40,7 @@ function Modal({ if (isOpen) { document.body.classList.add("overflow-y-hidden"); setRemoveDOM(false); + setIsInitialized(true); } else { timer = setTimeout(() => { setRemoveDOM(true); @@ -61,12 +67,16 @@ function Modal({ return ( (!removeDOM || keepMounted) && ( - +
) diff --git a/shared/components/Portal.tsx b/shared/components/Portal.tsx index 138a0025..964c18c4 100644 --- a/shared/components/Portal.tsx +++ b/shared/components/Portal.tsx @@ -3,10 +3,10 @@ import { createPortal } from "react-dom"; interface PortalProps { children: React.ReactNode; - rootId?: string; + rootId: string; } -function Portal({ children, rootId = "portal-root" }: PortalProps) { +function Portal({ children, rootId }: PortalProps) { const [targetRoot, setTargetRoot] = useState(null); useEffect(() => { From 353ff909a05c1e35380b25c7da3452b440307608 Mon Sep 17 00:00:00 2001 From: Johnson Mao <86179381+JohnsonMao@users.noreply.github.com> Date: Sat, 21 Dec 2024 18:56:56 +0800 Subject: [PATCH 06/32] refactor(utils): storage to ts --- utils/storage.js | 23 ----------------------- utils/storage.ts | 23 +++++++++++++++++++++++ 2 files changed, 23 insertions(+), 23 deletions(-) delete mode 100644 utils/storage.js create mode 100644 utils/storage.ts diff --git a/utils/storage.js b/utils/storage.js deleted file mode 100644 index a6fdd1f9..00000000 --- a/utils/storage.js +++ /dev/null @@ -1,23 +0,0 @@ -const fn = () => undefined; - -export default function createStorage(key, storage = localStorage) { - if (!storage) return { set: fn, get: fn, remove: fn }; - - const remove = () => storage.removeItem(key); - const set = (value) => storage.setItem(key, JSON.stringify(value)); - const get = () => { - try { - return JSON.parse(storage.getItem(key) || 'undefined'); - } catch { - return undefined; - } - }; - - return { set, get, remove }; -} - -export const getTokenStorage = () => createStorage('_token'); -export const getRedirectionStorage = () => createStorage('_r'); -export const getTrustWebsitesStorage = () => createStorage('_trustWeb'); -export const getReminderStorage = () => createStorage('_reminder'); -export const getMarathonErrorsStorage = () => createStorage('_marathonFormErrors'); diff --git a/utils/storage.ts b/utils/storage.ts new file mode 100644 index 00000000..96f214bb --- /dev/null +++ b/utils/storage.ts @@ -0,0 +1,23 @@ +const fn = () => undefined; + +export default function createStorage(key: string, storage = localStorage) { + if (!storage) return { set: fn, get: fn, remove: fn }; + + const remove = () => storage.removeItem(key); + const set = (value: T) => storage.setItem(key, JSON.stringify(value)); + const get = (): T | undefined => { + try { + return JSON.parse(storage.getItem(key) || 'undefined'); + } catch { + return undefined; + } + }; + + return { set, get, remove }; +} + +export const getTokenStorage = () => createStorage('_token'); +export const getRedirectionStorage = () => createStorage('_r'); +export const getTrustWebsitesStorage = () => createStorage('_trustWeb'); +export const getReminderStorage = () => createStorage('_reminder'); +export const getMarathonErrorsStorage = () => createStorage('_marathonFormErrors'); From b791da2687381f19def2187862504e5f825b6a75 Mon Sep 17 00:00:00 2001 From: Johnson Mao <86179381+JohnsonMao@users.noreply.github.com> Date: Sat, 21 Dec 2024 19:08:33 +0800 Subject: [PATCH 07/32] feat(signin): add token-based ProtectedComponent --- pages/signin/index.jsx | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/pages/signin/index.jsx b/pages/signin/index.jsx index 0fd63f0b..ac6b6b22 100644 --- a/pages/signin/index.jsx +++ b/pages/signin/index.jsx @@ -1,10 +1,8 @@ -import { useEffect, useState } from 'react'; -import { useRouter } from 'next/router'; -import Navigation from '@/shared/components/Navigation_v2'; -import Footer from '@/shared/components/Footer_v2'; -import { HomePageWrapper } from '@/components/Signin/Signin.styled'; +import { useState } from 'react'; +import { useRouter } from 'next/navigation'; +import toast from 'react-hot-toast'; import useProfileValidation from '@/components/Signin/useValidation'; -import { useAuth, useAuthDispatch } from '@/contexts/Auth'; +import { ProtectedComponent, useAuthDispatch } from '@/contexts/Auth'; import Step1 from '@/components/Signin/Step1'; import Step2 from '@/components/Signin/Step2'; import TipModal from '@/components/Signin/Interest/TipModal'; @@ -16,7 +14,6 @@ function SignInPage() { const { errors, onChangeHandler, userState, validateFields } = useProfileValidation(); - const { isLoggedIn, token } = useAuth(); const { updateUser } = useAuthDispatch(); const handleSubmit = async () => { @@ -28,22 +25,14 @@ function SignInPage() { }; try { await updateUser(payload); - } catch (error) { - console.error(error); + } catch { + toast.error('伺服器異常,請稍後再試'); } } }; - useEffect(() => { - if (isLoggedIn) { - setOpen(true); - } else if (!token) { - router.push('/'); - } - }, [isLoggedIn, token]); - return ( - <> + {step === 1 && ( - + ); } -SignInPage.getLayout = ({ children }) => { - return ( - - - {children} -