Trips Overview
The Trips page (dashboard-trips.html) is your central hub for managing all bookings, viewing trip details, and communicating with guides.
Trip Management Interface
Featured Trip Card
Your most relevant trip is prominently displayed with:
// Featured trip data structure
{
"id": "trip_100",
"title": "Historic Center Photo Tour",
"location": "Ciudad de Mexico",
"dateLabel": "15 Feb 2026",
"status": "confirmed",
"statusLabel": "Confirmado",
"guideId": "guide_210",
"guideName": "Luis Martinez",
"guideAvatar": "guide-avatar-url",
"image": "trip-cover-image"
}
Trip Image
Full-width background image showcasing the destination
Trip Details
Title, location (with pin icon), and travel dates
Guide Information
Guide avatar and name as a clickable link to their profile
Action Buttons
- Ver detalles: View full trip details
- Contactar guía: Open chat with your guide
Trip List
All your trips are displayed in a scrollable list below the featured card:
// Trip item rendering
state.trips.forEach((trip) => {
const status = normalizeStatus(trip.status);
const statusClass =
status === 'cancelled' ? 'is-cancelled' :
status === 'pending' || status === 'pending_change' ? 'is-pending' : '';
const canChat = canContactGuide(trip);
const canRequest = canRequestTripChange(trip);
// ... render trip card
});
Trip Statuses
Trips can have the following status values:
Trip is booked and confirmed with the guide. All details are finalized.status: "confirmed"
statusLabel: "Confirmado"
Trip request sent to guide, awaiting confirmation.status: "pending"
statusLabel: "Pendiente"
You’ve requested modifications to a confirmed trip.status: "pending_change"
statusLabel: "Cambio solicitado"
Trip has been cancelled by you or the guide.status: "cancelled"
statusLabel: "Cancelado"
You cannot contact guides or request changes for cancelled trips.
Trip Actions
View Details
Click “Ver detalles” to open the full trip information:
async function openTripDetails(tripId, options) {
const trip = findTripById(tripId);
if (!trip) return;
setFeaturedTrip(trip);
await hydrateTripDetail(trip);
renderFeatured();
renderTripList();
if (options.scrollToFeatured) {
document.querySelector('.trip-featured')?.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
showActionNotice(`Mostrando detalles de: ${trip.title}`, 'info');
}
This action:
- Sets the trip as featured
- Fetches additional details from the API
- Scrolls to the featured card
- Shows a confirmation notice
Click “Contactar guía” to open the chat widget:
if (action === 'chat') {
const tripTarget = findTripById(tripId);
if (!canContactGuide(tripTarget)) {
showActionNotice('No puedes contactar al guia en un viaje cancelado.', 'error');
return;
}
window.dispatchEvent(new CustomEvent('tourist-chat:open'));
}
Chat is only available for active trips. Cancelled trips disable the contact button.
Request Changes
Modify trip details by clicking “Solicitar cambio”:
Confirm Request
A confirmation dialog appears:const shouldContinue = window.confirm(
'Se enviara una solicitud de cambio para este viaje. Deseas continuar?'
);
Send Request
The system sends your change request to the guide:await api.update(trip.id, { status: 'pending_change' });
Update Status
Trip status updates to “Cambio solicitado” and the button becomes disabled
async function requestTripChange(tripId, triggerButton) {
const trip = findTripById(tripId);
if (!trip || !canRequestTripChange(trip)) return;
const shouldContinue = window.confirm(
'Se enviara una solicitud de cambio para este viaje. Deseas continuar?'
);
if (!shouldContinue) return;
triggerButton.disabled = true;
triggerButton.setAttribute('aria-busy', 'true');
try {
await window.KCTouristApi.trips.update(trip.id, { status: 'pending_change' });
trip.status = 'pending_change';
trip.statusLabel = 'Cambio solicitado';
setFeaturedTrip(trip);
showActionNotice('Solicitud de cambio enviada correctamente.', 'success');
} catch (error) {
showActionNotice('No fue posible solicitar el cambio. Intenta nuevamente.', 'error');
} finally {
triggerButton.removeAttribute('aria-busy');
}
}
You cannot request changes for:
- Cancelled trips
- Trips already in “pending_change” status
Guide Profile Integration
Click on any guide’s name to view their full profile:
function resolveGuideProfileHref(guideId) {
const encodedGuideId = encodeURIComponent(String(guideId || '').trim());
return encodedGuideId
? `../guia/profileGuide.html?guideId=${encodedGuideId}`
: '../guia/profileGuide.html';
}
The guide profile displays:
- Full bio and expertise areas
- Photo gallery of past tours
- Reviews from other tourists
- Available experiences
- Contact button
API Endpoints
List Trips
Fetch all your trips with pagination:
const trips = {
list: (query) => api.get('/tourist/trips', { params: query })
};
// Example request
const response = await trips.list({ page: 0, size: 20 });
const data = response?.data?.items || response?.data || [];
Trip Detail
Get detailed information for a specific trip:
const trips = {
detail: (tripId) => api.get(`/tourist/trips/${tripId}`)
};
// Hydrate trip with full details
async function hydrateTripDetail(trip) {
const response = await window.KCTouristApi.trips.detail(trip.id);
const detail = response?.data || {};
trip.location = detail.location || trip.location;
trip.dateLabel = detail.dateLabel || trip.dateLabel;
trip.status = normalizeStatus(detail.status || trip.status);
trip.statusLabel = detail.statusLabel || trip.statusLabel;
trip.guideId = detail.guide?.id || trip.guideId;
trip.guideName = detail.guide?.name || trip.guideName;
}
Create Trip
Book a new experience:
const trips = {
create: (payload) => api.post('/tourist/trips', payload)
};
// Example payload
const newTrip = {
"guideId": "guide_210",
"experienceId": "exp_1",
"datePreference": "2026-03-15",
"numberOfPeople": 2,
"message": "Interested in morning departure"
};
Update Trip
Modify an existing booking:
const trips = {
update: (tripId, payload) => api.put(`/tourist/trips/${tripId}`, payload)
};
// Request changes
await trips.update('trip_100', { status: 'pending_change' });
Cancel Trip
Cancel a booking:
const trips = {
cancel: (tripId, payload) => api.post(`/tourist/trips/${tripId}/cancel`, payload)
};
// Cancel with reason
await trips.cancel('trip_100', { reason: 'Schedule conflict' });
Action Notices
User feedback is displayed via toast-style notices:
function showActionNotice(message, tone) {
const notice = document.getElementById('tripActionNotice');
const normalizedTone =
tone === 'error' ? 'is-error' :
tone === 'success' ? 'is-success' : 'is-info';
notice.classList.add(normalizedTone);
notice.textContent = message;
// Auto-dismiss after 3.6 seconds
setTimeout(() => {
notice.textContent = '';
notice.classList.remove('is-error', 'is-success', 'is-info');
}, 3600);
}
Notice types:
- Success: Green background - “Solicitud de cambio enviada correctamente.”
- Error: Red background - “No fue posible solicitar el cambio.”
- Info: Blue background - “Mostrando detalles de: [Trip Title]“
The integrated chat system allows real-time communication with guides:
Opening Chat
// Trigger chat from anywhere
window.dispatchEvent(new CustomEvent('tourist-chat:open'));
Chat Features
Thread List
View all your active conversations with guides
Real-time Messages
Send and receive messages instantly
Guide Avatars
Visual identification of conversation participants
Mobile Optimized
Full-screen chat on mobile devices
Chat Implementation
// Chat widget structure
const threadData = {
'maria': [
{ from: 'guest', text: 'Hola, me gustaría confirmar el punto de encuentro.' },
{ from: 'guide', text: 'Claro, te comparto la ubicación exacta en un momento.' }
]
};
const threadProfiles = {
'maria': {
name: 'María R.',
avatarUrl: 'avatar-url'
}
};
Sending Messages
form.addEventListener('submit', async (event) => {
event.preventDefault();
const text = input.value.trim();
if (!text) return;
const apiThreadId = threadIdsByKey[activeThread];
try {
if (window.KCTouristApi?.chat?.sendMessage && apiThreadId) {
await window.KCTouristApi.chat.sendMessage(apiThreadId, { message: text });
}
} catch (error) {
console.warn('Send message error:', error);
}
// Update UI optimistically
const collection = threadData[activeThread] || [];
collection.push({ from: 'guide', text });
renderMessages(messagesEl, collection);
input.value = '';
});
URL Parameters
Deep link to specific trips using query parameters:
// Example URL: /trips.html?tripId=trip_100
function hydrateTripFromQuery() {
const params = new URLSearchParams(window.location.search);
const selectedTripId = params.get('tripId');
if (!selectedTripId) return;
const selected = findTripById(selectedTripId);
if (selected) setFeaturedTrip(selected);
}
Share trip URLs with guides to reference specific bookings in your conversations.
Empty States
If you have no trips:
<div class="guide-loading guide-loading--compact" role="status">
<span>No hay viajes para mostrar por ahora.</span>
</div>
Start exploring guides and experiences to book your first trip!
Best Practices
Book in Advance
Contact guides at least 1-2 weeks before your desired dates
Clear Communication
Provide details about group size, interests, and special needs
Review Trip Details
Verify all information before confirming the booking
Stay Responsive
Check notifications for guide responses and updates
Next Steps
Profile Management
Update your travel preferences and profile
API Reference
Explore trip management endpoints