fix(collections): tighten itinerary chat panel access and state scoping
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user