Toast type (success/warning/etc)
This commit is contained in:
@ -112,7 +112,7 @@ class Layout extends React.Component<Props> {
|
||||
</Content>
|
||||
</Flex>
|
||||
<Modals ui={ui} />
|
||||
<Toasts />
|
||||
<Toasts ui={ui} />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
);
|
||||
|
@ -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';
|
||||
|
@ -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)`
|
||||
|
@ -11,7 +11,7 @@ type Props = {
|
||||
auth: AuthStore,
|
||||
scopes?: string[],
|
||||
redirectUri?: string,
|
||||
state?: string,
|
||||
state: string,
|
||||
label?: string,
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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';
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
Reference in New Issue
Block a user