RoomKitExamples
Next.js App
Build a room booking UI with Next.js and RoomKit React
Overview
This example shows how to build a room booking frontend with Next.js 15 and @hfu.digital/roomkit-react.
Provider Setup
'use client';
import { RoomKitProvider } from '@hfu.digital/roomkit-react';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<RoomKitProvider
config={{
apiUrl: '/api/roomkit',
fetchOptions: {
credentials: 'include',
},
}}
>
{children}
</RoomKitProvider>
);
}import { Providers } from './providers';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}Room Finder Page
'use client';
import { useState } from 'react';
import {
useAvailability,
AvailabilitySearch,
RoomCard,
} from '@hfu.digital/roomkit-react';
import type { AvailabilityFilter } from '@hfu.digital/roomkit-react';
export default function RoomsPage() {
const [filters, setFilters] = useState<AvailabilityFilter>({
timeRange: {
startsAt: new Date(),
endsAt: new Date(Date.now() + 2 * 60 * 60 * 1000),
},
});
const { data, isLoading, error } = useAvailability({
filters,
pagination: { limit: 12 },
});
return (
<div style={{ display: 'flex', gap: '2rem', padding: '2rem' }}>
<aside style={{ width: '300px' }}>
<h2>Search</h2>
<AvailabilitySearch
equipmentOptions={['projector', 'whiteboard', 'microphone']}
accessibilityOptions={['wheelchair', 'hearing_loop']}
onChange={setFilters}
/>
</aside>
<main style={{ flex: 1 }}>
<h1>Available Rooms</h1>
{isLoading && <p>Searching...</p>}
{error && <p>Error: {error.message}</p>}
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: '1rem' }}>
{data?.items.map((item) => (
<RoomCard
key={item.room.id}
room={item.room}
score={item.score}
onClick={() => window.location.href = `/rooms/${item.room.id}`}
/>
))}
</div>
{data && (
<p>{data.totalMatching} rooms found</p>
)}
</main>
</div>
);
}Booking Detail Page
'use client';
import { use } from 'react';
import {
useBooking,
useCancelBooking,
BookingStatusBadge,
} from '@hfu.digital/roomkit-react';
export default function BookingPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = use(params);
const { data: booking, isLoading, refetch } = useBooking({ bookingId: id });
const cancelBooking = useCancelBooking({
bookingId: id,
onSuccess: () => refetch(),
});
if (isLoading) return <p>Loading...</p>;
if (!booking) return <p>Booking not found</p>;
return (
<div style={{ padding: '2rem' }}>
<h1>{booking.title}</h1>
<BookingStatusBadge status={booking.status} />
<dl>
<dt>Room</dt><dd>{booking.roomId}</dd>
<dt>Start</dt><dd>{booking.startsAt}</dd>
<dt>End</dt><dd>{booking.endsAt}</dd>
<dt>Purpose</dt><dd>{booking.purposeType}</dd>
<dt>Priority</dt><dd>{booking.priority}</dd>
</dl>
{booking.status !== 'cancelled' && booking.status !== 'completed' && (
<button
onClick={() => cancelBooking.mutate({ reason: 'Cancelled by user' })}
disabled={cancelBooking.isLoading}
>
Cancel Booking
</button>
)}
</div>
);
}Location Browser Page
'use client';
import { useLocationTree, LocationBrowser } from '@hfu.digital/roomkit-react';
export default function LocationsPage() {
const { data, isLoading } = useLocationTree();
if (isLoading) return <p>Loading locations...</p>;
return (
<div style={{ padding: '2rem' }}>
<h1>Locations</h1>
{data && (
<LocationBrowser
tree={data}
onSelect={(node) => {
if (node.type === 'room') {
window.location.href = `/rooms/${node.id}`;
}
}}
/>
)}
</div>
);
}Booking Form Page
'use client';
import { use } from 'react';
import { useCreateBooking, BookingForm } from '@hfu.digital/roomkit-react';
export default function BookRoomPage({ params }: { params: Promise<{ id: string }> }) {
const { id: roomId } = use(params);
const createBooking = useCreateBooking({
onSuccess: (booking) => {
window.location.href = `/bookings/${booking.id}`;
},
});
return (
<div style={{ padding: '2rem', maxWidth: '600px' }}>
<h1>Book Room</h1>
<BookingForm
roomId={roomId}
onSubmit={(data) => createBooking.mutate(data)}
isSubmitting={createBooking.isLoading}
/>
{createBooking.error && (
<p style={{ color: 'red' }}>Error: {createBooking.error.message}</p>
)}
</div>
);
}Running the Example
git clone https://github.com/hfu-digital/RoomKit.git
cd RoomKit/examples/nextjs-app
bun install
bun run dev