Skip to content

Commit

Permalink
1422/finder scaffolding + Q1 (#1448)
Browse files Browse the repository at this point in the history
* fix: added components from core

* fix: basic components

* fix: added copy components

* fix: core component updates

* fix: homepage finder button

* fix: wip css refinements

* fix: basic form functioning

* fix: corrected homepage button design

* fix: build error resolved

* fix: added strings to json

* fix: object pattern for multiple questions

* fix: clean-up mobile view

* fix: corrected padding

* fix: cleanup from feedback

* fix: px to rem

* fix: mobile styling

* fix: string + OnClick cleanup
  • Loading branch information
ColinBuyck authored Sep 26, 2022
1 parent ea32152 commit c8f1aec
Show file tree
Hide file tree
Showing 19 changed files with 759 additions and 105 deletions.
1 change: 0 additions & 1 deletion sites/public/layouts/eligibility.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ const EligibilityLayout = (props: EligibilityLayoutProps) => {
t(`eligibility.progress.sections.${label}`)
)}
mounted={OnClientSide()}
routes={ELIGIBILITY_SECTIONS.map((_label, i) => eligibilityRoute(i))}
/>
</div>
</div>
Expand Down
9 changes: 8 additions & 1 deletion sites/public/page_content/locale_overrides/general.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,12 @@
"basicsVideo.incomeRestrictionsSubtitle": "In this video, learn about income requirements for affordable housing that is paid for by governmental resources.",
"basicsVideo.residentTutorial": "Detroit Home Connect Resident Tutorial",
"basicsVideo.residentTutorialSubtitle": "Learn how to use the City's affordable housing locator, Detroit Home Connect, to understand affordable housing options in the City.",
"basicsCard.sectionTitle": "Learn more about the basics of affordable housing"
"basicsCard.sectionTitle": "Learn more about the basics of affordable housing",
"finder.progress.housingLabel": "Housing Needs",
"finder.progress.builingLabel": "Building Types",
"finder.progress.stepPreposition": "of",
"finder.bedRoomSize.question": "How many bedrooms do you need?",
"finder.questionSubtitle": "We'll use your selection to highlight possible rentals that match.",
"finder.multiselectHelper": "Select all that apply:",
"finder.skip": "Skip this and show me listings"
}
213 changes: 213 additions & 0 deletions sites/public/pages/finder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import {
encodeToFrontendFilterString,
FrontendListingFilterStateKeys,
ListingFilterState,
} from "@bloom-housing/shared-helpers"
import {
AppearanceStyleType,
Button,
Field,
Form,
FormCard,
ProgressNav,
StepHeader,
t,
} from "@bloom-housing/ui-components"
import axios from "axios"
import router from "next/router"

import React, { useEffect, useState } from "react"
import { useForm } from "react-hook-form"
import Layout from "../layouts/application"

interface finderField {
label: string
translation: string
selected: boolean
}

interface finderQuestion {
fieldGroupName: string
fields: finderField[]
}

interface finderForm {
[key: number]: finderQuestion
}

const Finder = () => {
// eslint-disable-next-line @typescript-eslint/unbound-method
const { register, handleSubmit, getValues } = useForm()
const [currentStep, setCurrentStep] = useState<number>(1)
const [formData, setFormData] = useState<finderForm>(null)
const activeQuestion = formData?.[currentStep]

const translationStringMap = {
studio: "studioPlus",
oneBdrm: "onePlus",
twoBdrm: "twoPlus",
threeBdrm: "threePlus",
fourBdrm: "fourPlus",
}

const stepLabels = [
t("finder.progress.housingLabel"),
t("t.accessibility"),
t("finder.progress.builingLabel"),
]

const onSubmit = (data: ListingFilterState) => {
void router.push(`/listings/filtered?page=${1}&limit=${8}${encodeToFrontendFilterString(data)}`)
}
useEffect(() => {
const getAndSetOptions = async () => {
try {
const response = await axios.get(`${process.env.backendApiBase}/listings/meta`)
const formQuestions: finderForm = {}
if (response?.data?.unitTypes) {
const bedroomFields = response.data.unitTypes.map((elem) => ({
label: elem.name,
translation: translationStringMap[elem.name],
selected: false,
}))
formQuestions[1] = { fieldGroupName: "bedRoomSize", fields: bedroomFields }
}
setFormData(formQuestions)
} catch (e) {
console.error(e)
}
}
void getAndSetOptions()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

const ProgressHeader = () => {
return (
<div className="flex flex-col w-full px-2 md:px-0">
<div className="flex flex-row flex-wrap justify-between gap-y-4 gap-x-0.5">
<div className="md:text-xl capitalize font-bold">
{t("listingFilters.buttonTitleExtended")}
</div>
<StepHeader
currentStep={currentStep}
totalSteps={3}
stepPreposition={t("finder.progress.stepPreposition")}
stepLabeling={stepLabels}
></StepHeader>
</div>
<ProgressNav
currentPageSection={currentStep}
completedSections={currentStep - 1}
labels={stepLabels}
mounted={true}
style="bar"
></ProgressNav>
</div>
)
}

const nextQuestion = () => {
const userSelections = getValues()[formData[currentStep]["fieldGroupName"]]
const formCopy = { ...formData }
formCopy[currentStep]["fields"].forEach(
(field) => (field["selected"] = userSelections.includes(field))
)
setFormData(formCopy)
setCurrentStep(currentStep + 1)
}
const previousQuestion = () => {
const userSelections = getValues()[formData[currentStep]["fieldGroupName"]]
const formCopy = { ...formData }
formCopy[currentStep]["fields"].forEach(
(field) => (field["selected"] = userSelections.includes(field))
)
setFormData(formCopy)
setCurrentStep(currentStep - 1)
}

return (
<Layout>
<Form onSubmit={handleSubmit(onSubmit)} className="bg-gray-300 border-t border-gray-450">
<div className="md:mb-8 mt-8 mx-auto max-w-5xl">
{ProgressHeader()}
<FormCard>
{formData && (
<>
<div className="px-10 md:px-20 pt-6 md:pt-12 ">
<div className="">
<div className="text-3xl pb-4">
{t(`finder.${activeQuestion?.fieldGroupName}.question`)}
</div>
<div className="pb-8 border-b border-gray-450">
{t("finder.questionSubtitle")}
</div>
</div>
<div className="py-8">
<p className="pb-4">{t("finder.multiselectHelper")}</p>
<div className="finder-grid">
{activeQuestion?.fields?.map((field) => {
return (
<div
className="finder-grid__field"
key={FrontendListingFilterStateKeys[field.label]}
>
<Field
name="bedRoomSize"
register={register}
id={FrontendListingFilterStateKeys[field.label]}
label={t(`listingFilters.bedroomsOptions.${field.translation}`)}
key={FrontendListingFilterStateKeys[field.label]}
type="checkbox"
inputProps={{
value: FrontendListingFilterStateKeys[field.label],
defaultChecked: field.selected,
}}
bordered
/>
</div>
)
})}
</div>
</div>
</div>

<div className="bg-gray-300 flex flex-row-reverse justify-between py-8 px-20">
{currentStep === Object.keys(formData).length ? (
<Button type="submit" styleType={AppearanceStyleType.primary}>
{t("t.submit")}
</Button>
) : (
<Button
type="button"
onClick={nextQuestion}
styleType={AppearanceStyleType.primary}
>
{t("t.next")}
</Button>
)}
{currentStep > 1 && (
<Button
type="button"
onClick={previousQuestion}
styleType={AppearanceStyleType.primary}
>
{t("t.back")}
</Button>
)}
</div>

<div className="flex justify-center align-center bg-white py-8">
<a className="underline" href="/listings">
{t("finder.skip")}
</a>
</div>
</>
)}
</FormCard>
</div>
</Form>
</Layout>
)
}

export default Finder
7 changes: 6 additions & 1 deletion sites/public/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ export default function Home({ latestListings, comingSoonListings }) {
const heroInset: React.ReactNode = (
<>
<Link href="/listings">
<a className="hero__button hero__home-button">{t("welcome.seeRentalListings")}</a>
<a className="hero__button hero__rentals-button">{t("welcome.seeRentalListings")}</a>
</Link>
<Link href="/finder">
<a className="hero__button hero__finder-button">
{t("listingFilters.buttonTitleExtended")}
</a>
</Link>
</>
)
Expand Down
23 changes: 21 additions & 2 deletions sites/public/styles/forms.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
.progress-nav {
padding: 20px 0;
padding-top: 1rem;
padding-bottom: 1.5rem;
@screen md {
padding: 31px 0;
padding-bottom: 3rem;
padding-top: 2rem;
}
}

Expand Down Expand Up @@ -45,3 +47,20 @@ li.progress-nav__item {
.field-note {
@apply font-normal;
}

.finder-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
row-gap: 0.5rem;
column-gap: 0.5rem;
.finder-grid__field {
.field {
--leftward-margin: 0rem;
}
width: 100%;
@screen md {
width: calc(50% - 0.25rem);
}
}
}
14 changes: 12 additions & 2 deletions sites/public/styles/headers.scss
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,6 @@
}

.hero__button {
color: black;
display: inline-block;
font-size: large;
max-width: 100%;
Expand All @@ -292,14 +291,25 @@
}
}

.hero__home-button {
.hero__rentals-button {
color: black;
background-color: #ffbe42;

&:hover {
@apply bg-primary;
color: white;
}
}
.hero__finder-button {
color: var(--bloom-color-white);
background-color: var(--bloom-color-primary-dark);
margin-left: var(--bloom-s2);
&:hover {
color: var(--bloom-color-white);
box-shadow: 0 0 0 var(--bloom-s0_5) var(--bloom-color-primary-dark) inset;
background-color: var(--bloom-color-black);
}
}

.page-header__title {
font-size: 1.5rem;
Expand Down
1 change: 1 addition & 0 deletions ui-components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export * from "./src/headers/Hero"
export * from "./src/headers/PageHeader"
export * from "./src/headers/SiteHeader"
export * from "./src/headers/Heading"
export * from "./src/headers/StepHeader"

/* Helpers */
// export * from "./src/helpers/tableSummaries"
Expand Down
54 changes: 54 additions & 0 deletions ui-components/src/forms/Field.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,57 @@ export const CurrencyFieldError = () => {
/>
)
}

export const checkboxDefault = () => {
const { register, getValues, setValue } = useForm({ mode: "onChange" })
return (
<Field
register={register}
name={"Test Input"}
describedBy={"Test Input"}
label={"Test Input"}
type={"checkbox"}
/>
)
}

export const checkboxBordered = () => {
const { register, getValues, setValue } = useForm({ mode: "onChange" })
return (
<Field
register={register}
name={"Test Input"}
describedBy={"Test Input"}
label={"Test Input"}
type={"checkbox"}
bordered
/>
)
}

export const radioDefault = () => {
const { register, getValues, setValue } = useForm({ mode: "onChange" })
return (
<Field
register={register}
name={"Test Input"}
describedBy={"Test Input"}
label={"Test Input"}
type={"radio"}
/>
)
}

export const radioBordered = () => {
const { register, getValues, setValue } = useForm({ mode: "onChange" })
return (
<Field
register={register}
name={"Test Input"}
describedBy={"Test Input"}
label={"Test Input"}
type={"radio"}
bordered
/>
)
}
Loading

0 comments on commit c8f1aec

Please sign in to comment.