Skip to content

Commit

Permalink
828 frontend dynamically fetch lodge prices on frontend (#829)
Browse files Browse the repository at this point in the history
* fetch prices dynamically

* add docs

* refactor and add docs

* fetch prices dynamically

* add docs

* refactor and add docs

* update stories
  • Loading branch information
choden-dev authored Nov 12, 2024
1 parent 19aaa01 commit ce3a190
Show file tree
Hide file tree
Showing 14 changed files with 186 additions and 44 deletions.
10 changes: 9 additions & 1 deletion client/src/app/Home.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,13 @@ const meta: Meta<typeof HomeComponent> = {
export default meta

export const DefaultHomePage = () => {
return <HomeComponent pricingData={[]} />
return (
<HomeComponent
membershipPricingData={[]}
lodgePricing={{
normal: 69,
moreExpensive: 420
}}
/>
)
}
35 changes: 29 additions & 6 deletions client/src/app/HomeComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
import { Footer } from "@/components/generic/Footer/Footer"
import { HomePage } from "@/models/sanity/HomePage/Utils"
import { Prices } from "@/services/AppData/AppDataService"
import {
LodgePricingProps,
MembershipPrices
} from "@/services/AppData/AppDataService"
import AboutSection from "./sections/AboutSection"
import BenefitSection from "./sections/BenefitSection"
import LandingSection from "./sections/LandingSection"
import PricingSection from "./sections/PricingSection"
import { benefits } from "./sections/utils/Benefits"
import { pricingBannerContent } from "./sections/utils/Pricing"
import { lodgeBookingPricingBannerMessages } from "./sections/utils/Pricing"

export type HomeProps = {
pricingData: Prices[]
/**
* Fetched prices for how much each type of membership costs
*/
membershipPricingData: MembershipPrices[]
/**
* Fetched prices showing how much it costs to book the lodge
*/
lodgePricing: LodgePricingProps
content?: HomePage
}

/**
* @deprecated do not use, use `WrappedHomeComponent` instead
*/
const HomeComponent = ({ pricingData, content }: HomeProps) => {
const HomeComponent = ({
membershipPricingData,
lodgePricing,
content
}: HomeProps) => {
return (
<>
<div>
Expand All @@ -35,8 +49,17 @@ const HomeComponent = ({ pricingData, content }: HomeProps) => {
/>
<PricingSection
note={content?.pricing?.discount}
pricings={pricingData}
bannerContent={pricingBannerContent}
pricings={membershipPricingData}
bannerContent={{
headline: lodgeBookingPricingBannerMessages.headline,
priceInformation:
lodgeBookingPricingBannerMessages.priceInformation(
lodgePricing.normal
),
disclaimer: lodgeBookingPricingBannerMessages.priceInformation(
lodgePricing.moreExpensive
)
}}
/>
</div>
<div className="pt-14">
Expand Down
3 changes: 3 additions & 0 deletions client/src/app/bookings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import { PortableText } from "@portabletext/react"
import { Policies, POLICIES_GROQ_QUERY } from "@/models/sanity/Policies/Utils"
import BookingPolicyStorage from "./BookingPolicyStorage"
import { PolicyWithTextBlocks } from "@/components/composite/Booking/BookingContext"
import AppDataService from "@/services/AppData/AppDataService"

const BookingPage = async () => {
const lodgeInfo = await sanityQuery<LodgeInformation[]>(
LODGE_INFORMATION_GROQ_QUERY
)

const lodgePrices = await AppDataService.getLodgePrices()
/**
* We assume there will be only one based on the way {@link LodgeInformation}
* is set up in sanity
Expand Down Expand Up @@ -55,6 +57,7 @@ const BookingPage = async () => {
<>
<BookingInformationAndCreation
enableNetworkRequests
lodgePricing={lodgePrices}
lodgeInfoProps={{
children: <RenderedContent />,
imageSrcs: processedImages
Expand Down
15 changes: 11 additions & 4 deletions client/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import AppDataService, { Prices } from "@/services/AppData/AppDataService"
import AppDataService, {
MembershipPrices
} from "@/services/AppData/AppDataService"
import HomeComponent from "./HomeComponent"
import { sanityQuery } from "../../sanity/lib/utils"
import { HOME_PAGE_GROQ_QUERY, HomePage } from "@/models/sanity/HomePage/Utils"

const Home = async () => {
let pricingData: Prices[]
let pricingData: MembershipPrices[]
try {
pricingData = await AppDataService.getMembershipPricingDetails()
} catch (e) {
pricingData = []
}

const lodgePricing = await AppDataService.getLodgePrices()

const [content] = await sanityQuery<HomePage[]>(HOME_PAGE_GROQ_QUERY)
console.log(content)

return (
<>
<HomeComponent pricingData={pricingData} content={content} />
<HomeComponent
membershipPricingData={pricingData}
content={content}
lodgePricing={lodgePricing}
/>
</>
)
}
Expand Down
12 changes: 8 additions & 4 deletions client/src/app/sections/PricingSection.story.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Meta } from "@storybook/react"

import PricingSection from "./PricingSection"
import { pricingBannerContent, pricingNote } from "./utils/Pricing"
import { HomeProps } from "../HomeComponent"

const meta: Meta<typeof PricingSection> = {
Expand All @@ -10,12 +9,17 @@ const meta: Meta<typeof PricingSection> = {

export default meta

export const DefaultPricingSection = ({ pricingData: data }: HomeProps) => {
export const DefaultPricingSection = ({
membershipPricingData: data
}: HomeProps) => {
return (
<PricingSection
pricings={data}
note={pricingNote}
bannerContent={pricingBannerContent}
note={"THis is an optional disclaimer"}
bannerContent={{
priceInformation: "asdkjasdjkaslk",
headline: "LOL STRAIGHT ZHAO"
}}
/>
)
}
6 changes: 3 additions & 3 deletions client/src/app/sections/PricingSection.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import PricingBanner from "@/components/generic/PricingBanner/PricingBanner"
import PricingCard from "@/components/generic/PricingCard/PricingCard"
import { PricingBannerContent } from "@/components/utils/types"
import { Prices } from "@/services/AppData/AppDataService"
import { MembershipPrices } from "@/services/AppData/AppDataService"
import Link from "next/link"
import HomeSectionHeading from "./utils/HomeSectionHeading"
import HomeSectionWrapper from "./utils/HomeSectionWrapper"

interface IPricingSection {
note?: string
pricings: Prices[]
bannerContent?: PricingBannerContent
pricings: MembershipPrices[]
bannerContent: PricingBannerContent
}

const PricingSection = ({ note, pricings, bannerContent }: IPricingSection) => (
Expand Down
37 changes: 28 additions & 9 deletions client/src/app/sections/utils/Pricing.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
import { Pricing, PricingBannerContent } from "@/components/utils/types"
import { MembershipPricing } from "@/components/utils/types"

export const pricingNote =
"*We have a discounted membership price on offer until Sunday 17th March so lock in now for a year of awesome memories!"
/**
* An object containing messages for the pricing banner.
*/
export const lodgeBookingPricingBannerMessages = {
/**
* The headline message for the pricing banner.
*/
headline: "Great nightly rates" as const,

export const pricingBannerContent: PricingBannerContent = {
headline: "Great nightly rates",
priceInformation: "$40 per night*",
disclaimer: "*$60 when booking a single Friday or Saturday"
}
/**
* A function that returns a formatted price information string.
*
* @param {number} normalPrice - The normal price per night.
* @returns {string} The formatted price information string.
*/
priceInformation: (normalPrice: number) =>
`$${normalPrice} per night*` as const,

export const Pricings: Pricing[] = [
/**
* A function that returns a formatted disclaimer message.
*
* @param {number} moreExpensivePrice - The price when booking a single Friday or Saturday.
* @returns {string} The formatted disclaimer message.
*/
disclaimer: (moreExpensivePrice: number) =>
`*$${moreExpensivePrice} when booking a single Friday or Saturday` as const
} as const

export const MembershipPricings: MembershipPricing[] = [
{
title: "UoA Student",
discountedPrice: "$45",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,10 @@ type Story = StoryObj<typeof meta>

export const DefaultCreateBookingPage: Story = {
decorators: [(Story) => <Story />],
args: {}
args: {
lodgePrices: {
normal: 69,
moreExpensive: 420
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { Timestamp } from "firebase/firestore"
import Checkbox from "@/components/generic/Checkbox/Checkbox"
import { DateRange, DateUtils } from "@/components/utils/DateUtils"
import { LodgePricingProps } from "@/services/AppData/AppDataService"

/*
* Swaps around dates if invalid
Expand Down Expand Up @@ -67,10 +68,9 @@ export interface ICreateBookingSection {
* If a request related to creating/fetching a booking is in progress
*/
isPending?: boolean
}

const NORMAL_PRICE = 40 as const
const SPECIAL_PRICE = 60 as const
lodgePrices: LodgePricingProps
}

/**
* A notification to the user informing the actual
Expand Down Expand Up @@ -110,13 +110,20 @@ export const CreateBookingSection = ({
handleBookingCreation,
handleAllergyChange,
hasExistingSession,
isPending
isPending,
lodgePrices
}: ICreateBookingSection) => {
const [selectedDateRange, setSelectedDateRange] = useState<DateRange>({
startDate: new Date(),
endDate: new Date()
})

/**
* Derive prices from the props
*/
const NORMAL_PRICE = lodgePrices.normal
const SPECIAL_PRICE = lodgePrices.moreExpensive

const [isValidForCreation, setIsValidForCreation] = useState<boolean>(false)

const { startDate: currentStartDate, endDate: currentEndDate } =
Expand Down Expand Up @@ -220,7 +227,7 @@ export const CreateBookingSection = ({
: NORMAL_PRICE

return `$${requiredPrice} * ${nights} night${nights > 1 ? "s" : ""} = $${requiredPrice * nights}` as const
}, [currentStartDate, currentEndDate])
}, [currentStartDate, currentEndDate, SPECIAL_PRICE, NORMAL_PRICE])

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
import { useAppData } from "@/store/Store"
import { SignUpNotif } from "@/components/generic/SignUpNotif/SignUpNotif"
import { useAvailableBookingsQuery } from "@/services/Booking/BookingQueries"
import { CreateBookingSection } from "./BookingCreation"
import { CreateBookingSection, ICreateBookingSection } from "./BookingCreation"
import { useContext, useEffect } from "react"
import { BookingContext } from "../BookingContext"

/**
* @deprecated not for direct consumption on pages, use `BookingInformationAndCreation` instead
*/
export const ProtectedCreateBookingSection = () => {
export const ProtectedCreateBookingSection = ({
lodgePrices
}: Pick<ICreateBookingSection, "lodgePrices">) => {
const [{ currentUser, currentUserClaims }] = useAppData()

const { data } = useAvailableBookingsQuery()
Expand Down Expand Up @@ -38,6 +40,7 @@ export const ProtectedCreateBookingSection = () => {
handleAllergyChange={setAllergies}
hasExistingSession={!!clientSecret}
isPending={isPending}
lodgePrices={lodgePrices}
/>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "../BookingCreation/BookingCreation"
import { ProtectedCreateBookingSection } from "../BookingCreation/ProtectedCreateBookingSection"
import { useSearchParams } from "next/navigation"
import { LodgePricingProps } from "@/services/AppData/AppDataService"

/**
* Utility type determining what should be displayed to the user in {@link BookingInformationAndCreation}
Expand All @@ -34,6 +35,11 @@ interface IBookingInformationAndCreation {
* uses the implementation of{@link CreateBookingSection}
*/
enableNetworkRequests?: boolean

/**
* How much each the different types of bookings cost, based on {@link LodgePricingProps}
*/
lodgePricing: LodgePricingProps
}

/**
Expand All @@ -43,7 +49,8 @@ interface IBookingInformationAndCreation {
const BookingInformationAndCreation = ({
bookingCreationProps,
lodgeInfoProps,
enableNetworkRequests
enableNetworkRequests,
lodgePricing
}: IBookingInformationAndCreation) => {
const params = useSearchParams()

Expand All @@ -66,9 +73,14 @@ const BookingInformationAndCreation = ({
)
case "booking-creation":
if (enableNetworkRequests) {
return <ProtectedCreateBookingSection />
return <ProtectedCreateBookingSection lodgePrices={lodgePricing} />
} else {
return <CreateBookingSection {...bookingCreationProps} />
return (
<CreateBookingSection
{...bookingCreationProps}
lodgePrices={lodgePricing}
/>
)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/utils/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type Benefit = {
/**
* For use with the pricing cards that have the `home` variant
*/
export type Pricing = {
export type MembershipPricing = {
title: string
originalPrice?: string
discountedPrice: string
Expand Down
Loading

0 comments on commit ce3a190

Please sign in to comment.