Code Examples
Các ví dụ code chi tiết để FE tham khảo.
Listings
Lấy danh sách Listings
'use client';
import { useGetListingsApiV1ListingsGet } from '@/generated/api/listings/listings';
export default function ListingList() {
const { data, isLoading, error, refetch } = useGetListingsApiV1ListingsGet({
page: 1,
limit: 20,
});
if (isLoading) return <Skeleton />;
if (error) return <ErrorDisplay error={error} />;
return (
<div>
<button onClick={() => refetch()}>Refresh</button>
<div className="listing-grid">
{data?.items?.map((listing) => (
<ListingCard key={listing.id} listing={listing} />
))}
</div>
</div>
);
}
Chi tiết một Listing
'use client';
import { useGetListingApiV1ListingsListingIdGet } from '@/generated/api/listings/listings';
interface Props {
listingId: string;
}
export default function ListingDetail({ listingId }: Props) {
const { data: listing, isLoading } = useGetListingApiV1ListingsListingIdGet({
listingId,
});
if (isLoading) return <Skeleton />;
return (
<div>
<h1>{listing?.name}</h1>
<p>{listing?.description}</p>
<ListingGallery images={listing?.images} />
<PricingInfo pricing={listing?.pricing} />
<AmenitiesList amenities={listing?.amenities} />
</div>
);
}
Tạo Listing mới
'use client';
import { useCreateListingApiV1ListingsPost } from '@/generated/api/listings/listings';
import { useRouter } from 'next/navigation';
export function CreateListingForm() {
const router = useRouter();
const createListing = useCreateListingApiV1ListingsPost();
const handleSubmit = async (formData: ListingFormData) => {
try {
const result = await createListing.mutateAsync({
data: {
name: formData.name,
type: formData.type,
location: formData.location,
capacity: formData.capacity,
// ... other fields
},
});
router.push(`/listings/${result.id}`);
} catch (error) {
console.error('Create failed:', error);
}
};
return <ListingForm onSubmit={handleSubmit} />;
}
Preview Listing trước khi tạo
'use client';
import { usePreviewListingApiV1ListingsPreviewPost } from '@/generated/api/listings/listings';
function PreviewBeforeSubmit({ formData }: { formData: ListingFormData }) {
const { data: preview, isLoading } = usePreviewListingApiV1ListingsPreviewPost({
data: formData,
});
if (isLoading) return <Loading />;
return (
<div>
{preview?.errors && preview.errors.length > 0 && (
<ValidationErrors errors={preview.errors} />
)}
{preview?.warnings && preview.warnings.length > 0 && (
<ValidationWarnings warnings={preview.warnings} />
)}
<EstimatedPricing pricing={preview?.estimated_pricing} />
</div>
);
}
Bookings
Lấy danh sách Bookings
'use client';
import { useGetMyBookingsApiV1BookingsMyGet } from '@/generated/api/bookings/bookings';
export function MyBookings() {
const { data, isLoading } = useGetMyBookingsApiV1BookingsMyGet({
page: 1,
limit: 20,
});
return (
<div>
{data?.items?.map((booking) => (
<BookingCard
key={booking.id}
booking={booking}
status={booking.state}
/>
))}
</div>
);
}
Chi tiết Booking
'use client';
import { useGetBookingApiV1BookingsBookingIdGet } from '@/generated/api/bookings/bookings';
interface Props {
bookingId: string;
}
export function BookingDetail({ bookingId }: Props) {
const { data: booking, isLoading } = useGetBookingApiV1BookingsBookingIdGet({
bookingId,
});
if (isLoading) return <Skeleton />;
return (
<div>
<BookingHeader booking={booking} />
<GuestInfo guest={booking?.guest_info} />
<StayDetails
checkIn={booking?.check_in}
checkOut={booking?.check_out}
guests={booking?.guests}
/>
<PaymentInfo payment={booking?.payment} />
<BookingTimeline status={booking?.state} />
</div>
);
}
Hủy Booking
'use client';
import { useCancelBookingApiV1BookingsBookingIdCancelPost } from '@/generated/api/bookings/bookings';
function CancelBookingButton({ bookingId }: { bookingId: string }) {
const cancelBooking = useCancelBookingApiV1BookingsBookingIdCancelPost();
const handleCancel = async (reason: string) => {
try {
await cancelBooking.mutateAsync({
bookingId,
data: { reason },
});
// Show success, redirect
} catch (error) {
// Handle error
}
};
return (
<button onClick={() => handleCancel('User requested')}>
Cancel Booking
</button>
);
}
Availability
Lấy Availability Calendar
'use client';
import { useGetListingAvailabilityApiV1ListingAvailabilityListingsListingIdGet } from '@/generated/api/availability/availability';
interface Props {
listingId: string;
month: string; // Format: '2025-03'
}
function AvailabilityCalendar({ listingId, month }: Props) {
const [year, monthNum] = month.split('-').map(Number);
const { data: availability } = useGetListingAvailabilityApiV1ListingAvailabilityListingsListingIdGet({
listingId,
year,
month: monthNum,
});
return (
<Calendar>
{availability?.days?.map((day) => (
<DayCell
key={day.date}
date={day.date}
status={day.status}
// AVAILABLE, BLOCKED, BOOKED, SOFT_LOCK
/>
))}
</Calendar>
);
}
Block dates
'use client';
import { useBlockListingAvailabilityApiV1ListingAvailabilityListingsListingIdBlocksPost } from '@/generated/api/availability/availability';
function BlockDatesForm({ listingId }: { listingId: string }) {
const blockDates = useBlockListingAvailabilityApiV1ListingAvailabilityListingsListingIdBlocksPost();
const handleBlock = async (startDate: string, endDate: string, reason: string) => {
await blockDates.mutateAsync({
listingId,
data: {
start_date: startDate,
end_date: endDate,
reason,
},
});
};
return <BlockDatesForm onSubmit={handleBlock} />;
}
Cart
Lấy Cart
'use client';
import { useGetCartApiV1CartGet } from '@/generated/api/cart/cart';
export function CartSummary() {
const { data: cart, isLoading } = useGetCartApiV1CartGet();
if (isLoading) return <CartSkeleton />;
return (
<div>
<h2>Giỏ hàng ({cart?.items?.length} items)</h2>
{cart?.items?.map((item) => (
<CartItem key={item.index} item={item} />
))}
<TotalDisplay total={cart?.total} />
</div>
);
}