Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: payment banners on landing and login pages #6431

Merged
merged 10 commits into from
Jun 8, 2023
4 changes: 3 additions & 1 deletion frontend/src/components/Banner/Banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ export interface BannerProps {
children: string
useMarkdown?: boolean
showCloseButton?: boolean
bannerColor?: string
}

export const Banner = ({
variant = 'info',
children,
useMarkdown = false,
showCloseButton,
bannerColor,
}: BannerProps): JSX.Element => {
const { isOpen, onToggle } = useDisclosure({
defaultIsOpen: true,
Expand All @@ -45,7 +47,7 @@ export const Banner = ({

return (
<Collapse style={{ overflow: 'visible' }} in={isOpen} animateOpacity>
<Box __css={styles.banner}>
<Box __css={styles.banner} bgColor={bannerColor}>
KenLSM marked this conversation as resolved.
Show resolved Hide resolved
<Flex sx={styles.item}>
<Flex>
<Icon
Expand Down
89 changes: 89 additions & 0 deletions frontend/src/components/FeatureBanner/FeatureBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import {
Box,
Center,
Flex,
Text,
useMultiStyleConfig,
VStack,
} from '@chakra-ui/react'

import { BannerVariant } from '~theme/components/Banner'
import { useIsMobile } from '~hooks/useIsMobile'
import Button from '~components/Button'

import { textStyles } from '../../theme/textStyles'

export interface FeatureBannerProps {
variant?: BannerVariant
bannerColorIntensity?: 500 | 600 // Update accordingly if other banner colors are needed
title?: string
body: string
learnMoreLink: string
}

export const FeatureBanner = ({
variant = 'info',
bannerColorIntensity = 500,
title,
body,
learnMoreLink,
}: FeatureBannerProps): JSX.Element => {
const isMobile = useIsMobile()
const styles = useMultiStyleConfig('Banner', { variant })

const LearnMoreButton = () => (
<Button
sx={{
...styles.button,
...(title ? textStyles['subhead-1'] : textStyles['subhead-2']),
minHeight: 'auto',
}}
variant="solid"
as="a"
href={learnMoreLink}
target="_blank"
borderColor="white"
bg="transparent"
_hover={{
color: 'white',
borderColor: 'white',
bg: `primary.${bannerColorIntensity - 100}`,
}}
>
Learn more
</Button>
)

return (
<Box __css={styles.banner} bgColor={`primary.${bannerColorIntensity}`}>
<Flex
sx={styles.item}
placeContent={title ? undefined : 'center'}
mx={isMobile ? '0.5rem' : '2rem'}
my={title ? (isMobile ? '0.5rem' : '1.5rem') : undefined}
>
<VStack
mr={isMobile ? undefined : '1.5rem'}
align={title ? 'flex-start' : undefined}
justifyContent="center"
spacing="auto"
>
{title && (
<Text as="h5" textStyle="h5" mb="0.25rem">
{title}
</Text>
)}
<Text as="h6" textStyle="h6" pb={isMobile ? '1.25rem' : undefined}>
{body}
</Text>
{isMobile ? <LearnMoreButton /> : null}
</VStack>
{isMobile ? null : (
<Center>
<LearnMoreButton />
</Center>
)}
</Flex>
</Box>
)
}
2 changes: 2 additions & 0 deletions frontend/src/constants/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export const GUIDE_EMAIL_RELIABILITY =
export const GUIDE_PREFILL = 'https://go.gov.sg/formsg-guide-prefills'
export const GUIDE_STRIPE_ONBOARDING =
'https://go.gov.sg/formsg-stripe-onboarding'
export const GUIDE_PAYMENTS_PUBLIC = 'https://go.gov.sg/formsg-guide-payments'
export const GUIDE_PAYMENTS_ENTRY = 'https://go.gov.sg/formsg-payment-overview'

export const ACCEPTED_FILETYPES_SPREADSHEET = 'https://go.gov.sg/formsg-cwl'

Expand Down
16 changes: 15 additions & 1 deletion frontend/src/features/login/LoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import { Box, chakra, Flex, GridItem, GridProps, Text } from '@chakra-ui/react'
import { AppFooter } from '~/app/AppFooter'

import { ReactComponent as BrandLogoSvg } from '~assets/svgs/brand/brand-hort-colour.svg'
import { GUIDE_PAYMENTS_PUBLIC } from '~constants/links'
import { LOGGED_IN_KEY } from '~constants/localStorage'
import { LANDING_ROUTE } from '~constants/routes'
import { useLocalStorage } from '~hooks/useLocalStorage'
import { getBannerProps } from '~utils/getBannerProps'
import { sendLoginOtp, verifyLoginOtp } from '~services/AuthService'
import { Banner } from '~components/Banner'
import { FeatureBanner } from '~components/FeatureBanner/FeatureBanner'
import Link from '~components/Link'
import { AppGrid } from '~templates/AppGrid'

Expand Down Expand Up @@ -149,13 +151,25 @@ export const LoginPage = (): JSX.Element => {
await sendLoginOtp(email).then(({ otpPrefix }) => setOtpPrefix(otpPrefix))
}

const bannerColorIntensity = 600
const bannerColor = `primary.${bannerColorIntensity}` // So banner colors are different from the blue background (left of login screen).

return (
<BackgroundBox>
{bannerProps ? (
<Banner useMarkdown variant={bannerProps.variant}>
<Banner
useMarkdown
variant={bannerProps.variant}
bannerColor={bannerColor}
>
{bannerProps.msg}
</Banner>
) : null}
<FeatureBanner
bannerColorIntensity={bannerColorIntensity}
body="You can now collect payments directly on your form!"
learnMoreLink={GUIDE_PAYMENTS_PUBLIC}
/>
<BaseGridLayout flex={1}>
<NonMobileSidebarGridArea>
<LoginImageSvgr maxW="100%" aria-hidden />
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/features/rollout-announcement/Announcements.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { GUIDE_PAYMENTS_ENTRY } from '~constants/links'

import PaymentsAnnouncementGraphic from './assets/payments.json'

// When updating this, remember to update the ROLLOUT_ANNOUNCEMENT_KEY_PREFIX with the new date
Expand All @@ -8,7 +10,7 @@ export const NEW_FEATURES = [
title: 'Collect payments on your form',
description:
'Citizens can now pay for fees and services directly on your form! We integrate with Stripe to provide reliable payments and hassle-free reconciliations. Payment methods we support include debit / credit cards and PayNow.',
learnMoreLink: 'https://go.gov.sg/formsg-payment-overview',
learnMoreLink: GUIDE_PAYMENTS_ENTRY,
LinHuiqing marked this conversation as resolved.
Show resolved Hide resolved
animationData: PaymentsAnnouncementGraphic,
},
]
5 changes: 3 additions & 2 deletions frontend/src/features/whats-new/FeatureUpdateList.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import dedent from 'dedent'
import { JsonObject, RequireExactlyOne } from 'type-fest'

import { GUIDE_PAYMENTS_ENTRY } from '~constants/links'

import Animation1 from './assets/1-payments.json'
import Animation2 from './assets/2-search-and-filter.json'
import Animation3 from './assets/3-dnd.json'
Expand Down Expand Up @@ -33,8 +35,7 @@ export const FEATURE_UPDATE_LIST: FeatureUpdateList = {
{
title: 'Collect payments on your form',
date: new Date('31 May 2023 GMT+8'),
description:
'Citizens can now pay for fees and services directly on your form! We integrate with Stripe to provide reliable payments and hassle-free reconciliations. Payment methods we support include debit / credit cards and PayNow. [Learn more](https://go.gov.sg/formsg-payment-overview)',
description: `Citizens can now pay for fees and services directly on your form! We integrate with Stripe to provide reliable payments and hassle-free reconciliations. Payment methods we support include debit / credit cards and PayNow. [Learn more](${GUIDE_PAYMENTS_ENTRY})`,
image: {
animationData: Animation1,
alt: 'Collect payments on your form',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMemo } from 'react'
import { Box, Container, Grid } from '@chakra-ui/react'

import { GUIDE_PAYMENTS_ENTRY } from '~constants/links'
import { ROLLOUT_ANNOUNCEMENT_KEY_PREFIX } from '~constants/localStorage'
import { useLocalStorage } from '~hooks/useLocalStorage'
import InlineMessage from '~components/InlineMessage'
Expand Down Expand Up @@ -39,6 +40,8 @@ export const WorkspacePageContent = ({
[isUserLoading, hasSeenAnnouncement],
)

const dashboardMessage = `Introducing payments! Citizens can now pay for fees and services directly on your form. [Learn more](${GUIDE_PAYMENTS_ENTRY})`

return totalFormsCount === 0 ? (
<EmptyWorkspace
handleOpenCreateFormModal={handleCreateFormModalOpen}
Expand All @@ -62,9 +65,7 @@ export const WorkspacePageContent = ({
py="1rem"
>
<InlineMessage useMarkdown mb="2rem" mx="-2rem">
Introducing payments! Citizens can now pay for fees and services
directly on your form. [Learn
more](https://go.gov.sg/formsg-payment-overview)
{dashboardMessage}
</InlineMessage>
<WorkspaceHeader
handleOpenCreateFormModal={handleCreateFormModalOpen}
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/pages/Landing/LandingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
FORM_GUIDE,
GUIDE_ATTACHMENT_SIZE_LIMIT,
GUIDE_E2EE,
GUIDE_PAYMENTS_PUBLIC,
GUIDE_SECRET_KEY_LOSS,
GUIDE_STORAGE_MODE,
GUIDE_TRANSFER_OWNERSHIP,
Expand All @@ -43,6 +44,7 @@ import { LOGIN_ROUTE } from '~constants/routes'
import { useIsMobile } from '~hooks/useIsMobile'
import { useMdComponents } from '~hooks/useMdComponents'
import Button from '~components/Button'
import { FeatureBanner } from '~components/FeatureBanner/FeatureBanner'
import Link from '~components/Link'
import { MarkdownText } from '~components/MarkdownText'
import { Tab } from '~components/Tabs'
Expand Down Expand Up @@ -89,6 +91,11 @@ export const LandingPage = (): JSX.Element => {

return (
<>
<FeatureBanner
title="Introducing Payments"
body="Citizens can now pay for fees and services directly on your form!"
learnMoreLink={GUIDE_PAYMENTS_PUBLIC}
/>
<AppPublicHeader />
<LandingSection bg="primary.100" pt={{ base: '2rem', md: 0 }} px="0">
<Stack
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/theme/textStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,20 @@ export const textStyles = {
letterSpacing: '-0.014em',
fontFeatureSettings: "'tnum' on, 'lnum' on, 'cv05' on",
},
h5: {
fontWeight: 600,
fontSize: '1.25rem',
lineHeight: '1.75rem',
letterSpacing: '-0.014em',
fontFeatureSettings: "'tnum' on, 'lnum' on, 'cv05' on",
},
h6: {
fontWeight: 500,
fontSize: '1.125rem',
lineHeight: '1.5rem',
letterSpacing: '-0.014em',
fontFeatureSettings: "'tnum' on, 'lnum' on, 'cv05' on",
},
'subhead-1': {
fontWeight: 500,
fontSize: '1rem',
Expand Down