Files
immich/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte
T
Andreas Gerstmayr 48927f5fb9 feat(server, web): include pictures of shared albums on map (#7439)
* feat(server, web): include pictures of shared albums on map

* run prettier

* re-create api clients

* implement suggestions from code review

* shared from partner -> shared from partners

* rename to 'include shared partner assets'

* chore: fix tsc error in server and prettier in web

* fix: include assets shared via owner albums

---------

Co-authored-by: Zack Pollard <zackpollard@ymail.com>
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2024-05-13 09:28:57 -04:00

148 lines
4.8 KiB
Svelte

<script lang="ts">
import { goto } from '$app/navigation';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import MapSettingsModal from '$lib/components/map-page/map-settings-modal.svelte';
import Map from '$lib/components/shared-components/map/map.svelte';
import Portal from '$lib/components/shared-components/portal/portal.svelte';
import { AppRoute } from '$lib/constants';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import type { MapSettings } from '$lib/stores/preferences.store';
import { mapSettings } from '$lib/stores/preferences.store';
import { featureFlags } from '$lib/stores/server-config.store';
import { getMapMarkers, type MapMarkerResponseDto } from '@immich/sdk';
import { isEqual } from 'lodash-es';
import { DateTime, Duration } from 'luxon';
import { onDestroy, onMount } from 'svelte';
import type { PageData } from './$types';
import { handlePromiseError } from '$lib/utils';
import { navigate } from '$lib/utils/navigation';
export let data: PageData;
let { isViewing: showAssetViewer, asset: viewingAsset, setAssetId } = assetViewingStore;
let abortController: AbortController;
let mapMarkers: MapMarkerResponseDto[] = [];
let viewingAssets: string[] = [];
let viewingAssetCursor = 0;
let showSettingsModal = false;
onMount(async () => {
mapMarkers = await loadMapMarkers();
});
onDestroy(() => {
abortController?.abort();
assetViewingStore.showAssetViewer(false);
});
$: $featureFlags.map || handlePromiseError(goto(AppRoute.PHOTOS));
const omit = (obj: MapSettings, key: string) => {
return Object.fromEntries(Object.entries(obj).filter(([k]) => k !== key));
};
async function loadMapMarkers() {
if (abortController) {
abortController.abort();
}
abortController = new AbortController();
const { includeArchived, onlyFavorites, withPartners, withSharedAlbums } = $mapSettings;
const { fileCreatedAfter, fileCreatedBefore } = getFileCreatedDates();
return await getMapMarkers(
{
isArchived: includeArchived && undefined,
isFavorite: onlyFavorites || undefined,
fileCreatedAfter: fileCreatedAfter || undefined,
fileCreatedBefore,
withPartners: withPartners || undefined,
withSharedAlbums: withSharedAlbums || undefined,
},
{
signal: abortController.signal,
},
);
}
function getFileCreatedDates() {
const { relativeDate, dateAfter, dateBefore } = $mapSettings;
if (relativeDate) {
const duration = Duration.fromISO(relativeDate);
return {
fileCreatedAfter: duration.isValid ? DateTime.now().minus(duration).toISO() : undefined,
};
}
try {
return {
fileCreatedAfter: dateAfter ? new Date(dateAfter).toISOString() : undefined,
fileCreatedBefore: dateBefore ? new Date(dateBefore).toISOString() : undefined,
};
} catch {
$mapSettings.dateAfter = '';
$mapSettings.dateBefore = '';
return {};
}
}
async function onViewAssets(assetIds: string[]) {
viewingAssets = assetIds;
viewingAssetCursor = 0;
await setAssetId(assetIds[0]);
}
async function navigateNext() {
if (viewingAssetCursor < viewingAssets.length - 1) {
await setAssetId(viewingAssets[++viewingAssetCursor]);
await navigate({ targetRoute: 'current', assetId: $viewingAsset.id });
}
}
async function navigatePrevious() {
if (viewingAssetCursor > 0) {
await setAssetId(viewingAssets[--viewingAssetCursor]);
await navigate({ targetRoute: 'current', assetId: $viewingAsset.id });
}
}
</script>
{#if $featureFlags.loaded && $featureFlags.map}
<UserPageLayout title={data.meta.title}>
<div class="isolate h-full w-full">
<Map bind:mapMarkers bind:showSettingsModal on:selected={(event) => onViewAssets(event.detail)} />
</div></UserPageLayout
>
<Portal target="body">
{#if $showAssetViewer}
{#await import('../../../../../lib/components/asset-viewer/asset-viewer.svelte') then { default: AssetViewer }}
<AssetViewer
asset={$viewingAsset}
showNavigation={viewingAssets.length > 1}
on:next={navigateNext}
on:previous={navigatePrevious}
on:close={() => assetViewingStore.showAssetViewer(false)}
isShared={false}
/>
{/await}
{/if}
</Portal>
{#if showSettingsModal}
<MapSettingsModal
settings={{ ...$mapSettings }}
on:close={() => (showSettingsModal = false)}
on:save={async ({ detail }) => {
const shouldUpdate = !isEqual(omit(detail, 'allowDarkMode'), omit($mapSettings, 'allowDarkMode'));
showSettingsModal = false;
$mapSettings = detail;
if (shouldUpdate) {
mapMarkers = await loadMapMarkers();
}
}}
/>
{/if}
{/if}