Skip to content

Commit

Permalink
feat: add toast component
Browse files Browse the repository at this point in the history
  • Loading branch information
chriswhong committed Jul 30, 2019
1 parent fdb84b9 commit 15497bd
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 19 deletions.
19 changes: 18 additions & 1 deletion app/actions/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import {
UI_TOGGLE_DATASET_LIST,
UI_SET_SIDEBAR_WIDTH,
UI_ACCEPT_TOS,
UI_SET_PEERNAME
UI_SET_PEERNAME,
UI_OPEN_TOAST,
UI_CLOSE_TOAST
} from '../reducers/ui'

import { ToastType } from '../models/store'

export const toggleDatasetList = () => {
return {
type: UI_TOGGLE_DATASET_LIST
Expand All @@ -31,3 +35,16 @@ export const setPeername = () => {
type: UI_SET_PEERNAME
}
}

export const openToast = (type: ToastType, message: string) => {
return {
type: UI_OPEN_TOAST,
payload: { type, message }
}
}

export const closeToast = () => {
return {
type: UI_CLOSE_TOAST
}
}
46 changes: 33 additions & 13 deletions app/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
import * as React from 'react'
import { ApiAction } from '../store/api'
import { Action } from 'redux'
import { CSSTransition } from 'react-transition-group'

import NoDatasets from './NoDatasets'
import Toast from './Toast'
import Onboard from './Onboard'
import AppLoading from './AppLoading'

import CreateDataset from './modals/CreateDataset'
import AddDataset from './modals/AddDataset'

import { ApiAction } from '../store/api'
import DatasetContainer from '../containers/DatasetContainer'
import NoDatasets from './NoDatasets'
import Onboard from './Onboard'
import { Modal, ModalType, NoModal } from '../models/modals'
import AppLoading from './AppLoading'
import { Action } from 'redux'
import { Toast as IToast } from '../models/store'

interface AppProps {
fetchSession: () => Promise<ApiAction>
fetchMyDatasetsAndLinks: () => Promise<ApiAction>
addDataset: (peername: string, name: string) => Promise<ApiAction>
initDataset: (path: string, name: string, format: string) => Promise<ApiAction>
acceptTOS: () => Action
setPeername: () => Action
hasDatasets: boolean
loading: boolean
sessionID: string
peername: string
hasAcceptedTOS: boolean
hasSetPeername: boolean
toast: IToast
fetchSession: () => Promise<ApiAction>
fetchMyDatasetsAndLinks: () => Promise<ApiAction>
addDataset: (peername: string, name: string) => Promise<ApiAction>
initDataset: (path: string, name: string, format: string) => Promise<ApiAction>
acceptTOS: () => Action
setPeername: () => Action
closeToast: () => Action
}

interface AppState {
Expand Down Expand Up @@ -100,9 +107,15 @@ export default class App extends React.Component<AppProps, AppState> {
hasAcceptedTOS,
peername,
acceptTOS,
setPeername
setPeername,
toast,
closeToast
} = this.props
return (<div style={{ height: '100%' }}>
return (<div style={{
height: '100%',
position: 'relative',
overflow: 'hidden'
}}>
{this.renderAppLoading()}
{this.renderModal()}
<Onboard
Expand All @@ -114,6 +127,13 @@ export default class App extends React.Component<AppProps, AppState> {
/>
{this.renderNoDatasets()}
{ this.props.hasDatasets && <DatasetContainer /> }
<Toast
type={toast.type}
message={toast.message}
isVisible={toast.visible}
timeout={3000}
onClose={closeToast}
/>
</div>)
}
}
46 changes: 46 additions & 0 deletions app/components/Toast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from 'react'
import { CSSTransition } from 'react-transition-group'
import classNames from 'classnames'
import { Action } from 'redux'
// import classNames from 'classnames'
import { ToastType } from '../models/store'

interface ToastProps {
type: ToastType
message: string
isVisible: boolean
timeout: number
onClose: () => Action
}

const Toast: React.FunctionComponent<ToastProps> = (props: ToastProps) => {
const { type, message, isVisible, timeout, onClose } = props
const icon = type === 'success'
? <span className='icon-inline'>checkmark</span>
: <span className='icon-inline'>warning</span>

React.useEffect(() => {
// set timeout
if (isVisible === true) {
setTimeout(onClose, timeout)
}
}, [isVisible])

return (
<CSSTransition
in={isVisible}
classNames="toast"
timeout={300}
>
<div className={classNames('toast', {
'success': type === 'success',
'error': type === 'error'
})}>
{icon}
{message}
</div>
</CSSTransition>
)
}

export default Toast
10 changes: 6 additions & 4 deletions app/containers/AppContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ import App from '../components/App'
import Store from '../models/store'

import { fetchSession, fetchMyDatasetsAndLinks, addDatasetAndFetch, initDatasetAndFetch } from '../actions/api'
import { acceptTOS, setPeername } from '../actions/ui'
import { acceptTOS, setPeername, closeToast } from '../actions/ui'

const AppContainer = connect(
(state: Store) => {
const { ui, myDatasets, session } = state
const loading = myDatasets.pageInfo.isFetching || session.id === ''
const hasDatasets = myDatasets.value.length !== 0
const { id: sessionID, peername } = session
const { hasAcceptedTOS, hasSetPeername } = ui
const { hasAcceptedTOS, hasSetPeername, toast } = ui
return {
hasAcceptedTOS,
hasSetPeername,
hasDatasets,
loading,
sessionID,
peername
peername,
toast
}
},
{
Expand All @@ -27,7 +28,8 @@ const AppContainer = connect(
acceptTOS,
setPeername,
addDataset: addDatasetAndFetch,
initDataset: initDatasetAndFetch
initDataset: initDatasetAndFetch,
closeToast
}
)(App)

Expand Down
9 changes: 9 additions & 0 deletions app/models/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ export interface Mutations {
[key: string]: Mutation
}

export type ToastType = 'success' | 'error'

export interface Toast {
type: ToastType
message: string
visible: false
}

export interface UI {
apiConnection: ApiConnection
showDatasetList: boolean
Expand All @@ -49,6 +57,7 @@ export interface UI {
showDiff: boolean
datasetSidebarWidth: number
commitSidebarWidth: number
toast: Toast
}

// currently selected dataset, tab, dataset component, commit, etc
Expand Down
32 changes: 31 additions & 1 deletion app/reducers/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export const UI_TOGGLE_DATASET_LIST = 'UI_TOGGLE_DATASET_LIST'
export const UI_SET_SIDEBAR_WIDTH = 'UI_SET_SIDEBAR_WIDTH'
export const UI_ACCEPT_TOS = 'UI_ACCEPT_TOS'
export const UI_SET_PEERNAME = 'UI_SET_PEERNAME'
export const UI_OPEN_TOAST = 'UI_OPEN_TOAST'
export const UI_CLOSE_TOAST = 'UI_CLOSE_TOAST'

export const defaultSidebarWidth = 250
export const hasAcceptedTOSKey = 'acceptedTOS'
Expand All @@ -18,6 +20,12 @@ const getSidebarWidth = (key: string): number => {
return defaultSidebarWidth
}

const defaultToast = {
type: 'success',
message: '',
visible: false
}

const initialState = {
apiConnection: 1,
showDatasetList: false,
Expand All @@ -27,7 +35,8 @@ const initialState = {
hasSetPeername: store().getItem(hasSetPeernameKey) === 'true',
showDiff: false,
datasetSidebarWidth: getSidebarWidth('datasetSidebarWidth'),
commitSidebarWidth: getSidebarWidth('commitSidebarWidth')
commitSidebarWidth: getSidebarWidth('commitSidebarWidth'),
toast: defaultToast
}

export default (state = initialState, action: AnyAction) => {
Expand Down Expand Up @@ -56,6 +65,27 @@ export default (state = initialState, action: AnyAction) => {
store().setItem(hasSetPeernameKey, 'true')
return Object.assign({}, state, { hasSetPeername: true })

case UI_OPEN_TOAST:
const { type: toastType, message } = action.payload
return {
...state,
toast: {
type: toastType,
message,
visible: true
}
}

case UI_CLOSE_TOAST:
return {
...state,
toast: {
type: 'success',
message: '',
visible: false
}
}

default:
return state
}
Expand Down
54 changes: 54 additions & 0 deletions app/scss/_toast.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.toast {
color: $text;
margin: 0 auto;
max-width: 500px;
padding: 8px 12px;
position: absolute;
bottom: 0;
left: 50%;
right: auto;
border-radius: 2px;
transform: translateX(-50%) translateY(100%);

.icon-inline {
margin-right: 8px;
position: relative;
top: 2px;
}

&.success {
background: #a6e2a6;
.icon-inline {
color: #459245
}
}

&.error {
background: #dcadad;
.icon-inline {
color: #b9525a
}
}
}

.toast-enter {
transform: translateX(-50%) translateY(100%);
}

.toast-enter-active {
transform: translateX(-50%) translateY(-50%);
transition: all 300ms ;
}

.toast-enter-done {
transform: translateX(-50%) translateY(-50%);
}

.toast-exit {
transform: translateX(-50%) translateY(-50%);
}

.toast-exit-active {
transform: translateX(-50%) translateY(100%);
transition: all 300ms ;
}
1 change: 1 addition & 0 deletions app/scss/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
@import "dataset";
@import "welcome";
@import "flex";
@import "toast";

@import '~handsontable/dist/handsontable.full.css';
@import "dialog"

0 comments on commit 15497bd

Please sign in to comment.