Skip to content

Commit

Permalink
feat: Payments thank you page (#6961)
Browse files Browse the repository at this point in the history
* feat: add payment thank you page

* change feedback form title for payment forms

* making fixes after review

* removing formId from FeedbackBlock page

---------

Co-authored-by: Kathleen Koh <[email protected]>
  • Loading branch information
kathleenkhy and Kathleen Koh authored Dec 20, 2023
1 parent 9397030 commit 1d9dd47
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import FormErrorMessage from '~components/FormControl/FormErrorMessage'
import FormLabel from '~components/FormControl/FormLabel'
import Textarea from '~components/Textarea'

import { usePublicFormContext } from '~features/public-form/PublicFormContext'

export type FeedbackFormInput = {
rating: number
comment?: string
Expand All @@ -34,6 +36,12 @@ export const FeedbackBlock = ({

const handleFormSubmit = handleSubmit((inputs) => onSubmit(inputs))

const { isPaymentEnabled } = usePublicFormContext()

const feedbackTitle = isPaymentEnabled
? 'How was your experience making payment on this form?'
: 'How was your form filling experience today?'

const colorScheme = useMemo(() => {
return `theme-${colorTheme}` as const
}, [colorTheme])
Expand All @@ -43,7 +51,7 @@ export const FeedbackBlock = ({
<chakra.form w="100%" maxW="100%" noValidate onSubmit={handleFormSubmit}>
<FormControl isInvalid={!!errors.rating} id="rating">
<FormLabel isRequired color="content.strong">
How was your form filling experience today?
{feedbackTitle}
</FormLabel>
<Controller
rules={{ required: 'Please select a rating' }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const PaymentStack = ({ children }: { children: React.ReactNode }) => (
spacing={{ base: '1.5rem', md: '2.25rem' }}
py={{ base: '1.5rem', md: '3rem' }}
px={{ base: '1.5rem', md: '4rem' }}
bg="white"
bg="grey.100"
w="100%"
divider={<Divider />}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,18 @@ import { chakra } from '@chakra-ui/react'

export const PaymentSuccessSvgr = chakra((props: SVGProps<SVGSVGElement>) => (
<svg
width={283}
height={165}
width="64"
height="64"
viewBox="0 0 64 64"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M1.074 12.18C1.074 6.005 6.08 1 12.254 1h258.783c6.175 0 11.18 5.005 11.18 11.18V165H1.074V12.18Z"
fill="#FBFCFD"
/>
<path
d="M272.069 1.094H12.112A10.963 10.963 0 0 0 1.249 12.157v6.883h281.676v-6.883c.056-6.053-4.804-11.005-10.856-11.063Z"
fill="#000"
/>
<ellipse cx={15.96} cy={10.073} rx={1.733} ry={1.765} fill="#fff" />
<ellipse cx={26.653} cy={10.073} rx={1.733} ry={1.765} fill="#fff" />
<ellipse cx={37.353} cy={10.073} rx={1.733} ry={1.765} fill="#fff" />
<path d="M1.256 19.059h281.669v4.461H1.255v-4.461Z" fill="#C9CCCF" />
<rect
x={45.769}
y={109.338}
width={67.474}
height={192.825}
rx={4.51}
transform="rotate(-90 45.769 109.338)"
fill="#E4E7F6"
/>
<rect
x={45.769}
y={129.77}
width={9.577}
height={192.825}
rx={4.51}
transform="rotate(-90 45.769 129.77)"
fill="#E4E7F6"
/>
<rect
x={45.769}
y={150.202}
width={9.577}
height={192.825}
rx={4.51}
transform="rotate(-90 45.769 150.202)"
fill="#E4E7F6"
/>
<circle
cx={142.338}
cy={75.727}
r={18.498}
fill="#05CC9A"
stroke="#000"
strokeWidth={0.638}
/>
<path
transform="rotate(42.529 -31.564 208.703) skewX(.036)"
stroke="#000"
strokeWidth={0.638}
d="M0-.319h8.672"
/>
<path
transform="rotate(-45.018 168.638 -126.857)"
stroke="#000"
strokeWidth={0.638}
d="M0-.319h18.082"
/>
<path
d="M282.217 165V12.18c0-6.175-5.005-11.18-11.18-11.18H12.254C6.08 1 1.074 6.005 1.074 12.18V165"
stroke="#000"
strokeWidth={0.638}
/>
<g id="Icon/check-circle-solid">
<path
id="Vector"
d="M32.0006 5.33203C17.2967 5.33203 5.33398 17.2947 5.33398 31.9987C5.33398 46.7027 17.2967 58.6654 32.0006 58.6654C46.7046 58.6654 58.6673 46.7027 58.6673 31.9987C58.6673 17.2947 46.7046 5.33203 32.0006 5.33203ZM26.67 43.7667L16.7687 33.8867L20.534 30.1107L26.6646 36.2307L40.782 22.1134L44.5527 25.884L26.67 43.7667Z"
fill="#05CC9A"
/>
</g>
</svg>
))
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useState } from 'react'
import { Stack, useToast } from '@chakra-ui/react'
import { Box, Stack, useToast } from '@chakra-ui/react'

import { FormPaymentsField, ProductItem } from '~shared/types'

Expand Down Expand Up @@ -74,7 +74,7 @@ export const StripeReceiptContainer = ({
/**
* PaymentStack is explictly added in this component due to https://github.com/chakra-ui/chakra-ui/issues/6757
*/
<Stack spacing="1.5rem">
<Stack>
<PaymentStack>
<DownloadReceiptBlock
formId={formId}
Expand All @@ -89,7 +89,9 @@ export const StripeReceiptContainer = ({
</PaymentStack>
<PaymentStack>
{!isFeedbackSubmitted && (
<FeedbackBlock onSubmit={handleSubmitFeedback} />
<Box backgroundColor="white" p="2rem">
<FeedbackBlock onSubmit={handleSubmitFeedback} />
</Box>
)}
</PaymentStack>
</Stack>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { useMemo } from 'react'
import { BiDownload } from 'react-icons/bi'
import { Box, Divider, Stack, Text } from '@chakra-ui/react'
import { Box, Divider, Flex, Stack, Text } from '@chakra-ui/react'
import { format } from 'date-fns'

import { PaymentType, ProductItem } from '~shared/types'
import {
ExtractTypeFromArray,
GetPaymentInfoDto,
PaymentType,
ProductItem,
} from '~shared/types'
import { centsToDollars } from '~shared/utils/payments'

import { useToast } from '~hooks/useToast'
Expand All @@ -22,7 +27,7 @@ type DownloadReceiptBlockProps = {
paymentDate: Date | null
}

const PaymentSummaryRow = ({
const PaymentDetailsRow = ({
title,
input,
}: {
Expand All @@ -34,22 +39,59 @@ const PaymentSummaryRow = ({
direction={{ base: 'column', md: 'row' }}
spacing={{ base: 0, md: '1.5rem' }}
>
<Text textStyle="body-2" width="6.5rem" color="content.medium">
<Text textStyle="body-1" width="6.5rem" color="secondary.400">
{title}
</Text>
<Text textStyle="body-1" color="secondary.700">
{input}
</Text>
</Stack>
)
}

const PaymentSummaryRow = ({
title,
input,
}: {
title: string
input: string
}): JSX.Element => {
return (
<Stack
direction="row"
spacing={{ base: 0, md: '3rem' }}
justify="space-between"
>
<Text
textStyle="body-1"
width="6.5rem"
color="secondary.700"
fontWeight="400"
>
{title}
</Text>
<Text textStyle="body-2" color="content.default">
<Text textStyle="body-1" color="secondary.700" fontWeight="500">
{input}
</Text>
</Stack>
)
}

// Extract selected product names for payment by products
const getProductNames = (products: ProductItem[]): string => {
return products
.filter((product) => product.selected)
.map((product) => `${product.data.name} x ${product.quantity}`)
.join(', ')
const LineItem = ({
productItem,
}: {
productItem: ExtractTypeFromArray<NonNullable<GetPaymentInfoDto['products']>>
}) => {
return (
<Flex textStyle={'body-1'} mb="1rem" justifyContent={'space-between'}>
<Text fontWeight="400" color="secondary.700">
{productItem.data.name} x {productItem.quantity}
</Text>
<Text fontWeight="500" color="secondary.700">
S${centsToDollars(productItem.quantity * productItem.data.amount_cents)}
</Text>
</Flex>
)
}

export const DownloadReceiptBlock = ({
Expand All @@ -64,16 +106,14 @@ export const DownloadReceiptBlock = ({
}: DownloadReceiptBlockProps) => {
const toast = useToast({ status: 'success', isClosable: true })

const formattedAmount = useMemo(() => `S$${centsToDollars(amount)}`, [amount])
const totalAmount = useMemo(() => `S$${centsToDollars(amount)}`, [amount])
const paymentTimestamp = useMemo(
() =>
paymentDate
? format(new Date(paymentDate), 'dd MMM yyyy, HH:mm:ss z')
: 'Payment date not found',
[paymentDate],
)
const productName =
paymentType === PaymentType.Products ? getProductNames(products) : name

const handleInvoiceClick = () => {
toast({
Expand All @@ -82,36 +122,59 @@ export const DownloadReceiptBlock = ({
window.location.href = getPaymentInvoiceDownloadUrl(formId, paymentId)
}
return (
<Box>
<Stack spacing="2rem">
<>
<Box bg="white" p="2rem">
<Stack tabIndex={-1} spacing="0.75rem">
<Text textStyle="h2" color="content.strong">
Your payment has been made successfully.
<Text textStyle="h2" color="secondary.500">
Thank you, your payment has been made successfully.
</Text>
<Text textStyle="subhead-1" color="content.strong">
<Text textStyle="subhead-1" color="secondary.500">
Your form has been submitted and payment has been made.
</Text>
</Stack>
<Divider />
</Box>
<Box mt="2rem" px="1rem" py="2rem" bgColor="white">
<Stack>
<Text textStyle="h2" mb="0.5rem" color="content.strong">
Payment summary
</Text>
<PaymentSummaryRow title="Product/service" input={productName} />
<PaymentSummaryRow title="Amount" input={formattedAmount} />
<PaymentSummaryRow title="Date" input={paymentTimestamp} />
<PaymentSummaryRow title="Response ID" input={submissionId} />
<Box mb="1.5rem" px="1.5rem">
<Text textStyle="h2" mb="0.5rem" color="secondary.500">
Payment details
</Text>
<PaymentDetailsRow title="Payment date" input={paymentTimestamp} />
<PaymentDetailsRow title="Response ID" input={submissionId} />
</Box>
<Box
bgColor="primary.100"
flexDir="row"
justifyContent="space-between"
mb="1rem"
py="1rem"
px="1.5rem"
>
<Text textStyle="h2" mb="0.5rem" color="secondary.500">
Summary
</Text>
<Stack spacing="0.75rem" my="1rem">
{products.map((product) => (
<LineItem productItem={product} />
))}
</Stack>
<Divider />
<Stack my="1rem">
<PaymentSummaryRow title="Total" input={totalAmount} />
</Stack>
</Box>
</Stack>
</Stack>

<Button
mt="2.75rem"
width={{ base: '100%', md: 'auto' }}
leftIcon={<BiDownload fontSize="1.5rem" />}
onClick={handleInvoiceClick}
>
Save proof of payment
</Button>
</Box>
<Stack mx={{ base: '0', md: '1.5rem' }} mt="1.5rem">
<Button
w="100%"
leftIcon={<BiDownload fontSize="1.5rem" />}
onClick={handleInvoiceClick}
>
Save proof of payment
</Button>
</Stack>
</Box>
</>
)
}

0 comments on commit 1d9dd47

Please sign in to comment.