feat(chatelet): guest booking UI — slice 1 (browse + availability) #142
1 changed files with 34 additions and 8 deletions
feat(chatelet): pick check-in/check-out with the shared DatePicker
Replace the two native <input type="date"> fields on the room detail page with the base DatePicker (Popover + shadcn Calendar), the same component the events editor uses. Check-in is floored at today and check-out at the morning after check-in; moving check-in past the current check-out clears it, and any change resets the last quote. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
commit
65770ad9be
|
|
@ -1,13 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { toast } from 'vue-sonner'
|
||||
import { addDays, format } from 'date-fns'
|
||||
import { MapPin, 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 { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import DatePicker from '@/modules/base/components/DatePicker.vue'
|
||||
import { useChatelet } from '../composables/useChatelet'
|
||||
import type { AvailabilityResult, Room } from '../types/room'
|
||||
|
||||
|
|
@ -21,6 +22,26 @@ const checkOut = ref('')
|
|||
const checking = ref(false)
|
||||
const result = ref<AvailabilityResult | null>(null)
|
||||
|
||||
// Same YYYY-MM-DD wire format the DatePicker speaks; the availability
|
||||
// endpoint takes the same strings.
|
||||
const today = computed(() => format(new Date(), 'yyyy-MM-dd'))
|
||||
|
||||
// Check-out must be at least the next morning. Bumping the floor also
|
||||
// clears a check-out that the new check-in has overtaken.
|
||||
const minCheckOut = computed(() =>
|
||||
checkIn.value
|
||||
? format(addDays(new Date(checkIn.value + 'T00:00:00'), 1), 'yyyy-MM-dd')
|
||||
: today.value,
|
||||
)
|
||||
|
||||
watch(checkIn, () => {
|
||||
if (checkOut.value && checkOut.value < minCheckOut.value) checkOut.value = ''
|
||||
result.value = null
|
||||
})
|
||||
watch(checkOut, () => {
|
||||
result.value = null
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
room.value = await getRoom(route.params.id as string)
|
||||
|
|
@ -86,13 +107,18 @@ async function onCheck() {
|
|||
<Card>
|
||||
<CardContent class="p-4 space-y-3">
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div class="space-y-1">
|
||||
<Label for="ci">Check-in</Label>
|
||||
<Input id="ci" type="date" v-model="checkIn" />
|
||||
<div class="space-y-1 min-w-0">
|
||||
<Label>Check-in</Label>
|
||||
<DatePicker v-model="checkIn" :min="today" placeholder="Check-in" />
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<Label for="co">Check-out</Label>
|
||||
<Input id="co" type="date" v-model="checkOut" />
|
||||
<div class="space-y-1 min-w-0">
|
||||
<Label>Check-out</Label>
|
||||
<DatePicker
|
||||
v-model="checkOut"
|
||||
:min="minCheckOut"
|
||||
:disabled="!checkIn"
|
||||
placeholder="Check-out"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue