Skip to content

Commit

Permalink
Merge branch 'sign-in-homepage'
Browse files Browse the repository at this point in the history
  • Loading branch information
littlelazer committed Nov 1, 2024
2 parents c5fa356 + ba86697 commit 2677d95
Show file tree
Hide file tree
Showing 13 changed files with 674 additions and 417 deletions.
Binary file added src/images/email-template-mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/email-template.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion src/network/useExchangeCodeForToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { navigate } from 'gatsby'

export const useExchangeCodeForToken = () => {
const code: string | null = currentUrlSearchParamsFor('code')
const [loading, setLoading] = useState(false)
const [loading, setLoading] = useState(!!code)
const [auth, setAuth] = useAuth()
const [errorMessage, setErrorMessage] = useState('')

Expand Down Expand Up @@ -38,6 +38,8 @@ export const useExchangeCodeForToken = () => {
fetchToken()
} else if (code && auth) {
navigate(window.location.pathname, { replace: true })
} else {
setLoading(false)
}
}, [code, auth])

Expand Down
10 changes: 10 additions & 0 deletions src/pages/__tests__/dashboard.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'
import { render } from '@testing-library/react'
import IndexPage from '../index'

describe('index - Root page', () => {
it('is displayed in a layout', () => {
const { baseElement } = render(<IndexPage />)
expect(baseElement.querySelector('.layout')).not.toBeNull()
})
})
71 changes: 66 additions & 5 deletions src/pages/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,77 @@
import React from 'react'
import { render } from '@testing-library/react'
import IndexPage from '../index'
import { SIDEBAR_NAVIGATION_TEST_ID as sidebarNavigationTestId } from 'src/ui/SidebarNavigation'
import { currentUrlSearchParamsFor } from 'src/utils/currentUrlSearchParamsFor'
import { asMock, userIsNotSignedIn, userIsSignedIn } from 'src/testHelpers'
import { navigate } from 'gatsby'
import { AuthProvider } from 'src/utils/AuthContext'
import { useExchangeCodeForToken } from 'src/network/useExchangeCodeForToken'

jest.mock('src/utils/currentUrlSearchParamsFor', () => {
return {
currentUrlSearchParamsFor: jest.fn(),
}
})

jest.mock('src/network/useExchangeCodeForToken', () => {
return {
useExchangeCodeForToken: jest.fn(),
}
})

describe('index - Root page', () => {
it('is displayed in a layout', () => {
beforeEach(() => {
asMock(useExchangeCodeForToken).mockReturnValue({ loading: false, errorMessage: '' })
})

it('displays the layout', () => {
const { baseElement } = render(<IndexPage />)
expect(baseElement.querySelector('.layout')).not.toBeNull()
})

it('displays the sidebar navigation', () => {
const { queryByTestId } = render(<IndexPage />)
expect(queryByTestId(sidebarNavigationTestId)).not.toBeNull()
it('displays the loading overlay', () => {
const { queryByRole } = render(<IndexPage />)
const loadingOverlay = queryByRole('alert')
expect(loadingOverlay).toHaveTextContent('Signing in')
})

describe('when the user is signed in', () => {
it('navigates to /dashboard', () => {
userIsSignedIn()
render(
<AuthProvider>
<IndexPage />
</AuthProvider>,
)
expect(navigate).toHaveBeenCalledWith('/dashboard')
})
})

describe('when the user is not signed in', () => {
it('navigates to /sign-in', () => {
userIsNotSignedIn()
asMock(currentUrlSearchParamsFor).mockReturnValue(null)
asMock(navigate).mockImplementation(async () => {
asMock(currentUrlSearchParamsFor).mockReturnValue(null)
})
render(
<AuthProvider>
<IndexPage />
</AuthProvider>,
)
expect(navigate).toHaveBeenCalledWith('/sign-in')
})
})

describe('while auth is loading', () => {
it('does not navigate away from the page', () => {
asMock(useExchangeCodeForToken).mockReturnValue({ loading: true, errorMessage: '' })
render(
<AuthProvider>
<IndexPage />
</AuthProvider>,
)
expect(navigate).not.toHaveBeenCalled()
})
})
})
35 changes: 4 additions & 31 deletions src/pages/__tests__/sign-in.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react'
import { RenderResult, render } from '@testing-library/react'
import SignIn from '../sign-in'
import { SIDEBAR_NAVIGATION_TEST_ID as sidebarNavigationTestId } from 'src/ui/SidebarNavigation'
import userEvent, { UserEvent } from '@testing-library/user-event'
import { faker } from '@faker-js/faker'
import { navigate } from 'gatsby'
Expand Down Expand Up @@ -48,16 +47,6 @@ describe('Sign in page', () => {
await user.click(await getByRole('button', { name: 'Sign In' }))
}

it('displays the sidebar navigation', () => {
rendered = render(
<AuthProvider>
<SignIn />
</AuthProvider>,
)
const { queryByTestId } = rendered
expect(queryByTestId(sidebarNavigationTestId)).not.toBeNull()
})

describe('when signing in successfully', () => {
let idToken: string
let refreshToken: string
Expand All @@ -82,9 +71,9 @@ describe('Sign in page', () => {
)
})

it('redirects to the home page', async () => {
it('redirects to the dashboard page', async () => {
await fillOutAndSubmitForm()
expect(navigate).toHaveBeenCalledWith('/')
expect(navigate).toHaveBeenCalledWith('/dashboard')
expect(navigate).toHaveBeenCalledTimes(1)
})

Expand Down Expand Up @@ -165,24 +154,8 @@ describe('Sign in page', () => {
)
})

it('redirects to the home page', async () => {
expect(navigate).toHaveBeenCalledWith('/')
expect(navigate).toHaveBeenCalledTimes(1)
})
})

describe('when there is no backend url', () => {
beforeEach(() => {
mockBackendUrl(undefined)
rendered = render(
<AuthProvider>
<SignIn />
</AuthProvider>,
)
})

it('redirects to the home page', async () => {
expect(navigate).toHaveBeenCalledWith('/')
it('redirects to the dashboard page', async () => {
expect(navigate).toHaveBeenCalledWith('/dashboard')
expect(navigate).toHaveBeenCalledTimes(1)
})
})
Expand Down
165 changes: 165 additions & 0 deletions src/pages/dashboard.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
.index-or {
font-size: var(--font-huge);
font-weight: var(--weight-bold);
line-height: 2rem;
padding: 3rem 0;
}

.index-list {
align-items: stretch;
display: flex;
gap: 2rem;
}

.index-create-from-scratch-list {
align-items: stretch;
display: flex;
gap: 3rem;
}

.home-page-section h2 {
letter-spacing: -1px;
}

.heading-and-actions {
align-items: center;
display: flex;
justify-content: space-between;
}

.heading-and-actions a {
color: var(--blue);
font-weight: var(--weight-bold);
text-decoration-line: underline;
}

.index-list-item {
align-items: stretch;
display: flex;
flex-direction: column;
flex: 1;
max-width: 18rem;

h3,
p {
padding: 0;
margin: 0;
}

h3,
h3 a {
align-self: flex-start;
color: var(--blue-dark);
font-size: calc(var(--font-huge) - 0.05rem);
font-weight: var(--weight-bold);
padding-bottom: 0.5rem;
letter-spacing: -1px;
position: relative;
text-decoration: none;
}

h3::after {
background-color: var(--blue-dark);
bottom: 0.5rem;
content: ' ';
height: 2px;
left: 0;
position: absolute;
transition: width 150ms ease-in-out;
width: 0;
}

h3:hover::after,
h3:focus-within::after {
width: 100%;
}

p {
color: var(--gray-dark);
font-size: var(--font-small);
padding-bottom: 1rem;
}

.preview {
align-items: center;
border: 1px solid var(--black);
border-radius: 5px;
display: flex;
height: 13.5rem;
justify-content: center;
position: relative;
width: 18rem;
transition: border-color 100ms ease-in-out;
}

.preview:focus-within,
.preview:hover {
border-color: var(--blue-dark);
}

.preview .mask {
background-color: var(--blue-dark);
height: 100%;
left: 0;
opacity: 0;
position: absolute;
top: 0;
width: 100%;
transition: opacity 100ms ease-in-out;
z-index: 1;
}

.preview a {
align-items: center;
background-color: var(--white);
border-radius: 3px;
border: 2px solid var(--blue-dark);
color: var(--blue-dark);
display: flex;
font-weight: var(--weight-bold);
justify-content: center;
opacity: 0;
padding: 0.5rem 2.75rem;
transition: opacity 100ms ease-in-out;
text-decoration: none;
z-index: 2;
}

.preview:focus-within .mask,
.preview:hover .mask {
opacity: 0.5;
}

.preview:focus-within a,
.preview:hover a {
opacity: 1;
}

.image-container {
align-items: flex-end;
display: flex;
justify-content: center;
position: absolute;
top: 0;
left: 0;
height: 100%;
transform: translateY(5px);
width: 100%;
}
}

.link-button {
background-color: var(--blue);
border: 0;
border-radius: 3px;
color: var(--white);
font-size: var(--font-small);
font-weight: var(--weight-bold-light);
padding: 0.75rem 2.8rem;
width: fit-content;
text-decoration: none;
}

.create-from-scratch-list-item {
max-width: 15.625rem;
}
Loading

0 comments on commit 2677d95

Please sign in to comment.