|
1 | 1 | import { useQuery } from "@tanstack/react-query"; |
2 | | -import { multiPolygon } from "@turf/turf"; |
3 | 2 | import _ from "lodash"; |
4 | | -import { type GeoJSONGeometry, stringify } from "wellknown"; |
5 | 3 | import { usePublicConfig } from "@/hooks/use-public-config"; |
6 | | -import { ParkingCitationFeatureCollection, ParkingCitationProperties } from "@/types"; |
| 4 | +import { fetchParkingCitations } from "@/lib/socrata/parking-citations"; |
7 | 5 | import { useStore } from "./use-store"; |
8 | 6 |
|
9 | | -const GEO_LOCATION_COLUMN = "geocodelocation"; |
10 | | -const ISSUE_DATE_COLUMN = "issue_date"; |
11 | | - |
12 | | -const EMPTY_PARKING_CITATION_FEATURE_COLLECTION = { |
13 | | - type: "FeatureCollection", |
14 | | - features: [] satisfies ParkingCitationProperties[], |
15 | | -} satisfies ParkingCitationFeatureCollection; |
16 | | - |
17 | 7 | export const useCitations = () => { |
18 | 8 | const { data } = usePublicConfig(); |
19 | 9 | const { places, range } = useStore((state) => ({ places: state.getPlaces(), range: state.range })); |
20 | 10 |
|
21 | 11 | const placeIds = _.chain(places).map("id").compact().uniq().sort().value(); |
22 | 12 |
|
23 | | - const buildQuery = () => { |
24 | | - const startDate = range.from.toISOString().split("T")[0]; |
25 | | - const endDate = range.to.toISOString().split("T")[0]; |
26 | | - const dateFilter = `${ISSUE_DATE_COLUMN} BETWEEN '${startDate}' AND '${endDate}'`; |
27 | | - |
28 | | - if (!placeIds.length) return `SELECT * WHERE ${dateFilter}`; |
29 | | - |
30 | | - const coordinates = _.chain(places).map("geometry.coordinates").compact().value(); |
31 | | - const multipolygon = multiPolygon(coordinates); |
32 | | - const wkt = stringify(multipolygon.geometry as GeoJSONGeometry); |
33 | | - const geoFilter = `within_polygon(${GEO_LOCATION_COLUMN}, '${wkt}')`; |
34 | | - return `SELECT * WHERE ${dateFilter} AND ${geoFilter}`; |
35 | | - }; |
36 | | - |
37 | 13 | return useQuery({ |
38 | 14 | queryKey: ["citations", range.from.toISOString(), range.to.toISOString(), placeIds], |
39 | | - queryFn: async (): Promise<ParkingCitationFeatureCollection> => { |
40 | | - if (!(placeIds.length && data?.socrataAppToken)) return EMPTY_PARKING_CITATION_FEATURE_COLLECTION; |
41 | | - |
42 | | - const response = await fetch("https://data.lacity.org/api/v3/views/4f5p-udkv/query", { |
43 | | - method: "POST", |
44 | | - headers: { |
45 | | - Accept: "application/vnd.geo+json", |
46 | | - "Accept-Charset": "utf-8", |
47 | | - "Content-Type": "application/json", |
48 | | - "X-App-Token": data.socrataAppToken, |
49 | | - }, |
50 | | - // FIXME: Remove limit (pagination) when implementing full data fetching |
51 | | - body: JSON.stringify({ query: buildQuery(), page: { pageNumber: 1, pageSize: 50 } }), |
52 | | - }); |
53 | | - |
54 | | - return response.ok ? response.json() : EMPTY_PARKING_CITATION_FEATURE_COLLECTION; |
55 | | - }, |
| 15 | + queryFn: () => |
| 16 | + fetchParkingCitations({ |
| 17 | + token: data?.socrataAppToken, |
| 18 | + places, |
| 19 | + range, |
| 20 | + }), |
56 | 21 | staleTime: 60_000, // 1 minute |
57 | 22 | }); |
58 | 23 | }; |
0 commit comments