diff --git a/frontend/src/api_data/copData.ts b/frontend/src/api_data/copData.ts index 39be2bc5..e44635aa 100644 --- a/frontend/src/api_data/copData.ts +++ b/frontend/src/api_data/copData.ts @@ -9,6 +9,7 @@ import { interface copDatum { id: number; title: string; + subtitle: string; icon: React.ElementType; description: string; roles: string[]; @@ -18,6 +19,7 @@ const copData: copDatum[] = [ { id: 0, // will be replaced by useID when upgrade to React18+; see #200 title: "UI/UX", + subtitle: "UX Design and Writing", icon: CopIconUiux, description: "The User Interface/User Experience (UI/UX) Community of Practice (CoP) is a space for UI and UX designers and research professionals to share effective practices, and give and receive mentorship, set design and research standards, and to create guides for new projects. Recent meeting topics include how to create a professional online portfolio, a meet and greet with a Hack for LA alum who landed a job at Google, how to effectively network, and training in Figma.", @@ -31,6 +33,7 @@ const copData: copDatum[] = [ { id: 1, title: "Engineering", + subtitle: "Frontend and Backend", icon: CopIconEngineering, description: "The Engineering Community of Practice (CoP) is a space for developers to share effective practices and set development standards and give and receive mentorship. Recent meeting topics include career advancement strategy workshops and “tech talks” with discussions on architecture paradigms, testing, and new technology.", @@ -44,6 +47,7 @@ const copData: copDatum[] = [ { id: 2, title: "Data Science", + subtitle: "", icon: CopIconData, description: "The Data Science Community of Practice (CoP) is a space for data science professionals to discuss the current state of the field, share effective practices, give and receive mentorship, and to workshop projects. Recent meeting topics include reviewing popular tools for data analysis, using data science to improve Hack for LA workflows, and presenting research results to peers and leadership for feedback and mentoring.", @@ -57,6 +61,7 @@ const copData: copDatum[] = [ { id: 3, title: "Project/Product Management", + subtitle: "Planning and Organization", icon: CopIconProduct, description: "The Product Managers (PM) Community of Practice (CoP) is a space for product management professionals to share effective practices, and give and receive mentorship, set product management standards, and to create guides and templates for new projects. Recent meeting topics include a project management focused book club, discussing how to best manage knowledge and issues, and brainstorming solutions to various PM issues.", @@ -72,6 +77,7 @@ const copData: copDatum[] = [ { id: 4, title: "DevOps", + subtitle: "Dev and IT Operations", icon: CopIconOps, description: "The Operations (Ops) Community of Practice (CoP) is a space for operations professionals to discuss all areas of dev-ops, coordinate infrastructure improvement, and share effective practices, and give and receive mentorship. Recent meeting topics include improving AWS hosting, password vaults, and multi-tenant product architecture.", diff --git a/frontend/src/components/Navigation/ProgressBar.tsx b/frontend/src/components/Navigation/ProgressBar.tsx deleted file mode 100644 index 8bb75b81..00000000 --- a/frontend/src/components/Navigation/ProgressBar.tsx +++ /dev/null @@ -1,60 +0,0 @@ -// External Imports -import React, { Fragment, useId } from "react"; - -// Internal Imports -import { combineClasses, range } from "components/Utility/utils"; - -// Type declaration for props -interface ProgressBarProps { - addClass?: string; - label: string; - labelHidden?: boolean; - max?: 1 | 2 | 3 | 4; - value?: number; // Can only be 1, 2, 3, or 4 -} - -function ProgressBar({ - labelHidden = true, - max = 2, - value = 1, - ...props -}: ProgressBarProps) { - const ariaLabelledBy = useId(); - - return ( - - -
- {range(1, max).map((num, index) => { - return ( -
- ); - })} -
-
- ); -} - -export { ProgressBar }; diff --git a/frontend/src/components/Navigation/_ProgressBar.scss b/frontend/src/components/Navigation/_ProgressBar.scss deleted file mode 100644 index c43aa171..00000000 --- a/frontend/src/components/Navigation/_ProgressBar.scss +++ /dev/null @@ -1,26 +0,0 @@ -@use "../Basics" as *; - -$bars: 1, 2, 3, 4; -$bars-height: 12px; - -.progress-bar { - height: $bars-height; - width: 100%; -} - -@mixin progress-bar($num) { - background-color: $color-grey; - border-radius: 8px; - height: $bars-height; - width: calc(100% / #{$num}); - - &.active { - background-color: $color-blue-dark; - } -} - -@each $bar in $bars { - .progress-bar-#{$bar} { - @include progress-bar($bar); - } -} diff --git a/frontend/src/components/Navigation/_index.scss b/frontend/src/components/Navigation/_index.scss deleted file mode 100644 index 14058e4a..00000000 --- a/frontend/src/components/Navigation/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@forward "ProgressBar"; diff --git a/frontend/src/components/components.tsx b/frontend/src/components/components.tsx index 5765d192..9c3a9231 100644 --- a/frontend/src/components/components.tsx +++ b/frontend/src/components/components.tsx @@ -6,16 +6,13 @@ import { Checkbox } from "./Inputs/Checkbox"; import { Chip } from "./Inputs/Chip"; import { Dropdown, DropdownOption } from "./Inputs/Dropdown"; import { TextField } from "./Inputs/Textfield"; -import { ProgressBar } from "./Navigation/ProgressBar"; import { Notification } from "./Notification/Notification"; import { TransitionWrapper } from "./Transition/Wrapper"; import { ChevronScroll } from "./Scroll/ChevronScroll"; export { - // Buttons Button, IconButton, - // Carousel ScrollCarousel, ChevronScroll, // Dialog @@ -26,10 +23,6 @@ export { Dropdown, DropdownOption, TextField, - // Navigation - ProgressBar, - // Notification Notification, - // Transition TransitionWrapper, }; diff --git a/frontend/src/index.scss b/frontend/src/index.scss index 8b266f8a..cd4abad9 100644 --- a/frontend/src/index.scss +++ b/frontend/src/index.scss @@ -8,7 +8,6 @@ @use "@/components/Buttons" as *; @use "@/components/Carousel/ScrollCarousel"; @use "@/components/Inputs" as *; -@use "@/components/Navigation" as *; @use "@/components/Notification/Notification"; @use "@/components/Transition/Wrapper"; @use "@/components/Scroll/ChevronScroll"; @@ -17,7 +16,6 @@ @use "@/pages/Demo/Demo"; @use "@/pages/NotFoundPage/NotFoundPage"; @use "@/pages/LandingPage" as *; -@use "@/pages/QualifierPage" as *; body { font-family: Roboto, Tahoma, Verdana, sans-serif; diff --git a/frontend/src/pages/QualifierPage/QualifierComponents.tsx b/frontend/src/pages/QualifierPage/QualifierComponents.tsx deleted file mode 100644 index f2ec08d5..00000000 --- a/frontend/src/pages/QualifierPage/QualifierComponents.tsx +++ /dev/null @@ -1,36 +0,0 @@ -// External Imports -import React, { Fragment } from "react"; - -// Internal Imports -import { combineClasses } from "components/Utility/utils"; - -interface QualifierTitleProps { - children: React.ReactNode; - title: string; -} - -function QualifierTitle({ children, title }: QualifierTitleProps) { - return ( - -

{title}

-

{children}

-
- ); -} - -interface QualifierNavProps { - addClass?: string; - children?: React.ReactNode; -} - -function QualifierNav({ addClass, children }: QualifierNavProps) { - return ( -
- {children} -
- ); -} - -export { QualifierTitle, QualifierNav }; diff --git a/frontend/src/pages/QualifierPage/QualifierPageCalendar.tsx b/frontend/src/pages/QualifierPage/QualifierPageCalendar.tsx index d4001690..1575907c 100644 --- a/frontend/src/pages/QualifierPage/QualifierPageCalendar.tsx +++ b/frontend/src/pages/QualifierPage/QualifierPageCalendar.tsx @@ -1,8 +1,9 @@ // External Imports -import React, { Fragment, useEffect, useState } from "react"; +import React, { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; // Internal Imports +import Typography from "tw-components/Typography"; import { Dropdown, DropdownOption, @@ -10,7 +11,7 @@ import { IconButton, Button, } from "components/components"; -import { QualifierNav, QualifierTitle } from "./QualifierComponents"; +import { QualifierNav } from "./components/QualifierNav"; import { timezones } from "../../api_data/timezoneData"; import { iconArrowLeft } from "assets/images/images"; // import { useQualifiersContext } from "context/QualifiersContext"; @@ -21,12 +22,15 @@ function QualifierPageCalendar() { const navigate = useNavigate(); return ( - - +
+ + What is your weekly availability? + + Drag to select.   - +  = available - + - + navigate("../1", { relative: "path" })} + onClick={() => navigate("../2", { relative: "path" })} /> - +
); } @@ -61,7 +65,7 @@ function TimeZoneDropDown() { } }, []); return ( -
+
{ // console.log("Old Qualifiers:", qualifiers); const newQualifiers = { ...qualifiers, COPs: updatedCopQualifiers }; - console.log("New Qualifiers:", newQualifiers); + // console.log("New Qualifiers:", newQualifiers); updateQualifiers(newQualifiers); // Update qualifiers }; return ( - - + <> + + What type of Practice Area are you looking for? + + Select as many roles as you'd like to find opportunities in. - + +
{copData.map((cop, index) => { const cleanCopName = cop.title.replace(/\s+/g, "_"); @@ -167,13 +172,13 @@ const QualifierPageRoles: React.FC = () => {
{index < copData.length - 1 && ( -
+
)} ); })}
- + -
+ ); }; diff --git a/frontend/src/pages/QualifierPage/_QualifierComponents.scss b/frontend/src/pages/QualifierPage/_QualifierComponents.scss deleted file mode 100644 index aa5f529c..00000000 --- a/frontend/src/pages/QualifierPage/_QualifierComponents.scss +++ /dev/null @@ -1,15 +0,0 @@ -@use "@/components/Basics" as *; - -.qualifier-nav { - background-color: $color-white; - box-sizing: content-box; - bottom: 0; - position: sticky; - height: 100px; - opacity: 0.8; - width: 100%; - - &:hover { - opacity: 1; - } -} diff --git a/frontend/src/pages/QualifierPage/_QualifierPage.scss b/frontend/src/pages/QualifierPage/_QualifierPage.scss deleted file mode 100644 index be33262a..00000000 --- a/frontend/src/pages/QualifierPage/_QualifierPage.scss +++ /dev/null @@ -1,26 +0,0 @@ -@use "@/components/Basics" as *; - -// Main Page -.qualifier-content { - flex-wrap: nowrap; - width: fit-content; -} - -// Roles -.qroles-border { - color: $color-grey; -} - -// Calendar -.qcalendar-green-square { - background-color: $color-green; - border-radius: 2px; - display: inline-block; - height: 24px; - line-height: 30px; - width: 24px; -} - -.qcalendar-dropdown { - width: 100%; -} diff --git a/frontend/src/pages/QualifierPage/_index.scss b/frontend/src/pages/QualifierPage/_index.scss deleted file mode 100644 index a47dc78d..00000000 --- a/frontend/src/pages/QualifierPage/_index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@forward "QualifierComponents"; -@forward "QualifierPage"; diff --git a/frontend/src/pages/QualifierPage/components/ChipsSelection.tsx b/frontend/src/pages/QualifierPage/components/ChipsSelection.tsx new file mode 100644 index 00000000..45ea1ef3 --- /dev/null +++ b/frontend/src/pages/QualifierPage/components/ChipsSelection.tsx @@ -0,0 +1,40 @@ +import React from "react"; + +import Typography from "tw-components/Typography"; +import { Chip } from "components/components"; + +const tools: string[] = [ + "Figma", + "Adobe XD", + "Miro", + "Figjam", + "Github", + "UserTesting.com", + "Tailwind CSS", + "HTML", + "Optimal Workshop", + "JavaScript", + "CSS", + "Photoshop", + "ARIA", + "Illustrator", + "Lyssna", + "Web Content Accessibility (WCAG)", +]; + +function ChipsSelection() { + return ( +
+ + Technical Skills and Tools + +
+ {tools.map((tool) => { + return ; + })} +
+
+ ); +} + +export { ChipsSelection }; diff --git a/frontend/src/pages/QualifierPage/components/QualifierNav.tsx b/frontend/src/pages/QualifierPage/components/QualifierNav.tsx new file mode 100644 index 00000000..eda178ed --- /dev/null +++ b/frontend/src/pages/QualifierPage/components/QualifierNav.tsx @@ -0,0 +1,23 @@ +// External Imports +import React from "react"; +import clsx from "clsx"; + +interface QualifierNavProps { + className?: string; + children?: React.ReactNode; +} + +function QualifierNav({ className, children }: QualifierNavProps) { + return ( +
+ {children} +
+ ); +} + +export { QualifierNav }; diff --git a/frontend/src/pages/QualifierPage/components/RadioButtonForm.tsx b/frontend/src/pages/QualifierPage/components/RadioButtonForm.tsx new file mode 100644 index 00000000..eb11157b --- /dev/null +++ b/frontend/src/pages/QualifierPage/components/RadioButtonForm.tsx @@ -0,0 +1,96 @@ +import React from "react"; + +// Internal Imports +import Typography from "tw-components/Typography"; + +function RadioButtonForm() { + return ( + + + + + + + + + + + + + + + + + + + +
+ UX Research and Strategy + + Experience Level +
+ 0-2 yrs + + 2-4 yrs + + 4+ yrs +
+ ); +} + +interface SkillRowProps { + skillName: string; + description: string; +} + +function SkillRow({ skillName, description }: SkillRowProps) { + return ( + + + {skillName} + + {description} + + + + + + + + + + + + + ); +} + +interface RadioButtonProps { + value: string; + name: string; +} + +function RadioButton({ value, name }: RadioButtonProps) { + return ( + + ); +} + +export { RadioButtonForm }; diff --git a/frontend/src/pages/QualifierPage/components/Stepper.tsx b/frontend/src/pages/QualifierPage/components/Stepper.tsx new file mode 100644 index 00000000..7138851a --- /dev/null +++ b/frontend/src/pages/QualifierPage/components/Stepper.tsx @@ -0,0 +1,91 @@ +// External Imports +import React from "react"; +import { useParams } from "react-router-dom"; + +// Internal Imports +import Typography from "tw-components/Typography"; +import { IconCheckMark } from "assets/images/images"; + +function Stepper() { + return ( +
+ Practice Area + Individual Skill Evaluation + Availability +
+ ); +} + +interface StepProps extends React.PropsWithChildren { + step: "1" | "2" | "3"; +} + +function Step({ children, step }: StepProps) { + let { page } = useParams(); + if (!page) page = "1"; + + const stepStatus = + step < page ? "complete" : page === step ? "active" : "pending"; + + return ( +
+ + {children} + +
+ {renderSwitch(stepStatus)} +
+
+ ); +} + +type Status = "complete" | "active" | "pending"; + +function renderSwitch(stepStatus: Status) { + switch (stepStatus) { + case "complete": + return ; + case "active": + return ; + case "pending": + return ; + default: + return <>; + } +} + +function CompleteStep() { + return ( + <> +
+
+ +
+
+ + ); +} + +function ActiveStep() { + return ( + <> +
+
+
+ + ); +} + +function PendingStep() { + return ( + <> +
+
+
+ + ); +} + +export { Stepper }; diff --git a/frontend/src/pages/QualifierPage/QualifierPage.tsx b/frontend/src/pages/QualifierPage/index.tsx similarity index 57% rename from frontend/src/pages/QualifierPage/QualifierPage.tsx rename to frontend/src/pages/QualifierPage/index.tsx index d8cda37e..63dda816 100644 --- a/frontend/src/pages/QualifierPage/QualifierPage.tsx +++ b/frontend/src/pages/QualifierPage/index.tsx @@ -3,16 +3,20 @@ import React from "react"; import { useParams } from "react-router-dom"; // Internal Imports -import { ProgressBar } from "components/components"; +import { Stepper } from "./components/Stepper"; import { QualifiersProvider } from "context/QualifiersContext"; -import { QualifierPageRoles } from "./QualifierPageRoles"; import { QualifierPageCalendar } from "./QualifierPageCalendar"; +import { QualifierPage1 } from "./pages/QualifierPage1"; +import { QualifierPage2 } from "./pages/QualifierPage2"; + function Content({ page }: { page: string }) { switch (page) { case "1": - return ; + return ; case "2": + return ; + case "3": return ; default: throw new Error("Page not found"); @@ -27,18 +31,12 @@ function QualifierPage() { return ( -
- -
-
- -
+
+ +
+
-
+
); } diff --git a/frontend/src/pages/QualifierPage/pages/QualifierPage1.tsx b/frontend/src/pages/QualifierPage/pages/QualifierPage1.tsx new file mode 100644 index 00000000..0093643b --- /dev/null +++ b/frontend/src/pages/QualifierPage/pages/QualifierPage1.tsx @@ -0,0 +1,92 @@ +// External Imports +import React, { useState, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import clsx from "clsx"; + +// Internal Imports +import { copDatum, fetchAllCopData } from "api_data/copData"; +import Typography from "tw-components/Typography"; +import { Button } from "components/components"; +import { QualifierNav } from "../components/QualifierNav"; + +function QualifierPage1() { + const navigate = useNavigate(); + const [copData, setCopData] = useState([] as copDatum[]); + const [selectedCOP, setSelectedCOP] = useState(-1); + + useEffect(() => { + setCopData(fetchAllCopData()); + }, []); + + const handleSelectCOP = ( + e: React.MouseEvent, + cop: copDatum, + ) => { + e.stopPropagation(); + setSelectedCOP(cop.id); + }; + + return ( + <> +
+ + What type of Practice Area are you looking for? + + + Select one practice area + + + {/* COP Cards */} +
+ {copData.map((cop) => { + const isSelected = selectedCOP === cop.id; + + return ( +
handleSelectCOP(e, cop)} + role="button" + tabIndex={0} + > +
+
+ + {cop.title} + + + {cop.subtitle} + +
+ ); + })} +
+
+ + + + + ); +} + +export { QualifierPage1 }; diff --git a/frontend/src/pages/QualifierPage/pages/QualifierPage2.tsx b/frontend/src/pages/QualifierPage/pages/QualifierPage2.tsx new file mode 100644 index 00000000..c88370f5 --- /dev/null +++ b/frontend/src/pages/QualifierPage/pages/QualifierPage2.tsx @@ -0,0 +1,51 @@ +// External Imports +import React from "react"; +import { useNavigate } from "react-router-dom"; + +// Internal Imports +import Typography from "tw-components/Typography"; +import { Button, IconButton } from "components/components"; +import { iconArrowLeft } from "assets/images/images"; +import { QualifierNav } from "../components/QualifierNav"; + +import { RadioButtonForm } from "../components/RadioButtonForm"; +// import { ChipsSelection } from "../components/ChipsSelection"; + +function QualifierPage2() { + const navigate = useNavigate(); + + return ( + <> +
+ + Skill Evaluation + + + Evaluate each skill based on your experience + + + + {/* */} +
+ + navigate("../1", { relative: "path" })} + /> + + + + ); +} + +export { QualifierPage2 }; diff --git a/frontend/src/router/Router.tsx b/frontend/src/router/Router.tsx index 83e3e259..94575677 100644 --- a/frontend/src/router/Router.tsx +++ b/frontend/src/router/Router.tsx @@ -13,9 +13,7 @@ import HomeLayout from "layouts/HomeLayout"; import DefaultNavLayout from "layouts/DefaultNavLayout"; import PrivacyPolicyPage from "pages/PrivacyPolicyPage/PrivacyPolicyPage"; -const QualifierPage = lazy( - () => import("../pages/QualifierPage/QualifierPage"), -); +const QualifierPage = lazy(() => import("../pages/QualifierPage")); const router = createBrowserRouter([ { diff --git a/frontend/src/tw-components/HeaderNav.tsx b/frontend/src/tw-components/HeaderNav.tsx index 46ce641c..41019ee6 100644 --- a/frontend/src/tw-components/HeaderNav.tsx +++ b/frontend/src/tw-components/HeaderNav.tsx @@ -1,11 +1,11 @@ // External Imports import React from "react"; +import { Link } from "react-router-dom"; // Internal Imports import { logoHorizontal } from "assets/images/images"; import { IconHamburgerMenu } from "assets/images/images"; import { Button } from "../components/components"; -import { Link } from "react-router-dom"; interface menuObject { name?: string; @@ -23,13 +23,13 @@ const menuItems: menuObject[] = [ const Logo = () => { return ( - + Civic Tech Jobs - Home - + ); }; diff --git a/frontend/src/tw-components/StandardCard.tsx b/frontend/src/tw-components/StandardCard.tsx index 85b59b8d..607c2396 100644 --- a/frontend/src/tw-components/StandardCard.tsx +++ b/frontend/src/tw-components/StandardCard.tsx @@ -10,7 +10,7 @@ function Card({ ...props }: CardProps) { return (
diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 3f72b718..181b664f 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -13,6 +13,7 @@ module.exports = { "./src/pages/LandingPage/*.tsx", "./src/pages/PrivacyPolicyPage/*", "./src/pages/CreditsPage/*.tsx", + "./src/pages/QualifierPage/**/*.tsx", ], // Will change to "./src/**/*.{js,jsx,tsx}", "./templates/index.html" theme: { screens: { @@ -23,6 +24,7 @@ module.exports = { xl: "1201px", }, colors: { + transparent: "transparent", // Primary Colors "blue-dark": "#3450a1", "blue-darker": "#323d69", diff --git a/frontend/tests/components/ProgressBar.test.tsx b/frontend/tests/components/ProgressBar.test.tsx deleted file mode 100644 index b05740db..00000000 --- a/frontend/tests/components/ProgressBar.test.tsx +++ /dev/null @@ -1,35 +0,0 @@ -// External imports -import React from "react"; -import { render, screen } from "@testing-library/react"; -import "@testing-library/jest-dom"; - -// Internal imports -import { ProgressBar } from "components/components"; - -describe("ProgressBar", () => { - test("ProgressBar component", () => { - render(); - expect(screen.getByRole("progressbar")).toBeInTheDocument(); - }); - - test("ProgressBar accessibility", () => { - render(); - expect(screen.getByText("page number:")).toBeInTheDocument(); - expect(screen.getByRole("progressbar")).toHaveAttribute( - "aria-valuemin", - "1", - ); - expect(screen.getByRole("progressbar")).toHaveAttribute( - "aria-valuemax", - "4", - ); - expect(screen.getByRole("progressbar")).toHaveAttribute( - "aria-valuenow", - "2", - ); - expect(screen.getByRole("progressbar")).not.toHaveAttribute( - "aria-valuenow", - "1", - ); - }); -});