fix(collections): tighten itinerary chat panel access and state scoping

This commit is contained in:
2026-03-10 20:04:15 +00:00
parent e6a7c83a3a
commit 7b4541a075
2 changed files with 62 additions and 51 deletions

View File

@@ -88,7 +88,10 @@
}>(); }>();
const MODEL_PREFS_STORAGE_KEY = 'voyage_chat_model_prefs'; const MODEL_PREFS_STORAGE_KEY = 'voyage_chat_model_prefs';
const ACTIVE_CONV_KEY = 'voyage_active_conversation'; const ACTIVE_CONV_FALLBACK_KEY = 'voyage_active_conversation';
$: activeConvKey = collectionId
? `voyage_active_conversation_${collectionId}`
: ACTIVE_CONV_FALLBACK_KEY;
$: promptTripContext = collectionName || destination || ''; $: promptTripContext = collectionName || destination || '';
onMount(() => { onMount(() => {
@@ -138,9 +141,9 @@
try { try {
if (convId) { if (convId) {
window.localStorage.setItem(ACTIVE_CONV_KEY, convId); window.localStorage.setItem(activeConvKey, convId);
} else { } else {
window.localStorage.removeItem(ACTIVE_CONV_KEY); window.localStorage.removeItem(activeConvKey);
} }
} catch { } catch {
// ignore localStorage persistence failures // ignore localStorage persistence failures
@@ -152,7 +155,7 @@
return; return;
} }
const savedId = window.localStorage.getItem(ACTIVE_CONV_KEY); const savedId = window.localStorage.getItem(activeConvKey);
if (!savedId) { if (!savedId) {
return; return;
} }

View File

@@ -209,7 +209,7 @@
type ViewType = 'all' | 'itinerary' | 'map' | 'calendar' | 'recommendations' | 'stats'; type ViewType = 'all' | 'itinerary' | 'map' | 'calendar' | 'recommendations' | 'stats';
let currentView: ViewType = 'itinerary'; let currentView: ViewType = 'itinerary';
let chatPanelOpen = false; let chatPanelOpen = false;
let innerWidth = 0; let innerWidth = 1024;
// Determine if this is a folder view (no dates) or itinerary view (has dates) // Determine if this is a folder view (no dates) or itinerary view (has dates)
$: isFolderView = !collection?.start_date && !collection?.end_date; $: isFolderView = !collection?.start_date && !collection?.end_date;
@@ -293,6 +293,10 @@
// Enforce recommendations visibility only for owner/shared users // Enforce recommendations visibility only for owner/shared users
$: availableViews.recommendations = !!canModifyCollection; $: availableViews.recommendations = !!canModifyCollection;
$: if (!canModifyCollection && chatPanelOpen) {
chatPanelOpen = false;
}
function deriveCollectionDestination(current: Collection | null): string | undefined { function deriveCollectionDestination(current: Collection | null): string | undefined {
if (!current?.locations?.length) { if (!current?.locations?.length) {
return undefined; return undefined;
@@ -766,6 +770,12 @@
isImageModalOpen = true; isImageModalOpen = true;
} }
function handleImageKeydown(event: KeyboardEvent, imageIndex: number) {
if (event.key === 'Enter') {
openImageModal(imageIndex);
}
}
function formatDate(dateString: string | null) { function formatDate(dateString: string | null) {
if (!dateString) return ''; if (!dateString) return '';
return DateTime.fromISO(dateString).toLocaleString(DateTime.DATE_MED, { locale: 'en-GB' }); return DateTime.fromISO(dateString).toLocaleString(DateTime.DATE_MED, { locale: 'en-GB' });
@@ -1236,6 +1246,7 @@
</button> </button>
{/if} {/if}
</div> </div>
{#if canModifyCollection}
<button <button
class="btn btn-primary btn-sm gap-2 ml-4" class="btn btn-primary btn-sm gap-2 ml-4"
class:btn-outline={!chatPanelOpen} class:btn-outline={!chatPanelOpen}
@@ -1245,10 +1256,14 @@
<MessageCircle class="w-4 h-4" /> <MessageCircle class="w-4 h-4" />
<span class="hidden sm:inline">{$t('chat.travel_assistant')}</span> <span class="hidden sm:inline">{$t('chat.travel_assistant')}</span>
</button> </button>
{/if}
</div> </div>
</div> </div>
<div class="drawer drawer-end" class:drawer-open={chatPanelOpen && innerWidth >= 1024}> <div
class="drawer drawer-end"
class:drawer-open={canModifyCollection && chatPanelOpen && innerWidth >= 1024}
>
<input <input
id="collection-chat-drawer" id="collection-chat-drawer"
type="checkbox" type="checkbox"
@@ -1259,7 +1274,7 @@
<div class="drawer-content"> <div class="drawer-content">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6 sm:gap-10"> <div class="grid grid-cols-1 lg:grid-cols-4 gap-6 sm:gap-10">
<!-- Left Column - Main Content --> <!-- Left Column - Main Content -->
<div class="lg:col-span-3 space-y-8 sm:space-y-10"> <div class="{chatPanelOpen ? 'lg:col-span-4' : 'lg:col-span-3'} space-y-8 sm:space-y-10">
<!-- Description Card (always visible) --> <!-- Description Card (always visible) -->
{#if collection.description} {#if collection.description}
<div class="card bg-base-200 shadow-xl"> <div class="card bg-base-200 shadow-xl">
@@ -1366,15 +1381,6 @@
<!-- Recommendations View --> <!-- Recommendations View -->
{#if currentView === 'recommendations'} {#if currentView === 'recommendations'}
<div class="space-y-8"> <div class="space-y-8">
<AITravelChat
embedded={true}
collectionId={collection.id}
collectionName={collection.name}
startDate={collection.start_date || undefined}
endDate={collection.end_date || undefined}
destination={collectionDestination}
on:itemAdded={handleAssistantItemAdded}
/>
<CollectionRecommendationView bind:collection user={data.user} /> <CollectionRecommendationView bind:collection user={data.user} />
</div> </div>
{/if} {/if}
@@ -1632,7 +1638,7 @@
class="aspect-square bg-cover bg-center rounded-lg cursor-pointer transition-transform duration-200 group-hover:scale-105" class="aspect-square bg-cover bg-center rounded-lg cursor-pointer transition-transform duration-200 group-hover:scale-105"
style="background-image: url({image.image})" style="background-image: url({image.image})"
on:click={() => openImageModal(index)} on:click={() => openImageModal(index)}
on:keydown={(e) => e.key === 'Enter' && openImageModal(index)} on:keydown={(event) => handleImageKeydown(event, index)}
role="button" role="button"
tabindex="0" tabindex="0"
></div> ></div>
@@ -1661,6 +1667,7 @@
</div> </div>
</div> </div>
{#if canModifyCollection}
<div class="drawer-side z-40"> <div class="drawer-side z-40">
<label for="collection-chat-drawer" class="drawer-overlay"></label> <label for="collection-chat-drawer" class="drawer-overlay"></label>
<div class="bg-base-100 h-full w-full sm:w-96 border-l border-base-300 flex flex-col"> <div class="bg-base-100 h-full w-full sm:w-96 border-l border-base-300 flex flex-col">
@@ -1687,13 +1694,14 @@
</div> </div>
</div> </div>
</div> </div>
{/if}
</div> </div>
</div> </div>
{/if} {/if}
<!-- Floating Action Button (FAB) - Only shown if user can modify collection --> <!-- Floating Action Button (FAB) - Only shown if user can modify collection -->
{#if collection && canModifyCollection && !collection.is_archived} {#if collection && canModifyCollection && !collection.is_archived}
<div class="fixed bottom-6 right-6 z-[999]"> <div class="fixed bottom-6 right-6 {chatPanelOpen ? 'z-30' : 'z-[999]'}">
<div class="dropdown dropdown-top dropdown-end"> <div class="dropdown dropdown-top dropdown-end">
<div <div
tabindex="0" tabindex="0"