Skip to content

Commit

Permalink
Merge branch 'master' into fix/columns-sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
dominikx96 committed Mar 5, 2021
2 parents 13754ef + 63d0c23 commit de0da2a
Show file tree
Hide file tree
Showing 28 changed files with 265 additions and 81 deletions.
2 changes: 1 addition & 1 deletion backend/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bloom-housing/backend-core",
"version": "0.3.9",
"version": "0.3.10",
"description": "Listings service reference implementation for the Bloom affordable housing system",
"author": "Marcin Jedras <marcin.jedras@exygy.com>",
"private": false,
Expand Down
27 changes: 16 additions & 11 deletions backend/core/src/applications/applications.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,8 @@ import { IsBoolean, IsOptional, IsString } from "class-validator"
import { PaginationQueryParams } from "../shared/dto/pagination.dto"
import { ValidationsGroupsEnum } from "../shared/validations-groups.enum"
import { defaultValidationPipeOptions } from "../shared/default-validation-pipe-options"
import {
applicationFormattingMetadataAggregateFactory,
CSVFormattingType,
} from "../csv/formatting/application-formatting-metadata-factory"
import { CsvBuilder } from "../csv/csv-builder.service"
import { applicationPreferenceExtraModels } from "./entities/application-preferences.entity"
import { ApplicationCsvExporter } from "../csv/application-csv-exporter"

export class ApplicationsListQueryParams extends PaginationQueryParams {
@Expose()
Expand Down Expand Up @@ -94,6 +90,17 @@ export class ApplicationsCsvListQueryParams {
@Transform((value: string | undefined) => value === "true", { toClassOnly: true })
includeHeaders?: boolean

@Expose()
@ApiProperty({
type: Boolean,
example: true,
required: false,
})
@IsOptional({ groups: [ValidationsGroupsEnum.default] })
@IsBoolean({ groups: [ValidationsGroupsEnum.default] })
@Transform((value: string | undefined) => value === "true", { toClassOnly: true })
includeDemographics?: boolean

@Expose()
@ApiProperty({
type: String,
Expand Down Expand Up @@ -123,7 +130,7 @@ export class ApplicationsController {
private readonly emailService: EmailService,
private readonly listingsService: ListingsService,
private readonly authzService: AuthzService,
private readonly csvBuilder: CsvBuilder
private readonly applicationCsvExporter: ApplicationCsvExporter
) {}

@Get()
Expand Down Expand Up @@ -154,12 +161,10 @@ export class ApplicationsController {
await this.authorizeUserAction(req.user, application, authzActions.read)
})
)
return this.csvBuilder.build(
return this.applicationCsvExporter.export(
applications,
applicationFormattingMetadataAggregateFactory,
// Every application points to the same listing
applications.length ? applications[0].listing.CSVFormattingType : CSVFormattingType.basic,
queryParams.includeHeaders
queryParams.includeHeaders,
queryParams.includeDemographics
)
}

Expand Down
3 changes: 2 additions & 1 deletion backend/core/src/applications/applications.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ListingsModule } from "../listings/listings.module"
import { Address } from "../shared/entities/address.entity"
import { Applicant } from "./entities/applicant.entity"
import { ApplicationsSubmissionController } from "./applications-submission.controller"
import { ApplicationCsvExporter } from "../csv/application-csv-exporter"

@Module({
imports: [
Expand All @@ -19,7 +20,7 @@ import { ApplicationsSubmissionController } from "./applications-submission.cont
SharedModule,
ListingsModule,
],
providers: [ApplicationsService, CsvEncoder, CsvBuilder],
providers: [ApplicationsService, CsvEncoder, CsvBuilder, ApplicationCsvExporter],
exports: [ApplicationsService],
controllers: [ApplicationsController, ApplicationsSubmissionController],
})
Expand Down
41 changes: 41 additions & 0 deletions backend/core/src/csv/application-csv-exporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Injectable } from "@nestjs/common"
import { CsvBuilder } from "./csv-builder.service"
import { Application } from "../applications/entities/application.entity"
import {
applicationFormattingMetadataAggregateFactory,
CSVFormattingType,
} from "./formatting/application-formatting-metadata-factory"
import {
formatDemographicsEthnicity,
formatDemographicsGender,
formatDemographicsHowDidYouHear,
formatDemographicsRace,
formatDemographicsSexualOrientation,
} from "./formatting/format-blocks"

@Injectable()
export class ApplicationCsvExporter {
constructor(private readonly csvBuilder: CsvBuilder) {}
export(
applications: Application[],
includeHeaders?: boolean,
includeDemographics?: boolean
): string {
return this.csvBuilder.build(
applications,
applicationFormattingMetadataAggregateFactory,
// Every application points to the same listing
applications.length ? applications[0].listing.CSVFormattingType : CSVFormattingType.basic,
includeHeaders,
includeDemographics
? [
formatDemographicsEthnicity,
formatDemographicsRace,
formatDemographicsGender,
formatDemographicsSexualOrientation,
formatDemographicsHowDidYouHear,
]
: []
)
}
}
8 changes: 6 additions & 2 deletions backend/core/src/csv/csv-builder.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,16 @@ export class CsvBuilder {
arr: any[],
formattingMetadataAggregateFactory: FormattingMetadataAggregateFactory,
csvFormattingType: CSVFormattingType,
includeHeaders?: boolean
includeHeaders?: boolean,
extraFormatters?: Array<FormattingMetadata>
): string {
const formattingMetadataAggregate = formattingMetadataAggregateFactory(csvFormattingType)
let formattingMetadataAggregate = formattingMetadataAggregateFactory(csvFormattingType)
if (!formattingMetadataAggregate) {
return ""
}
if (extraFormatters) {
formattingMetadataAggregate = formattingMetadataAggregate.concat(extraFormatters)
}
const normalizedMetadataAggregate = this.normalizeMetadataArrays(
arr,
formattingMetadataAggregate
Expand Down
40 changes: 40 additions & 0 deletions backend/core/src/csv/formatting/format-blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,43 @@ export const formatApplicationType = {
return defaultFormatter(application.submissionType)
},
}

export const formatDemographicsEthnicity = {
label: "Demographics Ethnicity",
discriminator: "",
formatter: (application: Application) => {
return defaultFormatter(application.demographics.ethnicity)
},
}

export const formatDemographicsRace = {
label: "Demographics Race",
discriminator: "",
formatter: (application: Application) => {
return defaultFormatter(application.demographics.race)
},
}

export const formatDemographicsGender = {
label: "Demographics Gender",
discriminator: "",
formatter: (application: Application) => {
return defaultFormatter(application.demographics.gender)
},
}

export const formatDemographicsSexualOrientation = {
label: "Demographics Sexual Orientation",
discriminator: "",
formatter: (application: Application) => {
return defaultFormatter(application.demographics.sexualOrientation)
},
}

export const formatDemographicsHowDidYouHear = {
label: "Demographics How Did You Hear About Us",
discriminator: "",
formatter: (application: Application) => {
return joinArrayFormatter(application.demographics.howDidYouHear)
},
}
6 changes: 3 additions & 3 deletions backend/core/src/shared/units-transformations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const hmiData = (units: Units, byUnitType: UnitSummary[], amiPercentages: string
// TODO https://github.com/bloom-housing/bloom/issues/872
const amiChartItems = units[0].amiChart.items
const hmiHeaders = {
householdSize: bmrProgramChart ? "Unit Type" : "Household Size",
householdSize: bmrProgramChart ? "Unit Type" : "listings.householdSize",
} as AnyDict
const amiValues = amiPercentages
.map((percent) => {
Expand Down Expand Up @@ -91,8 +91,8 @@ const hmiData = (units: Units, byUnitType: UnitSummary[], amiPercentages: string
}
})
} else {
hmiHeaders["maxIncomeMonth"] = "Maximum Income/Month"
hmiHeaders["maxIncomeYear"] = "Maximum Income/Year"
hmiHeaders["maxIncomeMonth"] = "listings.maxIncomeMonth"
hmiHeaders["maxIncomeYear"] = "listings.maxIncomeYear"

new Array(maxHousehold).fill(maxHousehold).forEach((item, i) => {
const columns = { householdSize: null }
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"backend/core",
"ui-components"
],
"version": "0.3.9",
"version": "0.3.10",
"npmClient": "yarn",
"useWorkspaces": true
}
67 changes: 67 additions & 0 deletions sites/partners/lib/helpers.ts
Original file line number Diff line number Diff line change
@@ -1 +1,68 @@
import { t } from "@bloom-housing/ui-components"
import moment from "moment"
import { ApplicationSubmissionType } from "@bloom-housing/backend-core/types"

type DateTimePST = {
hour: string
minute: string
second: string
dayPeriod: string
year: string
day: string
month: string
}

export const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

export const convertDataToPst = (dateObj: Date, type: ApplicationSubmissionType) => {
if (!dateObj) {
return {
date: t("t.n/a"),
time: t("t.n/a"),
}
}

if (type === ApplicationSubmissionType.electronical) {
// convert date and time to PST (electronical applications)
const ptFormat = new Intl.DateTimeFormat("en-US", {
timeZone: "America/Los_Angeles",
hour: "numeric",
minute: "numeric",
second: "numeric",
year: "numeric",
day: "numeric",
month: "numeric",
})

const originalDate = new Date(dateObj)
const ptDateParts = ptFormat.formatToParts(originalDate)
const timeValues = ptDateParts.reduce((acc, curr) => {
Object.assign(acc, {
[curr.type]: curr.value,
})
return acc
}, {} as DateTimePST)

const { month, day, year, hour, minute, second, dayPeriod } = timeValues

const date = `${month}/${day}/${year}`
const time = `${hour}:${minute}:${second} ${dayPeriod} PT`

return {
date,
time,
}
}

if (type === ApplicationSubmissionType.paper) {
const momentDate = moment(dateObj)

const date = momentDate.utc().format("MM/DD/YYYY")
const time = momentDate.utc().format("hh:mm:ss A")

return {
date,
time,
}
}
}
4 changes: 2 additions & 2 deletions sites/partners/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bloom-housing/partners",
"version": "0.3.9",
"version": "0.3.10",
"description": "Partners app reference implementation for the Bloom affordable housing system",
"main": "index.js",
"license": "GPL-3.0",
Expand All @@ -16,7 +16,7 @@
"dev:all": "concurrently \"yarn dev:listings\" \"yarn dev:server-wait\""
},
"dependencies": {
"@bloom-housing/ui-components": "^0.3.9",
"@bloom-housing/ui-components": "^0.3.10",
"@zeit/next-sass": "^1.0.1",
"ag-grid-community": "^24.1.0",
"ag-grid-react": "^24.1.0",
Expand Down
33 changes: 18 additions & 15 deletions sites/partners/src/applications/ApplicationsColDefs.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import moment from "moment"
import { t, formatIncome, formatYesNoLabel } from "@bloom-housing/ui-components"
import { IncomePeriod } from "@bloom-housing/backend-core/types"
import { IncomePeriod, ApplicationSubmissionType } from "@bloom-housing/backend-core/types"
import { convertDataToPst } from "../../lib/helpers"
import moment from "moment"

function compareDates(a, b, node, nextNode, isInverted) {
if (a && b && a.isSame(b)) {
const dateStringFormat = "MM/DD/YYYY at hh:mm:ss A"

const dateA = moment(a, dateStringFormat)
const dateB = moment(b, dateStringFormat)

if (a && b && dateA.isSame(dateB)) {
return 0
} else if (a === "") {
return isInverted ? -1 : 1
} else if (b === "") {
return isInverted ? 1 : -1
} else {
return a.unix() - b.unix()
return dateA.unix() - dateB.unix()
}
}

Expand Down Expand Up @@ -38,20 +44,17 @@ export function getColDefs(maxHouseholdSize: number) {
width: 200,
minWidth: 150,
sort: "asc",
valueGetter: (row) => {
if (!row?.data?.submissionDate) return ""

const date = moment(row?.data?.submissionDate).utc()
valueGetter: ({ data }) => {
if (!data?.submissionDate) return ""

return date
},
valueFormatter: ({ value }) => {
if (!value || !value.isValid()) return ""
const { submissionDate } = data

const dateFormatted = value.format("MM/DD/YYYY")
const timeFormatted = value.format("hh:mm:ss A")
const dateTime = convertDataToPst(
submissionDate,
data?.submissionType || ApplicationSubmissionType.electronical
)

return `${dateFormatted} ${t("t.at")} ${timeFormatted}`
return `${dateTime.date} ${t("t.at")} ${dateTime.time}`
},
comparator: compareDates,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,19 @@
import React, { useContext, useMemo } from "react"
import moment from "moment"
import { t, GridSection, ViewItem, GridCell } from "@bloom-housing/ui-components"
import { ApplicationContext } from "../../ApplicationContext"
import { convertDataToPst } from "../../../../lib/helpers"
import { ApplicationSubmissionType } from "@bloom-housing/backend-core/types"

const DetailsApplicationData = () => {
const application = useContext(ApplicationContext)

const applicationDate = useMemo(() => {
if (!application) return null

const momentDate = moment(application.submissionDate)

const date = momentDate.utc().format("MM/DD/YYYY")
const time = momentDate.utc().format("hh:mm:ss A")

if (!momentDate.isValid()) {
return {
date: t("t.n/a"),
time: t("t.n/a"),
}
}

return {
date,
time,
}
return convertDataToPst(
application?.submissionDate,
application?.submissionType || ApplicationSubmissionType.electronical
)
}, [application])

return (
Expand Down
Loading

0 comments on commit de0da2a

Please sign in to comment.