From cf0091b74105f089319afeef77353962ed963b17 Mon Sep 17 00:00:00 2001 From: 3dtours Date: Wed, 23 Sep 2026 09:33:26 +0700 Subject: [PATCH] web: name a position that lands before the account is known MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A photo restored from the session reaches the stage while /me is still in flight, so the account reading that put it there saw `pro` as false, the place lookup was skipped, and reloading a photo left the stamp with bare coordinates. Naming now happens in one effect that watches the position itself: the first moment it is on the stage unnamed and the account is PRO, it gets a name, wherever it came from. A position typed in by hand earns its name too, and a guest's photo is named the moment they sign in. The two call sites that used to ask for the name — in locateMe and adoptPhoto — are gone, since the effect covers both. --- docker/frontend/src/App.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docker/frontend/src/App.tsx b/docker/frontend/src/App.tsx index d8739af..a390af9 100644 --- a/docker/frontend/src/App.tsx +++ b/docker/frontend/src/App.tsx @@ -695,6 +695,15 @@ export function Workspace() { .catch(() => undefined); }, []); + // Every position that reaches the stage still without a name is named here, + // once: a photo restored from the session lands at boot, before /me has + // answered, so the account reading that put it there saw `pro` as false — and + // a guest's photo earns its name the moment they sign in. PRO only, and a + // position the user has named by hand is left alone. + useEffect(() => { + if (pro && gps && !gps.locality) resolvePlace(gps.latitude, gps.longitude); + }, [pro, gps, resolvePlace]); + // iPhone Safari returns a frame shot through the in-page camera with no EXIF // at all (WebKit bug 207088), so the device's own position is the only // automatic source left. Tried the moment such a photo lands (see adoptPhoto) @@ -717,7 +726,6 @@ export function Workspace() { setGps({ latitude, longitude, locality: place, timestamp: when ?? capturedAt ?? Date.now(), source: 'device' }); setUseGeotag(true); setLocating(false); - resolvePlace(latitude, longitude); }, () => { setLocating(false); @@ -726,7 +734,7 @@ export function Workspace() { }, { enableHighAccuracy: true, timeout: 15000, maximumAge: 0 } ); - }, [place, t, resolvePlace, capturedAt]); + }, [place, t, capturedAt]); const adoptPhoto = useCallback( async (bytes: Uint8Array, name: string, blob: Blob, keepGeo = false) => { @@ -761,9 +769,6 @@ export function Workspace() { previewJobRef.current++; setPreviewBytes(preview); setGps(found); - // EXIF gave a position but never a name; ask the API for one. PRO only — - // the stamp is a PRO tool, and the lookup is a call to a public geocoder. - if (found && pro) resolvePlace(found.latitude, found.longitude); setIso(foundIso); // A new photo starts a new history whose floor is the default look, so // UNDO walks all the way back and still leaves the photo loaded. REDO has @@ -779,7 +784,7 @@ export function Workspace() { // location prompt. if (!found && pro && canLocate && !locDeniedRef.current) locateMe(taken); }, - [defaultLook, pro, locateMe, resolvePlace] + [defaultLook, pro, locateMe] ); const loadFile = useCallback(