From 95d187fedcb608f0482f3e792a59c9a64f0c2c86 Mon Sep 17 00:00:00 2001 From: Caleb Cox Date: Thu, 22 Aug 2024 16:36:50 -0500 Subject: [PATCH] Create setup start page --- pages/setup/start.page.test.tsx | 39 +++++++++ pages/setup/start.page.tsx | 100 +++++++++++++++++++++++ src/components/Setup/PageHeader.tsx | 30 +++++++ src/components/Setup/styledComponents.ts | 17 ++++ src/components/User/GetUser.graphql | 1 + 5 files changed, 187 insertions(+) create mode 100644 pages/setup/start.page.test.tsx create mode 100644 pages/setup/start.page.tsx create mode 100644 src/components/Setup/PageHeader.tsx create mode 100644 src/components/Setup/styledComponents.ts diff --git a/pages/setup/start.page.test.tsx b/pages/setup/start.page.test.tsx new file mode 100644 index 0000000000..57b1d9d7d7 --- /dev/null +++ b/pages/setup/start.page.test.tsx @@ -0,0 +1,39 @@ +import { render, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import TestRouter from '__tests__/util/TestRouter'; +import { GqlMockedProvider } from '__tests__/util/graphqlMocking'; +import StartPage from './start.page'; + +const push = jest.fn(); +const router = { + push, +}; + +describe('Setup start page', () => { + it('autocomplete renders and button saves and advances to the next page', async () => { + Object.defineProperty(window, 'navigator', { + value: { ...window.navigator, language: 'fr-FR' }, + }); + + const mutationSpy = jest.fn(); + const { getByRole } = render( + + + + + , + ); + + const autocomplete = getByRole('combobox'); + expect(autocomplete).toHaveValue('French (français)'); + userEvent.click(autocomplete); + userEvent.click(getByRole('option', { name: 'German (Deutsch)' })); + userEvent.click(getByRole('button', { name: "Let's Begin" })); + await waitFor(() => + expect(mutationSpy).toHaveGraphqlOperation('UpdatePersonalPreferences', { + input: { attributes: { locale: 'de' } }, + }), + ); + expect(push).toHaveBeenCalledWith('/setup/connect'); + }); +}); diff --git a/pages/setup/start.page.tsx b/pages/setup/start.page.tsx new file mode 100644 index 0000000000..dc107baefa --- /dev/null +++ b/pages/setup/start.page.tsx @@ -0,0 +1,100 @@ +import Head from 'next/head'; +import { useRouter } from 'next/router'; +import React, { ReactElement, useState } from 'react'; +import { Autocomplete, TextField } from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import { PrivacyPolicyLink, TermsOfUseLink } from 'src/components/Links/Links'; +import { useUpdatePersonalPreferencesMutation } from 'src/components/Settings/preferences/accordions/UpdatePersonalPreferences.generated'; +import { PageHeader } from 'src/components/Setup/PageHeader'; +import { + LargeButton, + PageWrapper, +} from 'src/components/Setup/styledComponents'; +import useGetAppSettings from 'src/hooks/useGetAppSettings'; +import { formatLanguage, languages } from 'src/lib/data/languages'; +import { loadSession } from '../api/utils/pagePropsHelpers'; + +// This is the first page of the tour, and it lets users choose their language. It is always shown. +const StartPage = (): ReactElement => { + const { t } = useTranslation(); + const { appName } = useGetAppSettings(); + const { push } = useRouter(); + const [savePreferences] = useUpdatePersonalPreferencesMutation(); + + const [locale, setLocale] = useState( + (typeof window === 'undefined' + ? null + : window.navigator.language.toLowerCase()) || 'en-us', + ); + + const handleSave = async () => { + await savePreferences({ + variables: { + input: { + attributes: { + locale, + }, + }, + }, + }); + push('/setup/connect'); + }; + + return ( + <> + + + {appName} | {t('Setup - Start')} + + + + +

+ {t( + `Developing a healthy team of ministry partners sets your ministry up to thrive. +{{ appName }} is designed to help you do the right things, with the right people at the right time to be fully funded.`, + { appName }, + )} +

+

+ {t( + `To get started, we're going to walk with you through a few key steps to set you up for success in {{ appName }}!`, + { appName }, + )} +

+

{t('It looks like you speak')}

+ { + setLocale(value); + }} + options={languages.map((language) => language.id) || []} + getOptionLabel={(locale) => formatLanguage(locale)} + fullWidth + renderInput={(params) => ( + + )} + /> +

+ {t('By Clicking "Let\'s Begin!" you have read and agree to the ')} + + {t(' and the ')} + +

+ + {t("Let's Begin")} + +
+ + ); +}; + +export const getServerSideProps = loadSession; + +export default StartPage; diff --git a/src/components/Setup/PageHeader.tsx b/src/components/Setup/PageHeader.tsx new file mode 100644 index 0000000000..2ad4eba188 --- /dev/null +++ b/src/components/Setup/PageHeader.tsx @@ -0,0 +1,30 @@ +import { CampaignOutlined } from '@mui/icons-material'; +import { Box, Divider, Typography } from '@mui/material'; +import { styled } from '@mui/material/styles'; + +const StyledIcon = styled(CampaignOutlined)(({ theme }) => ({ + width: 'auto', + height: theme.spacing(8), +})); + +const Wrapper = styled(Box)(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + gap: theme.spacing(1), +})); + +const StyledTypography = styled(Typography)({ fontWeight: 'bold' }); + +interface PageHeaderProps { + title: string; +} + +export const PageHeader: React.FC = ({ title }) => ( + <> + + + {title} + + + +); diff --git a/src/components/Setup/styledComponents.ts b/src/components/Setup/styledComponents.ts new file mode 100644 index 0000000000..69aad2e1ad --- /dev/null +++ b/src/components/Setup/styledComponents.ts @@ -0,0 +1,17 @@ +import { Box, Button } from '@mui/material'; +import { styled } from '@mui/material/styles'; + +export const PageWrapper = styled(Box)(({ theme }) => ({ + marginInline: 'auto', + padding: theme.spacing(4), + display: 'flex', + flexDirection: 'column', + gap: '1rem', + alignItems: 'center', + textAlign: 'center', + maxWidth: theme.spacing(100), +})); + +export const LargeButton = styled(Button)(({ theme }) => ({ + fontSize: theme.spacing(4), +})); diff --git a/src/components/User/GetUser.graphql b/src/components/User/GetUser.graphql index 1e5f329d3c..fd2f8e6933 100644 --- a/src/components/User/GetUser.graphql +++ b/src/components/User/GetUser.graphql @@ -10,6 +10,7 @@ query GetUser { email } preferences { + id language: locale locale: localeDisplay }