Skip to content

Commit

Permalink
feat: DAH-2661 nav bar WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
tallulahkay committed Dec 17, 2024
1 parent b092a38 commit b5a5d95
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 17 deletions.
6 changes: 1 addition & 5 deletions app/javascript/layouts/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,7 @@ const Layout = (props: LayoutProps) => {
mainContentId={"main-content"}
/>

<main
data-testid="main-content-test-id"
id="main-content"
className="md:overflow-x-hidden"
>
<main data-testid="main-content-test-id" id="main-content">
<ErrorBoundary boundaryScope={BoundaryScope.content}>{props.children}</ErrorBoundary>
</main>
</div>
Expand Down
54 changes: 54 additions & 0 deletions app/javascript/modules/listings/DirectoryPageNavigationBar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.directory-page-navigation-bar {
position: sticky;
top: 0;
z-index: 1;
background-color: #fff;
margin: 0 auto;
width: 100%;
max-width: var(--bloom-width-5xl);

--inter-row-gap: var(--bloom-s12);
--max-width: var(--bloom-width-3xl);
--max-width-large-screen: var(--bloom-width-5xl);
--margin: var(--inter-row-gap) auto;
--seeds-focus-ring-box-shadow: none !important;
--seeds-focus-ring-outline: none !important;

display: flex;
flex-direction: row;
max-width: var(--max-width);
overflow-x: auto;
overflow-y: hidden;
margin: var(--margin);

a:focus {
box-shadow: none !important;
}

@media (min-width: $screen-lg) {
--max-width: var(--max-width-large-screen);
}

.seeds-button {
flex: 1 0 0;
min-width: max-content;
margin-left: 16px;
padding: var(--sizes-size-s4, 16px) var(--sizes-size-s6, 24px);

background: var(--components-tabs-background-color, #fff);
color: var(--components-tabs-label-color, #767676);
border: var(--borders-width-1, 1px) solid var(--components-tabs-border-color, #dedee0);
border-radius: 0px;
}
.seeds-button:hover,
.active {
color: var(--components-tabs-active-label-color, #222);
background: var(--components-tabs-background-color);

border-top: var(--borders-width-1, 1px) solid var(--components-tabs-border-color, #dedee0);
border-right: var(--borders-width-1, 1px) solid var(--components-tabs-border-color, #dedee0);
border-left: var(--borders-width-1, 1px) solid var(--components-tabs-border-color, #dedee0);
border-bottom: var(--components-tabs-active-indicator-width, 2px) solid
var(--components-tabs-active-indicator-color, #0077da);
}
}
64 changes: 64 additions & 0 deletions app/javascript/modules/listings/DirectoryPageNavigationBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from "react"
import "./DirectoryPageNavigationBar.scss"
import { Button } from "@bloom-housing/ui-seeds"
import { Icon } from "@bloom-housing/ui-components"

const DirectoryPageNavigationBar = ({
directoryType,
listingLengths,
activeItem,
setActiveItem,
}: {
directoryType: string
listingLengths: { open: number; upcoming: number; fcfs: number; results: number }
activeItem: string
setActiveItem: React.Dispatch<string>
}) => {
return (
<div className="directory-page-navigation-bar">
<Button
onClick={() => {
document.querySelector("#enter-a-lottery").scrollIntoView({ behavior: "smooth" })
setActiveItem("enter-a-lottery")
}}
className={activeItem === "enter-a-lottery" ? "active" : ""}
>
<Icon size="medium" symbol="house" />
Enter a lottery ({listingLengths.open})
</Button>
{directoryType === "forSale" && (
<Button
onClick={() => {
document.querySelector("#buy-now").scrollIntoView({ behavior: "smooth" })
setActiveItem("buy-now")
}}
className={activeItem === "buy-now" ? "active" : ""}
>
<Icon size="medium" symbol="house" />
Buy now ({listingLengths.fcfs})
</Button>
)}
<Button
onClick={() => {
document.querySelector("#upcoming-lotteries").scrollIntoView({ behavior: "smooth" })
setActiveItem("upcoming-lotteries")
}}
className={activeItem === "upcoming-lotteries" ? "active" : ""}
>
<Icon size="medium" symbol="clock" />
Upcoming lotteries ({listingLengths.upcoming})
</Button>
<Button
onClick={() => {
document.querySelector("#lottery-results").scrollIntoView({ behavior: "smooth" })
setActiveItem("lottery-results")
}}
className={activeItem === "lottery-results" ? "active" : ""}
>
<Icon size="medium" symbol="clock" />
Lottery results ({listingLengths.results})
</Button>
</div>
)
}
export default DirectoryPageNavigationBar
3 changes: 3 additions & 0 deletions app/javascript/modules/listings/GenericDirectory.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.site-content {
scroll-behavior: smooth;
}
104 changes: 92 additions & 12 deletions app/javascript/modules/listings/GenericDirectory.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Dispatch, ReactNode, SetStateAction, useEffect, useState } from "react"
import React, { Dispatch, ReactNode, SetStateAction, useEffect, useRef, useState } from "react"
import { LoadingOverlay, StackedTableRow } from "@bloom-housing/ui-components"

import type RailsRentalListing from "../../api/types/rails/listings/RailsRentalListing"
Expand All @@ -16,6 +16,7 @@ import {
import { RailsListing } from "./SharedHelpers"
import "./ListingDirectory.scss"
import { MailingListSignup } from "../../components/MailingListSignup"
import DirectoryPageNavigationBar from "./DirectoryPageNavigationBar"

interface RentalDirectoryProps {
listingsAPI: (filters?: EligibilityFilters) => Promise<RailsListing[]>
Expand Down Expand Up @@ -44,6 +45,7 @@ export const GenericDirectory = (props: RentalDirectoryProps) => {
// Whether any listings are a match.
const [match, setMatch] = useState<boolean>(false)
const [filters, setFilters] = useState(props.filters ?? null)
const [activeItem, setActiveItem] = useState(null)

useEffect(() => {
void props.listingsAPI(props.filters).then((listings) => {
Expand All @@ -62,27 +64,83 @@ export const GenericDirectory = (props: RentalDirectoryProps) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [filters])

const observerRef = useRef(null)
useEffect(() => {
const handleIntersectionEvent = (element) => {
let newActiveItem = activeItem
let prevY = null
for (const e of element) {
if (e.isIntersecting) {
if (!prevY) {
console.log("first if")
prevY = e.boundingClientRect.y
newActiveItem = e.target.id
}

if (e.boundingClientRect.y < prevY) {
console.log("second if")
newActiveItem = e.target.id
}
}
}

setActiveItem(newActiveItem)
}

observerRef.current = new IntersectionObserver(handleIntersectionEvent)
}, [activeItem])

const hasFiltersSet = filters !== null
return (
<LoadingOverlay isLoading={loading}>
<div>
{!loading && (
<>
{props.getPageHeader(filters, setFilters, match)}
<DirectoryPageNavigationBar
directoryType={props.directoryType}
listingLengths={{
open: listings.open.length,
upcoming: listings.upcoming.length,
fcfs: listings.fcfsSalesNotYetOpen.length + listings.fcfsSalesOpen.length,
results: listings.results.length,
}}
activeItem={activeItem}
setActiveItem={setActiveItem}
/>
<div id="listing-results">
{openListingsView(
listings.open,
props.directoryType,
props.getSummaryTable,
hasFiltersSet
)}
{props.directoryType === "forSale" &&
fcfsSalesView(
[...listings.fcfsSalesOpen, ...listings.fcfsSalesNotYetOpen],
<div
id="enter-a-lottery"
ref={(el) => {
if (el) {
observerRef?.current?.observe(el)
}
}}
>
{openListingsView(
listings.open,
props.directoryType,
props.getSummaryTable,
hasFiltersSet
)}
</div>
{props.directoryType === "forSale" && (
<div
id="buy-now"
ref={(el) => {
if (el) {
observerRef?.current?.observe(el)
}
}}
>
{fcfsSalesView(
[...listings.fcfsSalesOpen, ...listings.fcfsSalesNotYetOpen],
props.directoryType,
props.getSummaryTable,
hasFiltersSet
)}
</div>
)}
{props.findMoreActionBlock}
{filters &&
additionalView(
Expand All @@ -91,8 +149,30 @@ export const GenericDirectory = (props: RentalDirectoryProps) => {
props.getSummaryTable,
hasFiltersSet
)}
{upcomingLotteriesView(listings.upcoming, props.directoryType, props.getSummaryTable)}
{lotteryResultsView(listings.results, props.directoryType, props.getSummaryTable)}
<div
id="upcoming-lotteries"
ref={(el) => {
if (el) {
observerRef?.current?.observe(el)
}
}}
>
{upcomingLotteriesView(
listings.upcoming,
props.directoryType,
props.getSummaryTable
)}
</div>
<div
id="lottery-results"
ref={(el) => {
if (el) {
observerRef?.current?.observe(el)
}
}}
>
{lotteryResultsView(listings.results, props.directoryType, props.getSummaryTable)}
</div>
</div>
</>
)}
Expand Down

0 comments on commit b5a5d95

Please sign in to comment.