Skip to content

Commit

Permalink
Waiting endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
w3bdesign committed Nov 20, 2024
1 parent 49930be commit dbe0c4b
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 18 deletions.
13 changes: 12 additions & 1 deletion backend/src/bookings/bookings.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,56 @@ import { Roles } from "../auth/decorators/roles.decorator";
import { UserRole } from "../users/entities/user.entity";

@Controller("bookings")
@UseGuards(JwtAuthGuard, RolesGuard)
export class BookingsController {
constructor(private readonly bookingsService: BookingsService) {}

@Get("upcoming/count")
async getUpcomingCount() {
return { count: await this.bookingsService.getUpcomingCount() };
}

@Post()
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(UserRole.CUSTOMER, UserRole.ADMIN)
async create(@Body() createBookingDto: CreateBookingDto) {
const booking = await this.bookingsService.create(createBookingDto);
return BookingResponseDto.fromEntity(booking);
}

@Get("upcoming")
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(UserRole.EMPLOYEE, UserRole.ADMIN)
async findUpcoming() {
const bookings = await this.bookingsService.findUpcoming();
return BookingResponseDto.fromEntities(bookings);
}

@Get("customer/:customerId")
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(UserRole.CUSTOMER, UserRole.ADMIN)
async findByCustomer(@Param("customerId") customerId: string) {
const bookings = await this.bookingsService.findByCustomer(customerId);
return BookingResponseDto.fromEntities(bookings);
}

@Get("employee/:employeeId")
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(UserRole.EMPLOYEE, UserRole.ADMIN)
async findByEmployee(@Param("employeeId") employeeId: string) {
const bookings = await this.bookingsService.findByEmployee(employeeId);
return BookingResponseDto.fromEntities(bookings);
}

@Get(":id")
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(UserRole.CUSTOMER, UserRole.EMPLOYEE, UserRole.ADMIN)
async findOne(@Param("id") id: string) {
const booking = await this.bookingsService.findOne(id);
return BookingResponseDto.fromEntity(booking);
}

@Put(":id")
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(UserRole.CUSTOMER, UserRole.EMPLOYEE, UserRole.ADMIN)
async update(
@Param("id") id: string,
Expand All @@ -68,6 +78,7 @@ export class BookingsController {
}

@Put(":id/cancel")
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(UserRole.CUSTOMER, UserRole.EMPLOYEE, UserRole.ADMIN)
async cancel(
@Param("id") id: string,
Expand Down
10 changes: 10 additions & 0 deletions backend/src/bookings/bookings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,14 @@ export class BookingsService {
order: { startTime: "ASC" },
});
}

async getUpcomingCount(): Promise<number> {
const now = new Date();
return this.bookingRepository.count({
where: {
startTime: MoreThan(now),
status: BookingStatus.CONFIRMED,
},
});
}
}
56 changes: 43 additions & 13 deletions frontend/customer/src/components/WaitingTimeDisplay.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,54 @@
<template>
<div class="bg-white rounded-lg shadow-lg p-6 max-w-sm mx-auto">
<div class="card bg-gradient-to-br from-white to-gray-50">
<div class="text-center">
<h2 class="text-2xl font-semibold text-gray-800 mb-4">Current Wait Time</h2>
<h2 class="text-2xl font-bold text-gradient mb-6">Current Wait Time</h2>

<div v-if="isLoading" class="animate-pulse">
<div class="h-8 bg-gray-200 rounded w-24 mx-auto mb-4"></div>
<div class="h-6 bg-gray-200 rounded w-32 mx-auto"></div>
<div v-if="isLoading" class="animate-pulse space-y-4">
<div class="h-12 bg-gray-200 rounded-lg w-32 mx-auto"></div>
<div class="h-6 bg-gray-200 rounded-lg w-24 mx-auto"></div>
</div>

<template v-else>
<div class="text-4xl font-bold text-primary-600 mb-2">
{{ formattedWaitTime }}
<div class="mb-4">
<div class="text-5xl font-bold text-gradient mb-2">
{{ formattedWaitTime }}
</div>
<div class="flex items-center justify-center space-x-2 text-gray-600">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
d="M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3zM6 8a2 2 0 11-4 0 2 2 0 014 0zM16 18v-3a5.972 5.972 0 00-.75-2.906A3.005 3.005 0 0119 15v3h-3zM4.75 12.094A5.973 5.973 0 004 15v3H1v-3a3 3 0 013.75-2.906z"
/>
</svg>
<span class="text-lg">{{ queueStatus.peopleWaiting }} waiting</span>
</div>
</div>

<div class="text-sm text-gray-500 flex items-center justify-center space-x-1">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z"
clip-rule="evenodd"
/>
</svg>
<span>Updated {{ new Date(queueStatus.lastUpdated).toLocaleTimeString() }}</span>
</div>
<p class="text-gray-600">{{ queueStatus.peopleWaiting }} people waiting</p>
<p class="text-sm text-gray-500 mt-4">
Last updated: {{ new Date(queueStatus.lastUpdated).toLocaleTimeString() }}
</p>
</template>

<div v-if="error" class="mt-4 text-red-600 text-sm">
<div
v-if="error"
class="mt-4 text-red-600 text-sm bg-red-50 border border-red-100 rounded-lg p-2"
>
{{ error }}
</div>
</div>
Expand All @@ -32,7 +62,7 @@ import { useWaitingStore } from '@/stores/waiting'
const waitingStore = useWaitingStore()
const { queueStatus, isLoading, error, formattedWaitTime } = waitingStore
let pollingInterval: number | undefined
let pollingInterval: ReturnType<typeof setInterval>
onMounted(() => {
pollingInterval = waitingStore.startPolling(30000) // Update every 30 seconds
Expand Down
8 changes: 4 additions & 4 deletions frontend/customer/src/stores/waiting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const useWaitingStore = defineStore('waiting', () => {
error.value = null

try {
const response = await fetch('http://localhost:3000/bookings/upcoming', {
const response = await fetch('http://localhost:3000/bookings/upcoming/count', {
headers: {
accept: '*/*',
},
Expand All @@ -40,10 +40,10 @@ export const useWaitingStore = defineStore('waiting', () => {
throw new Error('Failed to fetch queue status')
}

const data = await response.json()
const count = await response.json()
queueStatus.value = {
peopleWaiting: data.length, // Number of upcoming bookings
estimatedWaitTime: data.length * 30, // Rough estimate: 30 minutes per booking
peopleWaiting: count,
estimatedWaitTime: count * 30, // Rough estimate: 30 minutes per booking
lastUpdated: new Date().toISOString(),
}
} catch (err) {
Expand Down

0 comments on commit dbe0c4b

Please sign in to comment.