Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1402/multiple statuses under image card #1700

Merged
merged 10 commits into from
Aug 24, 2021
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ All notable changes to this project will be documented in this file. The format
- Added:

- Add ResponsiveTable for pricing
- Ability to have multiple statuses under the ImageCard ([#1700](https://github.com/bloom-housing/bloom/pull/1700)) (Emily Jablonski)
- **Breaking Change**: Removed three props (appStatus, appStatusContent, and appStatusSubContent) in favor of an array that contains that data - will need to transition any status information to the new array format

- Fixed:
- StandardTable styling bug ([#1632](https://github.com/bloom-housing/bloom/pull/1632)) (Emily Jablonski)
Expand Down
2 changes: 1 addition & 1 deletion sites/public/pages/applications/start/choose-language.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ const ApplicationChooseLanguage = () => {
<ImageCard
title={listing.name}
imageUrl={imageUrl}
appStatusContent={appStatusContent}
statuses={[{ content: appStatusContent }]}
/>
</div>
)}
Expand Down
20 changes: 18 additions & 2 deletions ui-components/__tests__/blocks/ImageCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,26 @@ describe("<ImageCard>", () => {
imageUrl={"/images/listing.jpg"}
title={"My Building"}
subtitle={"The Address"}
appStatus={ApplicationStatusType.Closed}
appStatusContent={t("listings.applicationsClosed")}
statuses={[
{ status: ApplicationStatusType.Closed, content: t("listings.applicationsClosed") },
]}
/>
)
expect(getByText("Applications Closed", { exact: false })).not.toBeNull()
})
it("renders with multiple applications status bars", () => {
const { getByText } = render(
<ImageCard
imageUrl={"/images/listing.jpg"}
title={"My Building"}
subtitle={"The Address"}
statuses={[
{ status: ApplicationStatusType.Closed, content: "Applications Closed" },
{ status: ApplicationStatusType.PreLottery, content: "Lottery Results Posted Tomorrow" },
]}
/>
)
expect(getByText("Applications Closed", { exact: false })).not.toBeNull()
expect(getByText("Lottery Results Posted Tomorrow", { exact: false })).not.toBeNull()
})
})
37 changes: 27 additions & 10 deletions ui-components/src/blocks/ImageCard.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import * as React from "react"
import { ImageCard } from "./ImageCard"
import { Listing } from "@bloom-housing/backend-core/types"
import { ArcherListing } from "@bloom-housing/backend-core/types/src/archer-listing"
import { t } from "../helpers/translator"
import { ApplicationStatusType } from "../global/ApplicationStatusType"

const listing = Object.assign({}, ArcherListing) as Listing

export default {
title: "Blocks/Image Card",
decorators: [(storyFn: any) => <div style={{ maxWidth: "700px" }}>{storyFn()}</div>],
Expand All @@ -26,13 +22,12 @@ export const withLink = () => (
<ImageCard href="/listings" imageUrl="/images/listing.jpg" title="Hello World" />
)

export const withListing = () => (
export const withOneStatus = () => (
<ImageCard
href="/listings"
imageUrl="/images/listing.jpg"
title="Hello World"
appStatus={ApplicationStatusType.Closed}
appStatusContent={t("listings.applicationsClosed")}
statuses={[{ status: ApplicationStatusType.Closed, content: t("listings.applicationsClosed") }]}
/>
)

Expand All @@ -44,14 +39,36 @@ export const withDescriptionAsAlt = () => (
/>
)

export const withListingAndTag = () => (
export const withOneStatusAndTag = () => (
<ImageCard
href="/listings"
imageUrl="/images/listing.jpg"
title="Hello World"
subtitle="55 Triton Park Lane, Foster City CA, 94404"
tagLabel="Label"
statuses={[{ status: ApplicationStatusType.Closed, content: t("listings.applicationsClosed") }]}
/>
)

export const withMultipleAppStatus = () => (
<ImageCard
href="/listings"
imageUrl="/images/listing.jpg"
title="Hello World"
subtitle="55 Triton Park Lane, Foster City CA, 94404"
tagLabel="Label"
appStatus={ApplicationStatusType.Closed}
appStatusContent={t("listings.applicationsClosed")}
statuses={[
{
status: ApplicationStatusType.Open,
content: "First Come First Served",
subContent: "Application Due Date: July 10th",
},
{ status: ApplicationStatusType.Closed, content: t("listings.applicationsClosed") },
{
status: ApplicationStatusType.PostLottery,
content: "Lottery Results Posted: September 3rd",
hideIcon: true,
},
]}
/>
)
55 changes: 28 additions & 27 deletions ui-components/src/blocks/ImageCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,47 @@ import { ApplicationStatusType } from "../global/ApplicationStatusType"
import { AppearanceStyleType } from "../global/AppearanceTypes"
import { t } from "../helpers/translator"

export interface StatusBarType {
status?: ApplicationStatusType
content: string
subContent?: string
hideIcon?: boolean
}

export interface ImageCardProps {
imageUrl: string
subtitle?: string
title: string
href?: string
description?: string
tagLabel?: string
appStatus?: ApplicationStatusType
appStatusContent?: string
appStatusSubContent?: string
statuses?: StatusBarType[]
}

const ImageCard = (props: ImageCardProps) => {
let statusLabel
let tag

if (props.appStatus !== undefined && props.appStatusContent !== undefined) {
statusLabel = (
<aside className="image-card__status">
<ApplicationStatus
status={props.appStatus}
content={props.appStatusContent}
subContent={props.appStatusSubContent}
vivid
/>
</aside>
)
}

if (props.tagLabel) {
tag = (
<div className="image-card-tag__wrapper">
<Tag styleType={AppearanceStyleType.warning}>{props.tagLabel}</Tag>
</div>
)
const getStatuses = () => {
return props.statuses?.map((status, index) => {
return (
<aside className="image-card__status" aria-label={status.content} key={index}>
<ApplicationStatus
status={status.status}
content={status.content}
subContent={status.subContent}
withIcon={!status.hideIcon}
vivid
/>
</aside>
)
})
}

const image = (
<div className="image-card__wrapper">
{tag}
{props.tagLabel && (
<div className="image-card-tag__wrapper">
<Tag styleType={AppearanceStyleType.warning}>{props.tagLabel}</Tag>
</div>
)}
<figure className="image-card">
{props.imageUrl && (
<img src={props.imageUrl} alt={props.description || t("listings.buildingImageAltText")} />
Expand All @@ -56,7 +57,7 @@ const ImageCard = (props: ImageCardProps) => {
{props.subtitle && <p className="image-card__subtitle">{props.subtitle}</p>}
</figcaption>
</figure>
{statusLabel}
{getStatuses()}
</div>
)

Expand Down
8 changes: 8 additions & 0 deletions ui-components/src/notifications/ApplicationStatus.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,11 @@ export const openedWithFCFSVivid = () => (
vivid
/>
)

export const postLottery = () => (
<ApplicationStatus
content={"Post-lottery content: " + moment().format("MMMM Do, Y")}
status={ApplicationStatusType.PostLottery}
withIcon={false}
/>
)
20 changes: 18 additions & 2 deletions ui-components/src/notifications/ApplicationStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,29 @@ export interface ApplicationStatusProps {
subContent?: string
status?: ApplicationStatusType
vivid?: boolean
withIcon?: boolean
}

const ApplicationStatus = (props: ApplicationStatusProps) => {
let bgColor = ""
// determine styling
const vivid = props.vivid || false
const textColor = vivid ? "text-white" : "text-gray-800"
let textColor = vivid ? "text-white" : "text-gray-800"
const textSize = vivid ? "text-xs" : "text-sm"

const status = props.status || ApplicationStatusType.Open
const content = props.content
const withIcon = props.withIcon ?? true

let icon

if (withIcon) {
icon = (
<span>
<Icon size="medium" symbol="clock" fill={vivid ? IconFillColors.white : undefined} /> &nbsp;
</span>
)
}

switch (status) {
case ApplicationStatusType.Open:
Expand All @@ -27,13 +39,17 @@ const ApplicationStatus = (props: ApplicationStatusProps) => {
case ApplicationStatusType.Closed:
bgColor = vivid ? "bg-alert" : "bg-alert-light"
break
case ApplicationStatusType.PostLottery:
bgColor = "bg-gray-850"
textColor = "text-white"
break
default:
bgColor = "bg-primary"
}

return (
<div className={`application-status ${textSize} ${textColor} ${bgColor}`}>
<Icon size="medium" symbol="clock" fill={vivid ? IconFillColors.white : undefined} /> &nbsp;
{icon}
{content}
{props.subContent && (
<>
Expand Down
4 changes: 1 addition & 3 deletions ui-components/src/page_components/listing/ListingsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,7 @@ const ListingsList = (props: ListingsProps) => {
subtitle={subtitle}
imageUrl={imageUrl}
href={`/listing/${listing.id}/${listing.urlSlug}`}
appStatus={appStatus}
appStatusContent={content}
appStatusSubContent={subContent}
statuses={[{ status: appStatus, content: content, subContent: subContent }]}
tagLabel={
listing.reservedCommunityType
? t(`listings.reservedCommunityTypes.${listing.reservedCommunityType.name}`)
Expand Down