This repository has been archived by the owner on Feb 28, 2020. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a modal to alert failed login attempts. #1
- Loading branch information
1 parent
f4723f7
commit 4430777
Showing
13 changed files
with
186 additions
and
18 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Component, createRef } from 'react' | ||
import { ModalHeader, ModalBody, Button } from 'reactstrap' | ||
|
||
export default class Alert extends Component { | ||
constructor(props) { | ||
super(props) | ||
this.dismissButtonRef = createRef() | ||
} | ||
handleDismissClick = () => { | ||
this.props.close() | ||
} | ||
componentDidMount() { | ||
setTimeout(() => this.dismissButtonRef.current.focus()) | ||
} | ||
render() { | ||
const { message } = this.props | ||
const { handleDismissClick, dismissButtonRef } = this | ||
return ( | ||
<> | ||
<ModalHeader className="py-4 justify-content-center"> | ||
{ message } | ||
</ModalHeader> | ||
<ModalBody className="d-flex justify-content-center"> | ||
<Button | ||
color="secondary" | ||
innerRef={dismissButtonRef} | ||
name="dismiss-modal" | ||
onClick={handleDismissClick}>Dismiss</Button> | ||
</ModalBody> | ||
</> | ||
) | ||
} | ||
} |
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 @@ | ||
export { default as Alert } from './alert' |
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 |
---|---|---|
@@ -1 +1,2 @@ | ||
export { default as Authenticate } from './authenticate' | ||
export { default as Modal } from './modal' |
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,48 @@ | ||
import noop from 'lodash/noop' | ||
import { Component } from 'react' | ||
import { Modal as ReactstrapModal } from 'reactstrap' | ||
import { withServices } from '../services' | ||
|
||
class Modal extends Component { | ||
constructor(props) { | ||
super(props) | ||
this.state = { | ||
isOpen: false, | ||
response: null | ||
} | ||
this.unsubscribe = noop | ||
} | ||
onClosed = () => { | ||
this.props.modal.close(this.state.response) | ||
} | ||
close = response => { | ||
this.setState({ isOpen: false, response }) | ||
} | ||
componentDidMount() { | ||
this.unsubscribe = this.props.modal.subscribe(({ isOpen }) => { | ||
this.setState({ isOpen }) | ||
}) | ||
} | ||
componentWillUnmount() { | ||
this.unsubscribe() | ||
} | ||
render() { | ||
const { isOpen } = this.state | ||
const { modal: { render } } = this.props | ||
const { close, onClosed, onOpened } = this | ||
return ( | ||
<ReactstrapModal | ||
autoFocus | ||
centered | ||
isOpen={isOpen} | ||
onClosed={onClosed} | ||
onOpened={onOpened}> | ||
{ render({ close }) } | ||
</ReactstrapModal> | ||
) | ||
} | ||
} | ||
|
||
export default withServices(Modal, ({ modal }) => ({ | ||
modal | ||
})) |
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 |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export { default as authorize } from './authorize' | ||
export { default as isServer } from './is-server' | ||
export { default as StateModel } from './state-model' |
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,29 @@ | ||
export default class StateModel { | ||
constructor() { | ||
this._listeners = [] | ||
this._state = this.initialState | ||
} | ||
get initialState() { | ||
return {} | ||
} | ||
subscribe(listener) { | ||
const listenerIndex = this._listeners.push(listener) - 1 | ||
listener(this._state) | ||
return () => { | ||
this._listeners.splice(listenerIndex, 1) | ||
} | ||
} | ||
setState(updater) { | ||
switch (typeof updater) { | ||
case 'function': | ||
this._state = { ...this._state, ...updater(this._state) } | ||
break | ||
case 'object': | ||
this._state = { ...this._state, ...updater } | ||
break | ||
default: | ||
throw new Error('updater passed to StateModel.setState must be a Function or an Object.') | ||
} | ||
this._listeners.forEach(listener => listener(this._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
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './context' | ||
export { default as initApi } from './api' | ||
export { default as initModal } from './modal' | ||
export { default as initSession } from './session' |
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 noop from 'lodash/noop' | ||
import { StateModel, isServer } from '../lib' | ||
|
||
class Modal extends StateModel { | ||
get initialState() { | ||
return { | ||
callback: noop, | ||
isOpen: false, | ||
render: noop | ||
} | ||
} | ||
get render() { | ||
return this._state.render | ||
} | ||
open({ callback = noop, render = noop }) { | ||
if (this._state.isOpen) return | ||
this.setState({ | ||
render, | ||
callback, | ||
isOpen: true | ||
}) | ||
} | ||
close(response) { | ||
if (!this._state.isOpen) return | ||
this._state.callback(response) | ||
this.setState(this.initialState) | ||
} | ||
} | ||
|
||
let modal | ||
|
||
export default function initModal() { | ||
if (isServer) return new Modal() | ||
modal = modal || new Modal() | ||
return modal | ||
} |