From 1bc7163bf93ccbf1c3a3cf1a8b85cb9b4ef8602b Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 19 Jan 2026 17:26:51 +0000 Subject: [PATCH] feat: 2-step post creation flow + auth fix - Step 1: Show crosshair to pick location with confirm/cancel buttons - Step 2: Open PostCreateModal with selected coords - Fix createPost to use authHeaders() automatically - Add location picker UI with hints and styled buttons Co-Authored-By: Claude Opus 4.5 --- package.json | 2 +- src/api/client.js | 3 +- src/components/Map/MapView.jsx | 66 ++++++++++++++++++++++++---- src/styles/map.css | 79 ++++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index da0e127..9dc0bd3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sociowire-frontend", "private": true, - "version": "0.0.51", + "version": "0.0.52", "type": "module", "scripts": { "dev": "vite --host 0.0.0.0", diff --git a/src/api/client.js b/src/api/client.js index 71742f3..62a89e4 100644 --- a/src/api/client.js +++ b/src/api/client.js @@ -274,9 +274,10 @@ export async function fetchIpLocation() { export async function createPost(payload, token) { const headers = { "Content-Type": "application/json", + ...authHeaders(), // Always include auth headers from stored token }; if (token) { - headers["Authorization"] = `Bearer ${token}`; + headers["Authorization"] = `Bearer ${token}`; // Override with explicit token if provided } const res = await fetch(`${apiBase()}/post`, { diff --git a/src/components/Map/MapView.jsx b/src/components/Map/MapView.jsx index 636ccf2..37fa249 100644 --- a/src/components/Map/MapView.jsx +++ b/src/components/Map/MapView.jsx @@ -557,7 +557,8 @@ export default function MapView({ weatherEnabled: weatherViewEnabled, }); - const [isCreating, setIsCreating] = useState(false); + const [isPickingLocation, setIsPickingLocation] = useState(false); // Step 1: pick location + const [isCreating, setIsCreating] = useState(false); // Step 2: show modal const [draftTitle, setDraftTitle] = useState(""); const [draftBody, setDraftBody] = useState(""); const [draftUrl, setDraftUrl] = useState(""); @@ -1486,8 +1487,10 @@ export default function MapView({ const closeCreateModal = () => { setIsCreating(false); + setIsPickingLocation(false); setModeSelectorVisible(false); setModeChosen(false); + setDraftCoords(null); }; const handleModeSelect = (modeId) => { @@ -1531,17 +1534,41 @@ export default function MapView({ return; } - // Get current map center as default coords - const map = mapRef.current; - if (map) { - const c = map.getCenter(); - setDraftCoords([c.lng, c.lat]); - } + // Step 1: Show crosshair to pick location setSaveError(""); setIsSaving(false); + setDraftCoords(null); + setIsPickingLocation(true); + }; + + // Confirm location and open modal + const handleConfirmLocation = () => { + const map = mapRef.current; + if (map) { + const stage = stageRef.current; + const crosshairEl = stage?.querySelector(".crosshair-aim"); + const containerEl = map.getContainer(); + let coords; + if (crosshairEl && containerEl) { + const cr = crosshairEl.getBoundingClientRect(); + const co = containerEl.getBoundingClientRect(); + const ll = map.unproject([cr.left + cr.width/2 - co.left, cr.top + cr.height/2 - co.top]); + coords = [ll.lng, ll.lat]; + } else { + const c = map.getCenter(); + coords = [c.lng, c.lat]; + } + setDraftCoords(coords); + } + setIsPickingLocation(false); setIsCreating(true); }; + const handleCancelLocation = () => { + setIsPickingLocation(false); + setDraftCoords(null); + }; + // Update ref for long-press callback useEffect(() => { longPressCallbackRef.current = handleOpenCreate; @@ -2133,7 +2160,30 @@ export default function MapView({ weatherEnabled={weatherViewEnabled} /> - {/* New Post Creation Modal */} + {/* Step 1: Location Picker with Crosshair */} + {isPickingLocation && ( + <> +
+
+
+
+
+ + Move the map to position your post +
+
+ + +
+
+ + )} + + {/* Step 2: Post Creation Modal */}