Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
532446d
feat(listing service search): change query construction to allow for …
cade-exygy Mar 19, 2024
c057b45
Merge branch 'main' into 512/unit-type-filtering
cade-exygy Mar 25, 2024
6293766
feat: create ButtonCheckboxGroup component
cade-exygy Apr 5, 2024
c71f19d
feat: uptake seeds and use CheckboxGroup
cade-exygy May 7, 2024
2d51b75
chore: merge main
cade-exygy May 7, 2024
ac4ec19
refactor(remove buttonselect): remove ButtonSelect
cade-exygy May 7, 2024
2c2728e
Merge branch 'main' into 512/unit-type-filtering
cade-exygy May 7, 2024
2eabdda
Merge branch 'main' into 512/unit-type-filtering
cade-exygy May 8, 2024
a3039a5
Merge branch 'main' into 512/unit-type-filtering
cade-exygy Jun 5, 2024
af3904c
refactor: create helper for unit filters
cade-exygy Jun 5, 2024
1f4c683
feat: checkboxGroup on LandingSearch
cade-exygy Jun 7, 2024
6622394
Merge branch 'main' into 512/unit-type-filtering
cade-exygy Jun 7, 2024
03212ce
fix: fix import
cade-exygy Jun 7, 2024
800a997
fix: test fix seeds intake
cade-exygy Jun 7, 2024
91afb0f
Merge branch 'main' into 512/unit-type-filtering
cade-exygy Jun 12, 2024
4b8c730
fix: seeds version and add padding
cade-exygy Jun 12, 2024
4d27c15
fix: latest seeds
cade-exygy Jun 12, 2024
cd025a9
fix: fix bedroom type
cade-exygy Jun 12, 2024
9141179
Merge branch 'main' into 512/unit-type-filtering
cade-exygy Jun 17, 2024
9bb15b0
fix: latest seeds after merge
cade-exygy Jun 17, 2024
9502659
Merge branch 'main' into 512/unit-type-filtering
cade-exygy Jun 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions api/src/dtos/listings/listings-filter-params.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ export class ListingFilterParams extends BaseFilter {

@Expose()
@ApiPropertyOptional({
example: '3',
example: ['3'],
})
@IsNumberString({}, { groups: [ValidationsGroupsEnum.default] })
[ListingFilterKeys.bedrooms]?: number;
@IsArray({ groups: [ValidationsGroupsEnum.default] })

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@YazeedLoonat Do you have preferences on stronger typing here?

[ListingFilterKeys.bedrooms]?: string[];

@Expose()
@ApiPropertyOptional({
example: '3',
example: ['3'],
})
@IsNumberString({}, { groups: [ValidationsGroupsEnum.default] })
[ListingFilterKeys.bathrooms]?: number;
@IsArray({ groups: [ValidationsGroupsEnum.default] })
[ListingFilterKeys.bathrooms]?: string[];

@Expose()
@ApiPropertyOptional({
Expand Down
11 changes: 7 additions & 4 deletions api/src/services/listing.service.ts
Comment thread
cade-exygy marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { startCronJob } from '../utilities/cron-job-starter';
import { PermissionService } from './permission.service';
import { permissionActions } from '../enums/permissions/permission-actions-enum';
import Unit from '../dtos/units/unit.dto';
import { buildInclusiveWhereQuery } from '../utilities/unit-filter-utilities';

export type getListingsArgs = {
skip: number;
Expand Down Expand Up @@ -259,16 +260,18 @@ export class ListingService implements OnModuleInit {
}
if (filter[ListingFilterKeys.bedrooms]) {
whereClauseArray.push(
`(combined_units->>'numBedrooms') = '${Math.floor(
buildInclusiveWhereQuery(
ListingFilterKeys.bedrooms,
filter[ListingFilterKeys.bedrooms],
)}'`,
),
);
}
if (filter[ListingFilterKeys.bathrooms]) {
whereClauseArray.push(
`(combined_units->>'numBathrooms') = '${Math.floor(
buildInclusiveWhereQuery(
ListingFilterKeys.bathrooms,
filter[ListingFilterKeys.bathrooms],
)}'`,
),
);
}
if (filter[ListingFilterKeys.monthlyRent]) {
Expand Down
53 changes: 53 additions & 0 deletions api/src/utilities/unit-filter-utilities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { BadRequestException } from '@nestjs/common';

enum ColumnName {
bedrooms = 'numBedrooms',
bathrooms = 'numBathrooms',
}
/* Takes a ColumnName and selected values to build a query that includes the values in the ColumnName
Returns a query String
*/

export const buildInclusiveWhereQuery = (
key: keyof typeof ColumnName,
values: string[],
): string => {
const columnName = ColumnName[key];

const inclusiveWhereArray = [];
values.forEach((value) => {
switch (value) {
case '0':
inclusiveWhereArray.push(
`((combined_units->>'${columnName}')::INTEGER =0)`,
);
break;
case '1':
inclusiveWhereArray.push(
`((combined_units->>'${columnName}')::INTEGER =1)`,
);
break;
case '2':
inclusiveWhereArray.push(
`((combined_units->>'${columnName}')::INTEGER =2)`,
);
break;
case '3':
inclusiveWhereArray.push(
`((combined_units->>'${columnName}')::INTEGER =3)`,
);
break;
case '4':
inclusiveWhereArray.push(
`((combined_units->>'${columnName}')::INTEGER >=4)`,
);
break;
default:
throw new BadRequestException(
`Invalid input for ${key} filter: "${value}"`,
);
}
});

return `(${inclusiveWhereArray.join(' OR ')})`;
};
2 changes: 1 addition & 1 deletion shared-helpers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"dependencies": {
"@bloom-housing/doorway-ui-components": "^1.0.0",
"@bloom-housing/ui-components": "12.1.6",
"@bloom-housing/ui-seeds": "1.14.0",
"@bloom-housing/ui-seeds": "1.16.1",
"@heroicons/react": "^2.1.1",
"axios-cookiejar-support": "4.0.6",
"tough-cookie": "4.1.3"
Expand Down
2 changes: 1 addition & 1 deletion shared-helpers/src/auth/Timeout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Button } from "@bloom-housing/ui-seeds"
import { Modal, t } from "@bloom-housing/ui-components"
import { NavigationContext } from "@bloom-housing/doorway-ui-components"
import { MessageContext } from "../utilities/MessageContext"

const PROMPT_TIMEOUT = 60000
const events = ["mousemove", "keypress", "scroll"]

Expand Down
4 changes: 2 additions & 2 deletions shared-helpers/src/types/backend-swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2207,10 +2207,10 @@ export interface ListingFilterParams {
neighborhood?: string

/** */
bedrooms?: number
bedrooms?: string[]

/** */
bathrooms?: number
bathrooms?: string[]

/** */
zipcode?: string
Expand Down
2 changes: 1 addition & 1 deletion sites/partners/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"@bloom-housing/doorway-ui-components": "^1.0.0",
"@bloom-housing/shared-helpers": "^7.7.1",
"@bloom-housing/ui-components": "12.1.6",
"@bloom-housing/ui-seeds": "1.14.0",
"@bloom-housing/ui-seeds": "1.16.1",
"@heroicons/react": "^2.1.1",
"@mapbox/mapbox-sdk": "^0.13.0",
"ag-grid-community": "^26.0.0",
Expand Down
2 changes: 1 addition & 1 deletion sites/public/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@bloom-housing/doorway-ui-components": "^1.0.0",
"@bloom-housing/shared-helpers": "^7.7.1",
"@bloom-housing/ui-components": "12.1.6",
"@bloom-housing/ui-seeds": "1.14.0",
"@bloom-housing/ui-seeds": "1.16.1",
"@heroicons/react": "^2.1.1",
"@react-google-maps/api": "^2.18.1",
"@sentry/nextjs": "^7.61.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
@apply font-semibold;
@apply text-sm;
min-width: auto;
padding-bottom: var(--seeds-s2);

@media (min-width: $screen-md) {
@apply text-xl;
Expand Down
35 changes: 15 additions & 20 deletions sites/public/src/components/listings/search/LandingSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@ import React, { useState, useEffect } from "react"
import { ListingSearchParams, buildSearchString } from "../../../lib/listings/search"
import {
Modal,
ButtonGroup,
FieldGroup,
FieldSingle,
Card,
Button,
ButtonGroupSpacing,
Field,
AppearanceSizeType,
} from "@bloom-housing/doorway-ui-components"
import { useForm } from "react-hook-form"
import { LinkButton, t } from "@bloom-housing/ui-components"
import styles from "./LandingSearch.module.scss"
import { FormOption } from "./ListingsSearchModal"
import { numericSearchFieldGenerator } from "./helpers"
import { getCheckboxValues, getFormValues, numericSearchFieldGenerator } from "./helpers"
import { CheckboxGroup } from "@bloom-housing/ui-seeds"

type LandingSearchProps = {
bedrooms: FormOption[]
Expand All @@ -24,7 +23,7 @@ type LandingSearchProps = {
// TODO: Refactor LandingSearch to utilize react-hook-form. It is currently using a custom form object and custom valueSetters
// which is mostly functional but fails to leverage UI-C's formatting, accessibility and any other future improvements to the
// package. To expedite development and avoid excessive workarounds (ie. line 121), a full form refactor should be completed.
export function LandingSearch(props: LandingSearchProps) {
export const LandingSearch = (props: LandingSearchProps) => {
// We hold a map of county label to county FormOption
const countyLabelMap = {}
const countyLabels = []
Expand All @@ -34,8 +33,8 @@ export function LandingSearch(props: LandingSearchProps) {
})

const nullState: ListingSearchParams = {
bedrooms: null,
bathrooms: null,
bedrooms: [],
bathrooms: [],
minRent: "",
monthlyRent: "",
counties: countyLabels,
Expand All @@ -58,26 +57,21 @@ export function LandingSearch(props: LandingSearchProps) {
// console.log(`${name} has been set to ${value}`) // uncomment to debug
}

const updateValueMulti = (name: string, labels: string[]) => {
const updateValueMulti = (name: string, values: string[]) => {
const newValues = { ...formValues } as ListingSearchParams
newValues[name] = labels
newValues[name] = values
setFormValues(newValues)
// console.log(`${name} has been set to ${value}`) // uncomment to debug
}

const translatedBedroomOptions: FormOption[] = [
{
label: t("listings.unitTypes.any"),
value: null,
},
{
label: t("listings.unitTypes.studio"),
value: "0",
},
]
const bedroomOptions: FormOption[] = [
...translatedBedroomOptions,
...numericSearchFieldGenerator(1, 3),
...numericSearchFieldGenerator(1, 4),
]

const mkCountyFields = (counties: FormOption[]): FieldSingle[] => {
Expand Down Expand Up @@ -132,13 +126,14 @@ export function LandingSearch(props: LandingSearchProps) {
<Card className="bg-accent-cool-light">
<div className={styles["input-section"]}>
<div className={styles["input-section_title"]}>{t("t.bedrooms")}</div>
<ButtonGroup
name="bedrooms"
<CheckboxGroup
id="bedrooms"
options={bedroomOptions}
onChange={updateValue}
value={formValues.bedrooms}
className="bg-accent-cool-light pt-2 md:py-0 md:px-0 landing-search-button-group"
spacing={ButtonGroupSpacing.left}
onChange={(values) => updateValueMulti("bedrooms", getFormValues(values))}
values={getCheckboxValues(formValues.bedrooms)}
size="md"
variant="primary-outlined"
checkedVariant="primary"
/>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ function ListingsSearchCombined(props: ListingsSearchCombinedProps) {

// Store the current search params for pagination
const searchParams = useRef({
bedrooms: null,
bathrooms: null,
bedrooms: [],
bathrooms: [],
monthlyRent: null,
counties: [],
} as ListingSearchParams)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.checkbox-group {
--inner-button-gap: var(--seeds-s3);
padding-top: var(--seeds-s4);
padding-bottom: var(--seeds-s4);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: missing EOF newline

66 changes: 26 additions & 40 deletions sites/public/src/components/listings/search/ListingsSearchModal.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
import React, { useEffect, useState } from "react"
import { ListingSearchParams, parseSearchString } from "../../../lib/listings/search"
import { t } from "@bloom-housing/ui-components"
import {
Modal,
ButtonGroup,
ButtonGroupSpacing,
Button,
Field,
FieldGroup,
FieldSingle,
} from "@bloom-housing/doorway-ui-components"
import { Modal, Field, FieldGroup, FieldSingle } from "@bloom-housing/doorway-ui-components"
import { CheckboxGroup, Button } from "@bloom-housing/ui-seeds"
import { useForm } from "react-hook-form"
import { numericSearchFieldGenerator } from "./helpers"
import { getCheckboxValues, getFormValues, numericSearchFieldGenerator } from "./helpers"
import styles from "./ListingsSearchModal.module.scss"

const inputSectionStyle: React.CSSProperties = {
margin: "0px 15px",
Expand Down Expand Up @@ -81,8 +75,8 @@ export function ListingsSearchModal(props: ListingsSearchModalProps) {
})

const nullState: ListingSearchParams = {
bedrooms: null,
bathrooms: null,
bedrooms: [],
bathrooms: [],
minRent: "",
monthlyRent: "",
counties: countyLabels,
Expand Down Expand Up @@ -137,39 +131,25 @@ export function ListingsSearchModal(props: ListingsSearchModalProps) {
// console.log(`${name} has been set to ${value}`) // uncomment to debug
}

const updateValueMulti = (name: string, labels: string[]) => {
const updateValueMulti = (name: string, values: string[]) => {
const newValues = { ...formValues } as ListingSearchParams
newValues[name] = labels
newValues[name] = values
setFormValues(newValues)
// console.log(`${name} has been set to ${value}`) // uncomment to debug
}

const translatedBedroomOptions: FormOption[] = [
{
label: t("listings.unitTypes.any"),
value: null,
},
{
label: t("listings.unitTypes.studio"),
value: "0",
},
]

const translatedBathroomOptions: FormOption[] = [
{
label: t("listings.unitTypes.any"),
value: null,
},
]

const bedroomOptions: FormOption[] = [
...translatedBedroomOptions,
...numericSearchFieldGenerator(1, 4),
]
const bathroomOptions: FormOption[] = [
...translatedBathroomOptions,
...numericSearchFieldGenerator(1, 4),
]

const bathroomOptions: FormOption[] = [...numericSearchFieldGenerator(1, 4)]
const mkCountyFields = (counties: FormOption[]): FieldSingle[] => {
const countyFields: FieldSingle[] = [] as FieldSingle[]

Expand Down Expand Up @@ -245,23 +225,29 @@ export function ListingsSearchModal(props: ListingsSearchModalProps) {
>
<div style={inputSectionStyle}>
<div style={sectionTitle}>{t("t.bedrooms")}</div>
<ButtonGroup
name="bedrooms"
<CheckboxGroup
id="bedrooms"
options={bedroomOptions}
onChange={updateValue}
value={formValues.bedrooms}
spacing={ButtonGroupSpacing.left}
values={getCheckboxValues(formValues.bedrooms)}
onChange={(values) => updateValueMulti("bedrooms", getFormValues(values))}
size="md"
variant="primary-outlined"
checkedVariant="primary"
className={styles["checkbox-group"]}
/>
</div>

<div style={inputSectionStyle}>
<div style={sectionTitle}>{t("t.bathrooms")}</div>
<ButtonGroup
name="bathrooms"
<CheckboxGroup
id="bathrooms"
options={bathroomOptions}
onChange={updateValue}
value={formValues.bathrooms}
spacing={ButtonGroupSpacing.left}
values={getCheckboxValues(formValues.bathrooms)}
onChange={(values) => updateValueMulti("bathrooms", getFormValues(values))}
size="md"
variant="primary-outlined"
checkedVariant="primary"
className={styles["checkbox-group"]}
/>
</div>
<div style={inputSectionStyle}>
Expand Down
Loading