diff --git a/src/app/api/proxy/map/route.ts b/src/app/api/proxy/map/route.ts index 6eebf4f5b..b8001b827 100644 --- a/src/app/api/proxy/map/route.ts +++ b/src/app/api/proxy/map/route.ts @@ -1,38 +1,70 @@ import assert from 'assert' -import { NextResponse } from 'next/server' +import { NextRequest, NextResponse } from 'next/server' import { z } from 'zod' -export const dynamic = 'force-dynamic' +import { MapTileProvider } from '@/app/types' -// TODO: Update infra env vars to use generic naming. -const clientUrl = process.env.ESRI_CLIENT_URL -const clientId = process.env.ESRI_CLIENT_KEY -const clientSecret = process.env.ESRI_CLIENT_SECRET +export const dynamic = 'force-dynamic' -const clientResponseSchema = z.object({ +const osmClientResponseSchema = z.object({ access_token: z.string(), expires_in: z.string(), issued_at: z.string(), token_type: z.string(), }) -export async function POST() { +const esriClientResponseSchema = z.object({ + access_token: z.string(), + expires_in: z.coerce.string(), +}) + +export async function POST(request: NextRequest) { + const body = await request.json() + + let clientUrl + let clientId + let clientSecret + + const provider: MapTileProvider = body.provider + + if (provider === 'ArcGISEsri') { + clientUrl = process.env.ESRI_CLIENT_URL + clientId = process.env.ESRI_CLIENT_KEY + clientSecret = process.env.ESRI_CLIENT_SECRET + } + + if (provider === 'OrdinanceSurveyMaps') { + clientUrl = process.env.OSM_CLIENT_URL + clientId = process.env.OSM_CLIENT_KEY + clientSecret = process.env.OSM_CLIENT_SECRET + } + assert(clientUrl) assert(clientId) assert(clientSecret) - const basicAuth = btoa(`${clientId}:${clientSecret}`) + const osmBasicAuth = { Authorization: `Basic ${btoa(`${clientId}:${clientSecret}`)}` } + const esriAuth = { client_id: clientId, client_secret: clientSecret } const req = await fetch(clientUrl, { method: 'POST', - headers: { Authorization: `Basic ${basicAuth}`, 'Content-Type': 'application/x-www-form-urlencoded' }, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + ...(provider === 'OrdinanceSurveyMaps' && osmBasicAuth), + }, body: new URLSearchParams({ + ...(provider === 'ArcGISEsri' && esriAuth), grant_type: 'client_credentials', + expiration: '5', }), }) const json = await req.json() - const { access_token: token, expires_in: expiresIn } = clientResponseSchema.parse(json) + + console.log('json', json) + const parser = provider === 'ArcGISEsri' ? esriClientResponseSchema : osmClientResponseSchema + + const { access_token: token, expires_in: expiresIn } = parser.parse(json) return NextResponse.json({ token, diff --git a/src/app/components/ui/ukhsa/Map/health-alerts/HealthAlertsMapDialog.tsx b/src/app/components/ui/ukhsa/Map/health-alerts/HealthAlertsMapDialog.tsx index 8774bd4e4..76b28d5d0 100644 --- a/src/app/components/ui/ukhsa/Map/health-alerts/HealthAlertsMapDialog.tsx +++ b/src/app/components/ui/ukhsa/Map/health-alerts/HealthAlertsMapDialog.tsx @@ -22,7 +22,7 @@ import useWeatherHealthAlertList from '@/app/hooks/queries/useWeatherHealthAlert import { useTranslation } from '@/app/i18n/client' import { MapTileProvider } from '@/app/types' -const { Map, BaseLayer, BaseLayerOSM, ChoroplethLayer, HealthAlertControl } = { +const { Map, BaseLayer, BaseLayerOSM, BaseLayerEsri, ChoroplethLayer, HealthAlertControl } = { Map: dynamic(() => import('@/app/components/ui/ukhsa/Map/Map'), { ssr: false, loading: () => , @@ -33,6 +33,9 @@ const { Map, BaseLayer, BaseLayerOSM, ChoroplethLayer, HealthAlertControl } = { BaseLayerOSM: dynamic(() => import('@/app/components/ui/ukhsa/Map/shared/layers/BaseLayerOSM'), { ssr: false, }), + BaseLayerEsri: dynamic(() => import('@/app/components/ui/ukhsa/Map/shared/layers/BaseLayerEsri'), { + ssr: false, + }), ChoroplethLayer: dynamic(() => import('@/app/components/ui/ukhsa/Map/shared/layers/ChoroplethLayer'), { ssr: false, }), @@ -62,8 +65,12 @@ export default function HealthAlertsMapDialog({ featureCollection, mapTileProvid const alertsQuery = useWeatherHealthAlertList({ type }) const baseLayer = useMemo(() => { + console.log('mapTileProvider', mapTileProvider) if (mapTileProvider === 'OrdinanceSurveyMaps') { - return + return + } + if (mapTileProvider === 'ArcGISEsri') { + return } return }, [mapTileProvider]) diff --git a/src/app/components/ui/ukhsa/Map/health-alerts/HealthAlertsMapWrapper.tsx b/src/app/components/ui/ukhsa/Map/health-alerts/HealthAlertsMapWrapper.tsx index 0f4193fc2..92814546e 100644 --- a/src/app/components/ui/ukhsa/Map/health-alerts/HealthAlertsMapWrapper.tsx +++ b/src/app/components/ui/ukhsa/Map/health-alerts/HealthAlertsMapWrapper.tsx @@ -20,6 +20,8 @@ export async function HealthAlertsMapWrapper() { {mapTileProvider === 'OrdinanceSurveyMaps' ? ( + ) : mapTileProvider === 'ArcGISEsri' ? ( + ) : ( )} diff --git a/src/app/components/ui/ukhsa/Map/shared/layers/BaseLayerEsri.tsx b/src/app/components/ui/ukhsa/Map/shared/layers/BaseLayerEsri.tsx index e1e01ab01..c03c16515 100644 --- a/src/app/components/ui/ukhsa/Map/shared/layers/BaseLayerEsri.tsx +++ b/src/app/components/ui/ukhsa/Map/shared/layers/BaseLayerEsri.tsx @@ -9,6 +9,7 @@ import { ComponentProps } from 'react' import VectorBasemapLayer from 'react-esri-leaflet/plugins/VectorBasemapLayer' import useMapAuthToken from '@/app/hooks/queries/useMapAuthToken' +import { MapTileProvider } from '@/app/types' import { useBaseLayerEsri } from '../hooks/useBaseLayerEsri' @@ -16,13 +17,14 @@ type EsriProps = ComponentProps interface BaseLayerEsriProps extends Omit { name?: EsriProps['name'] + provider: MapTileProvider } -const BaseLayerEsri = ({ name = 'ArcGIS:Navigation', ...rest }: BaseLayerEsriProps) => { +const BaseLayerEsri = ({ name = 'ArcGIS:Navigation', provider, ...rest }: BaseLayerEsriProps) => { useBaseLayerEsri() const { data: { token }, - } = useMapAuthToken() + } = useMapAuthToken(provider) if (!token) return null return ( {} +interface BaseLayerProps extends Partial { + provider: MapTileProvider +} const attribution = `\n\n© Crown copyright ${new Date().getFullYear()} OS ${ordinanceSurveyMapsLicense}. Use of this data is subject to terms and conditions.\n You are granted a non-exclusive, royalty free revocable licence solely to view the licensed data for non-commercial purposes for the period during which UKHSA makes it available; You are not permitted to copy, sub-license, distribute, sell or otherwise make available the licensed data to third parties in any form; and Third party rights to enforce the terms of this licence shall be reserved to OS.\n Ⓗ Hawlfraint y Goron ${new Date().getFullYear()} Arolwg Ordnans ${ordinanceSurveyMapsLicense}. Defnyddio data hwn yn amodol ar delerau ac amodau.\nRhoddir trwydded ddirymiadwy, anghyfyngedig a heb freindal i chi i weld y data trwyddedig at ddibenion anfasnachol am y cyfnod y mae ar gael gan UKHSA. Ni chewch gopïo, is-drwyddedu, dosbarthu na gwerthu unrhyw ran o’r data hwn i drydydd partïon mewn unrhyw ffurf; ac. Yr Arolwg Ordnans fydd yn cadw’r hawlio trydydd parti i orfodi amodau’r drwydded hon. ` -const BaseLayerOSM = ({ ...rest }: BaseLayerProps) => { +const BaseLayerOSM = ({ provider, ...rest }: BaseLayerProps) => { const { data: { token }, - } = useMapAuthToken() + } = useMapAuthToken(provider) return ( getToken(provider), retry: RETRY_ATTEMPTS, refetchInterval: (query) => { // Extract the token expiration time (in seconds) and set the query refetch interval