Use Google Maps feature IDs for place map links

This commit is contained in:
Azalea
2026-06-21 07:54:39 +00:00
committed by Maurice
parent 9669642c62
commit 91fcaa50f6
25 changed files with 271 additions and 62 deletions
+11 -2
View File
@@ -751,13 +751,20 @@ describe('searchPlaces (fetch stubbed)', () => {
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
ok: true,
json: async () => ({
places: [{ id: 'gid1', displayName: { text: 'Eiffel Tower' }, formattedAddress: 'Paris', location: { latitude: 48.8, longitude: 2.3 } }],
places: [{
id: 'gid1',
displayName: { text: 'Eiffel Tower' },
formattedAddress: 'Paris',
location: { latitude: 48.8, longitude: 2.3 },
googleMapsUri: 'https://www.google.com/maps/place/?q=Eiffel%20Tower&ftid=0x882bf179e806d471:0x8591dde29c821a93',
}],
}),
}));
const { searchPlaces } = await import('../../../src/services/mapsService');
const result = await searchPlaces(1, 'Eiffel Tower');
expect(result.source).toBe('google');
expect((result.places[0] as any).google_place_id).toBe('gid1');
expect((result.places[0] as any).google_ftid).toBe('0x882bf179e806d471:0x8591dde29c821a93');
});
it('MAPS-039b: throws with Google error status when Google API returns non-ok', async () => {
@@ -813,6 +820,7 @@ describe('searchPlaces (fetch stubbed)', () => {
const result = await searchPlaces(1, 'sparse');
const place = result.places[0] as any;
expect(place.google_place_id).toBe('gid-sparse');
expect(place.google_ftid).toBeNull();
expect(place.name).toBe('');
expect(place.address).toBe('');
expect(place.lat).toBeNull();
@@ -1082,7 +1090,7 @@ describe('getPlaceDetails (fetch stubbed)', () => {
weekdayDescriptions: ['Monday: 9:00 AM 12:00 AM'],
openNow: true,
},
googleMapsUri: 'https://maps.google.com/?cid=123',
googleMapsUri: 'https://maps.google.com/?cid=123&ftid=0x882bf179e806d471:0x8591dde29c821a93',
editorialSummary: { text: 'Iconic iron tower.' },
reviews: [
{
@@ -1099,6 +1107,7 @@ describe('getPlaceDetails (fetch stubbed)', () => {
const result = await getPlaceDetails(1, 'ChIJ123');
const place = result.place as any;
expect(place.google_place_id).toBe('ChIJ123');
expect(place.google_ftid).toBe('0x882bf179e806d471:0x8591dde29c821a93');
expect(place.name).toBe('Eiffel Tower');
expect(place.rating).toBe(4.7);
expect(place.rating_count).toBe(200000);
@@ -449,6 +449,57 @@ describe('importGoogleList', () => {
expect(result.places[1].name).toBe('London');
});
it('PLACE-SVC-028b — stores a Google Maps ftid separately from google_place_id', async () => {
const { user } = createUser(testDb);
const trip = createTrip(testDb, user.id);
const listPayload = [
[null, null, null, null, 'My Test List', null, null, null, [
[null, [null, null, null, null, '878 Weber St N', [null, null, 43.5118527, -80.5542617], ['-8634542354666695567', '-8822026229683971437']], "St. Jacobs Farmers' Market"],
]],
];
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
ok: true,
text: async () => 'prefix\n' + JSON.stringify(listPayload),
}));
const url = 'https://www.google.com/maps/placelists/list/ABC123DEF456';
const result = await importGoogleList(String(trip.id), url) as any;
expect(result.places).toHaveLength(1);
expect(result.places[0].google_place_id).toBeNull();
expect(result.places[0].google_ftid).toBe('0x882bf179e806d471:0x8591dde29c821a93');
});
it('PLACE-SVC-028c — backfills google_ftid when re-import skips a duplicate', async () => {
const { user } = createUser(testDb);
const trip = createTrip(testDb, user.id);
const existing = createPlace(testDb, trip.id, {
name: "St. Jacobs Farmers' Market",
lat: 43.5118527,
lng: -80.5542617,
}) as any;
const listPayload = [
[null, null, null, null, 'My Test List', null, null, null, [
[null, [null, null, null, null, '878 Weber St N', [null, null, 43.5118527, -80.5542617], ['-8634542354666695567', '-8822026229683971437']], "St. Jacobs Farmers' Market"],
]],
];
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
ok: true,
text: async () => 'prefix\n' + JSON.stringify(listPayload),
}));
const url = 'https://www.google.com/maps/placelists/list/ABC123DEF456';
const result = await importGoogleList(String(trip.id), url) as any;
const row = testDb.prepare('SELECT google_place_id, google_ftid FROM places WHERE id = ?').get(existing.id) as any;
expect(result.places).toHaveLength(0);
expect(result.skipped).toBe(1);
expect(row.google_place_id).toBeNull();
expect(row.google_ftid).toBe('0x882bf179e806d471:0x8591dde29c821a93');
});
it('PLACE-SVC-029 — returns error when list items array is empty', async () => {
const { user } = createUser(testDb);
const trip = createTrip(testDb, user.id);
@@ -33,6 +33,7 @@ function makeRow(overrides: Partial<AssignmentRow> = {}): AssignmentRow {
image_url: 'https://example.com/img.jpg',
transport_mode: 'walk',
google_place_id: 'ChIJLU7jZClu5kcR4PcOOO6p3I0',
google_ftid: '0x47e66e2c94e34e2d:0x8ddca9ee380ef7e0',
website: 'https://eiffel-tower.com',
phone: '+33 1 2345 6789',
...overrides,
@@ -66,6 +67,7 @@ describe('formatAssignmentWithPlace', () => {
expect(place.image_url).toBe('https://example.com/img.jpg');
expect(place.transport_mode).toBe('walk');
expect(place.google_place_id).toBe('ChIJLU7jZClu5kcR4PcOOO6p3I0');
expect(place.google_ftid).toBe('0x47e66e2c94e34e2d:0x8ddca9ee380ef7e0');
expect(place.website).toBe('https://eiffel-tower.com');
expect(place.phone).toBe('+33 1 2345 6789');
});