From 13491c26878b9e050155ffa693aa1d68bf796224 Mon Sep 17 00:00:00 2001 From: sydneyzhang18 <114766656+sydneyzhang18@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:23:55 -0700 Subject: [PATCH 1/8] major mobile/tablet progress --- frontend/src/app/login/login.css | 102 +++++++++++++++++- frontend/src/app/login/page.tsx | 8 +- .../shared/input/InputField/styles.module.css | 15 +++ 3 files changed, 120 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/login/login.css b/frontend/src/app/login/login.css index b085b59..168794f 100644 --- a/frontend/src/app/login/login.css +++ b/frontend/src/app/login/login.css @@ -44,6 +44,10 @@ html { width: 190px; height: 90px; } +.image { + width: 190px; + height: 90px; +} .welcome-text { color: #000; @@ -57,18 +61,19 @@ html { } .login-form { - width: 100%; + width: 80%; margin-top: 22px; /* Gap between Name and Password */ } .input-group { - margin-bottom: 22px; /* Gap between Password and Forgot Password */ + margin-bottom: 32px; /* Gap between Password and Forgot Password */ } label { display: block; margin-bottom: 5px; color: gray; + font-size: 16px; } input { @@ -79,7 +84,12 @@ input { } .forgot-password { - color: blue; + color: #4274f4; + + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; text-align: center; margin-bottom: 48px; /* Gap between Forgot password and Log In */ } @@ -98,4 +108,90 @@ input { font-style: normal; font-weight: 700; line-height: normal; + margin-bottom: 49px; +} + +/* tablet version */ +@media screen and (max-width: 850px) { + .background-image { + object-fit: cover; + object-position: 35% 10%; + } + .login-box { + width: 90%; + max-width: 500px; + } + + .login-form { + width: 80%; + margin-top: 22px; /* Gap between Name and Password */ + } + + .input-group { + margin-bottom: 32px; /* Gap between Password and Forgot Password */ + } + + .forgot-password { + color: #4274f4; + font-size: 12px; + margin-bottom: 38px; /* Gap between Forgot password and Log In */ + } + + .login-button { + font-size: 18px; + font-weight: 600; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .background-image { + object-fit: cover; + object-position: 35% 10%; + } + .login-box { + width: 90%; + max-width: 500px; + } + + .logo-container { + top: -15%; + padding: 10px; + gap: 10px; + } + + .logo-image { + width: 130px; + height: 60px; + } + .image { + width: 130px; + height: 60px; + } + + .welcome-text { + font-size: 28px; + margin-top: 32px; /* Gap between Welcome and Name field */ + } + + .login-form { + width: 100%; + margin-top: 16px; /* Gap between Name and Password */ + } + + .input-group { + margin-bottom: 32px; /* Gap between Password and Forgot Password */ + } + + .forgot-password { + color: #4274f4; + font-size: 12px; + margin-bottom: 32px; /* Gap between Forgot password and Log In */ + } + + .login-button { + font-size: 18px; + font-weight: 600; + margin-bottom: 17px; + } } diff --git a/frontend/src/app/login/page.tsx b/frontend/src/app/login/page.tsx index 19f2fe3..abae197 100644 --- a/frontend/src/app/login/page.tsx +++ b/frontend/src/app/login/page.tsx @@ -8,6 +8,7 @@ import "@/app/login/login.css"; import { signInWithEmailAndPassword } from "firebase/auth"; import { initFirebase } from "@/firebase/firebase"; import { useRouter } from "next/navigation"; +import { max } from "moment"; const Login = () => { const [email, setEmail] = useState(""); @@ -65,15 +66,18 @@ const Login = () => { src="/Images/login_bg.png" alt="" layout="fill" + objectFit="cover" + // objectPosition="35% 10%" priority /* Inline styling due to using Image Component*/ style={{ position: "absolute", top: "0", left: "0", - right: "0", + right: "30", bottom: "0", }} + className="background-image" />
{
- Logo + Logo
Welcome!
diff --git a/frontend/src/components/shared/input/InputField/styles.module.css b/frontend/src/components/shared/input/InputField/styles.module.css index fde5652..c3609c9 100644 --- a/frontend/src/components/shared/input/InputField/styles.module.css +++ b/frontend/src/components/shared/input/InputField/styles.module.css @@ -30,3 +30,18 @@ font-weight: 300; line-height: normal; } + +@media screen and (max-width: 550px) { + .label { + font-size: 12px; + } + + .input { + font-size: 12px; + font-weight: 400; + } + + .input::placeholder { + font-size: 12px; + } +} From 83ecc8da611e3524562638ee82d81a2899c272a5 Mon Sep 17 00:00:00 2001 From: benjaminjohnson2204 Date: Tue, 12 Mar 2024 10:05:35 -0700 Subject: [PATCH 2/8] Minor CSS touch-ups --- frontend/src/app/login/login.css | 27 +++++++++++++-------------- frontend/src/app/login/page.tsx | 13 ++++++++++--- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/frontend/src/app/login/login.css b/frontend/src/app/login/login.css index 168794f..b2e7144 100644 --- a/frontend/src/app/login/login.css +++ b/frontend/src/app/login/login.css @@ -24,12 +24,12 @@ html { background: #fff; box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); width: 70%; - max-width: 500px; + max-width: 580px; } .logo-container { position: absolute; - top: -20%; + top: -65px; display: inline-flex; padding: 15px; align-items: flex-start; @@ -57,16 +57,17 @@ html { font-style: normal; font-weight: 700; line-height: normal; - margin-top: 50px; /* Gap between Welcome and Name field */ + margin-top: 65px; /* Gap between Welcome and Name field */ } .login-form { width: 80%; - margin-top: 22px; /* Gap between Name and Password */ + margin-top: 54px; /* Gap between Name and Password */ } .input-group { - margin-bottom: 32px; /* Gap between Password and Forgot Password */ + margin-bottom: 16px; /* Gap between Password and Forgot Password */ + padding-top: 6px; } label { @@ -91,6 +92,7 @@ input { font-weight: 400; line-height: normal; text-align: center; + padding-top: 30px; margin-bottom: 48px; /* Gap between Forgot password and Log In */ } @@ -124,11 +126,7 @@ input { .login-form { width: 80%; - margin-top: 22px; /* Gap between Name and Password */ - } - - .input-group { - margin-bottom: 32px; /* Gap between Password and Forgot Password */ + margin-top: 32px; /* Gap between Name and Password */ } .forgot-password { @@ -155,7 +153,7 @@ input { } .logo-container { - top: -15%; + top: -65px; padding: 10px; gap: 10px; } @@ -171,21 +169,22 @@ input { .welcome-text { font-size: 28px; - margin-top: 32px; /* Gap between Welcome and Name field */ + margin-top: 17px; /* Gap between Welcome and Name field */ } .login-form { width: 100%; - margin-top: 16px; /* Gap between Name and Password */ + margin-top: 32px; /* Gap between Name and Password */ } .input-group { - margin-bottom: 32px; /* Gap between Password and Forgot Password */ + padding-top: 0; } .forgot-password { color: #4274f4; font-size: 12px; + padding-top: 16px; margin-bottom: 32px; /* Gap between Forgot password and Log In */ } diff --git a/frontend/src/app/login/page.tsx b/frontend/src/app/login/page.tsx index abae197..8566328 100644 --- a/frontend/src/app/login/page.tsx +++ b/frontend/src/app/login/page.tsx @@ -8,7 +8,7 @@ import "@/app/login/login.css"; import { signInWithEmailAndPassword } from "firebase/auth"; import { initFirebase } from "@/firebase/firebase"; import { useRouter } from "next/navigation"; -import { max } from "moment"; +import { useMediaQuery } from "@mui/material"; const Login = () => { const [email, setEmail] = useState(""); @@ -18,6 +18,8 @@ const Login = () => { const router = useRouter(); + const isMobile = useMediaQuery("@media screen and (max-width: 550px)"); + const sendTokenToBackend = async (token: string) => { try { const response = await fetch(`http://localhost:3001/api/whoami`, { @@ -67,7 +69,6 @@ const Login = () => { alt="" layout="fill" objectFit="cover" - // objectPosition="35% 10%" priority /* Inline styling due to using Image Component*/ style={{ @@ -92,7 +93,13 @@ const Login = () => {
- Logo + Logo
Welcome!
From 0fc5b02e65a47b365db81d706b2f372b3b785e7b Mon Sep 17 00:00:00 2001 From: benjaminjohnson2204 Date: Wed, 13 Mar 2024 20:43:30 -0700 Subject: [PATCH 3/8] Clean up CSS --- frontend/src/app/login/layout.tsx | 12 --- .../app/login/{login.css => page.module.css} | 73 ++++++++----------- frontend/src/app/login/page.tsx | 26 +++---- 3 files changed, 42 insertions(+), 69 deletions(-) delete mode 100644 frontend/src/app/login/layout.tsx rename frontend/src/app/login/{login.css => page.module.css} (78%) diff --git a/frontend/src/app/login/layout.tsx b/frontend/src/app/login/layout.tsx deleted file mode 100644 index cd37163..0000000 --- a/frontend/src/app/login/layout.tsx +++ /dev/null @@ -1,12 +0,0 @@ -export const metadata = { - title: "Patriots & Paws", - description: "Web application for Patriots & Paws", -}; - -export default function LoginLayout({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ); -} diff --git a/frontend/src/app/login/login.css b/frontend/src/app/login/page.module.css similarity index 78% rename from frontend/src/app/login/login.css rename to frontend/src/app/login/page.module.css index b2e7144..c06f1c5 100644 --- a/frontend/src/app/login/login.css +++ b/frontend/src/app/login/page.module.css @@ -1,17 +1,12 @@ /* Login.css */ -body, -html { - height: 100%; - margin: 0; -} - -.login-container { +.loginContainer { position: relative; - height: 100%; + height: 100vh; + margin: 0; } -.login-box { +.loginBox { position: absolute; top: 50%; left: 50%; @@ -27,7 +22,7 @@ html { max-width: 580px; } -.logo-container { +.logoContainer { position: absolute; top: -65px; display: inline-flex; @@ -39,17 +34,18 @@ html { box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25); } -.logo-image { +.logoImage { background: lightgray no-repeat; width: 190px; height: 90px; } + .image { width: 190px; height: 90px; } -.welcome-text { +.welcomeText { color: #000; text-align: center; font-family: Lora; @@ -60,31 +56,31 @@ html { margin-top: 65px; /* Gap between Welcome and Name field */ } -.login-form { +.loginForm { width: 80%; margin-top: 54px; /* Gap between Name and Password */ } -.input-group { +.inputGroup { margin-bottom: 16px; /* Gap between Password and Forgot Password */ padding-top: 6px; } -label { +.label { display: block; margin-bottom: 5px; color: gray; font-size: 16px; } -input { +.input { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; } -.forgot-password { +.forgotPassword { color: #4274f4; font-size: 16px; @@ -96,7 +92,7 @@ input { margin-bottom: 48px; /* Gap between Forgot password and Log In */ } -.login-button { +.loginButton { width: 100%; height: 50px; flex-shrink: 0; @@ -115,27 +111,26 @@ input { /* tablet version */ @media screen and (max-width: 850px) { - .background-image { + .backgroundImage { object-fit: cover; object-position: 35% 10%; } - .login-box { + + .loginBox { width: 90%; max-width: 500px; } - .login-form { - width: 80%; + .loginForm { margin-top: 32px; /* Gap between Name and Password */ } - .forgot-password { - color: #4274f4; + .forgotPassword { font-size: 12px; margin-bottom: 38px; /* Gap between Forgot password and Log In */ } - .login-button { + .loginButton { font-size: 18px; font-weight: 600; } @@ -143,54 +138,44 @@ input { /* mobile version */ @media screen and (max-width: 550px) { - .background-image { + .backgroundImage { object-fit: cover; object-position: 35% 10%; } - .login-box { - width: 90%; - max-width: 500px; - } - .logo-container { - top: -65px; + .logoContainer { padding: 10px; - gap: 10px; } - .logo-image { + .logoImage { width: 130px; height: 60px; } + .image { width: 130px; height: 60px; } - .welcome-text { + .welcomeText { font-size: 28px; margin-top: 17px; /* Gap between Welcome and Name field */ } - .login-form { + .loginForm { width: 100%; - margin-top: 32px; /* Gap between Name and Password */ } - .input-group { + .inputGroup { padding-top: 0; } - .forgot-password { - color: #4274f4; - font-size: 12px; + .forgotPassword { padding-top: 16px; margin-bottom: 32px; /* Gap between Forgot password and Log In */ } - .login-button { - font-size: 18px; - font-weight: 600; + .loginButton { margin-bottom: 17px; } } diff --git a/frontend/src/app/login/page.tsx b/frontend/src/app/login/page.tsx index 8566328..44278e5 100644 --- a/frontend/src/app/login/page.tsx +++ b/frontend/src/app/login/page.tsx @@ -4,7 +4,7 @@ import React, { useState } from "react"; import InputField from "@/components/shared/input/InputField"; import Image from "next/image"; -import "@/app/login/login.css"; +import styles from "@/app/login/page.module.css"; import { signInWithEmailAndPassword } from "firebase/auth"; import { initFirebase } from "@/firebase/firebase"; import { useRouter } from "next/navigation"; @@ -63,7 +63,7 @@ const Login = () => { return ( -
+
{ right: "30", bottom: "0", }} - className="background-image" + className={styles.backgroundImage} />
{ background: "#232220D9", }} /> -
-
-
+
+
+
Logo
-
Welcome!
-
-
+
Welcome!
+ +
{ onChange={(e) => setEmail(e.target.value)} />
-
+
{ type="password" />
-
Forgot Password?
- From e654a5c7ca420ab30c01d189e9ff571555994844 Mon Sep 17 00:00:00 2001 From: benjaminjohnson2204 Date: Fri, 22 Mar 2024 20:26:08 -0700 Subject: [PATCH 4/8] Update VSR message content --- frontend/src/app/vsr/page.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/vsr/page.tsx b/frontend/src/app/vsr/page.tsx index 7264500..4fd15e4 100644 --- a/frontend/src/app/vsr/page.tsx +++ b/frontend/src/app/vsr/page.tsx @@ -178,17 +178,17 @@ const VeteranServiceRequest: React.FC = () => {

Veteran Service Request Form

- Welcome, Veterans, Active Duty, and Reservists. We invite you to schedule an appointment - to explore a selection of household furnishings and essential items available in our - warehouse. + Welcome, Veterans, Active Duty, Reservists, and Families. If you're in need of + furnishings, we're here to assist you. Please complete and submit the form below to + request what you require.



- Let us know your specific needs, and we'll provide the best assistance possible. - Expect a response within 48 business hours; remember to check your junk mail if needed. + Upon submission, a copy of your VSR form will be sent to your email. We'll promptly + review it and respond via email as soon as possible. Remember to check your spam folder + if you don't receive a response within 48 business hours.



- If you're a Veteran or Active Military Reservist in search of our services, simply - fill out and submit the form below. + If you have any questions or concerns, send us an email at veteran@patriotsandpaws.org.

From bc79d718da498a91a43689123f15774d9c3f2ea3 Mon Sep 17 00:00:00 2001 From: benjaminjohnson2204 Date: Fri, 22 Mar 2024 22:40:06 -0700 Subject: [PATCH 5/8] Implement tablet & mobile versions of VSR page --- frontend/src/app/vsr/page.module.css | 224 ++++++----- frontend/src/app/vsr/page.tsx | 361 ++++++++++-------- .../VSRForm/PageNumber/styles.module.css | 15 + .../FurnitureItemSelection/styles.module.css | 17 +- .../shared/input/BinaryChoice/index.tsx | 19 +- .../input/BinaryChoice/styles.module.css | 24 -- .../shared/input/Dropdown/index.tsx | 24 +- .../shared/input/Dropdown/styles.module.css | 26 -- .../shared/input/FormField/index.tsx | 25 ++ .../shared/input/FormField/styles.module.css | 41 ++ .../shared/input/MultipleChoice/index.tsx | 16 +- .../input/MultipleChoice/styles.module.css | 37 +- .../shared/input/TextField/index.tsx | 14 +- .../shared/input/TextField/styles.module.css | 43 +-- 14 files changed, 500 insertions(+), 386 deletions(-) create mode 100644 frontend/src/components/shared/input/FormField/index.tsx create mode 100644 frontend/src/components/shared/input/FormField/styles.module.css diff --git a/frontend/src/app/vsr/page.module.css b/frontend/src/app/vsr/page.module.css index c520a45..99248b7 100644 --- a/frontend/src/app/vsr/page.module.css +++ b/frontend/src/app/vsr/page.module.css @@ -15,6 +15,10 @@ line-height: normal; } +.title { + font-size: 40px; +} + .description { color: #000; /* Desktop/Body 1 */ @@ -25,18 +29,9 @@ line-height: normal; } -.personalInfo { - color: var(--Accent-Blue-1, #102d5f); - /* Desktop/H2 */ - font-family: Lora; - font-size: 24px; - font-style: normal; - font-weight: 700; - line-height: normal; -} - .fieldsMarked { color: #000; + font-family: "Open Sans"; font-size: 16px; font-style: normal; font-weight: 400; @@ -70,6 +65,16 @@ align-self: flex-start; } +.sectionTitle { + color: var(--Accent-Blue-1, #102d5f); + /* Desktop/H2 */ + font-family: Lora; + font-size: 24px; + font-style: normal; + font-weight: 700; + line-height: normal; +} + .formRow { width: 100%; display: flex; @@ -78,68 +83,23 @@ align-items: start; } +.desktopRowTabletColumn { + flex-direction: row; +} + .numChildren { display: flex; flex-direction: column; gap: 20px; align-items: center; flex: 1; + width: 100%; } .asterisk { color: var(--Secondary-2, #be2d46); } -.buttonContainer { - display: flex; - justify-content: space-between; -} - -.submitButton { - align-self: end; -} - -.submit { - width: 306px; - height: 64px; - background-color: #102d5f; - color: white; - cursor: pointer; - font-family: Lora; - font-size: 24px; - font-style: normal; - font-weight: 700; - line-height: normal; - border: none; - border-radius: 4px; -} -.enabled { - background-color: #102d5f; -} - -.disabled { - background-color: grey; -} - -.backButton { - align-self: start; -} - -.back { - width: 306px; - height: 64px; - background-color: white; - color: #102d5f; - cursor: pointer; - font-family: Lora; - font-size: 24px; - font-style: normal; - font-weight: 700; - line-height: normal; - border: #102d5f; - border-radius: 4px; -} - .sectionHeader { gap: 4px; font-size: 16px; @@ -153,17 +113,13 @@ .longText { flex: 1; + width: 100%; } .childInputWrapper { width: 100%; } -.page { - margin: 0; - box-sizing: border-box; - background-color: var(--color-tse-primary-light); -} .canvas { border-radius: 20px; background-color: #fff; @@ -172,6 +128,7 @@ margin-top: 128px; padding: 64px; } + .title { color: var(--Accent-Blue-1, #102d5f); font-family: "Lora"; @@ -180,9 +137,7 @@ font-weight: 700; line-height: normal; } -.sections { - padding-top: 32px; -} + .section:not(:last-child) { padding-bottom: 64px; } @@ -204,6 +159,7 @@ .furnitureItemsSectionLabel { padding-bottom: 16px; + font-size: 16px; /* Capitalize names of furniture categories */ text-transform: capitalize; } @@ -215,43 +171,141 @@ gap: 16px; } -.actions { +.bottomRow { display: flex; flex-direction: row; justify-content: space-between; - width: calc(100vw * 5 / 6); - margin: auto; - align-items: baseline; - padding-top: 64px; + align-items: center; + width: 100%; + gap: 64px; + padding-top: 32px; padding-bottom: 128px; } -.submit { +.bottomRowMobile { + display: flex; + flex-direction: row; + width: 100%; + gap: 32px; +} + +.bottomButton { width: 306px; height: 64px; - color: white; cursor: pointer; font-family: "Lora"; font-size: 24px; font-style: normal; font-weight: 700; line-height: normal; - border: none; border-radius: 4px; } +.submit { + color: white; + border: none; +} + +.enabled { + background-color: #102d5f; +} + +.disabled { + background-color: grey; +} + .back { - width: 306px; - height: 64px; background-color: var(--color-tse-primary-light); color: #102d5f; - cursor: pointer; - font-family: "Lora"; - font-size: 24px; - font-style: normal; - font-weight: 700; - line-height: normal; - border-radius: 4px; border: 1px solid var(--Secondary-1, #102d5f); background: rgba(255, 255, 255, 0); } + +/* tablet version */ +@media screen and (max-width: 850px) { + .main { + padding: 48px; + padding-top: 64px; + } + + .title { + font-size: 36px; + } + + .description { + font-size: 18px; + } + + .fieldsMarked { + font-size: 14px; + } + + .formContainer { + padding: 48px 32px; + } + + .sectionTitle { + font-size: 28px; + } + + .formRow { + gap: 32px; + } + + .desktopRowTabletColumn { + flex-direction: column; + } + + .bottomRow { + padding-bottom: 64px; + } + + .bottomButton { + width: 100%; + } + + .furnitureItemsSectionLabel { + font-size: 14px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .main { + padding: 24px; + padding-top: 35px; + } + + .title { + font-size: 28px; + } + + .description { + font-size: 14px; + } + + .fieldsMarked { + font-size: 12px; + } + + .formContainer { + padding: 32px 16px; + } + + .sectionTitle { + font-size: 20px; + } + + .formRow { + flex-direction: column; + } + + .bottomRow { + gap: 32px; + flex-direction: column; + } + + .furnitureItemsSectionLabel { + font-size: 12px; + } +} diff --git a/frontend/src/app/vsr/page.tsx b/frontend/src/app/vsr/page.tsx index d1d724f..9ac0e0b 100644 --- a/frontend/src/app/vsr/page.tsx +++ b/frontend/src/app/vsr/page.tsx @@ -8,6 +8,7 @@ import Dropdown from "@/components/shared/input/Dropdown"; import HeaderBar from "@/components/shared/HeaderBar"; import PageNumber from "@/components/VSRForm/PageNumber"; import { createVSR, CreateVSRRequest, FurnitureInput } from "@/api/VSRs"; +import { useMediaQuery } from "@mui/material"; import { FurnitureItem, getFurnitureItems } from "@/api/FurnitureItems"; import BinaryChoice from "@/components/shared/input/BinaryChoice"; import { FurnitureItemSelection } from "@/components/VeteranForm/FurnitureItemSelection"; @@ -252,6 +253,8 @@ const VeteranServiceRequest: React.FC = () => { })); }; + const isMobile = useMediaQuery("@media screen and (max-width: 550px)"); + // Execute when submit button is pressed const onSubmit: SubmitHandler = async (data) => { // Construct the request object @@ -326,7 +329,7 @@ const VeteranServiceRequest: React.FC = () => { <>
{ />
-
- {/* Cap it at 99 children per gender to avoid freezing web browser */} - {Array.from({ length: Math.min(numChildrenThisGender, 99) }, (_, index) => ( -
- -
- ))} -
+ {numChildrenThisGender > 0 ? ( +
+ {/* Cap it at 99 children per gender to avoid freezing web browser */} + {Array.from({ length: Math.min(numChildrenThisGender, 99) }, (_, index) => ( +
+ +
+ ))} +
+ ) : null} ); }; + const renderPageNumber = () => { + return ; + }; + + const renderBackButton = () => { + return pageNumber === 1 ? ( +
+ ) : ( + + ); + }; + + const renderNextButton = () => { + return ( + + ); + }; + + const renderBottomRow = () => { + if (isMobile) { + return ( +
+ +
+ {pageNumber === 1 ? null : renderBackButton()} + {renderNextButton()} +
+
+ ); + } else { + return ( +
+ {renderBackButton()} + {renderPageNumber()} + {renderNextButton()} +
+ ); + } + }; + if (pageNumber == 1) { return (
-

Veteran Service Request Form

+

Veteran Service Request Form

Welcome, Veterans, Active Duty, Reservists, and Families. If you're in need of furnishings, we're here to assist you. Please complete and submit the form below @@ -405,7 +459,7 @@ const VeteranServiceRequest: React.FC = () => {

-

Personal Information

+

Personal Information

@@ -419,8 +473,8 @@ const VeteranServiceRequest: React.FC = () => { helperText={errors.name?.message} />
- {/* Add an empty div here with flex: 1 to take up the right half of the row */} -
+ {/* Add an empty div here with flex: 1 to take up the right half of the row, on non-mobile */} + {isMobile ? null :
}
@@ -505,9 +559,9 @@ const VeteranServiceRequest: React.FC = () => {

Children (under 18)

-
- {renderChildInput("boy")} - {renderChildInput("girl")} +
+
{renderChildInput("boy")}
+
{renderChildInput("girl")}
@@ -607,15 +661,7 @@ const VeteranServiceRequest: React.FC = () => { />
-
- -
- + {renderBottomRow()}
@@ -629,72 +675,75 @@ const VeteranServiceRequest: React.FC = () => {
-

Contact Information

- -
-
- -
+

Contact Information

-
- -
+
+
+
+ +
-
- ( - field.onChange(e)} - required - error={!!errors.state} - helperText={errors.state?.message} - placeholder="Select a state" - /> - )} - /> +
+ +
+
+
+ ( + field.onChange(e)} + required + error={!!errors.state} + helperText={errors.state?.message} + placeholder="Select a state" + /> + )} + /> +
-
- +
+ +
@@ -740,7 +789,7 @@ const VeteranServiceRequest: React.FC = () => {
-

Military Background

+

Military Background

{
-

Additional Information

- +

Additional Information

{
-
-
- -
- -
- -
-
+ {renderBottomRow()}
); } else { return ( -
+
-
-
Furnishings
-
- {Object.entries(furnitureCategoriesToItems ?? {}).map(([category, items]) => ( -
-

{category}

-
- {(items ?? []).map((furnitureItem) => ( - handleSelectionChange(newSelection)} - /> +
+
+
+
+
Furnishings
+
+ {Object.entries(furnitureCategoriesToItems ?? {}).map(([category, items]) => ( +
+

{category}

+
+ {(items ?? []).map((furnitureItem) => ( + + handleSelectionChange(newSelection) + } + /> + ))} +
+
))} +
+ setAdditionalItems(e.target.value)} + > +
- ))} -
- setAdditionalItems(e.target.value)} - >
-
-
-
- -
- -
- -
+ {renderBottomRow()}
diff --git a/frontend/src/components/VSRForm/PageNumber/styles.module.css b/frontend/src/components/VSRForm/PageNumber/styles.module.css index baa68f8..d4ccce6 100644 --- a/frontend/src/components/VSRForm/PageNumber/styles.module.css +++ b/frontend/src/components/VSRForm/PageNumber/styles.module.css @@ -7,4 +7,19 @@ font-style: normal; font-weight: 400; line-height: normal; + white-space: nowrap; +} + +/* tablet version */ +@media screen and (max-width: 850px) { + .pageNumber { + font-size: 14px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .pageNumber { + font-size: 12px; + } } diff --git a/frontend/src/components/VeteranForm/FurnitureItemSelection/styles.module.css b/frontend/src/components/VeteranForm/FurnitureItemSelection/styles.module.css index c7f73be..318b0f2 100644 --- a/frontend/src/components/VeteranForm/FurnitureItemSelection/styles.module.css +++ b/frontend/src/components/VeteranForm/FurnitureItemSelection/styles.module.css @@ -1,7 +1,5 @@ .chip { white-space: nowrap; - border-width: 1px; - border-style: solid; text-align: center; font-family: "OpenSans"; font-size: 16px; @@ -15,6 +13,7 @@ .chipContent { display: flex; flex-direction: row; + align-items: center; padding: 9px 16px; align-content: baseline; } @@ -84,3 +83,17 @@ filter: brightness(0) saturate(100%) invert(100%) sepia(0%) saturate(0%) hue-rotate(36deg) brightness(103%) contrast(103%); } + +/* tablet version */ +@media screen and (max-width: 850px) { + .chip { + font-size: 14px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .chip { + font-size: 12px; + } +} diff --git a/frontend/src/components/shared/input/BinaryChoice/index.tsx b/frontend/src/components/shared/input/BinaryChoice/index.tsx index a459430..69a4110 100644 --- a/frontend/src/components/shared/input/BinaryChoice/index.tsx +++ b/frontend/src/components/shared/input/BinaryChoice/index.tsx @@ -1,6 +1,7 @@ import { useState } from "react"; import Chip from "@mui/material/Chip"; import styles from "@/components/shared/input/BinaryChoice/styles.module.css"; +import { FormField } from "../FormField"; export interface BinaryChoiceProps { label: string; @@ -11,7 +12,14 @@ export interface BinaryChoiceProps { helperText?: string; } -const BinaryChoice = ({ label, value, onChange, required, helperText }: BinaryChoiceProps) => { +const BinaryChoice = ({ + label, + value, + onChange, + required, + error, + helperText, +}: BinaryChoiceProps) => { const [selectedOption, setSelectedOption] = useState(value); const handleOptionClick = (newOption: boolean | null) => { @@ -20,11 +28,7 @@ const BinaryChoice = ({ label, value, onChange, required, helperText }: BinaryCh }; return ( -
-

- {required ? * : null} - {label} -

+
- {helperText ?
{helperText}
: null} -
+ ); }; diff --git a/frontend/src/components/shared/input/BinaryChoice/styles.module.css b/frontend/src/components/shared/input/BinaryChoice/styles.module.css index 2f69852..c40c320 100644 --- a/frontend/src/components/shared/input/BinaryChoice/styles.module.css +++ b/frontend/src/components/shared/input/BinaryChoice/styles.module.css @@ -1,19 +1,5 @@ /* BinaryChoice.module.css */ -.wrapperClass { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 16px; - flex: 1 0 0; - font-size: 16px; - color: var(--Light-Gray, #818181); - font-family: "Open Sans"; - font-style: normal; - font-weight: 400; - line-height: normal; -} - .chip { border-width: 1px; border-style: solid; @@ -52,13 +38,3 @@ .chipUnselected:hover { background: rgb(213, 232, 239); } - -.requiredAsterisk { - color: var(--Secondary-2, #be2d46); - text-align: left; -} - -.helperText { - color: var(--Secondary-2, #be2d46); - font-size: 12px; -} diff --git a/frontend/src/components/shared/input/Dropdown/index.tsx b/frontend/src/components/shared/input/Dropdown/index.tsx index be8f073..ccec258 100644 --- a/frontend/src/components/shared/input/Dropdown/index.tsx +++ b/frontend/src/components/shared/input/Dropdown/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import styles from "@/components/shared/input/Dropdown/styles.module.css"; -import { FormControl, Select, MenuItem, SelectChangeEvent } from "@mui/material"; +import { FormControl, Select, MenuItem, SelectChangeEvent, useMediaQuery } from "@mui/material"; +import { FormField } from "../FormField"; export interface DropDownProps { label: string; @@ -23,15 +24,14 @@ const Dropdown = ({ helperText, placeholder, }: DropDownProps) => { + const isMobile = useMediaQuery("@media screen and (max-width: 550px)"); + const isTablet = useMediaQuery("@media screen and (max-width: 850px)"); + return ( -
-

- {required ? * : null} - {label} -

+ - {helperText ?
{helperText}
: null} -
+ ); }; diff --git a/frontend/src/components/shared/input/Dropdown/styles.module.css b/frontend/src/components/shared/input/Dropdown/styles.module.css index dfd998b..0a9c1b5 100644 --- a/frontend/src/components/shared/input/Dropdown/styles.module.css +++ b/frontend/src/components/shared/input/Dropdown/styles.module.css @@ -1,25 +1,9 @@ -.wrapperClass { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 4px; - flex: 1 0 0; - font-size: 16px; - color: var(--Light-Gray, #818181); - font-family: "Open Sans"; - font-style: normal; - font-weight: 400; - line-height: normal; -} - .dropDown { color: var(--Dark-Gray, #484848); font-family: "Open Sans"; font-size: 16px; - font-style: italic; font-weight: 300; line-height: normal; - align-items: flex-start; gap: 10px; align-self: stretch; } @@ -29,16 +13,6 @@ height: 100%; } -.requiredAsterisk { - color: var(--Secondary-2, #be2d46); - text-align: left; -} - -.helperText { - color: var(--Secondary-2, #be2d46); - font-size: 12px; -} - .placeholder { font-size: 16px; font-style: italic; diff --git a/frontend/src/components/shared/input/FormField/index.tsx b/frontend/src/components/shared/input/FormField/index.tsx new file mode 100644 index 0000000..4ef3b50 --- /dev/null +++ b/frontend/src/components/shared/input/FormField/index.tsx @@ -0,0 +1,25 @@ +import styles from "@/components/shared/input/FormField/styles.module.css"; +import { ReactNode } from "react"; + +export interface FormFieldProps { + label: string; + required: boolean; + error?: boolean; + helperText?: string; + children: ReactNode; +} + +export const FormField = ({ label, required, error, helperText, children }: FormFieldProps) => { + return ( +
+

+ {required ? * : null} + {label} +

+ {children} + {helperText ? ( +
{helperText}
+ ) : null} +
+ ); +}; diff --git a/frontend/src/components/shared/input/FormField/styles.module.css b/frontend/src/components/shared/input/FormField/styles.module.css new file mode 100644 index 0000000..82b9ab1 --- /dev/null +++ b/frontend/src/components/shared/input/FormField/styles.module.css @@ -0,0 +1,41 @@ +.wrapperClass { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + flex: 1 0 0; + font-size: 16px; + color: var(--Light-Gray, #818181); + font-family: "Open Sans"; + font-style: normal; + font-weight: 400; + line-height: normal; +} + +.requiredAsterisk { + color: var(--Secondary-2, #be2d46); + text-align: left; +} + +.helperText { + color: var(--Neutral-Gray6, #484848); + font-size: 12px; +} + +.errorText { + color: var(--Secondary-2, #be2d46); +} + +/* tablet version */ +@media screen and (max-width: 850px) { + .wrapperClass { + font-size: 14px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .wrapperClass { + font-size: 12px; + } +} diff --git a/frontend/src/components/shared/input/MultipleChoice/index.tsx b/frontend/src/components/shared/input/MultipleChoice/index.tsx index c4b9132..23b2566 100644 --- a/frontend/src/components/shared/input/MultipleChoice/index.tsx +++ b/frontend/src/components/shared/input/MultipleChoice/index.tsx @@ -1,5 +1,6 @@ import Chip from "@mui/material/Chip"; import styles from "@/components/shared/input/MultipleChoice/styles.module.css"; +import { FormField } from "../FormField"; export interface MultipleChoiceProps { label: string; @@ -19,14 +20,11 @@ const MultipleChoice = ({ onChange, required, allowMultiple = false, + error, helperText, }: MultipleChoiceProps) => { return ( -
-

- {required ? * : null} - {label} -

+
{options.map((option) => { const optionIsSelected = allowMultiple ? value?.includes(option) : value === option; @@ -58,12 +56,16 @@ const MultipleChoice = ({ optionIsSelected ? styles.chipSelected : styles.chipUnselected }`} clickable + sx={{ + ".MuiChip-label": { + padding: "0 !important", + }, + }} /> ); })}
- {helperText ?
{helperText}
: null} -
+ ); }; diff --git a/frontend/src/components/shared/input/MultipleChoice/styles.module.css b/frontend/src/components/shared/input/MultipleChoice/styles.module.css index b3a1f93..1076148 100644 --- a/frontend/src/components/shared/input/MultipleChoice/styles.module.css +++ b/frontend/src/components/shared/input/MultipleChoice/styles.module.css @@ -1,22 +1,7 @@ /* MultipleChoice.module.css */ -.wrapperClass { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 16px; - flex: 1 0 0; - font-size: 16px; - color: var(--Light-Gray, #818181); - font-family: "Open Sans"; - font-style: normal; - font-weight: 400; - line-height: normal; -} - .chip { border-width: 1px; - border-style: solid; text-align: center; font-family: "Open Sans"; font-size: 16px; @@ -25,6 +10,8 @@ line-height: normal; border-radius: 64px; border: 1px solid var(--Secondary-1, #102d5f); + padding: 8px 16px; + height: 40px; } .chipSelected { @@ -50,15 +37,21 @@ /*Need exact color for this*/ .chipUnselected:hover { - background: rgb(213, 232, 239); + background: rgb(142, 166, 175); } -.requiredAsterisk { - color: var(--Secondary-2, #be2d46); - text-align: left; +/* tablet version */ +@media screen and (max-width: 850px) { + .chip { + font-size: 14px; + height: 36px; + } } -.helperText { - color: var(--Secondary-2, #be2d46); - font-size: 12px; +/* mobile version */ +@media screen and (max-width: 550px) { + .chip { + font-size: 12px; + height: 30px; + } } diff --git a/frontend/src/components/shared/input/TextField/index.tsx b/frontend/src/components/shared/input/TextField/index.tsx index 2dc9e10..0e71772 100644 --- a/frontend/src/components/shared/input/TextField/index.tsx +++ b/frontend/src/components/shared/input/TextField/index.tsx @@ -1,6 +1,7 @@ import styles from "@/components/shared/input/TextField/styles.module.css"; import MUITextField, { TextFieldProps as MUITextFieldProps } from "@mui/material/TextField"; import { ForwardedRef, forwardRef } from "react"; +import { FormField } from "../FormField"; export interface TextFieldProps extends MUITextFieldProps<"outlined"> { label: string; @@ -15,11 +16,7 @@ const TextField = forwardRef( ref: ForwardedRef, ) => { return ( -
-

- {required ? * : null} - {label} -

+ - {helperText ? ( -
- {helperText} -
- ) : null} -
+ ); }, ); diff --git a/frontend/src/components/shared/input/TextField/styles.module.css b/frontend/src/components/shared/input/TextField/styles.module.css index 40565fa..0aebaae 100644 --- a/frontend/src/components/shared/input/TextField/styles.module.css +++ b/frontend/src/components/shared/input/TextField/styles.module.css @@ -1,22 +1,3 @@ -.wrapperClass { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 4px; - flex: 1 0 0; - font-size: 16px; - color: var(--Light-Gray, #818181); - font-family: "Open Sans"; - font-style: normal; - font-weight: 400; - line-height: normal; -} - -.requiredAsterisk { - color: var(--Secondary-2, #be2d46); - text-align: left; -} - .inputClass { display: flex; align-items: flex-start; @@ -28,13 +9,9 @@ line-height: normal; } -.helperText { - color: var(--Neutral-Gray6, #484848); - font-size: 12px; -} - -.errorText { - color: var(--Secondary-2, #be2d46); +.input { + height: 22px; + padding: 6px 12px; } .input::placeholder { @@ -43,3 +20,17 @@ font-weight: 300; color: var(--Dark-Gray, #484848); } + +/* tablet version */ +@media screen and (max-width: 850px) { + .input { + height: 19px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .input { + height: 16px; + } +} From ce5c88275e945a16102933822b7d6d8e61f6a878 Mon Sep 17 00:00:00 2001 From: benjaminjohnson2204 Date: Thu, 28 Mar 2024 23:54:11 -0700 Subject: [PATCH 6/8] Implement tablet & mobile versions of VSR table page --- frontend/src/app/login/page.tsx | 4 +- frontend/src/app/staff/vsr/page.module.css | 45 +++++- frontend/src/app/staff/vsr/page.tsx | 26 ++- frontend/src/app/vsr/page.tsx | 4 +- .../components/VSRTable/PageTitle/index.tsx | 6 +- .../VSRTable/PageTitle/styles.module.css | 16 +- .../components/VSRTable/VSRTable/index.tsx | 152 ++++++++++-------- .../src/components/shared/HeaderBar/index.tsx | 10 +- .../shared/HeaderBar/styles.module.css | 12 ++ .../shared/StatusChip/styles.module.css | 8 + .../shared/input/Dropdown/index.tsx | 6 +- frontend/src/util/useScreenSizes.ts | 14 ++ 12 files changed, 212 insertions(+), 91 deletions(-) create mode 100644 frontend/src/util/useScreenSizes.ts diff --git a/frontend/src/app/login/page.tsx b/frontend/src/app/login/page.tsx index 44278e5..d4dcdbd 100644 --- a/frontend/src/app/login/page.tsx +++ b/frontend/src/app/login/page.tsx @@ -8,7 +8,7 @@ import styles from "@/app/login/page.module.css"; import { signInWithEmailAndPassword } from "firebase/auth"; import { initFirebase } from "@/firebase/firebase"; import { useRouter } from "next/navigation"; -import { useMediaQuery } from "@mui/material"; +import { useScreenSizes } from "@/util/useScreenSizes"; const Login = () => { const [email, setEmail] = useState(""); @@ -18,7 +18,7 @@ const Login = () => { const router = useRouter(); - const isMobile = useMediaQuery("@media screen and (max-width: 550px)"); + const { isMobile } = useScreenSizes(); const sendTokenToBackend = async (token: string) => { try { diff --git a/frontend/src/app/staff/vsr/page.module.css b/frontend/src/app/staff/vsr/page.module.css index 0920eaf..3818081 100644 --- a/frontend/src/app/staff/vsr/page.module.css +++ b/frontend/src/app/staff/vsr/page.module.css @@ -7,10 +7,9 @@ display: flex; flex-direction: column; justify-content: center; - margin: 105px auto 0; + margin: 105px 120px 0; padding: 0px; gap: 40px; - max-width: 1200px; } .flex { @@ -22,7 +21,7 @@ .button_row { display: flex; flex-direction: row; - align-items: flex-start; + align-items: center; justify-content: space-between; } @@ -30,7 +29,7 @@ gap: 40px; display: flex; flex-direction: row; - align-items: flex-start; + align-items: center; } .statusContainer { @@ -53,14 +52,14 @@ } .statusWrapper { - min-width: 240px; + min-width: 230px; } .row_right { gap: 40px; display: flex; flex-direction: row; - align-items: flex-end; + align-items: center; } .buttons { @@ -95,3 +94,37 @@ align-items: center; width: 100%; } + +/* shrink the margins at a screen size larger than tablet to avoid overflow */ +@media screen and (max-width: 1150px) { + .column { + margin: 52px 48px 0; + } +} + +@media screen and (max-width: 600px) { + .row_right { + gap: 4px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .column { + margin: 37px 24px 0; + } + + .statusWrapper { + min-width: 190px; + } + + .statusLabel { + font-size: 12px; + } +} + +@media screen and (max-width: 475px) { + .statusWrapper { + min-width: unset; + } +} diff --git a/frontend/src/app/staff/vsr/page.tsx b/frontend/src/app/staff/vsr/page.tsx index 716a2fa..f34a762 100644 --- a/frontend/src/app/staff/vsr/page.tsx +++ b/frontend/src/app/staff/vsr/page.tsx @@ -8,8 +8,13 @@ import HeaderBar from "@/components/shared/HeaderBar"; import Image from "next/image"; import React from "react"; import { StatusDropdown } from "@/components/VSRIndividual"; +import { useMediaQuery } from "@mui/material"; export default function VSRTableView() { + const searchOnOwnRow = useMediaQuery("@media screen and (max-width: 1000px)"); + const buttonIconsOnly = useMediaQuery("@media screen and (max-width: 700px)"); + const buttonIconSize = buttonIconsOnly ? 16 : 24; + return (
@@ -17,7 +22,7 @@ export default function VSRTableView() {
- + {searchOnOwnRow ? null : }

Status:

@@ -28,15 +33,26 @@ export default function VSRTableView() {
+ {searchOnOwnRow ? : null}
diff --git a/frontend/src/app/vsr/page.tsx b/frontend/src/app/vsr/page.tsx index 9ac0e0b..268573b 100644 --- a/frontend/src/app/vsr/page.tsx +++ b/frontend/src/app/vsr/page.tsx @@ -8,10 +8,10 @@ import Dropdown from "@/components/shared/input/Dropdown"; import HeaderBar from "@/components/shared/HeaderBar"; import PageNumber from "@/components/VSRForm/PageNumber"; import { createVSR, CreateVSRRequest, FurnitureInput } from "@/api/VSRs"; -import { useMediaQuery } from "@mui/material"; import { FurnitureItem, getFurnitureItems } from "@/api/FurnitureItems"; import BinaryChoice from "@/components/shared/input/BinaryChoice"; import { FurnitureItemSelection } from "@/components/VeteranForm/FurnitureItemSelection"; +import { useScreenSizes } from "@/util/useScreenSizes"; interface IFormInput { name: string; @@ -253,7 +253,7 @@ const VeteranServiceRequest: React.FC = () => { })); }; - const isMobile = useMediaQuery("@media screen and (max-width: 550px)"); + const { isMobile } = useScreenSizes(); // Execute when submit button is pressed const onSubmit: SubmitHandler = async (data) => { diff --git a/frontend/src/components/VSRTable/PageTitle/index.tsx b/frontend/src/components/VSRTable/PageTitle/index.tsx index cdf9491..f52bbde 100644 --- a/frontend/src/components/VSRTable/PageTitle/index.tsx +++ b/frontend/src/components/VSRTable/PageTitle/index.tsx @@ -2,9 +2,5 @@ import React from "react"; import styles from "@/components/VSRTable/PageTitle/styles.module.css"; export default function PageTitle() { - return ( -
- Service Requests -
- ); + return Service Requests; } diff --git a/frontend/src/components/VSRTable/PageTitle/styles.module.css b/frontend/src/components/VSRTable/PageTitle/styles.module.css index 3665bbe..3d4f4ad 100644 --- a/frontend/src/components/VSRTable/PageTitle/styles.module.css +++ b/frontend/src/components/VSRTable/PageTitle/styles.module.css @@ -3,10 +3,22 @@ color: var(--color-tse-secondary-1); font-family: var(--font-title); font-size: 40px; - font-style: normal; font-weight: 700; - line-height: 51.2px; display: flex; flex-direction: row; align-items: flex-start; } + +/* tablet version */ +@media screen and (max-width: 850px) { + .items { + font-size: 36px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .items { + font-size: 28px; + } +} diff --git a/frontend/src/components/VSRTable/VSRTable/index.tsx b/frontend/src/components/VSRTable/VSRTable/index.tsx index 29d692e..b51fe37 100644 --- a/frontend/src/components/VSRTable/VSRTable/index.tsx +++ b/frontend/src/components/VSRTable/VSRTable/index.tsx @@ -11,80 +11,102 @@ import moment from "moment"; import { useRouter } from "next/navigation"; import { StatusChip } from "@/components/shared/StatusChip"; import { STATUS_OPTIONS } from "@/components/shared/StatusDropdown"; +import { useScreenSizes } from "@/util/useScreenSizes"; const formatDateReceived = (dateReceived: Date) => { // Return the empty string on a falsy date received, instead of defaulting to today's date return dateReceived ? moment(dateReceived).format("MMMM D, YYYY") : ""; }; -const columns: GridColDef[] = [ - { - ...GRID_CHECKBOX_SELECTION_COL_DEF, - width: 72, - headerClassName: "header", - }, - { - field: "_id", - headerName: "Case ID", - type: "string", - flex: 1, - headerAlign: "left", - headerClassName: "header", - disableColumnMenu: true, - hideSortIcons: true, - }, - { - field: "militaryID", - headerName: "Military ID (Last 4)", - type: "string", - flex: 1, - headerClassName: "header", - disableColumnMenu: true, - hideSortIcons: true, - }, - { - field: "name", - headerName: "Name", - flex: 1, - headerClassName: "header", - disableColumnMenu: true, - hideSortIcons: true, - }, - - { - field: "dateReceived", - headerName: "Date Received", - type: "date", - sortable: true, - flex: 1, - headerClassName: "header", - disableColumnMenu: true, - hideSortIcons: true, - valueFormatter: (params) => formatDateReceived(params?.value), - }, - { - field: "status", - headerName: "Status", - type: "string", - flex: 1, - headerClassName: "header", - disableColumnMenu: true, - hideSortIcons: true, - renderCell: (params) => ( - statusOption.value === params.value) ?? - STATUS_OPTIONS[0] - } - /> - ), - }, -]; - export default function VSRTable() { const [vsrs, setVsrs] = React.useState(); const router = useRouter(); + const { isMobile, isTablet } = useScreenSizes(); + + const columns: GridColDef[] = React.useMemo(() => { + const result = [ + { + ...GRID_CHECKBOX_SELECTION_COL_DEF, + width: 72, + headerClassName: "header", + }, + ]; + + if (!isMobile) { + result.push({ + field: "_id", + headerName: "Case ID", + type: "string", + flex: 1, + headerAlign: "left", + headerClassName: "header", + disableColumnMenu: true, + hideSortIcons: true, + width: 100, + }); + } + + if (!isTablet) { + result.push({ + field: "militaryID", + headerName: "Military ID (Last 4)", + type: "string", + flex: 1, + headerClassName: "header", + disableColumnMenu: true, + hideSortIcons: true, + width: 100, + }); + } + + result.push({ + field: "name", + headerName: "Name", + flex: 1, + headerClassName: "header", + disableColumnMenu: true, + hideSortIcons: true, + width: 100, + }); + + if (!isTablet) { + result.push({ + field: "dateReceived", + headerName: "Date Received", + type: "date", + sortable: true, + flex: 1, + headerClassName: "header", + disableColumnMenu: true, + hideSortIcons: true, + valueFormatter: (params) => formatDateReceived(params?.value), + width: 100, + }); + } + + result.push({ + field: "status", + headerName: "Status", + type: "string", + flex: 1, + headerClassName: "header", + disableColumnMenu: true, + hideSortIcons: true, + renderCell: (params) => ( + statusOption.value === params.value) ?? + STATUS_OPTIONS[0] + } + /> + ), + width: 100, + }); + + return result; + }, [isMobile, isTablet]); + useEffect(() => { getAllVSRs().then((result) => { if (result.success) { @@ -121,7 +143,7 @@ export default function VSRTable() { cursor: "pointer", }, ".MuiDataGrid-cellContent": { - fontSize: "1rem", + fontSize: isMobile ? "0.75rem" : isTablet ? "0.875rem" : "1rem", }, "&.MuiDataGrid-root": { border: "none", diff --git a/frontend/src/components/shared/HeaderBar/index.tsx b/frontend/src/components/shared/HeaderBar/index.tsx index 4bc1507..d5b927d 100644 --- a/frontend/src/components/shared/HeaderBar/index.tsx +++ b/frontend/src/components/shared/HeaderBar/index.tsx @@ -1,11 +1,19 @@ import Image from "next/image"; import React from "react"; import styles from "@/components/shared/HeaderBar/styles.module.css"; +import { useScreenSizes } from "@/util/useScreenSizes"; const HeaderBar = () => { + const { isTablet } = useScreenSizes(); return (
- logo + logo
); }; diff --git a/frontend/src/components/shared/HeaderBar/styles.module.css b/frontend/src/components/shared/HeaderBar/styles.module.css index c71779b..07117de 100644 --- a/frontend/src/components/shared/HeaderBar/styles.module.css +++ b/frontend/src/components/shared/HeaderBar/styles.module.css @@ -12,3 +12,15 @@ margin-top: 27px; margin-left: 63px; } + +/* tablet version */ +@media screen and (max-width: 850px) { + .headerBar { + height: 115px; + } + + .logo { + margin-top: 52px; + margin-left: 24px; + } +} diff --git a/frontend/src/components/shared/StatusChip/styles.module.css b/frontend/src/components/shared/StatusChip/styles.module.css index 6cb88b8..f870e0a 100644 --- a/frontend/src/components/shared/StatusChip/styles.module.css +++ b/frontend/src/components/shared/StatusChip/styles.module.css @@ -3,4 +3,12 @@ padding: 2px 8px; border-radius: 8px; width: max-content; + font-size: 16px; +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .statusChip { + font-size: 12px; + } } diff --git a/frontend/src/components/shared/input/Dropdown/index.tsx b/frontend/src/components/shared/input/Dropdown/index.tsx index ccec258..e0ed938 100644 --- a/frontend/src/components/shared/input/Dropdown/index.tsx +++ b/frontend/src/components/shared/input/Dropdown/index.tsx @@ -1,7 +1,8 @@ import React from "react"; import styles from "@/components/shared/input/Dropdown/styles.module.css"; -import { FormControl, Select, MenuItem, SelectChangeEvent, useMediaQuery } from "@mui/material"; +import { FormControl, Select, MenuItem, SelectChangeEvent } from "@mui/material"; import { FormField } from "../FormField"; +import { useScreenSizes } from "@/util/useScreenSizes"; export interface DropDownProps { label: string; @@ -24,8 +25,7 @@ const Dropdown = ({ helperText, placeholder, }: DropDownProps) => { - const isMobile = useMediaQuery("@media screen and (max-width: 550px)"); - const isTablet = useMediaQuery("@media screen and (max-width: 850px)"); + const { isMobile, isTablet } = useScreenSizes(); return ( diff --git a/frontend/src/util/useScreenSizes.ts b/frontend/src/util/useScreenSizes.ts new file mode 100644 index 0000000..01dee83 --- /dev/null +++ b/frontend/src/util/useScreenSizes.ts @@ -0,0 +1,14 @@ +import { useMediaQuery } from "@mui/material"; + +/** + * A hook to determine the screen size (desktop vs. tablet vs. mobile) + */ +export const useScreenSizes = () => { + const isMobile = useMediaQuery("@media screen and (max-width: 550px)"); + const isTablet = useMediaQuery("@media screen and (max-width: 850px)"); + + return { + isMobile, + isTablet, + }; +}; From 03d055a2d77eb29dc093ecbf30fcb3da8cefba5a Mon Sep 17 00:00:00 2001 From: benjaminjohnson2204 Date: Fri, 29 Mar 2024 22:34:25 -0700 Subject: [PATCH 7/8] Implement tablet and mobile versions of VSR view page --- .../VSRIndividual/CaseDetails/index.tsx | 14 +- .../CaseDetails/styles.module.css | 17 ++- .../ListDetail/styles.module.css | 32 ++++- .../components/VSRIndividual/Page/index.tsx | 125 ++++++++++-------- .../VSRIndividual/Page/styles.module.css | 71 +++++++--- .../VSRIndividual/SingleDetail/index.tsx | 4 +- .../SingleDetail/styles.module.css | 39 ++++++ .../VSRIndividualAccordion/styles.module.css | 24 ++-- .../VeteranTag/styles.module.css | 16 +++ 9 files changed, 250 insertions(+), 92 deletions(-) diff --git a/frontend/src/components/VSRIndividual/CaseDetails/index.tsx b/frontend/src/components/VSRIndividual/CaseDetails/index.tsx index 834153d..650a4bc 100644 --- a/frontend/src/components/VSRIndividual/CaseDetails/index.tsx +++ b/frontend/src/components/VSRIndividual/CaseDetails/index.tsx @@ -5,6 +5,7 @@ import moment from "moment"; import { VSRIndividualAccordion } from "@/components/VSRIndividual/VSRIndividualAccordion"; import { STATUS_OPTIONS } from "@/components/shared/StatusDropdown"; import { StatusChip } from "@/components/shared/StatusChip"; +import { useScreenSizes } from "@/util/useScreenSizes"; export interface CaseDetailsProp { vsr: VSR; @@ -21,6 +22,8 @@ const formatDate = (date: Date) => { }; export const CaseDetails = ({ vsr, onUpdateVSR }: CaseDetailsProp) => { + const { isMobile, isTablet } = useScreenSizes(); + const renderStatus = () => { if (vsr.status === "Received" || vsr.status === undefined) { return ( @@ -43,22 +46,25 @@ export const CaseDetails = ({ vsr, onUpdateVSR }: CaseDetailsProp) => { ); }; + const valueFontSize = isMobile ? 14 : isTablet ? 18 : 20; + return (
- - +
); diff --git a/frontend/src/components/VSRIndividual/CaseDetails/styles.module.css b/frontend/src/components/VSRIndividual/CaseDetails/styles.module.css index ec40012..d0e9067 100644 --- a/frontend/src/components/VSRIndividual/CaseDetails/styles.module.css +++ b/frontend/src/components/VSRIndividual/CaseDetails/styles.module.css @@ -5,9 +5,22 @@ margin-right: 4px; padding-bottom: 5px; margin-top: 15px; + justify-content: space-between; overflow: auto; } -.details > * { - padding-right: 100px; +.singleDetail { +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .details { + flex-direction: column; + gap: 18px; + } + + .singleDetail { + flex-direction: row !important; + justify-content: space-between !important; + } } diff --git a/frontend/src/components/VSRIndividual/ListDetail/styles.module.css b/frontend/src/components/VSRIndividual/ListDetail/styles.module.css index 69f310e..b4c433d 100644 --- a/frontend/src/components/VSRIndividual/ListDetail/styles.module.css +++ b/frontend/src/components/VSRIndividual/ListDetail/styles.module.css @@ -23,6 +23,7 @@ flex-direction: row; flex-wrap: wrap; } + .listItem { color: #fff; text-align: center; @@ -31,7 +32,6 @@ font-style: normal; font-weight: 400; line-height: normal; - height: 40px; border-radius: 64px; border: 1px solid var(--color-tse-accent-blue-1); background: var(--color-tse-accent-blue-1); @@ -48,3 +48,33 @@ font-size: 16px; font-style: italic; } + +/* tablet version */ +@media screen and (max-width: 550px) { + .title { + font-size: 14px; + } + + .listItem { + font-size: 14px; + } + + .noList { + font-size: 14px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .title { + font-size: 12px; + } + + .listItem { + font-size: 12px; + } + + .noList { + font-size: 12px; + } +} diff --git a/frontend/src/components/VSRIndividual/Page/index.tsx b/frontend/src/components/VSRIndividual/Page/index.tsx index 4d422bb..d50aed5 100644 --- a/frontend/src/components/VSRIndividual/Page/index.tsx +++ b/frontend/src/components/VSRIndividual/Page/index.tsx @@ -14,6 +14,7 @@ import Image from "next/image"; import { type VSR, getVSR, updateVSRStatus } from "@/api/VSRs"; import { useParams } from "next/navigation"; import { FurnitureItem, getFurnitureItems } from "@/api/FurnitureItems"; +import { useScreenSizes } from "@/util/useScreenSizes"; export const Page = () => { const [vsr, setVSR] = useState({} as VSR); @@ -21,21 +22,42 @@ export const Page = () => { const [errorMessage, setErrorMessage] = useState(null); const [furnitureItems, setFurnitureItems] = useState(); - const renderApproveButton = () => ( - + const newVsr = res.success ? res.data : vsr; + + setVSR(newVsr); + }} + > + Approve VSR + + ) : null; + + const renderActions = () => ( + ); useEffect(() => { @@ -71,57 +93,48 @@ export const Page = () => { }, []); return ( -
+ <> - - - -
-
-
- {errorMessage &&
{errorMessage}
} - - -
- +
+
+ + + + {isMobile ? renderActions() : null}
-
- -
-
- - - - +
+
+
+ {errorMessage &&
{errorMessage}
} + +
-
- -
- {vsr.status == "Received" || vsr.status === undefined - ? renderApproveButton() - : null} + {isMobile ? null : renderActions()} +
+
+ +
+ {isTablet ? renderApproveButton() : null} +
+ + + + +
+
+ + {isTablet ? null : ( +
{renderApproveButton()}
+ )}
+
-
-
+ ); }; diff --git a/frontend/src/components/VSRIndividual/Page/styles.module.css b/frontend/src/components/VSRIndividual/Page/styles.module.css index 08beac9..303d516 100644 --- a/frontend/src/components/VSRIndividual/Page/styles.module.css +++ b/frontend/src/components/VSRIndividual/Page/styles.module.css @@ -1,17 +1,18 @@ .page { background-color: var(--color-background); + padding: 0 120px; +} + +.toDashboardRow { + padding-top: 35px; } .toDashboard { display: flex; color: var(--color-tse-accent-blue-1); - margin-top: 35px; max-width: 137px; width: 100%; - height: 40px; - padding-left: 10px; - padding-top: 8px; - margin-left: calc(100vw * 1 / 12); + padding: 8px 10px; border-radius: 4px; border: 1px solid var(--Secondary-Accent1, #102d5f); font-family: var(--font-open-sans); @@ -32,11 +33,10 @@ flex-direction: row; justify-content: space-between; width: 100%; + gap: 12px; } .actions { - margin-top: 29px; - margin-bottom: 32px; gap: 32px; align-self: center; display: flex; @@ -47,7 +47,6 @@ border-radius: 4px; border: 1px solid var(--color-tse-accent-blue-1); background-color: var(--color-tse-accent-blue-1); - height: 46px; padding: 8px 16px; font-family: var(--font-open-sans); font-size: 16px; @@ -57,17 +56,17 @@ text-align: center; color: white; cursor: pointer; + display: flex; + flex-direction: row; + gap: 6px; + align-items: center; + white-space: nowrap; } #edit:hover { background-color: #c7def1; } -.button > * { - padding-right: 6px; - vertical-align: middle; -} - .name { margin-top: 29px; margin-bottom: 32px; @@ -77,8 +76,7 @@ display: flex; flex-direction: column; align-items: center; - width: calc(100% * 5 / 6); - margin: 0 auto; + width: 100%; } .bodyDetails { @@ -95,7 +93,7 @@ .personalInfo { display: flex; flex-direction: column; - flex: 38%; + flex: 1; } .personalInfo > * { @@ -103,7 +101,7 @@ } .rightColumn { - flex: 62%; + flex: 1; } .finalActions { @@ -158,3 +156,42 @@ font-weight: 400; line-height: 40px; } + +/* tablet version */ +@media screen and (max-width: 850px) { + .otherDetails { + flex-direction: column-reverse; + } + + .toDashboardRow { + padding-top: 43px; + } + + .approveButton { + width: 100%; + padding: 12px 24px; + } + + .page { + padding: 0 48px; + } + + .button { + font-size: 14px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .page { + padding: 0 24px; + } + + .toDashboardRow { + padding-top: 20px; + } + + .actions { + gap: 16px; + } +} diff --git a/frontend/src/components/VSRIndividual/SingleDetail/index.tsx b/frontend/src/components/VSRIndividual/SingleDetail/index.tsx index 65d7c15..38bb134 100644 --- a/frontend/src/components/VSRIndividual/SingleDetail/index.tsx +++ b/frontend/src/components/VSRIndividual/SingleDetail/index.tsx @@ -4,7 +4,7 @@ import styles from "src/components/VSRIndividual/SingleDetail/styles.module.css" export interface SingleDetailProps { title: string; value: string | number | number[] | ReactNode; - valueFontSize?: string; + valueFontSize?: string | number; className?: string; } @@ -29,7 +29,7 @@ export function SingleDetail({ title, value, valueFontSize, className }: SingleD return (
-
+
{title}
{typeof value === "string" && value.includes("@") ? email diff --git a/frontend/src/components/VSRIndividual/SingleDetail/styles.module.css b/frontend/src/components/VSRIndividual/SingleDetail/styles.module.css index a0ba4be..03c0afa 100644 --- a/frontend/src/components/VSRIndividual/SingleDetail/styles.module.css +++ b/frontend/src/components/VSRIndividual/SingleDetail/styles.module.css @@ -18,6 +18,7 @@ .value { color: #222; font-family: var(--font-open-sans); + font-size: 16px; font-style: normal; font-weight: 400; line-height: normal; @@ -53,3 +54,41 @@ font-size: 16px; font-style: italic; } + +/* tablet version */ +@media screen and (max-width: 550px) { + .title { + font-size: 14px; + } + + .value { + font-size: 14px; + } + + .email { + font-size: 14px; + } + + .noValue { + font-size: 14px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .title { + font-size: 12px; + } + + .value { + font-size: 12px; + } + + .email { + font-size: 12px; + } + + .noValue { + font-size: 12px; + } +} diff --git a/frontend/src/components/VSRIndividual/VSRIndividualAccordion/styles.module.css b/frontend/src/components/VSRIndividual/VSRIndividualAccordion/styles.module.css index 9f221b8..eb34b9c 100644 --- a/frontend/src/components/VSRIndividual/VSRIndividualAccordion/styles.module.css +++ b/frontend/src/components/VSRIndividual/VSRIndividualAccordion/styles.module.css @@ -16,16 +16,6 @@ line-height: normal; } -.title { - font-family: var(--font-title); - color: var(--Primary-Background-Dark, #232220); - font-size: 24px; - font-style: normal; - font-weight: 700; - line-height: normal; - padding-left: 6px; -} - .details { display: flex; flex-direction: column; @@ -34,3 +24,17 @@ padding-left: 6px; padding-right: 6px; } + +/* tablet version */ +@media screen and (max-width: 550px) { + .title { + font-size: 28px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .title { + font-size: 20px; + } +} diff --git a/frontend/src/components/VSRIndividual/VeteranTag/styles.module.css b/frontend/src/components/VSRIndividual/VeteranTag/styles.module.css index 9b521b5..be2c037 100644 --- a/frontend/src/components/VSRIndividual/VeteranTag/styles.module.css +++ b/frontend/src/components/VSRIndividual/VeteranTag/styles.module.css @@ -5,4 +5,20 @@ font-size: 40px; font-weight: 700; line-height: 40px; + text-overflow: ellipsis; + overflow-wrap: anywhere; +} + +/* tablet version */ +@media screen and (max-width: 850px) { + .items span { + font-size: 36px; + } +} + +/* mobile version */ +@media screen and (max-width: 550px) { + .items span { + font-size: 28px; + } } From 1f13b1596de1bfdb8eab07a6c50519f7714322e4 Mon Sep 17 00:00:00 2001 From: benjaminjohnson2204 Date: Fri, 29 Mar 2024 22:41:17 -0700 Subject: [PATCH 8/8] Fix children label on VSR --- frontend/src/app/vsr/page.module.css | 13 +++++++++++-- frontend/src/app/vsr/page.tsx | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/vsr/page.module.css b/frontend/src/app/vsr/page.module.css index 99248b7..ee4dc60 100644 --- a/frontend/src/app/vsr/page.module.css +++ b/frontend/src/app/vsr/page.module.css @@ -103,12 +103,12 @@ .sectionHeader { gap: 4px; font-size: 16px; - color: black; + color: var(--Light-Gray, #818181); font-family: "Open Sans"; font-style: normal; font-weight: 400; line-height: normal; - margin: 16px 0 -8px; + margin: 0 0 -16px; } .longText { @@ -252,6 +252,10 @@ gap: 32px; } + .sectionHeader { + font-size: 14px; + } + .desktopRowTabletColumn { flex-direction: column; } @@ -300,6 +304,11 @@ flex-direction: column; } + .sectionHeader { + font-size: 12px; + margin: 0; + } + .bottomRow { gap: 32px; flex-direction: column; diff --git a/frontend/src/app/vsr/page.tsx b/frontend/src/app/vsr/page.tsx index 268573b..29bd642 100644 --- a/frontend/src/app/vsr/page.tsx +++ b/frontend/src/app/vsr/page.tsx @@ -557,7 +557,7 @@ const VeteranServiceRequest: React.FC = () => {
) : null} -

Children (under 18)

+

Children Under the Age of 18:

{renderChildInput("boy")}