mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 07:53:09 +00:00
35566690e9
- The editor's 'Pick a picture' is the one place a place's picture is set, on the desktop dialog and the phone sheet alike: upload one from the device, keep the current one (now shown as chosen), take an image attached to the place, or one of the sources' photos, or remove it. Nothing is sent before the save: the upload and the attached file are put in place once the place is saved, so Cancel leaves the picture as it was and a new place can get one too. Without the details column the same picker sits in the form. - The view (inspector and phone sheet) shows the picture plainly; a click opens the gallery of its own picture and its sources' photos. - The gallery drops an answer that arrives after the place changed, and its credits link to their source pages. The lightbox is a labelled modal dialog that takes and gives back focus, names its arrows and follows the reading direction. - The picker leaves the details column (PlaceImagePicker), the column reads the shared enrichment cache, and PlaceAvatarUpload and usePlaceImagePick, which only the view used, are gone.
58 lines
2.1 KiB
TypeScript
58 lines
2.1 KiB
TypeScript
import { useMemo } from 'react';
|
|
import { useShallow } from 'zustand/react/shallow';
|
|
|
|
import { useTripStore } from '../../store/tripStore';
|
|
import type { Place, TripFile } from '../../types';
|
|
import { filesForPlace } from '../../utils/placeFiles';
|
|
import type { PlaceImageOwn } from './PlaceImagePicker';
|
|
import { chosenImage, pickableImages, type ChosenImage, type PendingPlaceImage } from './placeImageChoice';
|
|
|
|
interface PlaceImageFieldOptions {
|
|
/** The place being edited; null or undefined while a new one is made. */
|
|
place: Pick<Place, 'id' | 'image_url'> | null | undefined;
|
|
/** The form's image field: undefined keeps the picture, null drops it, a URL takes a source's photo. */
|
|
imageUrl: string | null | undefined;
|
|
pendingImage: PendingPlaceImage | null;
|
|
canUploadFiles: boolean;
|
|
stageUpload: (file: File) => void;
|
|
stageAttached: (file: TripFile) => void;
|
|
removeImage: () => void;
|
|
}
|
|
|
|
/**
|
|
* The editor's picture of a place, the same for the desktop dialog and the
|
|
* phone sheet: the picture it has now, the images attached to it, the one
|
|
* waiting for the save, and which tile of the picker stands for the choice.
|
|
* A new place has no attached files yet; it can still be given a picture from
|
|
* the device, uploaded once the save has made it.
|
|
*/
|
|
export function usePlaceImageField({
|
|
place,
|
|
imageUrl,
|
|
pendingImage,
|
|
canUploadFiles,
|
|
stageUpload,
|
|
stageAttached,
|
|
removeImage,
|
|
}: PlaceImageFieldOptions): { own: PlaceImageOwn; chosen: ChosenImage } {
|
|
const { files, reservations } = useTripStore(useShallow((s) => ({ files: s.files, reservations: s.reservations })));
|
|
const placeId = place?.id;
|
|
const attached = useMemo(
|
|
() => (placeId ? pickableImages(filesForPlace(files, placeId, reservations)) : []),
|
|
[files, placeId, reservations]
|
|
);
|
|
const currentUrl = place?.image_url ?? null;
|
|
return {
|
|
own: {
|
|
currentUrl,
|
|
attached,
|
|
pendingPreview: pendingImage?.kind === 'upload' ? pendingImage.preview : null,
|
|
canUpload: canUploadFiles,
|
|
onUpload: stageUpload,
|
|
onPickAttached: stageAttached,
|
|
onRemove: removeImage,
|
|
},
|
|
chosen: chosenImage(imageUrl, pendingImage, currentUrl),
|
|
};
|
|
}
|