Retrieving the Order collection considering user role and privacy
Author
james
Date Published

AI Booking Assistant
Get personalized recommendations and book your perfect stay
To use the AI assistant and complete bookings, please log in.
Log InReadΒ case study
Innovative client delivering medical cannabis according to a schedule
comprises of 2 files
Start by adding the - Booking collection
using established patterns to make the funnel delightful by communicating the activity
|_ π src
| |_ π app
| |_ π blocks
| |_ π collection
| | |_ π Bookings
| | | |_ π access
| | | | |_ π adminOrSelfOrGuests.ts
| | | |_ π index.ts
|_ π paylaod types.ts
|_ π payload.config.ts
1import { getPayload, Where } from 'payload'2import config from '@payload-config'3import React from 'react'4import { Post, User } from '@/payload-types'5import { getMeUser } from '@/utilities/getMeUser'6import PageClient from './page.client'7import BookingCard from '../../../components/Bookings/BookingCard'8import { redirect } from 'next/navigation'910export default async function Bookings() {11 const currentUser = await getMeUser()1213 if (!currentUser) {14 redirect('/login')15 }1617 const [upcomingBookings, pastBookings] = await Promise.all([18 getBookings('upcoming', currentUser.user),19 getBookings('past', currentUser.user),20 ])2122 const formattedUpcomingBookings = upcomingBookings.docs.map((booking) => ({23 ...(booking.post as Pick<Post, 'meta' | 'slug' | 'title'>),24 fromDate: booking.fromDate,25 toDate: booking.toDate,26 guests: booking.guests?.map(guest => typeof guest === 'number' ? guest.toString() : guest) || null,27 id: booking.id.toString(),28 }))2930 const formattedPastBookings = pastBookings.docs.map((booking) => ({31 ...(booking.post as Pick<Post, 'meta' | 'slug' | 'title'>),32 fromDate: booking.fromDate,33 toDate: booking.toDate,34 guests: booking.guests,35 id: booking.id,36 }))3738 console.log(upcomingBookings, pastBookings)3940 return (41 <>42 <PageClient />43 <div className="my-10 container space-y-10">44 <div>45 {upcomingBookings.docs.length > 0 && (46 <h2 className="text-4xl font-medium tracking-tighter my-6">Upcoming stays</h2>47 )}4849 <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2">50 {formattedUpcomingBookings.map((booking) => (51 <BookingCard key={booking.id} booking={booking} />52 ))}53 </div>54 </div>5556 {pastBookings.docs.length > 0 && (57 <h2 className="text-4xl font-medium tracking-tighter my-6">Past stays</h2>58 )}5960 <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2">61 {formattedPastBookings.map((booking) => (62 <BookingCard key={booking.id} booking={booking} />63 ))}64 </div>65 </div>66 </>67 )68}6970const getBookings = async (type: 'upcoming' | 'past', currentUser: User) => {71 const payload = await getPayload({ config })7273 let whereQuery: Where7475 if (type === 'upcoming') {76 whereQuery = {77 and: [78 {79 fromDate: {80 greater_than_equal: new Date(),81 },82 },83 {84 customer: {85 equals: currentUser.id,86 },87 },88 ],89 }90 } else {91 whereQuery = {92 and: [93 {94 fromDate: {95 less_than: new Date(),96 },97 },98 {99 customer: {100 equals: currentUser.id,101 },102 },103 ],104 }105 }106107 const bookings = await payload.find({108 collection: 'bookings',109 limit: 100,110 where: whereQuery,111 depth: 2,112 sort: '-fromDate',113 select: {114 slug: true,115 post: true,116 guests: true,117 fromDate: true,118 toDate: true,119 },120 })121122 return bookings123}

Folder structure becomes the taxonomy
To create a booking collection comprises of 2 files predominately
Brackets () are omitted - Front end
|_ π app
| |_ π (frontend)
| | |_ π bookings
| | | |_ π page.client.tsx
| | | |_ π page.tsx
|_ π (payload)
|_ π collections
|_ π paylaod types.ts
|_ π payload.config.ts
Back-end collection
src/collections/policy/index.ts
1import { adminOrSelf } from '@/access/adminOrSelf'2import { adminOrSelfField } from '@/access/adminOrSelfField'3import { isAdmin } from '@/access/isAdmin'4import { isAdminField } from '@/access/isAdminField'5import { slugField } from '@/fields/slug'6import { CollectionConfig } from 'payload'7import { adminOrSelfOrGuests } from './access/adminOrSelfOrGuests'89export const Policy: CollectionConfig = {10 slug: 'policys',11 labels: {12 singular: 'Policy',13 plural: 'Policys',14 },15 typescript: {16 interface: 'Policy',17 },18 admin: {19 useAsTitle: 'title',20 defaultColumns: ['title', 'fromDate', 'toDate', 'slug', 'customer'],21 },22 access: {23 read: adminOrSelfOrGuests('customer', 'guests'),24 create: isAdmin,25 delete: isAdmin,26 },27 fields: [28 {29 name: 'title',30 label: 'Title',31 type: 'text',32 required: true,33 access: {34 update: isAdminField,35 },36 },37 {38 name: 'customer',39 type: 'relationship',40 relationTo: 'users',41 filterOptions: {42 role: {43 equals: 'customer',44 },45 },46 access: {47 update: isAdminField,48 },49 },50 {51 name: 'guests',52 type: 'relationship',53 hasMany: true,54 relationTo: 'users',55 access: {56 update: adminOrSelfField('customer'),57 },58 admin: {59 isSortable: true,60 },61 },62 ...slugField('title', {63 checkboxOverrides: {64 access: {65 update: isAdminField,66 },67 },68 slugOverrides: {69 access: {70 update: isAdminField,71 },72 },73 }),74 {75 name: 'post',76 relationTo: 'posts',77 type: 'relationship',78 required: true,79 access: {80 update: isAdminField,81 },82 },83 {84 name: 'paymentStatus',85 label: 'Payment Status',86 type: 'select',87 admin: {88 position: 'sidebar',89 },90 options: [91 {92 label: 'Paid',93 value: 'paid',94 },95 {96 label: 'Unpaid',97 value: 'unpaid',98 },99 ],100 access: {101 update: isAdminField,102 },103 },104 {105 name: 'fromDate',106 type: 'date',107 required: true,108 index: true,109 label: 'Check-in Date',110 admin: {111 position: 'sidebar',112 date: {113 pickerAppearance: 'dayAndTime',114 },115 },116 access: {117 update: isAdminField,118 },119 },120 {121 name: 'toDate',122 type: 'date',123 required: true,124 label: 'Check-out Date',125 admin: {126 position: 'sidebar',127 date: {128 pickerAppearance: 'dayAndTime',129 },130 },131 access: {132 update: isAdminField,133 },134 },135 ],136}137


Front end template: [src/ui/frontend/index.ts]

Add a component to your design system. Use a hooks to join/relate User Agreement creating the ideal unchallenged User experience

Subscription payment and Sharing the policy using a protected route with a paywall to ensure privacy of users the payment is intended for