Skip to content

Commit b24a7b7

Browse files
feat: add shelter filter by geolocation radius (#93)
1 parent 9362f4c commit b24a7b7

File tree

3 files changed

+69
-3
lines changed

3 files changed

+69
-3
lines changed

src/shelter/ShelterSearch.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Prisma } from '@prisma/client';
22

3+
import { calculateGeolocationBounds } from '@/utils/utils';
34
import { SupplyPriority } from 'src/supply/types';
45
import { PrismaService } from '../prisma/prisma.service';
56
import {
@@ -129,11 +130,31 @@ class ShelterSearch {
129130
};
130131
}
131132

133+
get geolocation(): Prisma.ShelterWhereInput {
134+
if (!this.formProps.geolocation) return {};
135+
136+
const { minLat, maxLat, minLong, maxLong } = calculateGeolocationBounds(
137+
this.formProps.geolocation,
138+
);
139+
140+
return {
141+
latitude: {
142+
gte: minLat,
143+
lte: maxLat,
144+
},
145+
longitude: {
146+
gte: minLong,
147+
lte: maxLong,
148+
},
149+
};
150+
}
151+
132152
get query(): Prisma.ShelterWhereInput {
133153
if (Object.keys(this.formProps).length === 0) return {};
134154
const queryData = {
135155
AND: [
136156
this.cities,
157+
this.geolocation,
137158
{ OR: this.search },
138159
{ OR: this.shelterStatus },
139160
this.priority(this.formProps.supplyIds),

src/shelter/types/search.types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ export type ShelterTagType = z.infer<typeof ShelterTagTypeSchema>;
2121

2222
export type ShelterTagInfo = z.infer<typeof ShelterTagInfoSchema>;
2323

24+
export const GeolocationFilterSchema = z.object({
25+
latitude: z.coerce.number(),
26+
longitude: z.coerce.number(),
27+
radiusInMeters: z.coerce.number(),
28+
});
29+
30+
export type GeolocationFilter = z.infer<typeof GeolocationFilterSchema>;
31+
2432
export const ShelterSearchPropsSchema = z.object({
2533
search: z.string().optional(),
2634
priority: z.preprocess(
@@ -32,6 +40,7 @@ export const ShelterSearchPropsSchema = z.object({
3240
shelterStatus: z.array(ShelterStatusSchema).optional(),
3341
tags: ShelterTagInfoSchema.nullable().optional(),
3442
cities: z.array(z.string()).optional(),
43+
geolocation: GeolocationFilterSchema.optional(),
3544
});
3645

3746
export type ShelterSearchProps = z.infer<typeof ShelterSearchPropsSchema>;

src/utils/utils.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Logger } from '@nestjs/common';
2+
import { GeolocationFilter } from 'src/shelter/types/search.types';
23

34
class ServerResponse<T> {
45
readonly message: string;
@@ -75,10 +76,45 @@ function deepMerge(target: Record<string, any>, source: Record<string, any>) {
7576
}
7677
}
7778

79+
interface Coordinates {
80+
maxLat: number;
81+
minLat: number;
82+
maxLong: number;
83+
minLong: number;
84+
}
85+
86+
function calculateGeolocationBounds({
87+
latitude,
88+
longitude,
89+
radiusInMeters,
90+
}: GeolocationFilter): Coordinates {
91+
const earthRadius = 6371000;
92+
93+
const latRad = (latitude * Math.PI) / 180;
94+
95+
const radiusRad = radiusInMeters / earthRadius;
96+
97+
const maxLat = latitude + radiusRad * (180 / Math.PI);
98+
const minLat = latitude - radiusRad * (180 / Math.PI);
99+
100+
const deltaLong = Math.asin(Math.sin(radiusRad) / Math.cos(latRad));
101+
102+
const maxLong = longitude + deltaLong * (180 / Math.PI);
103+
const minLong = longitude - deltaLong * (180 / Math.PI);
104+
105+
return {
106+
maxLat,
107+
minLat,
108+
maxLong,
109+
minLong,
110+
};
111+
}
112+
78113
export {
79114
ServerResponse,
80-
removeNotNumbers,
81-
getSessionData,
82-
deepMerge,
115+
calculateGeolocationBounds,
83116
capitalize,
117+
deepMerge,
118+
getSessionData,
119+
removeNotNumbers,
84120
};

0 commit comments

Comments
 (0)