Skip to content

Commit

Permalink
feat(frontend): handle location IDs in share links
Browse files Browse the repository at this point in the history
Refs: #19
  • Loading branch information
resah committed Jul 15, 2023
1 parent 7d7ff07 commit 7efe6ad
Show file tree
Hide file tree
Showing 20 changed files with 133 additions and 62 deletions.
2 changes: 1 addition & 1 deletion workspaces/frontend/src/components/InfoPaneSideBar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ describe('InfoPaneSideBar', () => {

describe('initialized with a marker', () => {
beforeEach(async () => {
await locationStore.init();
await markerTypeStore.init();
await locationStore.init();
await markerStore.init();
const marker = get(markerStore)[1];
marker.mapMarker.onAdd(viewport.getLeafletMap());
Expand Down
6 changes: 3 additions & 3 deletions workspaces/frontend/src/components/InfoPaneSideBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import { _ } from 'svelte-i18n';
import RangeSlider from 'svelte-range-slider-pips';
import { afterUpdate } from 'svelte';
import { markerStore } from '../stores/markers.js';
import { currentLocation } from '../stores/locations';
import { markerStore } from '../stores/markers';
import { currentLocation } from '../stores/currentLocation';
import { markerTypeVariantByName } from '../ts/MarkerType';
import { generateMarker } from '../ts/Marker';
import { viewport } from '../ts/ViewportSingleton';
Expand Down Expand Up @@ -195,7 +195,7 @@
{#if !editMode}
<ShareButton
title={$_('marker.info.share')}
text={`${window.location.host}${window.location.pathname}#/markers/${viewMarker.id}`} />
text={`${window.location.host}${window.location.pathname}#/locations/${$currentLocation.id}/markers/${viewMarker.id}`} />
{/if}
</div>

Expand Down
14 changes: 7 additions & 7 deletions workspaces/frontend/src/components/NavigationSideBar.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<script lang="ts">
import Icon from '@iconify/svelte';
import { _ } from 'svelte-i18n';
import { markerFilter, markerStore, markerTypeCounter, markerTypeTooltips, markerTypeVisibility, visibleMarkers } from '../stores/markers.js';
import { markerFilter, markerStore, markerTypeCounter, markerTypeTooltips, markerTypeVisibility, visibleMarkers } from '../stores/markers';
import { locationStore } from '../stores/locations';
import { currentLocation } from '../stores/currentLocation';
import { MARKER_ICON_LIBRARY, markerTypeStore } from '../stores/markerTypes';
import type { MType } from '../ts/MarkerType';
import { viewport } from '../ts/ViewportSingleton';
import { Location } from '../ts/Location';
import type { MType } from '../ts/MarkerType';
import { generateMarker } from '../ts/Marker';
import NavigationItem from './NavigationItem.svelte';
import { currentLocation, locationStore } from '../stores/locations';
import { Location } from '../ts/Location';
let slim = false;
Expand Down Expand Up @@ -36,9 +37,8 @@
locationStore.createItem(newLocation);
};
const selectLocation = (location: Location): void => {
currentLocation.set(location);
document.dispatchEvent(new CustomEvent('location', { detail: { action: 'select', location: location } }));
const selectLocation = async (location: Location): Promise<void> => {
await currentLocation.select(location);
};
function createMarker(markerType: MType): void {
Expand Down
31 changes: 21 additions & 10 deletions workspaces/frontend/src/components/Screen.svelte
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
<script lang="ts">
import * as L from 'leaflet';
import { get } from 'svelte/store';
import { markerStore } from '../stores/markers';
import { locationStore } from '../stores/locations';
import { currentLocation } from '../stores/currentLocation';
import { mapAction, viewport, viewportInitialized } from '../ts/ViewportSingleton';
import FloorPlanPaneSideBar from './locations/LocationSideBar.svelte';
import InfoPane from './InfoPaneSideBar.svelte';
import Navigation from './NavigationSideBar.svelte';
import { markerStore } from '../stores/markers';
import FloorPlanPaneSideBar from './locations/LocationSideBar.svelte';
export let params = {};
$: if ($viewportInitialized) {
if (params['markerId']) {
const result = get(markerStore).find((m) => m.id === params['markerId']);
if (result) {
document.dispatchEvent(new CustomEvent('marker', { detail: { action: 'select', marker: result } }));
viewport.flyTo([result.lat, result.lng], 0);
if (params['locationId']) {
const targetLocation = get(locationStore).find((l) => l.id === params['locationId']);
if (targetLocation) {
currentLocation.select(targetLocation).then(() => {
if (params['markerId']) {
const targetMarker = get(markerStore).find((m) => m.id === params['markerId']);
if (targetMarker) {
document.dispatchEvent(new CustomEvent('marker', { detail: { action: 'select', marker: targetMarker } }));
viewport.flyTo([targetMarker.lat, targetMarker.lng], 0);
}
}
if (params['lat'] && params['lng'] && params['zoom']) {
viewport.flyTo(L.latLng(params['lat'], params['lng']), parseInt(params['zoom']));
}
});
}
}
if (params['lat'] && params['lng'] && params['zoom']) {
viewport.flyTo(L.latLng(params['lat'], params['lng']), parseInt(params['zoom']));
}
}
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<script lang="ts">
import { _ } from 'svelte-i18n';
import fetch from 'cross-fetch';
import { currentLocation, locationStore } from '../../stores/locations';
import { locationStore } from '../../stores/locations';
import { currentLocation } from '../../stores/currentLocation';
import { getApiUrl } from '../../ts/ApiUrl';
import { viewport } from '../../ts/ViewportSingleton';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { beforeEach, describe, expect, it } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/svelte';
import { currentLocation } from '../../stores/locations';
import { markerTypeStore } from '../../stores/markerTypes';
import { currentLocation } from '../../stores/currentLocation';
import { Location } from '../../ts/Location';
import LocationSideBar from './LocationSideBar.svelte';

describe('LocationSideBar', () => {
const location = new Location({
id: '1000',
name: 'abc',
shortName: 'def',
description: 'ghi',
Expand All @@ -14,7 +16,8 @@ describe('LocationSideBar', () => {
});

beforeEach(async () => {
currentLocation.set(location);
await markerTypeStore.init();
await currentLocation.select(location);
});

it('should be initialized', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<script lang="ts">
import { afterUpdate } from 'svelte';
import { _ } from 'svelte-i18n';
import { currentLocation, locationStore } from '../../stores/locations';
import { locationStore } from '../../stores/locations';
import { currentLocation } from '../../stores/currentLocation';
import { viewport } from '../../ts/ViewportSingleton';
import FloorPlanUpload from './FloorPlanUpload.svelte';
import ConfirmationDialog from '../ConfirmationDialog.svelte';
import FloorPlanUpload from './FloorPlanUpload.svelte';
let open = false;
let showDeleteConfirmationDialog = false;
Expand Down
22 changes: 14 additions & 8 deletions workspaces/frontend/src/mocks/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ const locations = [
width: 123,
height: 456,
},
{
id: '2000',
name: 'Location 2',
shortName: 'loc2',
description: 'This is another example location',
},
];
export const markers = [
{
Expand Down Expand Up @@ -64,38 +70,38 @@ export const handlers = [
return res(ctx.status(200), ctx.json(newLocation));
}),

rest.get('api/locations/1000', (req, res, ctx) => {
rest.get('api/locations/:locationId', (req, res, ctx) => {
return res(ctx.status(200), ctx.json(locations[0]));
}),

rest.put('api/locations/1000', async (req, res, ctx) => {
rest.put('api/locations/:locationId', async (req, res, ctx) => {
const newLocation = await req.json();
return res(ctx.status(200), ctx.json(newLocation));
}),

rest.delete('api/locations/1000', async (req, res, ctx) => {
rest.delete('api/locations/:locationId', async (req, res, ctx) => {
return res(ctx.status(200), ctx.json({}));
}),

// marker endpoints
rest.get('api/locations/1000/markers', (req, res, ctx) => {
rest.get('api/locations/:locationId/markers', (req, res, ctx) => {
return res(ctx.status(200), ctx.json(markers));
}),

rest.post('api/locations/1000/markers', async (req, res, ctx) => {
rest.post('api/locations/:locationId/markers', async (req, res, ctx) => {
const newMarker = await req.json();
return res(ctx.status(200), ctx.json(newMarker));
}),

rest.put('api/locations/1000/markers/1', (req, res, ctx) => {
rest.put('api/locations/:locationId/markers/1', (req, res, ctx) => {
return res(ctx.status(200), ctx.json(markers[0]));
}),

rest.put('api/locations/1000/markers/2', (req, res, ctx) => {
rest.put('api/locations/:locationId/markers/2', (req, res, ctx) => {
return res(ctx.status(200), ctx.json(markers[1]));
}),

rest.delete('api/locations/1000/markers/1', async (req, res, ctx) => {
rest.delete('api/locations/:locationId/markers/1', async (req, res, ctx) => {
return res(ctx.status(200), ctx.json({}));
}),
];
5 changes: 4 additions & 1 deletion workspaces/frontend/src/stores/RemoteWritable.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type { Writable } from 'svelte/types/runtime/store';
import type { Writable } from 'svelte/store';

export interface RemoteWritable<T> extends Writable<T[]> {
init(): Promise<boolean>;

createItem(obj: T): void;

updateItem(obj: T): void;

deleteItem(obj: T): void;
}
24 changes: 24 additions & 0 deletions workspaces/frontend/src/stores/currentLocation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { writable, type Writable } from 'svelte/store';
import { Location } from '../ts/Location';
import { markerStore } from './markers';

export interface CurrentLocationWritable extends Writable<Location> {
select(obj: Location): Promise<void>;
}

const createCurrentLocation = (): CurrentLocationWritable => {
const internalStore: Writable<Location> = writable();
const { subscribe, update, set } = internalStore;

return {
subscribe,
update,
set,
select: async (location: Location): Promise<void> => {
set(location);
await markerStore.init();
document.dispatchEvent(new CustomEvent('location', { detail: { action: 'select', location: location } }));
},
};
};
export const currentLocation = createCurrentLocation();
14 changes: 12 additions & 2 deletions workspaces/frontend/src/stores/locations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ import { afterEach, beforeEach, describe, expect, test } from 'vitest';
import { get } from 'svelte/store';
import { server } from '../mocks/server';
import { Location } from '../ts/Location';
import { markerTypeStore } from './markerTypes';
import { locationStore } from './locations';

describe('Locations store', () => {
beforeEach(async () => {
await markerTypeStore.init();
await locationStore.init();

});

afterEach(async () => {
Expand All @@ -18,15 +21,21 @@ describe('Locations store', () => {
expect(locationStore).not.toBeNull();

const locations = get(locationStore);
expect(locations).toHaveLength(1);
expect(locations).toHaveLength(2);
expect(locations[0].name).toBe('Location');
expect(locations[1].name).toBe('Location 2');
});

test('should create new location', async () => {
const locationsBeforeCreation = get(locationStore).length;
const expectedLocationName = `[New Location]`;
const location = new Location({
id: '1000',
name: expectedLocationName,
shortName: '-',
description: 'anything',
width: 111,
height: 222,
});

locationStore.createItem(location);
Expand All @@ -42,7 +51,8 @@ describe('Locations store', () => {
const locations = get(locationStore);
expect(locations).toHaveLength(locationsBeforeCreation + 1);
expect(locations[0].name).toBe('Location');
expect(locations[1].name).toBe(expectedLocationName);
expect(locations[1].name).toBe('Location 2');
expect(locations[2].name).toBe(expectedLocationName);
});

test('should update location', async () => {
Expand Down
15 changes: 7 additions & 8 deletions workspaces/frontend/src/stores/locations.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import type { Writable } from 'svelte/store';
import { writable } from 'svelte/store';
import { get, writable } from 'svelte/store';
import fetch from 'cross-fetch';
import { getApiUrl } from '../ts/ApiUrl';
import { Location } from '../ts/Location';
import { currentLocation } from './currentLocation';
import type { RemoteWritable } from './RemoteWritable';

export const currentLocation = writable<Location>();

const createLocationStore = (): RemoteWritable<Location> => {
const internalStore: Writable<Location[]> = writable([]);
const { subscribe, update, set } = internalStore;
Expand All @@ -17,7 +16,7 @@ const createLocationStore = (): RemoteWritable<Location> => {
const json: any[] = await res.json();
const resultObjects: Location[] = json.map((item) => new Location(item)).filter((item) => item !== null);
set(resultObjects);
currentLocation.set(resultObjects[0]);
await currentLocation.select(resultObjects[0]);
}
return res.ok;
};
Expand All @@ -35,14 +34,12 @@ const createLocationStore = (): RemoteWritable<Location> => {
});
if (response.ok) {
const responseJson = await response.json();
locationDto.id = responseJson.id;
const location = new Location(locationDto);
const location = new Location(responseJson);
update((l) => {
l.push(location);
return l;
});
currentLocation.set(location);
document.dispatchEvent(new CustomEvent('location', { detail: { action: 'select', location: location } }));
await currentLocation.select(location);
} else {
console.error('Error:', response.statusText);
}
Expand Down Expand Up @@ -83,6 +80,8 @@ const createLocationStore = (): RemoteWritable<Location> => {
l.splice(indexToRemove, 1);
return l;
});

await currentLocation.select(get(internalStore)[0]);
} else {
console.error('Error:', response.statusText);
}
Expand Down
2 changes: 1 addition & 1 deletion workspaces/frontend/src/stores/markers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { markerStore } from './markers';

describe('Markers store', () => {
beforeEach(async () => {
await locationStore.init();
await markerTypeStore.init();
await locationStore.init();
await markerStore.init();
});

Expand Down
4 changes: 2 additions & 2 deletions workspaces/frontend/src/stores/markers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { MarkerTypeTable } from '../ts/MarkerTypeTable';
import { generateMarkerTypeTableFromProperty, generateMarkerTypeTableWithDefaultValue } from '../ts/MarkerTypeTable';
import type { RemoteWritable } from './RemoteWritable';
import { markerTypeStore } from './markerTypes';
import { currentLocation } from './locations';
import { currentLocation } from './currentLocation';

const createMarkerStore = (): RemoteWritable<Marker> => {
const internalStore: Writable<Marker[]> = writable([]);
Expand Down Expand Up @@ -146,7 +146,7 @@ export const visibleMarkers = derived(
});

return $markerStore.filter((m) => viewport?.hasLayer(m.mapMarker));
}
},
);

export const markerTypeCounter = derived([visibleMarkers, markerTypeStore], ([$visibleMarkers, $markerTypeStore]) => {
Expand Down
1 change: 1 addition & 0 deletions workspaces/frontend/src/ts/MarkerType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface MTypeVariant {
mapWidth: number;
mapHeight: number;
}

export interface MTypeProperty {
name: string;
type: 'boolean' | 'text' | 'link' | 'csv' | 'number';
Expand Down
Loading

0 comments on commit 7efe6ad

Please sign in to comment.