From be7d25739baa6f6ba30059713c701c4f5c631e54 Mon Sep 17 00:00:00 2001 From: Aaron Chan <42254254+aaronchan32@users.noreply.github.com> Date: Mon, 4 Nov 2024 00:39:41 -0800 Subject: [PATCH] feat: update register mobile --- .eslintrc.json | 1 + public/images/badge/vertical-bar.svg | 0 public/images/icons/newtab-icon.svg | 4 + public/images/icons/right-arrow-icon.svg | 3 + public/images/logos/stride-logo.svg | 18 +- src/app/badge/Badge.scss | 84 ++++++++ src/app/badge/page.tsx | 168 ++++++++++++++++ src/app/register/Register.scss | 112 +++++++++++ src/app/register/page.tsx | 91 ++++++++- src/app/styles/_var.scss | 7 +- src/components/Icons/BlockIcon.tsx | 6 +- src/components/Icons/CloseIcon.tsx | 33 ---- src/components/Icons/RightArrow.tsx | 12 +- .../MascotCircles/MascotCircles.scss | 42 ++++ .../MascotCircles/MascotCircles.tsx | 13 ++ src/components/Navbar/Navbar.scss | 2 + src/components/Register/FeeTag.tsx | 44 +++++ .../Register/FolderTabs/FolderTabs.scss | 40 +++- .../Register/FolderTabs/FolderTabs.tsx | 9 +- .../FormComponents/FormSelect/FormSelect.scss | 10 +- .../FormComponents/FormSelect/FormSelect.tsx | 9 +- .../FormComponents/FormText/FormText.scss | 9 +- .../FormComponents/FormText/FormText.tsx | 2 +- .../FormSteps/FormStep1/FormStep1.tsx | 13 +- .../FormSteps/FormStep2/FormStep2.tsx | 13 +- .../FormSteps/FormStep3/FormStep3.scss | 55 ++++-- .../FormSteps/FormStep3/FormStep3.tsx | 6 +- .../FormSteps/FormStep4/FormStep4.scss | 186 ++++++++++++++---- .../FormSteps/FormStep4/FormStep4.tsx | 68 +++++-- .../Register/Mascot/Hats/TestHat.tsx | 2 - src/components/Register/Mascot/Mascot.tsx | 2 +- .../Register/MascotBadge/HorizontalBar.tsx | 22 +++ .../Register/MascotBadge/VerticalBar.tsx | 22 +++ src/components/Register/Register.scss | 35 ---- src/components/Register/Register.tsx | 156 --------------- src/components/Register/StrideLogo.tsx | 46 +++++ src/components/Register/types.ts | 19 +- 37 files changed, 986 insertions(+), 378 deletions(-) create mode 100644 public/images/badge/vertical-bar.svg create mode 100644 public/images/icons/newtab-icon.svg create mode 100644 public/images/icons/right-arrow-icon.svg create mode 100644 src/app/badge/Badge.scss create mode 100644 src/app/badge/page.tsx create mode 100644 src/app/register/Register.scss delete mode 100644 src/components/Icons/CloseIcon.tsx create mode 100644 src/components/MascotCircles/MascotCircles.scss create mode 100644 src/components/MascotCircles/MascotCircles.tsx create mode 100644 src/components/Register/FeeTag.tsx create mode 100644 src/components/Register/MascotBadge/HorizontalBar.tsx create mode 100644 src/components/Register/MascotBadge/VerticalBar.tsx delete mode 100644 src/components/Register/Register.scss delete mode 100644 src/components/Register/Register.tsx create mode 100644 src/components/Register/StrideLogo.tsx diff --git a/.eslintrc.json b/.eslintrc.json index afa65d1..900918f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -12,6 +12,7 @@ "project": "./tsconfig.json" }, "rules": { + "react/no-unescaped-entities": "off", "react/jsx-props-no-spreading": "off", "jsx-a11y/label-has-associated-control": "off", "arrow-body-style": "off", diff --git a/public/images/badge/vertical-bar.svg b/public/images/badge/vertical-bar.svg new file mode 100644 index 0000000..e69de29 diff --git a/public/images/icons/newtab-icon.svg b/public/images/icons/newtab-icon.svg new file mode 100644 index 0000000..9eef9ff --- /dev/null +++ b/public/images/icons/newtab-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/images/icons/right-arrow-icon.svg b/public/images/icons/right-arrow-icon.svg new file mode 100644 index 0000000..dfca9c5 --- /dev/null +++ b/public/images/icons/right-arrow-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/logos/stride-logo.svg b/public/images/logos/stride-logo.svg index 62f92c4..fd1ba36 100644 --- a/public/images/logos/stride-logo.svg +++ b/public/images/logos/stride-logo.svg @@ -1,10 +1,10 @@ - - - - - - - - - + + + + + + + + + diff --git a/src/app/badge/Badge.scss b/src/app/badge/Badge.scss new file mode 100644 index 0000000..7ea44b1 --- /dev/null +++ b/src/app/badge/Badge.scss @@ -0,0 +1,84 @@ +#badge-page-container { + margin-top: $nav-height; + padding: $main-padding-mobile; + height: calc(100dvh - $nav-height); + font-family: $p-font; + display: flex; + flex-direction: column; + justify-content: space-between; + overflow: hidden; + + #badge-page-main-content { + height: 100%; + display: flex; + flex-direction: column; + @media (min-width: 580px) { + width: 30rem; + margin-inline: auto; + } + + form { + display: flex; + flex-direction: column; + justify-content: space-between; + height: 100%; + } + + h1 { + margin-bottom: 2rem; + } + + #badge-form-body { + height: 100%; + } + } + + #badge-footer { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.5rem; + + #current-step-small { + @media (min-width: 400px) { + display: none; + } + } + + #current-step-large { + display: none; + + @media (min-width: 400px) { + display: block; + } + } + + p { + font-size: 1.2rem; + } + + button { + border-radius: 22px; + padding: 0.5rem 1rem; + font-size: 1.2rem; + font-family: $p-font; + font-weight: 600; + display: flex; + gap: 0.5rem; + border: none; + align-items: center; + border: 2px solid $white; + cursor: pointer; + + .right-arrow { + transform: rotate(180deg); + color: white; + } + } + + .back-button { + background-color: transparent; + color: white; + } + } +} diff --git a/src/app/badge/page.tsx b/src/app/badge/page.tsx new file mode 100644 index 0000000..f7d0c1c --- /dev/null +++ b/src/app/badge/page.tsx @@ -0,0 +1,168 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import './Badge.scss'; +import FormStep1 from '@/components/Register/FormSteps/FormStep1/FormStep1'; +import { + RegistrationSchema, + TFormData, + ValidFieldNames +} from '@/components/Register/types'; +import RightArrow from '@/components/Icons/RightArrow'; +import FormStep2 from '@/components/Register/FormSteps/FormStep2/FormStep2'; +import FormStep3 from '@/components/Register/FormSteps/FormStep3/FormStep3'; +import FormStep4 from '@/components/Register/FormSteps/FormStep4/FormStep4'; +import Link from 'next/link'; + +export default function Register() { + const [nextButtonText, setNextButtonText] = useState('Next'); + const [currentFormStep, setCurrentFormStep] = useState(1); + const { + register, + control, + handleSubmit, + formState: { errors }, + trigger, + getValues + } = useForm({ + resolver: zodResolver(RegistrationSchema) + }); + + useEffect(() => { + if (currentFormStep === 4) { + setNextButtonText('Home'); + } else if (currentFormStep === 3) { + setNextButtonText('Finish'); + } else { + setNextButtonText('Next'); + } + }, [currentFormStep]); + + const onSubmit = async (data: TFormData) => { + try { + console.log(data); + } catch (e) { + console.error(e); + } + }; + + const handleFormNext = async () => { + // Input Validation for Steps 1 and 2 + if (currentFormStep <= 2) { + let fieldsToValidate: Array = [ + 'name', + 'pronouns', + 'year' + ]; + if (currentFormStep === 2) { + fieldsToValidate = ['email', 'link']; + } + + const isValid = await trigger(fieldsToValidate); + if (!isValid) return; + } + + if (currentFormStep === 3) { + handleSubmit(onSubmit)(); + } + + if (currentFormStep >= 4) { + // setOpen(false); + return; + } + setCurrentFormStep(currentFormStep + 1); + }; + + const handleFormPrev = () => { + if (currentFormStep <= 1) return; + setCurrentFormStep(currentFormStep - 1); + }; + + return ( +
+
+

+ {currentFormStep === 4 ? 'Badge Complete!' : 'Create Your Badge'} +

+
{ + console.error('Validation errors:', validationError); + })} + className="modal-form" + > +
+ {currentFormStep === 1 && ( + + )} + {currentFormStep === 2 && ( + + )} + {currentFormStep === 3 && } + {currentFormStep === 4 && } +
+
+
+ + + ); +} diff --git a/src/app/register/Register.scss b/src/app/register/Register.scss new file mode 100644 index 0000000..41579af --- /dev/null +++ b/src/app/register/Register.scss @@ -0,0 +1,112 @@ +#register-page-container { + margin-top: $nav-height; + padding: $main-padding-mobile; + height: calc(100dvh - $nav-height); + display: flex; + flex-direction: column; + justify-content: space-between; + + #register-top { + #smaller-register-header { + font-size: 2.25rem; + text-align: center; + margin-bottom: 3rem; + + svg { + margin-top: 11px; + margin-inline: auto; + max-width: 13ch; + } + + @media (min-width: 400px) { + display: none; + } + } + + #larger-register-header { + display: none; + + @media (min-width: 400px) { + font-size: 4rem; + display: block; + width: fit-content; + margin-inline: auto; + + span { + display: flex; + align-items: center; + gap: 1rem; + margin-bottom: 1.25rem; + } + } + } + + @media (min-width: 400px) { + font-size: 1rem; + } + + > p { + margin-inline: auto; + max-width: 30ch; + + @media (min-width: 400px) { + max-width: 38ch; + } + } + } + + #register-bottom { + margin-top: auto; + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + max-width: 17.5rem; + margin-inline: auto; + + a, + button { + width: 100%; + font-family: $p-font; + font-size: 1.25rem; + line-height: 100%; + text-decoration: none; + border-radius: 30px; + background: $white; + color: black; + border: 2px solid $white; + text-align: center; + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; + padding: 0.5rem 1rem; + + @media (min-width: 400px) { + padding: 1rem 2rem; + } + } + + #luma-button-container { + width: 100%; + position: relative; + svg { + pointer-events: none; + position: absolute; + top: -30%; + right: -8%; + } + } + + #create-badge-button { + background-color: transparent; + color: white; + cursor: pointer; + } + + p { + font-size: 0.875rem; + text-align: center; + } + } +} diff --git a/src/app/register/page.tsx b/src/app/register/page.tsx index 824f781..ce8d0e2 100644 --- a/src/app/register/page.tsx +++ b/src/app/register/page.tsx @@ -1,9 +1,92 @@ -import Register from '@/components/Register/Register'; +'use client'; + +import Image from 'next/image'; +import './Register.scss'; +import { useEffect, useState } from 'react'; +import Link from 'next/link'; +import StrideLogo from '@/components/Register/StrideLogo'; +import FeeTag from '@/components/Register/FeeTag'; export default function RegisterPage() { + // This is to ensure users don't click on register button before the script is loaded + const [scriptLoaded, setScriptLoaded] = useState(false); + + useEffect(() => { + const script = document.createElement('script'); + script.src = 'https://embed.lu.ma/checkout-button.js'; + script.async = true; + document.body.appendChild(script); + setScriptLoaded(true); + + return () => { + document.body.removeChild(script); + }; + }, []); + return ( -
- -
+
+
+

+ Register For + +

+

+ Register + + For + Stride Logo + +

+

Lorem Ipsum Dolor Sit Amet Include something about the $5 fee?

+
+
+ + + + Create Your Badge{' '} + + New Tab + + +

+ contact designatucsd@gmail.com for inquiries about financial + assistance +

+
+
); } diff --git a/src/app/styles/_var.scss b/src/app/styles/_var.scss index b1a2162..982cbab 100644 --- a/src/app/styles/_var.scss +++ b/src/app/styles/_var.scss @@ -3,10 +3,15 @@ $heading-font: var(--font-iosevka); $mono-font: var(--font-iosevka); $light-green: #68dea3; +$dark-green: #58c988; $white: #fbfefc; +$dark-gray: #565656; $mobile-breakpoint: 768px; -$tablet-breakpoint: 1366px; +$tablet-breakpoint: 1024px; + +// Stride Logo + DCo Logo + Logo Gap + padding +$nav-height: calc(60px + 12px + 10px + 2 * 3.75rem); $nav-padding-mobile: 24px; $nav-padding-desktop: 36px; diff --git a/src/components/Icons/BlockIcon.tsx b/src/components/Icons/BlockIcon.tsx index d684410..55881e5 100644 --- a/src/components/Icons/BlockIcon.tsx +++ b/src/components/Icons/BlockIcon.tsx @@ -17,9 +17,9 @@ export default function BlockIcon({ onClick }: BlockIconProps) { ); diff --git a/src/components/Icons/CloseIcon.tsx b/src/components/Icons/CloseIcon.tsx deleted file mode 100644 index f4f4956..0000000 --- a/src/components/Icons/CloseIcon.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { SVGProps } from 'react'; - -export function CloseIcon(props: SVGProps) { - return ( - - - - - - ); -} diff --git a/src/components/Icons/RightArrow.tsx b/src/components/Icons/RightArrow.tsx index fca8a3c..99a92ad 100644 --- a/src/components/Icons/RightArrow.tsx +++ b/src/components/Icons/RightArrow.tsx @@ -4,18 +4,16 @@ export default function RightArrow(props: SVGProps) { return ( ); diff --git a/src/components/MascotCircles/MascotCircles.scss b/src/components/MascotCircles/MascotCircles.scss new file mode 100644 index 0000000..08a8c79 --- /dev/null +++ b/src/components/MascotCircles/MascotCircles.scss @@ -0,0 +1,42 @@ +.mascot-circles-container { + display: grid; + place-items: center; + position: relative; + height: 100%; + bottom: -35%; + + .mascot-container { + position: absolute; + transform-origin: bottom; + margin-inline: auto; + width: 35%; + left: 0; + right: 0; + z-index: 1; + bottom: 15%; + } + + .half-badge-circle { + aspect-ratio: 1; + background-color: $white; + border-radius: 50%; + left: 0; + right: 0; + margin-inline: auto; + position: absolute; + z-index: 0; + + &.outer { + width: 100%; + background-color: #16643d; + } + &.middle { + width: 62.5%; + background-color: #68dea3; + } + &.inner { + width: 42.5%; + background-color: $white; + } + } +} diff --git a/src/components/MascotCircles/MascotCircles.tsx b/src/components/MascotCircles/MascotCircles.tsx new file mode 100644 index 0000000..9b66663 --- /dev/null +++ b/src/components/MascotCircles/MascotCircles.tsx @@ -0,0 +1,13 @@ +import Mascot from '../Register/Mascot/Mascot'; +import './MascotCircles.scss'; + +export default function MascotCircles() { + return ( +
+ +
+
+
+
+ ); +} diff --git a/src/components/Navbar/Navbar.scss b/src/components/Navbar/Navbar.scss index 73aa0fd..937ee2f 100644 --- a/src/components/Navbar/Navbar.scss +++ b/src/components/Navbar/Navbar.scss @@ -1,5 +1,6 @@ #navbar { position: absolute; + top: 0; z-index: 1; padding: 3.5rem 3.75rem; display: flex; @@ -26,6 +27,7 @@ border: 2px solid $white; background: black; padding: 0.5rem 0.75rem; + padding-left: 8px; display: flex; align-items: center; gap: 0.5rem; diff --git a/src/components/Register/FeeTag.tsx b/src/components/Register/FeeTag.tsx new file mode 100644 index 0000000..f552e86 --- /dev/null +++ b/src/components/Register/FeeTag.tsx @@ -0,0 +1,44 @@ +import { SVGProps } from 'react'; + +export default function FeeTag(props: SVGProps) { + return ( + + + + + + + + ); +} diff --git a/src/components/Register/FolderTabs/FolderTabs.scss b/src/components/Register/FolderTabs/FolderTabs.scss index 5532186..2b35bb6 100644 --- a/src/components/Register/FolderTabs/FolderTabs.scss +++ b/src/components/Register/FolderTabs/FolderTabs.scss @@ -7,14 +7,23 @@ position: relative; padding: 0; margin: 0; - padding: 0.5rem 1.5rem; border: none; background: none; color: white; cursor: pointer; + padding: 0.5rem 1.25rem; + margin-left: 0.5rem; + + @media (min-width: 300px) { + margin-left: 1rem; + } + + @media (min-width: 400px) { + padding: 0.75rem 1.75rem; + } &:not(:first-child) { - margin-left: -10px; + margin-left: -12px; .active-line3 { display: none; } @@ -23,7 +32,20 @@ span { position: relative; z-index: 2; - font-size: 1.2rem; + font-family: $p-font; + font-size: 0.85rem; + + @media (min-width: 325px) { + font-size: 1rem; + } + + @media (min-width: 400px) { + font-size: 1rem; + } + + @media (min-width: 480px) { + font-size: 1.2rem; + } } &::before, @@ -40,19 +62,19 @@ } &::before { - border-radius: 10px 0 0 0; + border-radius: 8px 0 0 0; border-right: 0; left: 0; transform-origin: bottom; - transform: skew(-20deg); + transform: skew(-15deg); } &::after { - border-radius: 0 10px 0 0; + border-radius: 0 8px 0 0; border-left: 0; right: 0; transform-origin: bottom; - transform: skew(20deg); + transform: skew(15deg); } } @@ -77,7 +99,7 @@ border-right: 0; left: 0; transform-origin: bottom; - transform: skew(-20deg); + transform: skew(-15deg); } &::after { @@ -85,7 +107,7 @@ border-left: 0; right: 0; transform-origin: bottom; - transform: skew(20deg); + transform: skew(15deg); } } diff --git a/src/components/Register/FolderTabs/FolderTabs.tsx b/src/components/Register/FolderTabs/FolderTabs.tsx index 6a21113..63201f7 100644 --- a/src/components/Register/FolderTabs/FolderTabs.tsx +++ b/src/components/Register/FolderTabs/FolderTabs.tsx @@ -36,12 +36,9 @@ function FolderTab({ {label} {activeTab && ( - <> -
-
-
-
- +
+
+
)} ); diff --git a/src/components/Register/FormComponents/FormSelect/FormSelect.scss b/src/components/Register/FormComponents/FormSelect/FormSelect.scss index 0fc89e7..607c75d 100644 --- a/src/components/Register/FormComponents/FormSelect/FormSelect.scss +++ b/src/components/Register/FormComponents/FormSelect/FormSelect.scss @@ -1,14 +1,18 @@ @use '@/app/styles/_var' as *; -.registration-textfield { +.registration-textfield-container { + &.registration-select-container { + gap: 1rem; + } .other-field { margin-top: 1rem; } } + .register-select { button { font-family: $p-font; - font-size: 1.2rem; + font-size: 1.25rem; display: flex; align-items: center; background: transparent; @@ -28,7 +32,7 @@ border: 2px solid #68dea3; border-radius: 22px; font-family: $p-font; - font-size: 1.2rem; + font-size: 1.25rem; overflow-y: auto; background-color: black; padding: 0 1rem; diff --git a/src/components/Register/FormComponents/FormSelect/FormSelect.tsx b/src/components/Register/FormComponents/FormSelect/FormSelect.tsx index 9b8af8f..65904b8 100644 --- a/src/components/Register/FormComponents/FormSelect/FormSelect.tsx +++ b/src/components/Register/FormComponents/FormSelect/FormSelect.tsx @@ -20,6 +20,7 @@ export default function FormSelect({ control, options = [], defaultValue, + defaultLabel, hasOtherOption = false, width = 'auto', error @@ -37,7 +38,7 @@ export default function FormSelect({ }; return ( -
+
- - -
{ - console.error('Validation errors:', validationError); - })} - className="modal-form" - > -
- Registration - -
-
- {currentFormStep === 1 && ( - - )} - {currentFormStep === 2 && ( - - )} - {currentFormStep === 3 && } - {currentFormStep === 4 && } -
- -
- {/*

{`${currentFormStep} of 4`}

*/} - {currentFormStep > 1 && ( - - )} - -
-
-
-
-
- ); -} diff --git a/src/components/Register/StrideLogo.tsx b/src/components/Register/StrideLogo.tsx new file mode 100644 index 0000000..636cd0f --- /dev/null +++ b/src/components/Register/StrideLogo.tsx @@ -0,0 +1,46 @@ +import { SVGProps } from 'react'; + +export default function StrideLogo(props: SVGProps) { + return ( + + + + + + + + + + + ); +} diff --git a/src/components/Register/types.ts b/src/components/Register/types.ts index d8e769c..46cb3fc 100644 --- a/src/components/Register/types.ts +++ b/src/components/Register/types.ts @@ -17,8 +17,8 @@ export type TFormData = { name: string; pronouns: string; year: string; - interest: string; - interest_other?: string; + // interest: string; + // interest_other?: string; email: string; link: string; }; @@ -41,7 +41,8 @@ export type FormSelectProps = { name: keyof TFormData; control: Control; options: Array; - defaultValue: string; + defaultValue?: string; + defaultLabel?: string; hasOtherOption?: boolean; error?: FieldError; width?: string; @@ -66,12 +67,12 @@ export const RegistrationSchema: ZodType = z.object({ }, { message: 'Year must be between 2022 and 2029' } ), - interest: z.string().min(2, { message: 'Interest is too short' }), - interest_other: z - .string() - .min(2, { message: 'Interest is too short' }) - .max(50, { message: 'Interest needs to be under 30 characters.' }) - .optional(), + // interest: z.string().min(2, { message: 'Interest is too short' }), + // interest_other: z + // .string() + // .min(2, { message: 'Interest is too short' }) + // .max(50, { message: 'Interest needs to be under 30 characters.' }) + // .optional(), link: z .string() .includes('linkedin.com', { message: 'Invalid LinkedIn URL' }),