Skip to content

Commit

Permalink
fix: styling and validation
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinBuyck committed Jan 13, 2025
1 parent 9d6609a commit 7127b3c
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 43 deletions.
2 changes: 1 addition & 1 deletion api/src/services/listing.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ export class ListingService implements OnModuleInit {
//remove most special characters and escape those that are allowed
//add FE validation to search fields to mantain working url, and some partners stuff too
const cleanedValue = filter[ListingFilterKeys.name]
.replace(/[^a-zA-Z0-9' -]/g, '')
.replace(/[^a-zA-Z0-9:"' -]/g, '')
.replace(/[']/g, "''");
whereClauseArray.push(
`UPPER(combined.name) ${comparison} UPPER('%${cleanedValue}%')`,
Expand Down
2 changes: 2 additions & 0 deletions shared-helpers/src/utilities/regex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ export const httpsRegex = /^https?:\/\//i

export const urlRegex =
/(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})$/

export const propertySearchRegex = /[^a-zA-Z0-9:"' -]/g
30 changes: 14 additions & 16 deletions sites/public/src/components/listings/search/LandingSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { useState, useEffect } from "react"
import { ListingSearchParams, buildSearchString } from "../../../lib/listings/search"
import React, { useState, useEffect, ChangeEvent } from "react"
import { useForm } from "react-hook-form"
import { propertySearchRegex } from "@bloom-housing/shared-helpers"
import { FilterAvailabilityEnum } from "@bloom-housing/shared-helpers/src/types/backend-swagger"
import {
ButtonGroup,
FieldGroup,
Expand All @@ -9,13 +11,12 @@ import {
Field,
AppearanceSizeType,
} from "@bloom-housing/doorway-ui-components"
import { useForm } from "react-hook-form"
import { LinkButton, t, Card } from "@bloom-housing/ui-components"
import { Dialog } from "@bloom-housing/ui-seeds"
import { numericSearchFieldGenerator } from "./helpers"
import styles from "./LandingSearch.module.scss"
import { FormOption } from "./ListingsSearchModal"
import { numericSearchFieldGenerator } from "./helpers"
import { Dialog } from "@bloom-housing/ui-seeds"
import { FilterAvailabilityEnum } from "@bloom-housing/shared-helpers/src/types/backend-swagger"
import { ListingSearchParams, buildSearchString } from "../../../lib/listings/search"

type LandingSearchProps = {
bedrooms: FormOption[]
Expand Down Expand Up @@ -121,6 +122,12 @@ export function LandingSearch(props: LandingSearchProps) {
// eslint-disable-next-line @typescript-eslint/unbound-method
const { register, getValues, setValue, watch } = useForm()

const validateSearchInput = (e: ChangeEvent<HTMLInputElement>) => {
const cleanedValue = e.target.value.replace(propertySearchRegex, "")
setValue("propertyName", cleanedValue)
updateValue("propertyName", cleanedValue)
}

// workaround to leverage UI-C's currency formatting without full refactor
const monthlyRentFormatted = watch("monthlyRent")
useEffect(() => {
Expand All @@ -132,14 +139,6 @@ export function LandingSearch(props: LandingSearchProps) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [monthlyRentFormatted])

const propertyName = watch("propertyName")
useEffect(() => {
if (propertyName) {
updateValue("propertyName", propertyName)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [propertyName])

return (
<Card className="bg-accent-cool-light">
<div className={styles["input-section"]}>
Expand Down Expand Up @@ -192,8 +191,7 @@ export function LandingSearch(props: LandingSearchProps) {
name="propertyName"
subNote={t("listings.popertyName.helper")}
register={register}
setValue={setValue}
getValues={getValues}
onChange={validateSearchInput}
defaultValue={formValues.propertyName}
className="doorway-field p-0 md:-mt-1"
inputClassName="typed-input"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ function ListingsSearchCombined(props: ListingsSearchCombinedProps) {
// Search the listings by both the filter & the visible markers - but search the markers by only the filter, so that you can scroll out of the currently searched view and still see the markers
const listingIdsOnlyQb = generateSearchQuery(modifiedParams)
const genericQb = generateSearchQuery(searchFilter)
console.log(genericQb)

let newListings = null
let newMeta
Expand Down
36 changes: 20 additions & 16 deletions sites/public/src/components/listings/search/ListingsSearchModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useState } from "react"
import { ListingSearchParams, parseSearchString } from "../../../lib/listings/search"
import { t } from "@bloom-housing/ui-components"
import React, { ChangeEvent, useCallback, useEffect, useState } from "react"
import { useForm } from "react-hook-form"
import { propertySearchRegex } from "@bloom-housing/shared-helpers"
import { FilterAvailabilityEnum } from "@bloom-housing/shared-helpers/src/types/backend-swagger"
import {
ButtonGroup,
ButtonGroupSpacing,
Expand All @@ -9,10 +10,10 @@ import {
FieldGroup,
FieldSingle,
} from "@bloom-housing/doorway-ui-components"
import { t } from "@bloom-housing/ui-components"
import { Dialog } from "@bloom-housing/ui-seeds"
import { useForm } from "react-hook-form"
import { numericSearchFieldGenerator } from "./helpers"
import { FilterAvailabilityEnum } from "@bloom-housing/shared-helpers/src/types/backend-swagger"
import { ListingSearchParams, parseSearchString } from "../../../lib/listings/search"

const inputSectionStyle: React.CSSProperties = {
margin: "0px 15px",
Expand Down Expand Up @@ -45,6 +46,10 @@ const rentStyle: React.CSSProperties = {
display: "flex",
}

const propertySearchTitle: React.CSSProperties = {
paddingBottom: "var(--seeds-s4)",
}

const clearButtonStyle: React.CSSProperties = {
textDecoration: "underline",
}
Expand Down Expand Up @@ -209,9 +214,14 @@ export function ListingsSearchModal(props: ListingsSearchModalProps) {
const { register, getValues, setValue, watch } = useForm()
const monthlyRentFormatted = watch("monthlyRent")
const minRentFormatted = watch("minRent")
const propertyName = watch("propertyName")
const currencyFormatting = /,|\.\d{2}/g

const validateSearchInput = (e: ChangeEvent<HTMLInputElement>) => {
const cleanedValue = e.target.value.replace(propertySearchRegex, "")
setValue("propertyName", cleanedValue)
updateValue("propertyName", cleanedValue)
}

// workarounds to leverage UI-C's currency formatting without full refactor
useEffect(() => {
if (typeof minRentFormatted !== "undefined") {
Expand All @@ -229,13 +239,6 @@ export function ListingsSearchModal(props: ListingsSearchModalProps) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [monthlyRentFormatted])

useEffect(() => {
if (propertyName) {
updateValue("propertyName", propertyName)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [propertyName])

return (
<Dialog
className="listings-search-dialog"
Expand Down Expand Up @@ -313,15 +316,16 @@ export function ListingsSearchModal(props: ListingsSearchModalProps) {
</div>
</div>
<div style={inputSectionStyle}>
<div style={sectionTitle}>{t("listings.propertyName")}</div>
<div style={{ ...sectionTitle, ...propertySearchTitle }}>
{t("listings.propertyName")}
</div>
<Field
type="text"
id="propertyName"
name="propertyName"
subNote={t("listings.popertyName.helper")}
register={register}
setValue={setValue}
getValues={getValues}
onChange={validateSearchInput}
defaultValue={formValues.propertyName}
className="doorway-field"
inputClassName="typed-input"
Expand Down
21 changes: 12 additions & 9 deletions sites/public/src/lib/listings/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,26 @@ export function parseSearchString<T extends object>(search: string, format: T):
}

const parts = input.split(":")

// There can only be two parts: name and value
if (parts.length > 2) {
console.log(`Invalid search input [${input}]; too many components`)
return
}

const name = parts[0]
let value

// Make sure it's allowed
if (!(name in format)) {
console.log(`Cannot assign unrecognized search parameter "${name}"`)
return
}

// Check the values
const value = parts[1]
// Handle colon as possible input for text fields
if (name === "propertyName") {
value = parts.slice(1, parts.length).join(":")
} else {
// Otherwise there can only be two parts: name and value
if (parts.length > 2) {
console.log(`Invalid search input [${input}]; too many components`)
return
}
value = parts[1]
}

// If it is supposed to be an array, treat it like one
if (Array.isArray(results[name])) {
Expand Down

0 comments on commit 7127b3c

Please sign in to comment.