Skip to content

Commit

Permalink
feat: geocoding preference set up fixed layers (#3808)
Browse files Browse the repository at this point in the history
* feat: add geocoding map layers to multiselect option

* fix: remove link from select description

* fix: default value for mapLayerId

* fix: add decorators for mapLayers dto's and entities

* fix: use smaller font for mapLayer select helper text
  • Loading branch information
KrissDrawing authored Jan 19, 2024
1 parent 6681687 commit aa8e3a6
Show file tree
Hide file tree
Showing 18 changed files with 306 additions and 2 deletions.
2 changes: 2 additions & 0 deletions backend/core/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { PaperApplicationsModule } from "./paper-applications/paper-applications
import { ActivityLogModule } from "./activity-log/activity-log.module"
import { logger } from "./shared/middlewares/logger.middleware"
import { CatchAllFilter } from "./shared/filters/catch-all-filter"
import { MapLayersModule } from "./map-layers/map-layers.module"

export function applicationSetup(app: INestApplication) {
const { httpAdapter } = app.get(HttpAdapterHost)
Expand Down Expand Up @@ -106,6 +107,7 @@ export class AppModule {
UnitTypesModule,
UnitRentTypesModule,
UnitAccessibilityPriorityTypesModule,
MapLayersModule,
],
}
}
Expand Down
18 changes: 18 additions & 0 deletions backend/core/src/map-layers/dto/map-layer.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Expose } from "class-transformer"
import { IsString, IsUUID } from "class-validator"
import { ValidationsGroupsEnum } from "../../shared/types/validations-groups-enum"

export class MapLayerDto {
@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
@IsUUID(4, { groups: [ValidationsGroupsEnum.default] })
id: string

@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
name: string

@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
jurisdictionId: string
}
16 changes: 16 additions & 0 deletions backend/core/src/map-layers/dto/map-layers-query-params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Expose } from "class-transformer"
import { ApiProperty } from "@nestjs/swagger"
import { IsOptional, IsString } from "class-validator"
import { ValidationsGroupsEnum } from "../../shared/types/validations-groups-enum"

export class MapLayersQueryParams {
@Expose()
@ApiProperty({
name: "jurisdictionId",
required: false,
type: String,
})
@IsOptional({ groups: [ValidationsGroupsEnum.default] })
@IsString({ groups: [ValidationsGroupsEnum.default] })
jurisdictionId?: string
}
23 changes: 23 additions & 0 deletions backend/core/src/map-layers/entities/map-layer.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
import { Expose } from "class-transformer"
import { IsString, IsUUID } from "class-validator"
import { ValidationsGroupsEnum } from "../../shared/types/validations-groups-enum"

@Entity({ name: "map_layers" })
export class MapLayer {
@PrimaryGeneratedColumn("uuid")
@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
@IsUUID(4, { groups: [ValidationsGroupsEnum.default] })
id: string

@Expose()
@Column()
@IsString({ groups: [ValidationsGroupsEnum.default] })
name: string

@Expose()
@Column()
@IsString({ groups: [ValidationsGroupsEnum.default] })
jurisdictionId: string
}
26 changes: 26 additions & 0 deletions backend/core/src/map-layers/map-layers.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Controller, Get, Query, UseGuards, UsePipes, ValidationPipe } from "@nestjs/common"
import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger"
import { MapLayersService } from "./map-layers.service"
import { ResourceType } from "../auth/decorators/resource-type.decorator"
import { OptionalAuthGuard } from "../auth/guards/optional-auth.guard"
import { AuthzGuard } from "../auth/guards/authz.guard"
import { defaultValidationPipeOptions } from "../shared/default-validation-pipe-options"
import { mapTo } from "../shared/mapTo"
import { MapLayerDto } from "./dto/map-layer.dto"
import { MapLayersQueryParams } from "./dto/map-layers-query-params"

@Controller("/mapLayers")
@ApiTags("mapLayers")
@ApiBearerAuth()
@ResourceType("mapLayer")
@UseGuards(OptionalAuthGuard, AuthzGuard)
@UsePipes(new ValidationPipe(defaultValidationPipeOptions))
export class MapLayersController {
constructor(private readonly mapLayerService: MapLayersService) {}

@Get()
@ApiOperation({ summary: "List map layers", operationId: "list" })
async list(@Query() queryParams: MapLayersQueryParams): Promise<MapLayerDto[]> {
return mapTo(MapLayerDto, await this.mapLayerService.list(queryParams))
}
}
13 changes: 13 additions & 0 deletions backend/core/src/map-layers/map-layers.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Module } from "@nestjs/common"
import { MapLayersService } from "./map-layers.service"
import { MapLayersController } from "./map-layers.controller"
import { TypeOrmModule } from "@nestjs/typeorm"
import { MapLayer } from "./entities/map-layer.entity"
import { AuthModule } from "../auth/auth.module"

@Module({
imports: [TypeOrmModule.forFeature([MapLayer]), AuthModule],
providers: [MapLayersService],
controllers: [MapLayersController],
})
export class MapLayersModule {}
20 changes: 20 additions & 0 deletions backend/core/src/map-layers/map-layers.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Injectable } from "@nestjs/common"
import { InjectRepository } from "@nestjs/typeorm"
import { Repository } from "typeorm"
import { MapLayer } from "./entities/map-layer.entity"
import { MapLayersQueryParams } from "./dto/map-layers-query-params"

@Injectable()
export class MapLayersService {
constructor(
@InjectRepository(MapLayer)
private readonly mapLayerRepository: Repository<MapLayer>
) {}

list(queryParams: MapLayersQueryParams): Promise<MapLayer[]> {
if (queryParams.jurisdictionId) {
return this.mapLayerRepository.find({ where: { jurisdictionId: queryParams.jurisdictionId } })
}
return this.mapLayerRepository.find()
}
}
15 changes: 15 additions & 0 deletions backend/core/src/migration/1704908499461-addMapLayers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { MigrationInterface, QueryRunner } from "typeorm"

export class addMapLayers1704908499461 implements MigrationInterface {
name = "addMapLayers1704908499461"

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "map_layers" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying NOT NULL, "jurisdiction_id" character varying NOT NULL, CONSTRAINT "PK_d1bcb10041ba88ffea330dc10d9" PRIMARY KEY ("id"))`
)
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "map_layers"`)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ export class MultiselectOption {
@ApiProperty({ required: false })
radiusSize?: number

@Expose()
@IsOptional({ groups: [ValidationsGroupsEnum.default] })
@IsString({ groups: [ValidationsGroupsEnum.default] })
@ApiProperty({ required: false })
mapLayerId?: string

@Expose()
@IsOptional({ groups: [ValidationsGroupsEnum.default] })
@IsBoolean({ groups: [ValidationsGroupsEnum.default] })
Expand Down
4 changes: 4 additions & 0 deletions backend/core/src/seeder/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { UnitTypesService } from "../unit-types/unit-types.service"
import dayjs from "dayjs"
import { CountyCode } from "../shared/types/county-code"
import { ApplicationFlaggedSetsCronjobService } from "../application-flagged-sets/application-flagged-sets-cronjob.service"
import { MapLayerSeeder } from "./seeds/map-layers"

const argv = yargs.scriptName("seed").options({
test: { type: "boolean", default: false },
Expand Down Expand Up @@ -224,6 +225,9 @@ async function seed() {
await seedAmiCharts(app)
const listings = await seedListings(app, rolesRepo, jurisdictions)

const mapLayerSeeder = app.get<MapLayerSeeder>(MapLayerSeeder)
await mapLayerSeeder.seed(jurisdictions)

const user1 = await userService.createPublicUser(
plainToClass(UserCreateDto, {
email: "[email protected]",
Expand Down
4 changes: 4 additions & 0 deletions backend/core/src/seeder/seeder.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ import { AmiDefaultTritonDetroit } from "../seeder/seeds/ami-charts/triton-ami-c
import { AmiDefaultSanJose } from "../seeder/seeds/ami-charts/default-ami-chart-san-jose"
import { AmiDefaultSanMateo } from "../seeder/seeds/ami-charts/default-ami-chart-san-mateo"
import { Asset } from "../assets/entities/asset.entity"
import { MapLayer } from "../map-layers/entities/map-layer.entity"
import { MapLayerSeeder } from "./seeds/map-layers"

@Module({})
export class SeederModule {
Expand Down Expand Up @@ -80,6 +82,7 @@ export class SeederModule {
ApplicationMethod,
PaperApplication,
Jurisdiction,
MapLayer,
]),
ThrottlerModule.forRoot({
ttl: 60,
Expand Down Expand Up @@ -119,6 +122,7 @@ export class SeederModule {
AmiDefaultTritonDetroit,
AmiDefaultSanJose,
AmiDefaultSanMateo,
MapLayerSeeder,
],
}
}
Expand Down
38 changes: 38 additions & 0 deletions backend/core/src/seeder/seeds/map-layers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { InjectRepository } from "@nestjs/typeorm"
import { Repository } from "typeorm"
import { MapLayer } from "../../map-layers/entities/map-layer.entity"
import { Jurisdiction } from "../../../types"

export class MapLayerSeeder {
constructor(
@InjectRepository(MapLayer)
protected readonly mapLayerRepository: Repository<MapLayer>
) {}

async seed(jurisdictions: Jurisdiction[]) {
const mapLayers = [
{
name: "Map Layer 1",
jurisdictionId: jurisdictions?.[0]?.id ?? "1",
},
{
name: "Map Layer 2",
jurisdictionId: jurisdictions?.[0]?.id ?? "1",
},
{
name: "Map Layer 3",
jurisdictionId: jurisdictions?.[0]?.id ?? "1",
},
{
name: "Map Layer 4",
jurisdictionId: jurisdictions?.[1]?.id ?? "2",
},
{
name: "Map Layer 5",
jurisdictionId: jurisdictions?.[2]?.id ?? "3",
},
]

await this.mapLayerRepository.save(mapLayers)
}
}
38 changes: 38 additions & 0 deletions backend/core/types/src/backend-swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2329,6 +2329,30 @@ export class UnitAccessibilityPriorityTypesService {
}
}

export class MapLayersService {
/**
* List map layers
*/
list(
params: {
/** */
jurisdictionId?: string
} = {} as any,
options: IRequestOptions = {}
): Promise<MapLayer[]> {
return new Promise((resolve, reject) => {
let url = basePath + "/mapLayers"

const configs: IRequestConfig = getConfigs("get", "application/json", url, options)
configs.params = { jurisdictionId: params["jurisdictionId"] }
let data = null

configs.data = data
axios(configs, resolve, reject)
})
}
}

export interface AmiChartItem {
/** */
percentOfAmi: number
Expand Down Expand Up @@ -4532,6 +4556,9 @@ export interface MultiselectOption {
/** */
radiusSize?: number

/** */
mapLayerId?: string

/** */
collectName?: boolean

Expand Down Expand Up @@ -6186,6 +6213,17 @@ export interface UnitAccessibilityPriorityTypeUpdate {
id: string
}

export interface MapLayer {
/** */
id: string

/** */
name: string

/** */
jurisdictionId: string
}

export enum IncomePeriod {
"perMonth" = "perMonth",
"perYear" = "perYear",
Expand Down
5 changes: 4 additions & 1 deletion shared-helpers/src/auth/AuthContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
RequestMfaCodeResponse,
EnumRequestMfaCodeMfaType,
EnumLoginMfaType,
MapLayersService,
} from "@bloom-housing/backend-core/types"
import { GenericRouter, NavigationContext } from "@bloom-housing/ui-components"
import {
Expand Down Expand Up @@ -46,9 +47,10 @@ type ContextProps = {
userProfileService: UserProfileService
authService: AuthService
multiselectQuestionsService: MultiselectQuestionsService
unitTypesService: UnitTypesService
reservedCommunityTypeService: ReservedCommunityTypesService
unitPriorityService: UnitAccessibilityPriorityTypesService
unitTypesService: UnitTypesService
mapLayersService: MapLayersService
loadProfile: (redirect?: string) => void
login: (
email: string,
Expand Down Expand Up @@ -213,6 +215,7 @@ export const AuthProvider: FunctionComponent<React.PropsWithChildren> = ({ child
userProfileService: new UserProfileService(),
authService: new AuthService(),
multiselectQuestionsService: new MultiselectQuestionsService(),
mapLayersService: new MapLayersService(),
reservedCommunityTypeService: new ReservedCommunityTypesService(),
unitPriorityService: new UnitAccessibilityPriorityTypesService(),
unitTypesService: new UnitTypesService(),
Expand Down
3 changes: 3 additions & 0 deletions sites/partners/page_content/locale_overrides/general.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,11 @@
"settings.preferenceShowOnListing": "Show preference on listing?",
"settings.preferenceValidatingAddress": "Do you need help validating the address?",
"settings.preferenceValidatingAddress.checkWithinRadius": "Yes, check if within geographic radius of property",
"settings.preferenceValidatingAddress.checkWithArcGisMap": "Yes, check with ArcGIS map",
"settings.preferenceValidatingAddress.checkManually": "No, will check manually",
"settings.preferenceValidatingAddress.howManyMiles": "How many miles is the qualifying geographic radius?",
"settings.preferenceValidatingAddress.selectMapLayer": "Select a map layer",
"settings.preferenceValidatingAddress.selectMapLayerDescription": "Select your map layer based on your district. If you don't see your map contact us",
"settings.preferenceDeleteConfirmation": "Deleting a preference cannot be undone.",
"settings.preferenceChangesRequired": "Changes required before deleting",
"settings.preferenceDeleteError": "This preference is currently added to listings and needs to be removed before being deleted.",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.helperText {
font-size: var(--seeds-font-size-2xs);
color: var(--field-value-help-text-color);
}
Loading

0 comments on commit aa8e3a6

Please sign in to comment.