-
Notifications
You must be signed in to change notification settings - Fork 81
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(example app): add modals page example 204 (#250)
* WIP Set up basic layout, router * Switch to react-router, add placeholder content * feat(example app): add modals example page * feat(example app): add redux for modals * hook up modals page * feat(example app): add hook modal * fix(modals page): fixes from PR review * fix(modals page): pr update * fix(modals page): remove comment * fix(modals page): add import back in Co-authored-by: Suzanne Rozier <suz@truss.works>
- Loading branch information
Showing
11 changed files
with
311 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import React from 'react' | ||
import { | ||
Modal, | ||
Button, | ||
connectModal, | ||
ConnectedModalProps, | ||
useModal | ||
} from '@trussworks/react-uswds' | ||
import { connect, ConnectedProps } from 'react-redux' | ||
|
||
import { openModalAction, closeModalAction } from './../redux/actions' | ||
import { AppState, ModalState } from './../redux/types' | ||
|
||
|
||
interface TestModalProps extends ConnectedModalProps { | ||
modalKey?: string | ||
children: React.ReactNode | ||
} | ||
|
||
const TestModal = ({ onClose, children }: TestModalProps): React.ReactElement => ( | ||
<Modal | ||
title={<h2>Test Modal</h2>} | ||
actions={ | ||
<> | ||
<Button type="button" outline onClick={onClose}> | ||
Cancel | ||
</Button> | ||
<Button type="button" onClick={onClose}> | ||
Close | ||
</Button> | ||
</> | ||
}> | ||
{ children } | ||
</Modal> | ||
) | ||
|
||
/** Example of Modal Component Using Redux */ | ||
const ConnectedTestModal = connectModal(TestModal) | ||
|
||
const mapStateToProps = (state: AppState): ModalState => ({ | ||
openModalKey: state.modalState.openModalKey, | ||
}) | ||
|
||
const mapDispatchToProps = { | ||
openModalAction: openModalAction, | ||
closeModalAction: closeModalAction, | ||
} | ||
|
||
const connector = connect(mapStateToProps, mapDispatchToProps) | ||
/** End of Example of Modal Component Using Redux */ | ||
|
||
const ExamplePage = ({ | ||
openModalKey, | ||
openModalAction, | ||
closeModalAction, | ||
}: ConnectedProps<typeof connector>): React.ReactElement => { | ||
|
||
/** Example of Modal Component Using Hooks */ | ||
const { isOpen, openModal, closeModal } = useModal() | ||
/** End of Example of Modal Component Using Hooks */ | ||
|
||
return ( | ||
<section> | ||
<h1>Modals</h1> | ||
|
||
<p className="usa-intro"> | ||
This page provides examples of how modals may be used within an | ||
application. | ||
</p> | ||
|
||
<div style={{ margin: '8px'}}> | ||
<Button type="button" onClick={() => openModalAction('testModal')}> | ||
Click me! | ||
</Button> | ||
{/* Example of modal using redux for state management */} | ||
<ConnectedTestModal | ||
modalKey="testModal" | ||
isOpen={'testModal' === openModalKey} | ||
onClose={() => closeModalAction('testModal')}> | ||
<p>This is a modal that uses redux!</p> | ||
</ConnectedTestModal> | ||
</div> | ||
<div style={{ margin: '8px'}}> | ||
<Button type="button" onClick={openModal}> | ||
Click me! | ||
</Button> | ||
{/* Example of modal using hooks for state management */} | ||
<ConnectedTestModal isOpen={isOpen} onClose={closeModal} > | ||
<p>This is a modal that uses hooks!</p> | ||
</ConnectedTestModal> | ||
</div> | ||
</section> | ||
) | ||
} | ||
|
||
const ConnectedExamplePage = connector(ExamplePage) | ||
|
||
export default ConnectedExamplePage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { | ||
CLOSE_MODAL, | ||
OPEN_MODAL, | ||
} from './types' | ||
import { | ||
closeModalAction, | ||
openModalAction, | ||
} from './actions' | ||
|
||
describe('Modal actions', () => { | ||
describe('closeModal Action', () => { | ||
it('returns the CLOSE_MODAL action type', () => { | ||
const expectedAction = { | ||
type: CLOSE_MODAL, | ||
payload: 'testkey' | ||
} | ||
expect(closeModalAction('testkey')).toEqual(expectedAction) | ||
}) | ||
}) | ||
|
||
describe('openModal Action', () => { | ||
it('returns the OPEN_MODAL action type', () => { | ||
const expectedAction = { | ||
type: OPEN_MODAL, | ||
payload: 'testkey' | ||
} | ||
expect(openModalAction('testkey')).toEqual(expectedAction) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
|
||
import { OPEN_MODAL, CLOSE_MODAL } from "./types"; | ||
|
||
export function openModalAction( modalKey: string) { | ||
return { | ||
type: OPEN_MODAL, | ||
payload: modalKey | ||
}; | ||
} | ||
|
||
export function closeModalAction(modalKey: string) { | ||
return { | ||
type: CLOSE_MODAL, | ||
payload: modalKey | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { initialState, rootReducer } from './reducers' | ||
import { OpenModalAction, CloseModalAction, AppState } from './types' | ||
|
||
describe('rootReducer', () => { | ||
it('should set the openModalKey state', () => { | ||
const openModalAction: OpenModalAction = { | ||
type: 'OPEN_MODAL', | ||
payload: 'testModal', | ||
} | ||
|
||
const expectedState : AppState = { | ||
modalState : { | ||
openModalKey: 'testModal' | ||
} | ||
} | ||
|
||
expect(rootReducer(initialState, openModalAction)).toEqual(expectedState) | ||
}) | ||
|
||
it('should set the openModalKey state', () => { | ||
const closeModalAction: CloseModalAction = { | ||
type: 'CLOSE_MODAL', | ||
payload: 'testModal', | ||
} | ||
|
||
const expectedState : AppState = { | ||
modalState : { | ||
openModalKey: '' | ||
} | ||
} | ||
|
||
expect(rootReducer(initialState, closeModalAction)).toEqual(expectedState) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { | ||
OPEN_MODAL, | ||
CLOSE_MODAL, | ||
ModalActionTypes, | ||
AppState | ||
} from "./types"; | ||
|
||
export const initialState: AppState = { | ||
modalState : { | ||
openModalKey: '' | ||
} | ||
}; | ||
|
||
export function rootReducer ( | ||
state = initialState, | ||
action: ModalActionTypes | ||
): AppState { | ||
switch (action.type) { | ||
case OPEN_MODAL: | ||
return { | ||
...state, | ||
modalState: { | ||
openModalKey: action.payload | ||
} | ||
} | ||
case CLOSE_MODAL: | ||
return { | ||
...state, | ||
modalState: { | ||
openModalKey: '' | ||
} | ||
} | ||
default: | ||
return state | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/** Modal Types */ | ||
export interface ModalState { | ||
// string is the key of the open modal. This only allows a single modal to be open in the app at any time. | ||
openModalKey: string | ||
} | ||
|
||
export const OPEN_MODAL = "OPEN_MODAL"; | ||
export const CLOSE_MODAL = "CLOSE_MODAL"; | ||
|
||
export interface OpenModalAction { | ||
type: typeof OPEN_MODAL; | ||
payload: string; | ||
} | ||
|
||
export interface CloseModalAction { | ||
type: typeof CLOSE_MODAL; | ||
payload: string; | ||
} | ||
|
||
export type ModalActionTypes = OpenModalAction | CloseModalAction; | ||
|
||
export interface AppState { | ||
modalState: ModalState | ||
} |
Oops, something went wrong.