feat(chatelet): stay calendar, room gallery + house rules, My bookings #156
2 changed files with 52 additions and 4 deletions
feat(chatelet): photo gallery and house rules on the room page
Swap the single hero image for the shared ImageViewer (thumbnails, lightbox and cycle controls when a room has more than one photo, as the marketplace product page does) and add a 'Things to know' card: check-in from / check-out by, guest cap, minimum stay and the cancellation policy. The rules come from the room owner's operator settings (chatelet ≥ v0.5.0) so the card only renders when the extension sends them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
commit
fb0478c028
|
|
@ -2,6 +2,13 @@
|
|||
// Note: operator-private fields (wallet, checkin_instructions) are stripped
|
||||
// server-side by public_room_dict and never reach the client.
|
||||
|
||||
/** The room owner's rules, from their operator settings (chatelet ≥ v0.5.0). */
|
||||
export interface HouseRules {
|
||||
checkin_time: string
|
||||
checkout_time: string
|
||||
cancellation_policy: string
|
||||
}
|
||||
|
||||
export interface Room {
|
||||
id: string
|
||||
title: string
|
||||
|
|
@ -19,6 +26,10 @@ export interface Room {
|
|||
listing_event_id: string | null
|
||||
created_at: string
|
||||
updated_at: string
|
||||
/** Absent on chatelet < v0.5.0. */
|
||||
house_rules?: HouseRules
|
||||
/** Rails the owner accepts for this room: 'lightning' and maybe 'fiat'. Absent on < v0.5.0. */
|
||||
payment_methods?: string[]
|
||||
}
|
||||
|
||||
export interface AvailabilityResult {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ import { computed, onMounted, ref, watch } from 'vue'
|
|||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { toast } from 'vue-sonner'
|
||||
import { watchDebounced } from '@vueuse/core'
|
||||
import { MapPin, Users } from 'lucide-vue-next'
|
||||
import { Clock, MapPin, Moon, Users } from 'lucide-vue-next'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { ImageViewer } from '@/components/ui/image'
|
||||
import { formatSats } from '@/lib/utils/formatting'
|
||||
import { useAuth } from '@/composables/useAuthService'
|
||||
import { useChatelet } from '../composables/useChatelet'
|
||||
|
|
@ -129,11 +130,18 @@ watch(showBooking, (open) => {
|
|||
<div v-else-if="!room" class="text-muted-foreground py-12">Room not found.</div>
|
||||
|
||||
<div v-else class="space-y-4">
|
||||
<img
|
||||
<!-- Gallery: thumbnails + lightbox when there is more than one photo
|
||||
(same ImageViewer the marketplace product page uses). -->
|
||||
<ImageViewer
|
||||
v-if="room.images?.length"
|
||||
:src="room.images[0]"
|
||||
:images="room.images"
|
||||
:alt="room.title"
|
||||
class="w-full h-56 object-cover rounded-lg"
|
||||
container-class="aspect-[4/3] sm:aspect-video rounded-lg overflow-hidden bg-muted"
|
||||
image-class="w-full h-full object-cover"
|
||||
:show-thumbnails="room.images.length > 1"
|
||||
:show-lightbox="true"
|
||||
:show-badge="room.images.length > 1"
|
||||
:show-cycle-controls="room.images.length > 1"
|
||||
/>
|
||||
|
||||
<div>
|
||||
|
|
@ -161,6 +169,35 @@ watch(showBooking, (open) => {
|
|||
{{ room.description }}
|
||||
</p>
|
||||
|
||||
<!-- House rules come from the room owner's operator settings; older
|
||||
extensions don't send them, so the card is conditional. -->
|
||||
<Card v-if="room.house_rules">
|
||||
<CardContent class="p-4 space-y-2">
|
||||
<h2 class="font-semibold text-foreground">Things to know</h2>
|
||||
<ul class="text-sm text-muted-foreground space-y-1">
|
||||
<li class="flex items-center gap-2">
|
||||
<Clock class="h-4 w-4 shrink-0" />
|
||||
Check-in from {{ room.house_rules.checkin_time }} · check-out by
|
||||
{{ room.house_rules.checkout_time }}
|
||||
</li>
|
||||
<li class="flex items-center gap-2">
|
||||
<Users class="h-4 w-4 shrink-0" />
|
||||
Up to {{ room.max_guests }} guest{{ room.max_guests === 1 ? '' : 's' }}
|
||||
</li>
|
||||
<li class="flex items-center gap-2">
|
||||
<Moon class="h-4 w-4 shrink-0" />
|
||||
Minimum stay {{ room.min_nights }} night{{ room.min_nights === 1 ? '' : 's' }}
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="room.house_rules.cancellation_policy" class="pt-1">
|
||||
<p class="text-sm font-medium text-foreground">Cancellation policy</p>
|
||||
<p class="text-sm text-muted-foreground whitespace-pre-line">
|
||||
{{ room.house_rules.cancellation_policy }}
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardContent class="p-4 space-y-4">
|
||||
<StayDatePicker
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue