mirror of
https://github.com/immich-app/immich.git
synced 2025-12-20 09:15:35 +03:00
fix: navigate to time action (#20928)
* fix: navigate to time action * change-date -> DateSelectionModal; use luxon; use handle* for callback fn name * refactor change-date dialogs * Review comments * chore: clean up --------- Co-authored-by: Jason Rasmussen <jason@rasm.me>
This commit is contained in:
84
web/src/lib/modals/AssetChangeDateModal.svelte
Normal file
84
web/src/lib/modals/AssetChangeDateModal.svelte
Normal file
@@ -0,0 +1,84 @@
|
||||
<script lang="ts">
|
||||
import Combobox from '$lib/components/shared-components/combobox.svelte';
|
||||
import DateInput from '$lib/elements/DateInput.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import { getPreferredTimeZone, getTimezones, toIsoDate } from '$lib/modals/timezone-utils';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { updateAsset } from '@immich/sdk';
|
||||
import { Button, HStack, Modal, ModalBody, ModalFooter, VStack } from '@immich/ui';
|
||||
import { mdiCalendarEdit } from '@mdi/js';
|
||||
import { DateTime } from 'luxon';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
interface Props {
|
||||
initialDate?: DateTime;
|
||||
initialTimeZone?: string;
|
||||
timezoneInput?: boolean;
|
||||
asset: TimelineAsset;
|
||||
onClose: (success: boolean) => void;
|
||||
}
|
||||
|
||||
let { initialDate = DateTime.now(), initialTimeZone, timezoneInput = true, asset, onClose }: Props = $props();
|
||||
|
||||
let selectedDate = $state(initialDate.toFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"));
|
||||
const timezones = $derived(getTimezones(selectedDate));
|
||||
|
||||
// svelte-ignore state_referenced_locally
|
||||
let lastSelectedTimezone = $state(getPreferredTimeZone(initialDate, initialTimeZone, timezones));
|
||||
// the offsets (and validity) for time zones may change if the date is changed, which is why we recompute the list
|
||||
let selectedOption = $derived(getPreferredTimeZone(initialDate, initialTimeZone, timezones, lastSelectedTimezone));
|
||||
|
||||
const handleClose = async () => {
|
||||
if (!date.isValid || !selectedOption) {
|
||||
onClose(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the local date/time components from the selected string using neutral timezone
|
||||
const isoDate = toIsoDate(selectedDate, selectedOption);
|
||||
try {
|
||||
await updateAsset({ id: asset.id, updateAssetDto: { dateTimeOriginal: isoDate } });
|
||||
onClose(true);
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_change_date'));
|
||||
onClose(false);
|
||||
}
|
||||
};
|
||||
|
||||
// when changing the time zone, assume the configured date/time is meant for that time zone (instead of updating it)
|
||||
const date = $derived(DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true }));
|
||||
</script>
|
||||
|
||||
<Modal title={$t('edit_date_and_time')} icon={mdiCalendarEdit} onClose={() => onClose(false)} size="small">
|
||||
<ModalBody>
|
||||
<VStack fullWidth>
|
||||
<HStack fullWidth>
|
||||
<label class="immich-form-label" for="datetime">{$t('date_and_time')}</label>
|
||||
</HStack>
|
||||
<HStack fullWidth>
|
||||
<DateInput
|
||||
class="immich-form-input text-gray-700 w-full"
|
||||
id="datetime"
|
||||
type="datetime-local"
|
||||
bind:value={selectedDate}
|
||||
/>
|
||||
</HStack>
|
||||
{#if timezoneInput}
|
||||
<div class="w-full">
|
||||
<Combobox
|
||||
bind:selectedOption
|
||||
label={$t('timezone')}
|
||||
options={timezones}
|
||||
placeholder={$t('search_timezone')}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</VStack>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<HStack fullWidth>
|
||||
<Button shape="round" color="secondary" fullWidth onclick={() => onClose(false)}>{$t('cancel')}</Button>
|
||||
<Button shape="round" type="submit" fullWidth onclick={handleClose}>{$t('confirm')}</Button>
|
||||
</HStack>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
Reference in New Issue
Block a user