Compare commits

...

2 Commits

Author SHA1 Message Date
Julien Calixte
360244dc08 refactor(exchange): switch rates API to frankfurter.dev
Drop HRK and RUB from the currency list since frankfurter.dev no longer
publishes them, and request only the rates we need via the symbols param.
2026-06-01 21:47:19 +02:00
Julien Calixte
39accae46e refactor(map): switch reverse geocoding from Bing to Mapbox
Reuse the existing Mapbox token instead of maintaining a separate Bing
Maps key. Note the coordinate order flips to lon,lat for the Mapbox
geocoding endpoint.
2026-06-01 21:47:09 +02:00
6 changed files with 20 additions and 62 deletions

1
.env
View File

@@ -1,3 +1,2 @@
VITE_COUCHDB=https://couch.apoena.dev VITE_COUCHDB=https://couch.apoena.dev
VITE_MAP_KEY=AnLDo_m_IGvMsQPLuBak9igWj3gNYvqBodj0esZZ7VfI1OkqVWvg04eTZ4U9R0Y2
VITE_MAPBOX_KEY=pk.eyJ1IjoiamNhbGl4dGUiLCJhIjoiY2s3cmo1aHhlMDZ3dDNtc2Z0OXl3M3c5dSJ9.rkkIAZ4lKSJZssoFvH7Fpw VITE_MAPBOX_KEY=pk.eyJ1IjoiamNhbGl4dGUiLCJhIjoiY2s3cmo1aHhlMDZ3dDNtc2Z0OXl3M3c5dSJ9.rkkIAZ4lKSJZssoFvH7Fpw

View File

@@ -36,5 +36,4 @@ Create `.env` (gitignored) with:
``` ```
VITE_COUCHDB=https://your-couchdb-host VITE_COUCHDB=https://your-couchdb-host
VITE_MAPBOX_KEY=pk.your-mapbox-token VITE_MAPBOX_KEY=pk.your-mapbox-token
VITE_MAP_KEY=your-bing-maps-key
``` ```

View File

@@ -15,8 +15,6 @@ export default [
{ name: 'Swiss franc', code: 'CHF' }, { name: 'Swiss franc', code: 'CHF' },
{ name: 'Icelandic krona', code: 'ISK', symbol: 'kr' }, { name: 'Icelandic krona', code: 'ISK', symbol: 'kr' },
{ name: 'Norwegian krone', code: 'NOK', symbol: 'øre' }, { name: 'Norwegian krone', code: 'NOK', symbol: 'øre' },
{ name: 'Croatian kuna', code: 'HRK', symbol: 'kn' },
{ name: 'Russian rouble', code: 'RUB' },
{ name: 'Turkish lira', code: 'TRY' }, { name: 'Turkish lira', code: 'TRY' },
{ name: 'Australian dollar', code: 'AUD', symbol: 'A$' }, { name: 'Australian dollar', code: 'AUD', symbol: 'A$' },
{ name: 'Brazilian real', code: 'BRL', symbol: 'R$' }, { name: 'Brazilian real', code: 'BRL', symbol: 'R$' },

View File

@@ -1,44 +1,11 @@
export default interface ILocationQuery { export default interface ILocationQuery {
authenticationResultCode: string type: string
brandLogoUri: string features: Array<{
copyright: string id: string
resourceSets: [ type: string
{ place_type: string[]
estimatedTotal: number text: string
resources: [ place_name: string
{ center: number[]
__type: string }>
bbox: number[]
name: string
point: {
type: string
coordinates: number[]
}
address: {
addressLine: string
adminDistrict: string
adminDistrict2: string
countryRegion: string
formattedAddress: string
locality: string
postalCode: string
}
confidence: string
entityType: string
geocodePoints: [
{
type: string
coordinates: number[]
calculationMethod: string
usageTypes: string[]
}
]
matchCodes: string[]
}
]
}
]
statusCode: number
statusDescription: string
traceId: string
} }

View File

@@ -3,7 +3,7 @@ import couchService from '@/services/CouchService'
import formatDate from '@/utils/format-date' import formatDate from '@/utils/format-date'
class ExchangeService { class ExchangeService {
private baseUrl: string = 'https://api.exchangeratesapi.io/' private baseUrl: string = 'https://api.frankfurter.dev/v1/'
/** /**
* Get an exchange with defined date and desired currencies * Get an exchange with defined date and desired currencies
@@ -42,12 +42,16 @@ class ExchangeService {
} }
} }
} else { } else {
const url = new URL( const url = new URL(`${this.baseUrl}${date ? formattedDate : 'latest'}`)
date ? `${this.baseUrl}${formattedDate}` : 'latest'
)
if (base) { if (base) {
url.searchParams.append('base', base) url.searchParams.append('base', base)
} }
if (rates.length) {
url.searchParams.append(
'symbols',
rates.filter((r) => r !== base).join(',')
)
}
const response = await fetch(url.toString()) const response = await fetch(url.toString())
if (response.ok) { if (response.ok) {
exchange = await response.json() exchange = await response.json()

View File

@@ -2,7 +2,7 @@ import ILocation from '@/models/ILocation'
import ILocationQuery from '@/models/ILocationQuery' import ILocationQuery from '@/models/ILocationQuery'
class MapService { class MapService {
private key: string = import.meta.env.VITE_MAP_KEY || '' private token: string = import.meta.env.VITE_MAPBOX_KEY || ''
public async getPosition(): Promise<ILocation | null> { public async getPosition(): Promise<ILocation | null> {
const position = await this.getCurrentPosition() const position = await this.getCurrentPosition()
@@ -28,20 +28,11 @@ class MapService {
return '' return ''
} }
const json: ILocationQuery = await result.json() const json: ILocationQuery = await result.json()
if ( return json?.features?.[0]?.text ?? ''
!json ||
!json.resourceSets ||
!json.resourceSets.length ||
!json.resourceSets[0].resources.length
) {
return ''
}
const address = json.resourceSets[0].resources[0].address
return address ? address.locality : ''
} }
private url(latitude: number, longitude: number) { private url(latitude: number, longitude: number) {
return `https://dev.virtualearth.net/REST/v1/Locations/${latitude},${longitude}?key=${this.key}` return `https://api.mapbox.com/geocoding/v5/mapbox.places/${longitude},${latitude}.json?types=place&limit=1&access_token=${this.token}`
} }
private getCurrentPosition(): Promise<GeolocationPosition | null> { private getCurrentPosition(): Promise<GeolocationPosition | null> {