From 083eeb243744889cdf511094d3e8fce3d0e993c5 Mon Sep 17 00:00:00 2001 From: Phoenix Pereira <47909638+phoenixpereira@users.noreply.github.com> Date: Sat, 24 Feb 2024 15:20:36 +1030 Subject: [PATCH 1/8] chore: Improve mobile responsiveness (#104) * chore: remove extra margin on join us page * feat: make account boxes fit better on mobile * refactor: simplify bool component props and rename isFormButton to size * feat(home): Add join us button at end of page * fix(home): Center sponsors on screen resize * feat(home): Use join us link instead of button * chore: spelling and grammar fixes (#86) * chore: more spelling and grammar fixes (#88) * feat: add button loading to indicate request in progress (#89) * chore: add loading for pay online button (#92) * feat: enable ssr for header * feat(api): remove unnecessary apis * feat: refresh rsc after mutation (#94) * feat: add titles for all pages * feat(seo): disable robot for few pages * fix(seo): remove metadata on client components * fix(header): mobile menu has correct links and behaviour (#96) * chore: Add underline styling to mobile menu links (#98) * fix(contact): minor fix for mobile style (#100) * fix: make button component valid after merge * chore: use self-closing tag for divs * chore: make settings container wider on desktop * fix(settings): responsive style for setting tabs --------- Co-authored-by: Ray <22254748+rayokamoto@users.noreply.github.com> Co-authored-by: Timothy Choi <101849050+tinnamchoi@users.noreply.github.com> Co-authored-by: jsun969 --- src/app/(account)/forgot-password/page.tsx | 6 +- src/app/(account)/join/page.tsx | 10 +- src/app/(account)/join/steps/StepFour.tsx | 12 +- src/app/(account)/join/steps/StepOne.tsx | 14 ++- src/app/(account)/join/steps/StepThree.tsx | 6 +- src/app/(account)/join/steps/StepTwo.tsx | 8 +- src/app/(account)/settings/Settings.tsx | 6 +- src/app/(account)/settings/Sidebar.tsx | 9 +- src/app/(account)/settings/page.tsx | 32 +++--- .../settings/tabs/AccountSettings.tsx | 8 +- .../settings/tabs/MembershipSettings.tsx | 6 +- .../settings/tabs/NotificationsSettings.tsx | 2 +- .../settings/tabs/PersonalInfoSettings.tsx | 2 +- src/app/(account)/signin/page.tsx | 106 +++++++++--------- src/app/(home)/page.tsx | 12 +- src/app/about/FAQ.tsx | 2 +- src/app/about/page.tsx | 16 +-- src/app/events/FridayNight.tsx | 2 +- src/app/events/Info.tsx | 2 +- src/components/Button.tsx | 17 ++- src/components/FancyRectangle.tsx | 2 +- src/components/Link.tsx | 2 +- 22 files changed, 153 insertions(+), 129 deletions(-) diff --git a/src/app/(account)/forgot-password/page.tsx b/src/app/(account)/forgot-password/page.tsx index 203968ea..17e3f347 100644 --- a/src/app/(account)/forgot-password/page.tsx +++ b/src/app/(account)/forgot-password/page.tsx @@ -126,9 +126,9 @@ export default function ForgotPasswordPage() { }); return ( -
- -
+
+ +

Forgot Your Password?

{STEP_INSTRUCTIONS[step]}

{step === 1 && ( diff --git a/src/app/(account)/join/page.tsx b/src/app/(account)/join/page.tsx index 6147cb90..dce7418b 100644 --- a/src/app/(account)/join/page.tsx +++ b/src/app/(account)/join/page.tsx @@ -28,7 +28,7 @@ export default function JoinPage() { }, [isSignedIn]); return ( -
+
Join Us
@@ -53,11 +53,11 @@ export default function JoinPage() {

-
- -
+
+ +

{heading.title}

-

{heading.description}

+

{heading.description}

diff --git a/src/app/(account)/join/steps/StepFour.tsx b/src/app/(account)/join/steps/StepFour.tsx index a32dc9ff..4441da7e 100644 --- a/src/app/(account)/join/steps/StepFour.tsx +++ b/src/app/(account)/join/steps/StepFour.tsx @@ -53,11 +53,17 @@ export default function StepFour() { type="checkbox" />
-
- -
diff --git a/src/app/(account)/join/steps/StepOne.tsx b/src/app/(account)/join/steps/StepOne.tsx index d4a710fd..a2d8edba 100644 --- a/src/app/(account)/join/steps/StepOne.tsx +++ b/src/app/(account)/join/steps/StepOne.tsx @@ -153,14 +153,15 @@ export default function StepOne() { return (
-
-
+

or

-
+
@@ -173,11 +174,12 @@ export default function StepOne() { control={form.control} name="password" /> -
+
-
diff --git a/src/app/(account)/join/steps/StepTwo.tsx b/src/app/(account)/join/steps/StepTwo.tsx index 7e9e7de2..8331bca8 100644 --- a/src/app/(account)/join/steps/StepTwo.tsx +++ b/src/app/(account)/join/steps/StepTwo.tsx @@ -70,11 +70,9 @@ export default function StepTwo() { {form.watch('studentStatus') === 'At The University of Adelaide' && ( )} -
- -
+ ); } diff --git a/src/app/(account)/settings/Settings.tsx b/src/app/(account)/settings/Settings.tsx index ee14e335..8282fce5 100644 --- a/src/app/(account)/settings/Settings.tsx +++ b/src/app/(account)/settings/Settings.tsx @@ -26,7 +26,7 @@ export default function Settings({ settingData }: { settingData: SettingData }) const { refresh } = useRouter(); return ( - <> +
{ @@ -34,9 +34,9 @@ export default function Settings({ settingData }: { settingData: SettingData }) refresh(); }} /> -
+
- +
); } diff --git a/src/app/(account)/settings/Sidebar.tsx b/src/app/(account)/settings/Sidebar.tsx index ed1ba8f6..2b1ce4ea 100644 --- a/src/app/(account)/settings/Sidebar.tsx +++ b/src/app/(account)/settings/Sidebar.tsx @@ -10,7 +10,7 @@ function SidebarTab({ tabName, currentTab, onTabChange }: SidebarTabProps) { const selected = currentTab === tabName; return (
); } diff --git a/src/app/(account)/settings/tabs/AccountSettings.tsx b/src/app/(account)/settings/tabs/AccountSettings.tsx index 0c1a2c59..1fc598d4 100644 --- a/src/app/(account)/settings/tabs/AccountSettings.tsx +++ b/src/app/(account)/settings/tabs/AccountSettings.tsx @@ -63,7 +63,7 @@ export default function AccountSettings({ Membership Status: Payment Required -
+

Finalise your membership by{' '}

Change Email

-
+

Email address

Change Password

-
+
+ ); } diff --git a/src/app/(home)/page.tsx b/src/app/(home)/page.tsx index 8b321096..13fd40d5 100644 --- a/src/app/(home)/page.tsx +++ b/src/app/(home)/page.tsx @@ -27,14 +27,14 @@ export default function HomePage() {

LEARN,

-
+

SOCIALISE,

-
+
CODE. -
+

Computer Science Club

@@ -46,7 +46,7 @@ export default function HomePage() { {/* Right side */}
- +
-
+
{/* */}
-
+
Thinking about Joining? diff --git a/src/app/about/FAQ.tsx b/src/app/about/FAQ.tsx index 41c48e18..1ba269d8 100644 --- a/src/app/about/FAQ.tsx +++ b/src/app/about/FAQ.tsx @@ -19,7 +19,7 @@ const FAQ = ({ question, answer, colour }: FAQProps) => { }; return ( - +
- + {'Meetto
- +
  • @@ -161,7 +161,7 @@ export default function AboutPage() {

- + {'Quiz
FAQ
-
+
{/* FAQ */}
diff --git a/src/app/events/FridayNight.tsx b/src/app/events/FridayNight.tsx index 674ee31c..d900ab0c 100644 --- a/src/app/events/FridayNight.tsx +++ b/src/app/events/FridayNight.tsx @@ -52,7 +52,7 @@ function Ducks() { function Details() { return ( - +
  • Need to blow off some steam from a long week of studying?
  • diff --git a/src/app/events/Info.tsx b/src/app/events/Info.tsx index 89b75b15..aaecb161 100644 --- a/src/app/events/Info.tsx +++ b/src/app/events/Info.tsx @@ -15,7 +15,7 @@ export default function Info({ className }: { className?: string }) {

    For further information, take a look at some of the events below!

- +
diff --git a/src/components/Button.tsx b/src/components/Button.tsx index ba12f1ec..1339ac22 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -11,20 +11,31 @@ interface ButtonProps { type?: 'button' | 'submit' | 'reset'; width?: string; loading?: boolean; + size?: 'base' | 'small'; font?: string; } -const Button = ({ children, colour, href, onClick, width, type, loading, font }: ButtonProps) => { +const Button = ({ + children, + colour, + href, + onClick, + width, + type, + loading, + font, + size = 'base', +}: ButtonProps) => { const isAnchor = !!href; const Component = isAnchor ? 'a' : 'button'; return ( - + {children} diff --git a/src/components/FancyRectangle.tsx b/src/components/FancyRectangle.tsx index b14d8e3d..07db8bc5 100644 --- a/src/components/FancyRectangle.tsx +++ b/src/components/FancyRectangle.tsx @@ -39,7 +39,7 @@ const FancyRectangle = ({ className={`absolute bottom-0 right-0 h-full w-full ${ filled ? BG_COLOURS[colour] : BORDER_COLOURS[colour] } ${rounded ? 'rounded-xl' : ''}`} - >
+ />
{children}
diff --git a/src/components/Link.tsx b/src/components/Link.tsx index 513f0282..906e768d 100644 --- a/src/components/Link.tsx +++ b/src/components/Link.tsx @@ -11,7 +11,7 @@ interface LinkProps { export default function Link({ name, link, icon: Icon, borderColour }: LinkProps) { return ( - + Date: Sat, 24 Feb 2024 19:00:32 +1030 Subject: [PATCH 2/8] feat: convert `forgot-password` `join` `signin` to rsc --- .../forgot-password/ForgotPassword.tsx | 186 +++++++++++++++++ src/app/(account)/forgot-password/page.tsx | 195 +----------------- src/app/(account)/join/Join.tsx | 73 +++++++ src/app/(account)/join/page.tsx | 79 +------ src/app/(account)/signin/SignIn.tsx | 151 ++++++++++++++ src/app/(account)/signin/page.tsx | 157 +------------- 6 files changed, 429 insertions(+), 412 deletions(-) create mode 100644 src/app/(account)/forgot-password/ForgotPassword.tsx create mode 100644 src/app/(account)/join/Join.tsx create mode 100644 src/app/(account)/signin/SignIn.tsx diff --git a/src/app/(account)/forgot-password/ForgotPassword.tsx b/src/app/(account)/forgot-password/ForgotPassword.tsx new file mode 100644 index 00000000..8e4c0800 --- /dev/null +++ b/src/app/(account)/forgot-password/ForgotPassword.tsx @@ -0,0 +1,186 @@ +'use client'; + +import Button from '@/components/Button'; +import ControlledField from '@/components/ControlledField'; +import FancyRectangle from '@/components/FancyRectangle'; +import { useSignIn } from '@clerk/nextjs'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import { handleClerkErrors } from '../helpers'; +import { codeSchema, emailSchema, passwordSchema } from '../schemas'; + +const sendCodeSchema = z.object({ + email: emailSchema, +}); +const resetPasswordSchema = z + .object({ + code: codeSchema, + password: passwordSchema, + confirmPassword: z.string().min(1, { message: 'Please confirm password' }), + }) + .refine((data) => data.password === data.confirmPassword, { + message: 'Passwords do not match', + path: ['confirmPassword'], + }); + +const STEP_INSTRUCTIONS = [ + '', // Step start from 1 + 'Enter your email to receive a reset code.', + 'Enter your new password and the code received in your email.', + 'Password reset complete!', +] as const; + +export default function ForgotPassword() { + const [step, setStep] = useState(1); + const { isLoaded, signIn, setActive } = useSignIn(); + + const sendCodeForm = useForm>({ + defaultValues: { email: '' }, + resolver: zodResolver(sendCodeSchema), + }); + const resetPasswordForm = useForm>({ + defaultValues: { code: '', password: '' }, + resolver: zodResolver(resetPasswordSchema), + }); + + const [sendCodeLoading, setSendCodeLoading] = useState(false); + const [resetPasswordLoading, setResetPasswordLoading] = useState(false); + + const handleSendCode = sendCodeForm.handleSubmit(async ({ email }) => { + if (!isLoaded) return; + + setSendCodeLoading(true); + + try { + const result = await signIn.create({ + strategy: 'reset_password_email_code', + identifier: email, + }); + if (result) { + setStep(2); + } + } catch (error) { + handleClerkErrors(error, sendCodeForm, [ + { + code: 'form_identifier_not_found', + field: 'email', + message: + "Couldn't find account with given email. Please create an account first.", + }, + { + code: 'form_conditional_param_value_disallowed', + field: 'email', + message: 'Account was created through Google. Please sign in using Google.', + }, + ]); + } + + setSendCodeLoading(false); + }); + + const handleResetPassword = resetPasswordForm.handleSubmit(async ({ code, password }) => { + if (!isLoaded) return; + + setResetPasswordLoading(true); + + try { + const resetResult = await signIn.attemptFirstFactor({ + strategy: 'reset_password_email_code', + code, + password, + }); + if (resetResult.status === 'complete') { + setActive({ session: resetResult.createdSessionId }); + setStep(3); + } + } catch (error) { + handleClerkErrors(error, resetPasswordForm, [ + { + code: 'form_password_not_strong_enough', + field: 'password', + message: + 'Given password is not strong enough. For account safety, please use a different password.', + }, + { + code: 'form_password_not_strong_enough', + field: 'password', + message: + 'Password has been found in an online data breach. For account safety, please use a different password.', + }, + { + code: 'form_code_incorrect', + field: 'code', + message: 'Incorrect Code. Please enter the code from your email.', + }, + ]); + } + + setResetPasswordLoading(false); + }); + + return ( +
+ +
+

Forgot Your Password?

+

{STEP_INSTRUCTIONS[step]}

+ {step === 1 && ( +
+ + + + )} + + {step === 2 && ( +
+ + + + + + )} + + {step === 3 && ( + + )} +
+
+
+ ); +} diff --git a/src/app/(account)/forgot-password/page.tsx b/src/app/(account)/forgot-password/page.tsx index 17e3f347..1a52a001 100644 --- a/src/app/(account)/forgot-password/page.tsx +++ b/src/app/(account)/forgot-password/page.tsx @@ -1,191 +1,10 @@ -'use client'; - -import Button from '@/components/Button'; -import ControlledField from '@/components/ControlledField'; -import FancyRectangle from '@/components/FancyRectangle'; -import { useSignIn } from '@clerk/nextjs'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { useState } from 'react'; -import { useForm } from 'react-hook-form'; -import { z } from 'zod'; -import { handleClerkErrors } from '../helpers'; -import { codeSchema, emailSchema, passwordSchema } from '../schemas'; - -// export const metadata: Metadata = { -// title: 'Forgot Password', -// robots: { index: false, follow: false }, -// }; - -const sendCodeSchema = z.object({ - email: emailSchema, -}); -const resetPasswordSchema = z - .object({ - code: codeSchema, - password: passwordSchema, - confirmPassword: z.string().min(1, { message: 'Please confirm password' }), - }) - .refine((data) => data.password === data.confirmPassword, { - message: 'Passwords do not match', - path: ['confirmPassword'], - }); - -const STEP_INSTRUCTIONS = [ - '', // Step start from 1 - 'Enter your email to receive a reset code.', - 'Enter your new password and the code received in your email.', - 'Password reset complete!', -] as const; +import type { Metadata } from 'next'; +import ForgotPassword from './ForgotPassword'; +export const metadata: Metadata = { + title: 'Forgot Password', + robots: { index: false, follow: false }, +}; export default function ForgotPasswordPage() { - const [step, setStep] = useState(1); - const { isLoaded, signIn, setActive } = useSignIn(); - - const sendCodeForm = useForm>({ - defaultValues: { email: '' }, - resolver: zodResolver(sendCodeSchema), - }); - const resetPasswordForm = useForm>({ - defaultValues: { code: '', password: '' }, - resolver: zodResolver(resetPasswordSchema), - }); - - const [sendCodeLoading, setSendCodeLoading] = useState(false); - const [resetPasswordLoading, setResetPasswordLoading] = useState(false); - - const handleSendCode = sendCodeForm.handleSubmit(async ({ email }) => { - if (!isLoaded) return; - - setSendCodeLoading(true); - - try { - const result = await signIn.create({ - strategy: 'reset_password_email_code', - identifier: email, - }); - if (result) { - setStep(2); - } - } catch (error) { - handleClerkErrors(error, sendCodeForm, [ - { - code: 'form_identifier_not_found', - field: 'email', - message: - "Couldn't find account with given email. Please create an account first.", - }, - { - code: 'form_conditional_param_value_disallowed', - field: 'email', - message: 'Account was created through Google. Please sign in using Google.', - }, - ]); - } - - setSendCodeLoading(false); - }); - - const handleResetPassword = resetPasswordForm.handleSubmit(async ({ code, password }) => { - if (!isLoaded) return; - - setResetPasswordLoading(true); - - try { - const resetResult = await signIn.attemptFirstFactor({ - strategy: 'reset_password_email_code', - code, - password, - }); - if (resetResult.status === 'complete') { - setActive({ session: resetResult.createdSessionId }); - setStep(3); - } - } catch (error) { - handleClerkErrors(error, resetPasswordForm, [ - { - code: 'form_password_not_strong_enough', - field: 'password', - message: - 'Given password is not strong enough. For account safety, please use a different password.', - }, - { - code: 'form_password_not_strong_enough', - field: 'password', - message: - 'Password has been found in an online data breach. For account safety, please use a different password.', - }, - { - code: 'form_code_incorrect', - field: 'code', - message: 'Incorrect Code. Please enter the code from your email.', - }, - ]); - } - - setResetPasswordLoading(false); - }); - - return ( -
- -
-

Forgot Your Password?

-

{STEP_INSTRUCTIONS[step]}

- {step === 1 && ( -
- - - - )} - - {step === 2 && ( -
- - - - - - )} - - {step === 3 && ( - - )} -
-
-
- ); + return ; } diff --git a/src/app/(account)/join/Join.tsx b/src/app/(account)/join/Join.tsx new file mode 100644 index 00000000..e1114c03 --- /dev/null +++ b/src/app/(account)/join/Join.tsx @@ -0,0 +1,73 @@ +'use client'; + +import FancyRectangle from '@/components/FancyRectangle'; +import Title from '@/components/Title'; +import { SignedIn, SignedOut, useUser } from '@clerk/nextjs'; +import Link from 'next/link'; +import { useEffect } from 'react'; +import ProgressBar from './ProgressBar'; +import StepFour from './steps/StepFour'; +import StepOne from './steps/StepOne'; +import StepThree from './steps/StepThree'; +import StepTwo from './steps/StepTwo'; +import { useJoinUsHeading, useJoinUsStep } from './store'; + +export default function Join() { + const { step, setStep } = useJoinUsStep(); + const { heading } = useJoinUsHeading(); + + const { isSignedIn } = useUser(); + useEffect(() => { + if (isSignedIn) { + setStep(2); + } + }, [isSignedIn]); + + return ( +
+ Join Us +
+
+

New Members are

+
+

Always Welcome

+
+
+
+

+ Membership costs $10 for the full year. + You can pay for membership online here at our website. Alternatively, you + can pay at a club event or contact one of the{' '} + + committee members + + . +

+

+ Create an account below to start the + registration process. +

+
+
+
+ +
+

{heading.title}

+

{heading.description}

+ + + + + + + { + // eslint-disable-next-line react/jsx-key + [, , ][step - 2] + } + +
+
+
+
+ ); +} diff --git a/src/app/(account)/join/page.tsx b/src/app/(account)/join/page.tsx index dce7418b..72670acd 100644 --- a/src/app/(account)/join/page.tsx +++ b/src/app/(account)/join/page.tsx @@ -1,77 +1,10 @@ -'use client'; +import type { Metadata } from 'next'; +import Join from './Join'; -import FancyRectangle from '@/components/FancyRectangle'; -import Title from '@/components/Title'; -import { SignedIn, SignedOut, useUser } from '@clerk/nextjs'; -import Link from 'next/link'; -import { useEffect } from 'react'; -import ProgressBar from './ProgressBar'; -import StepFour from './steps/StepFour'; -import StepOne from './steps/StepOne'; -import StepThree from './steps/StepThree'; -import StepTwo from './steps/StepTwo'; -import { useJoinUsHeading, useJoinUsStep } from './store'; - -// export const metadata: Metadata = { -// title: 'Join', -// }; +export const metadata: Metadata = { + title: 'Join', +}; export default function JoinPage() { - const { step, setStep } = useJoinUsStep(); - const { heading } = useJoinUsHeading(); - - const { isSignedIn } = useUser(); - useEffect(() => { - if (isSignedIn) { - setStep(2); - } - }, [isSignedIn]); - - return ( -
- Join Us -
-
-

New Members are

-
-

Always Welcome

-
-
-
-

- Membership costs $10 for the full year. - You can pay for membership online here at our website. Alternatively, you - can pay at a club event or contact one of the{' '} - - committee members - - . -

-

- Create an account below to start the - registration process. -

-
-
-
- -
-

{heading.title}

-

{heading.description}

- - - - - - - { - // eslint-disable-next-line react/jsx-key - [, , ][step - 2] - } - -
-
-
-
- ); + return ; } diff --git a/src/app/(account)/signin/SignIn.tsx b/src/app/(account)/signin/SignIn.tsx new file mode 100644 index 00000000..c218171d --- /dev/null +++ b/src/app/(account)/signin/SignIn.tsx @@ -0,0 +1,151 @@ +'use client'; + +import Button from '@/components/Button'; +import ControlledField from '@/components/ControlledField'; +import FancyRectangle from '@/components/FancyRectangle'; +import { useSignIn } from '@clerk/clerk-react'; +import { zodResolver } from '@hookform/resolvers/zod'; +import Link from 'next/link'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { FcGoogle } from 'react-icons/fc'; +import { z } from 'zod'; +import { handleClerkErrors } from '../helpers'; +import { emailSchema } from '../schemas'; + +const signInSchema = z.object({ + email: emailSchema, + password: z.string().min(1, { message: 'Please enter your password' }), +}); + +export default function SignIn() { + const { isLoaded, signIn, setActive } = useSignIn(); + + const form = useForm>({ + defaultValues: { email: '', password: '' }, + resolver: zodResolver(signInSchema), + }); + + const [signInLoading, setSignInLoading] = useState(false); + + const router = useRouter(); + const handleSignIn = form.handleSubmit(async ({ email, password }) => { + if (!isLoaded) return; + + setSignInLoading(true); + + try { + const result = await signIn.create({ + identifier: email, + password, + }); + + if (result.status === 'complete') { + await setActive({ session: result.createdSessionId }); + router.push('/'); + router.refresh(); + } else { + console.log(result); + } + } catch (error) { + handleClerkErrors(error, form, [ + { + code: 'form_identifier_not_found', + field: 'email', + message: "Can't find your account.", + }, + { + code: 'form_password_incorrect', + field: 'password', + message: 'Password is incorrect. Try again, or use another method.', + }, + { + code: 'strategy_for_user_invalid', + field: 'password', + message: + 'Account is not set up for password sign-in. Please sign in with Google.', + }, + ]); + } + + setSignInLoading(false); + }); + + const handleGoogleSignIn = async () => { + if (!isLoaded) return; + try { + await signIn.authenticateWithRedirect({ + strategy: 'oauth_google', + redirectUrl: '/sso-callback', + redirectUrlComplete: '/', + }); + } catch (error) { + // Handle any errors that might occur during the sign-in process + console.error('Google Sign-In Error:', error); + } + }; + + return ( +
+
+ +
+ {/* Heading */} +

Sign In

+

Sign into your account

+ + + +
+
+

or

+
+
+
+ + + + Forgot password? + + + + + {/* Sign-up option */} +
+

+ Don't have an account yet?{' '} + + Join Us + +

+
+
+ +
+
+ ); +} diff --git a/src/app/(account)/signin/page.tsx b/src/app/(account)/signin/page.tsx index 9d7f2c37..e992b531 100644 --- a/src/app/(account)/signin/page.tsx +++ b/src/app/(account)/signin/page.tsx @@ -1,155 +1,10 @@ -'use client'; +import type { Metadata } from 'next'; +import SignIn from './SignIn'; -import Button from '@/components/Button'; -import ControlledField from '@/components/ControlledField'; -import FancyRectangle from '@/components/FancyRectangle'; -import { useSignIn } from '@clerk/clerk-react'; -import { zodResolver } from '@hookform/resolvers/zod'; -import Link from 'next/link'; -import { useRouter } from 'next/navigation'; -import { useState } from 'react'; -import { useForm } from 'react-hook-form'; -import { FcGoogle } from 'react-icons/fc'; -import { z } from 'zod'; -import { handleClerkErrors } from '../helpers'; -import { emailSchema } from '../schemas'; - -// export const metadata: Metadata = { -// title: 'Sign In', -// }; - -const signInSchema = z.object({ - email: emailSchema, - password: z.string().min(1, { message: 'Please enter your password' }), -}); +export const metadata: Metadata = { + title: 'Sign In', +}; export default function SignInPage() { - const { isLoaded, signIn, setActive } = useSignIn(); - - const form = useForm>({ - defaultValues: { email: '', password: '' }, - resolver: zodResolver(signInSchema), - }); - - const [signInLoading, setSignInLoading] = useState(false); - - const router = useRouter(); - const handleSignIn = form.handleSubmit(async ({ email, password }) => { - if (!isLoaded) return; - - setSignInLoading(true); - - try { - const result = await signIn.create({ - identifier: email, - password, - }); - - if (result.status === 'complete') { - await setActive({ session: result.createdSessionId }); - router.push('/'); - router.refresh(); - } else { - console.log(result); - } - } catch (error) { - handleClerkErrors(error, form, [ - { - code: 'form_identifier_not_found', - field: 'email', - message: "Can't find your account.", - }, - { - code: 'form_password_incorrect', - field: 'password', - message: 'Password is incorrect. Try again, or use another method.', - }, - { - code: 'strategy_for_user_invalid', - field: 'password', - message: - 'Account is not set up for password sign-in. Please sign in with Google.', - }, - ]); - } - - setSignInLoading(false); - }); - - const handleGoogleSignIn = async () => { - if (!isLoaded) return; - try { - await signIn.authenticateWithRedirect({ - strategy: 'oauth_google', - redirectUrl: '/sso-callback', - redirectUrlComplete: '/', - }); - } catch (error) { - // Handle any errors that might occur during the sign-in process - console.error('Google Sign-In Error:', error); - } - }; - - return ( -
-
- -
- {/* Heading */} -

Sign In

-

Sign into your account

- - - -
-
-

or

-
-
-
- - - - Forgot password? - - - - - {/* Sign-up option */} -
-

- Don't have an account yet?{' '} - - Join Us - -

-
-
- -
-
- ); + return ; } From a6ce1155f8e199aa94a97ef2178ac9b1ac1f978e Mon Sep 17 00:00:00 2001 From: jsun969 Date: Sat, 24 Feb 2024 20:59:33 +1030 Subject: [PATCH 3/8] fix: add clerk fallback url --- .env.local.example | 7 ++++++- src/env.mjs | 8 ++++++++ src/middleware.ts | 15 ++++++++++----- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/.env.local.example b/.env.local.example index 400206e7..5fa4c60e 100644 --- a/.env.local.example +++ b/.env.local.example @@ -1,8 +1,13 @@ # Clerk. See https://clerk.com NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY= CLERK_SECRET_KEY= +# DO NOT modify +NEXT_PUBLIC_CLERK_SIGN_IN_URL=/signin +NEXT_PUBLIC_CLERK_SIGN_UP_URL=/join +NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/ +NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/ -# Database. Do not modify in development. +# Database (DO NOT modify in development) DATABASE_URL=file:dev.sqlite DATABASE_AUTH_TOKEN= diff --git a/src/env.mjs b/src/env.mjs index 8695e18a..5c63107f 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -15,10 +15,18 @@ export const env = createEnv({ client: { NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), NEXT_PUBLIC_DRIVE_LINK: z.string().url().min(1), + NEXT_PUBLIC_CLERK_SIGN_IN_URL: z.literal('/signin'), + NEXT_PUBLIC_CLERK_SIGN_UP_URL: z.literal('/join'), + NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL: z.literal('/'), + NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL: z.literal('/'), }, experimental__runtimeEnv: { NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, NEXT_PUBLIC_DRIVE_LINK: process.env.NEXT_PUBLIC_DRIVE_LINK, + NEXT_PUBLIC_CLERK_SIGN_IN_URL: process.env.NEXT_PUBLIC_CLERK_SIGN_IN_URL, + NEXT_PUBLIC_CLERK_SIGN_UP_URL: process.env.NEXT_PUBLIC_CLERK_SIGN_UP_URL, + NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL: process.env.NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL, + NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL: process.env.NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL, }, skipValidation: process.env.SKIP_ENV_VALIDATION, }); diff --git a/src/middleware.ts b/src/middleware.ts index 9d9bdc5d..e28a478a 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,11 +1,16 @@ import { authMiddleware } from '@clerk/nextjs'; -const authRoutes = ['/account', '/dashboard', '/settings', '/admin']; - export default authMiddleware({ - publicRoutes: (req) => { - return !authRoutes.includes(req.nextUrl.pathname); - }, + publicRoutes: [ + '/', + '/about', + '/contact', + '/events', + '/sponsors', + '/signin', + '/join', + '/forgot-password', + ], }); export const config = { From 518ad4d473962c385d07e7fbc27e2ffa051659ba Mon Sep 17 00:00:00 2001 From: jsun969 Date: Sat, 24 Feb 2024 21:11:21 +1030 Subject: [PATCH 4/8] fix: check user before `signin` / `join` --- src/app/(account)/join/page.tsx | 12 +++++++++++- src/app/(account)/signin/page.tsx | 6 +++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/app/(account)/join/page.tsx b/src/app/(account)/join/page.tsx index 72670acd..cfeb0c00 100644 --- a/src/app/(account)/join/page.tsx +++ b/src/app/(account)/join/page.tsx @@ -1,10 +1,20 @@ +import { checkUserExists } from '@/server/check-user-exists'; +import { currentUser } from '@clerk/nextjs'; import type { Metadata } from 'next'; +import { redirect } from 'next/navigation'; import Join from './Join'; export const metadata: Metadata = { title: 'Join', }; -export default function JoinPage() { +export default async function JoinPage() { + const user = await currentUser(); + if (user) { + const userExists = await checkUserExists(user.id); + if (userExists) { + redirect('/settings'); + } + } return ; } diff --git a/src/app/(account)/signin/page.tsx b/src/app/(account)/signin/page.tsx index e992b531..7db5f167 100644 --- a/src/app/(account)/signin/page.tsx +++ b/src/app/(account)/signin/page.tsx @@ -1,10 +1,14 @@ +import { currentUser } from '@clerk/nextjs'; import type { Metadata } from 'next'; +import { redirect } from 'next/navigation'; import SignIn from './SignIn'; export const metadata: Metadata = { title: 'Sign In', }; -export default function SignInPage() { +export default async function SignInPage() { + const user = await currentUser(); + if (user) redirect('/settings'); return ; } From e0ed6a31ced84b3d46df9d622bb506007839c183 Mon Sep 17 00:00:00 2001 From: jsun969 Date: Sun, 25 Feb 2024 13:47:55 +1030 Subject: [PATCH 5/8] chore(env): add comment for clerk redundant urls --- src/env.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/env.mjs b/src/env.mjs index 5c63107f..f9302121 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -15,6 +15,7 @@ export const env = createEnv({ client: { NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), NEXT_PUBLIC_DRIVE_LINK: z.string().url().min(1), + // Clerk URLs. Redundant, but there is no other way from Clerk. NEXT_PUBLIC_CLERK_SIGN_IN_URL: z.literal('/signin'), NEXT_PUBLIC_CLERK_SIGN_UP_URL: z.literal('/join'), NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL: z.literal('/'), From b8afd2bdf5ac0edc47799d5d50c63c1bcb5f27be Mon Sep 17 00:00:00 2001 From: jsun969 Date: Sun, 25 Feb 2024 21:28:06 +1030 Subject: [PATCH 6/8] refactor(settings): use `authRoutes` --- src/middleware.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/middleware.ts b/src/middleware.ts index e28a478a..95373370 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,16 +1,9 @@ import { authMiddleware } from '@clerk/nextjs'; +const authRoutes = ['/settings', '/admin']; + export default authMiddleware({ - publicRoutes: [ - '/', - '/about', - '/contact', - '/events', - '/sponsors', - '/signin', - '/join', - '/forgot-password', - ], + publicRoutes: (req) => !authRoutes.includes(req.url), }); export const config = { From 691f045693bd763edbb03da6916b945869b1d487 Mon Sep 17 00:00:00 2001 From: Ray Okamoto <22254748+rayokamoto@users.noreply.github.com> Date: Sun, 25 Feb 2024 21:31:31 +1030 Subject: [PATCH 7/8] chore: Update comment on Clerk envs --- src/env.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/env.mjs b/src/env.mjs index f9302121..1db49b5a 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -15,7 +15,8 @@ export const env = createEnv({ client: { NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), NEXT_PUBLIC_DRIVE_LINK: z.string().url().min(1), - // Clerk URLs. Redundant, but there is no other way from Clerk. + // Clerk URLs. Redundant, but Clerk does not provide any other method for redirecting + // when user is/isn't signed in or has/hasn't signed up. NEXT_PUBLIC_CLERK_SIGN_IN_URL: z.literal('/signin'), NEXT_PUBLIC_CLERK_SIGN_UP_URL: z.literal('/join'), NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL: z.literal('/'), From b957be7916f670aba82c5abac0d86d0c34b2252a Mon Sep 17 00:00:00 2001 From: Ray <22254748+rayokamoto@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:03:38 +1030 Subject: [PATCH 8/8] style: Run prettier --- src/env.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/env.mjs b/src/env.mjs index 1db49b5a..f6494e30 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -15,7 +15,7 @@ export const env = createEnv({ client: { NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), NEXT_PUBLIC_DRIVE_LINK: z.string().url().min(1), - // Clerk URLs. Redundant, but Clerk does not provide any other method for redirecting + // Clerk URLs. Redundant, but Clerk does not provide any other method for redirecting // when user is/isn't signed in or has/hasn't signed up. NEXT_PUBLIC_CLERK_SIGN_IN_URL: z.literal('/signin'), NEXT_PUBLIC_CLERK_SIGN_UP_URL: z.literal('/join'),