Toast type (success/warning/etc)

This commit is contained in:
Tom Moor
2018-05-31 12:07:49 -07:00
parent f633f63a61
commit fb7a8f0312
11 changed files with 58 additions and 36 deletions

View File

@ -112,7 +112,7 @@ class Layout extends React.Component<Props> {
</Content>
</Flex>
<Modals ui={ui} />
<Toasts />
<Toasts ui={ui} />
</Container>
);
}

View File

@ -1,14 +1,18 @@
// @flow
import * as React from 'react';
import { inject, observer } from 'mobx-react';
import { observer } from 'mobx-react';
import styled from 'styled-components';
import { layout } from 'shared/styles/constants';
import Toast from './components/Toast';
import UiStore from '../../stores/UiStore';
type Props = {
ui: UiStore,
};
@observer
class Toasts extends React.Component<*> {
handleClose = index => {
this.props.ui.remove(index);
class Toasts extends React.Component<Props> {
handleClose = (index: number) => {
this.props.ui.removeToast(index);
};
render() {
@ -16,11 +20,11 @@ class Toasts extends React.Component<*> {
return (
<List>
{ui.toasts.map((error, index) => (
{ui.toasts.map((toast, index) => (
<Toast
key={index}
onRequestClose={this.handleClose.bind(this, index)}
message={error}
toast={toast}
/>
))}
</List>
@ -35,6 +39,7 @@ const List = styled.ol`
list-style: none;
margin: 0;
padding: 0;
z-index: 1000;
`;
export default inject('ui')(Toasts);
export default Toasts;

View File

@ -4,12 +4,12 @@ import styled from 'styled-components';
import { darken } from 'polished';
import { color } from 'shared/styles/constants';
import { fadeAndScaleIn } from 'shared/styles/animations';
import type { Toast as TToast } from '../../../types';
type Props = {
onRequestClose: () => void,
closeAfterMs: number,
message: string,
type: 'warning' | 'error' | 'info',
toast: TToast,
};
class Toast extends React.Component<Props> {
@ -17,7 +17,6 @@ class Toast extends React.Component<Props> {
static defaultProps = {
closeAfterMs: 3000,
type: 'warning',
};
componentDidMount() {
@ -32,14 +31,14 @@ class Toast extends React.Component<Props> {
}
render() {
const { type, onRequestClose } = this.props;
const { toast, onRequestClose } = this.props;
const message =
typeof this.props.message === 'string'
? this.props.message
: this.props.message.toString();
typeof toast.message === 'string'
? toast.message
: toast.message.toString();
return (
<Container onClick={onRequestClose} type={type}>
<Container onClick={onRequestClose} type={toast.type}>
<Message>{message}</Message>
</Container>
);

View File

@ -4,7 +4,7 @@ import { withRouter } from 'react-router-dom';
import { inject } from 'mobx-react';
import { MoreIcon } from 'outline-icons';
import { Share } from 'types';
import type { Share } from 'types';
import CopyToClipboard from 'components/CopyToClipboard';
import SharesStore from 'stores/SharesStore';
import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';

View File

@ -6,6 +6,7 @@ import styled from 'styled-components';
import { color, size } from 'shared/styles/constants';
import AuthStore from 'stores/AuthStore';
import UiStore from 'stores/UiStore';
import ImageUpload from './components/ImageUpload';
import Input, { LabelText } from 'components/Input';
import Button from 'components/Button';
@ -15,6 +16,7 @@ import Flex from 'shared/components/Flex';
type Props = {
auth: AuthStore,
ui: UiStore,
};
@observer
@ -41,6 +43,7 @@ class Profile extends React.Component<Props> {
name: this.name,
avatarUrl: this.avatarUrl,
});
this.props.ui.showToast('Profile saved', 'success');
};
handleNameChange = (ev: SyntheticInputEvent<*>) => {
@ -56,7 +59,7 @@ class Profile extends React.Component<Props> {
};
render() {
const { user } = this.props.auth;
const { user, isSaving } = this.props.auth;
if (!user) return null;
const avatarUrl = this.avatarUrl || user.avatarUrl;
@ -73,7 +76,7 @@ class Profile extends React.Component<Props> {
>
<Avatar src={avatarUrl} />
<Flex auto align="center" justify="center">
Upload new image
Upload
</Flex>
</ImageUpload>
</AvatarContainer>
@ -85,8 +88,8 @@ class Profile extends React.Component<Props> {
onChange={this.handleNameChange}
required
/>
<Button type="submit" disabled={this.isSaving || !this.name}>
Save
<Button type="submit" disabled={isSaving || !this.name}>
{isSaving ? 'Saving…' : 'Save'}
</Button>
</form>
</CenteredContent>
@ -101,7 +104,7 @@ const ProfilePicture = styled(Flex)`
const avatarStyles = `
width: 80px;
height: 80px;
border-radius: 10px;
border-radius: 50%;
`;
const AvatarContainer = styled(Flex)`

View File

@ -11,7 +11,7 @@ type Props = {
auth: AuthStore,
scopes?: string[],
redirectUri?: string,
state?: string,
state: string,
label?: string,
};

View File

@ -12,6 +12,7 @@ class AuthStore {
@observable user: ?User;
@observable team: ?Team;
@observable token: ?string;
@observable isSaving: boolean = false;
@observable isLoading: boolean = false;
@observable isSuspended: boolean = false;
@observable suspendedContactEmail: ?string;
@ -50,13 +51,19 @@ class AuthStore {
};
@action
updateUser = async (params: { name: string, avatarUrl?: string }) => {
updateUser = async (params: { name: string, avatarUrl: ?string }) => {
this.isSaving = true;
try {
const res = await client.post(`/user.update`, params);
invariant(res && res.data, 'User response not available');
runInAction('AuthStore#updateUser', () => {
this.user = res.data.user;
this.user = res.data;
});
} finally {
this.isSaving = false;
}
};
@action

View File

@ -4,7 +4,6 @@ import { client } from 'utils/ApiClient';
import _ from 'lodash';
import invariant from 'invariant';
import stores from 'stores';
import BaseStore from './BaseStore';
import UiStore from './UiStore';
import Collection from 'models/Collection';

View File

@ -2,6 +2,7 @@
import { observable, action } from 'mobx';
import Document from 'models/Document';
import Collection from 'models/Collection';
import type { Toast } from '../types';
class UiStore {
@observable activeModalName: ?string;
@ -11,7 +12,7 @@ class UiStore {
@observable progressBarVisible: boolean = false;
@observable editMode: boolean = false;
@observable mobileSidebarVisible: boolean = false;
@observable toasts: string[] = observable.array([]);
@observable toasts: Toast[] = observable.array([]);
/* Actions */
@action
@ -82,8 +83,11 @@ class UiStore {
}
@action
showToast = (message: string): void => {
this.toasts.push(message);
showToast = (
message: string,
type?: 'warning' | 'error' | 'info' | 'success' = 'warning'
): void => {
this.toasts.push({ message, type });
};
@action

View File

@ -9,6 +9,11 @@ export type User = {
isSuspended?: boolean,
};
export type Toast = {
message: string,
type: 'warning' | 'error' | 'info' | 'success',
};
export type Share = {
id: string,
url: string,

View File

@ -47,9 +47,9 @@ export const color = {
/* Brand */
primary: '#1AB6FF',
danger: '#D0021B',
warning: '#f08a24' /* replace */,
success: '#43AC6A' /* replace */,
info: '#a0d3e8' /* replace */,
warning: '#f08a24',
success: '#1AB6FF',
info: '#a0d3e8',
offline: '#000000',
/* Dark Grays */