Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMemo, useState } from 'react'
import MapView from './MapView.jsx'
import { searchMap } from './api.js'
import { associatedPhoneLabel, searchMap } from './api.js'

const EMPTY_COLLECTION = { features: [], providers: {}, metadata: {} }

Expand All @@ -23,7 +23,7 @@ function ResultCard({ item, onArchive }) {
{details.distance_miles != null && <Badge>{details.distance_miles} mi</Badge>}
</div>
{details.associated_phones?.length > 0 && (
<p className="metadata">Associated phones: {details.associated_phones.map((phone) => phone.phone || phone).join(', ')}</p>
<p className="metadata">Associated phones: {details.associated_phones.map(associatedPhoneLabel).join(', ')}</p>
)}
<details>
<summary>Provenance</summary>
Expand Down
3 changes: 2 additions & 1 deletion src/MapView.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useEffect } from 'react'
import L from 'leaflet'
import { MapContainer, Marker, Popup, TileLayer, useMap } from 'react-leaflet'
import { associatedPhoneLabel } from './api.js'

const markerIcon = L.divIcon({ className: 'evidence-marker', html: '<span></span>', iconSize: [22, 22], iconAnchor: [11, 11] })
const originIcon = L.divIcon({ className: 'origin-marker', html: '<span></span>', iconSize: [28, 28], iconAnchor: [14, 14] })
Expand Down Expand Up @@ -31,7 +32,7 @@ function MarkerDetails({ item }) {
{details.distance_miles != null && <><dt>Distance</dt><dd>{details.distance_miles} mi</dd></>}
</dl>
{details.associated_phones?.length > 0 && (
<p>Associated phone records: {details.associated_phones.map((phone) => phone.phone || phone).join(', ')}</p>
<p>Associated phone records: {details.associated_phones.map(associatedPhoneLabel).join(', ')}</p>
)}
{details.url && <a href={details.url} target="_blank" rel="noreferrer">Open source</a>}
</div>
Expand Down
5 changes: 5 additions & 0 deletions src/api.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export const API_BASE = (import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000').replace(/\/$/, '')

export function associatedPhoneLabel(phone) {
if (typeof phone === 'string') return phone
return phone?.phone_number || phone?.phone || 'Phone record'
}

export function buildSearchUrl({ place, radiusMiles, query, sources, limit = 100 }, apiBase = API_BASE) {
const params = new URLSearchParams({
place: place.trim(),
Expand Down
7 changes: 6 additions & 1 deletion src/api.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it, vi } from 'vitest'
import { buildSearchUrl, searchMap } from './api.js'
import { associatedPhoneLabel, buildSearchUrl, searchMap } from './api.js'

describe('map API', () => {
it('builds a canonical search URL', () => {
Expand All @@ -14,4 +14,9 @@ describe('map API', () => {
const fetcher = vi.fn().mockResolvedValue({ ok: false, status: 404, json: async () => ({ detail: 'place not found' }) })
await expect(searchMap({ place: 'Missing', radiusMiles: 10, query: '', sources: ['datasets'] }, fetcher)).rejects.toThrow('place not found')
})

it('formats associated phone metadata', () => {
expect(associatedPhoneLabel({ phone_number: '+12025550111' })).toBe('+12025550111')
expect(associatedPhoneLabel('+12025550112')).toBe('+12025550112')
})
})
Loading