chore: Improve toasts
This commit is contained in:
@ -60,7 +60,9 @@ class DropToImport extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(`Could not import file. ${err.message}`);
|
||||
this.props.ui.showToast(`Could not import file. ${err.message}`, {
|
||||
type: "error",
|
||||
});
|
||||
} finally {
|
||||
this.isImporting = false;
|
||||
importingLock = false;
|
||||
|
@ -52,7 +52,9 @@ function EditableTitle({ title, onSubmit, canUpdate }: Props) {
|
||||
setOriginalValue(value);
|
||||
} catch (error) {
|
||||
setValue(originalValue);
|
||||
ui.showToast(error.message);
|
||||
ui.showToast(error.message, {
|
||||
type: "error",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,9 @@ class SocketProvider extends React.Component<Props> {
|
||||
|
||||
this.socket.on("unauthorized", (err) => {
|
||||
this.socket.authenticated = false;
|
||||
ui.showToast(err.message);
|
||||
ui.showToast(err.message, {
|
||||
type: "error",
|
||||
});
|
||||
throw err;
|
||||
});
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// @flow
|
||||
import { CheckboxIcon, InfoIcon, WarningIcon } from "outline-icons";
|
||||
import { darken } from "polished";
|
||||
import * as React from "react";
|
||||
import styled, { css } from "styled-components";
|
||||
@ -14,7 +15,7 @@ type Props = {
|
||||
function Toast({ closeAfterMs = 3000, onRequestClose, toast }: Props) {
|
||||
const timeout = React.useRef();
|
||||
const [pulse, setPulse] = React.useState(false);
|
||||
const { action, reoccurring } = toast;
|
||||
const { action, type = "info", reoccurring } = toast;
|
||||
|
||||
React.useEffect(() => {
|
||||
timeout.current = setTimeout(onRequestClose, toast.timeout || closeAfterMs);
|
||||
@ -42,6 +43,10 @@ function Toast({ closeAfterMs = 3000, onRequestClose, toast }: Props) {
|
||||
onClick={action ? undefined : onRequestClose}
|
||||
type={toast.type || "success"}
|
||||
>
|
||||
{type === "info" && <InfoIcon color="currentColor" />}
|
||||
{type === "success" && <CheckboxIcon checked color="currentColor" />}
|
||||
{type === "warning" ||
|
||||
(type === "error" && <WarningIcon color="currentColor" />)}
|
||||
<Message>{message}</Message>
|
||||
{action && (
|
||||
<Action type={toast.type || "success"} onClick={action.onClick}>
|
||||
@ -78,10 +83,11 @@ const ListItem = styled.li`
|
||||
`;
|
||||
|
||||
const Container = styled.div`
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
animation: ${fadeAndScaleIn} 100ms ease;
|
||||
margin: 8px 0;
|
||||
padding: 0 12px;
|
||||
color: ${(props) => props.theme.toastText};
|
||||
background: ${(props) => props.theme.toastBackground};
|
||||
font-size: 15px;
|
||||
@ -95,7 +101,8 @@ const Container = styled.div`
|
||||
|
||||
const Message = styled.div`
|
||||
display: inline-block;
|
||||
padding: 10px 12px;
|
||||
font-weight: 500;
|
||||
padding: 10px 4px;
|
||||
`;
|
||||
|
||||
export default Toast;
|
||||
|
@ -66,7 +66,9 @@ class CollectionMenu extends React.Component<Props> {
|
||||
);
|
||||
this.props.history.push(document.url);
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, {
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -86,7 +86,7 @@ class DocumentMenu extends React.Component<Props> {
|
||||
// when duplicating, go straight to the duplicated document content
|
||||
this.redirectTo = duped.url;
|
||||
const { t } = this.props;
|
||||
this.props.ui.showToast(t("Document duplicated"));
|
||||
this.props.ui.showToast(t("Document duplicated"), { type: "success" });
|
||||
};
|
||||
|
||||
handleOpenTemplateModal = () => {
|
||||
@ -104,7 +104,7 @@ class DocumentMenu extends React.Component<Props> {
|
||||
handleArchive = async (ev: SyntheticEvent<>) => {
|
||||
await this.props.document.archive();
|
||||
const { t } = this.props;
|
||||
this.props.ui.showToast(t("Document archived"));
|
||||
this.props.ui.showToast(t("Document archived"), { type: "success" });
|
||||
};
|
||||
|
||||
handleRestore = async (
|
||||
@ -113,13 +113,13 @@ class DocumentMenu extends React.Component<Props> {
|
||||
) => {
|
||||
await this.props.document.restore(options);
|
||||
const { t } = this.props;
|
||||
this.props.ui.showToast(t("Document restored"));
|
||||
this.props.ui.showToast(t("Document restored"), { type: "success" });
|
||||
};
|
||||
|
||||
handleUnpublish = async (ev: SyntheticEvent<>) => {
|
||||
await this.props.document.unpublish();
|
||||
const { t } = this.props;
|
||||
this.props.ui.showToast(t("Document unpublished"));
|
||||
this.props.ui.showToast(t("Document unpublished"), { type: "success" });
|
||||
};
|
||||
|
||||
handlePin = (ev: SyntheticEvent<>) => {
|
||||
|
@ -28,13 +28,13 @@ class RevisionMenu extends React.Component<Props> {
|
||||
ev.preventDefault();
|
||||
await this.props.document.restore({ revisionId: this.props.revision.id });
|
||||
const { t } = this.props;
|
||||
this.props.ui.showToast(t("Document restored"));
|
||||
this.props.ui.showToast(t("Document restored"), { type: "success" });
|
||||
this.props.history.push(this.props.document.url);
|
||||
};
|
||||
|
||||
handleCopy = () => {
|
||||
const { t } = this.props;
|
||||
this.props.ui.showToast(t("Link copied"));
|
||||
this.props.ui.showToast(t("Link copied"), { type: "info" });
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -39,15 +39,15 @@ class ShareMenu extends React.Component<Props> {
|
||||
try {
|
||||
await this.props.shares.revoke(this.props.share);
|
||||
const { t } = this.props;
|
||||
this.props.ui.showToast(t("Share link revoked"));
|
||||
this.props.ui.showToast(t("Share link revoked"), { type: "info" });
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
}
|
||||
};
|
||||
|
||||
handleCopy = () => {
|
||||
const { t } = this.props;
|
||||
this.props.ui.showToast(t("Share link copied"));
|
||||
this.props.ui.showToast(t("Share link copied"), { type: "info" });
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -32,7 +32,7 @@ class CollectionDelete extends React.Component<Props> {
|
||||
this.props.history.push(homeUrl());
|
||||
this.props.onSubmit();
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
} finally {
|
||||
this.isDeleting = false;
|
||||
}
|
||||
|
@ -47,9 +47,11 @@ class CollectionEdit extends React.Component<Props> {
|
||||
sort: this.sort,
|
||||
});
|
||||
this.props.onSubmit();
|
||||
this.props.ui.showToast(t("The collection was updated"));
|
||||
this.props.ui.showToast(t("The collection was updated"), {
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
}
|
||||
|
@ -67,10 +67,11 @@ class AddGroupsToCollection extends React.Component<Props> {
|
||||
this.props.ui.showToast(
|
||||
t("{{ groupName }} was added to the collection", {
|
||||
groupName: group.name,
|
||||
})
|
||||
}),
|
||||
{ type: "success" }
|
||||
);
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(t("Could not add user"));
|
||||
this.props.ui.showToast(t("Could not add user"), { type: "error" });
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
@ -62,10 +62,13 @@ class AddPeopleToCollection extends React.Component<Props> {
|
||||
permission: "read_write",
|
||||
});
|
||||
this.props.ui.showToast(
|
||||
t("{{ userName }} was added to the collection", { userName: user.name })
|
||||
t("{{ userName }} was added to the collection", {
|
||||
userName: user.name,
|
||||
}),
|
||||
{ type: "success" }
|
||||
);
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(t("Could not add user"));
|
||||
this.props.ui.showToast(t("Could not add user"), { type: "error" });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -61,9 +61,11 @@ class CollectionMembers extends React.Component<Props> {
|
||||
collectionId: this.props.collection.id,
|
||||
userId: user.id,
|
||||
});
|
||||
this.props.ui.showToast(`${user.name} was removed from the collection`);
|
||||
this.props.ui.showToast(`${user.name} was removed from the collection`, {
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
this.props.ui.showToast("Could not remove user");
|
||||
this.props.ui.showToast("Could not remove user", { type: "error" });
|
||||
}
|
||||
};
|
||||
|
||||
@ -74,9 +76,11 @@ class CollectionMembers extends React.Component<Props> {
|
||||
userId: user.id,
|
||||
permission,
|
||||
});
|
||||
this.props.ui.showToast(`${user.name} permissions were updated`);
|
||||
this.props.ui.showToast(`${user.name} permissions were updated`, {
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
this.props.ui.showToast("Could not update user");
|
||||
this.props.ui.showToast("Could not update user", { type: "error" });
|
||||
}
|
||||
};
|
||||
|
||||
@ -86,9 +90,11 @@ class CollectionMembers extends React.Component<Props> {
|
||||
collectionId: this.props.collection.id,
|
||||
groupId: group.id,
|
||||
});
|
||||
this.props.ui.showToast(`${group.name} was removed from the collection`);
|
||||
this.props.ui.showToast(`${group.name} was removed from the collection`, {
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
this.props.ui.showToast("Could not remove group");
|
||||
this.props.ui.showToast("Could not remove group", { type: "error" });
|
||||
}
|
||||
};
|
||||
|
||||
@ -99,9 +105,11 @@ class CollectionMembers extends React.Component<Props> {
|
||||
groupId: group.id,
|
||||
permission,
|
||||
});
|
||||
this.props.ui.showToast(`${group.name} permissions were updated`);
|
||||
this.props.ui.showToast(`${group.name} permissions were updated`, {
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
this.props.ui.showToast("Could not update user");
|
||||
this.props.ui.showToast("Could not update user", { type: "error" });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -53,7 +53,7 @@ class CollectionNew extends React.Component<Props> {
|
||||
this.props.onSubmit();
|
||||
this.props.history.push(collection.url);
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
}
|
||||
|
@ -100,6 +100,7 @@ class DocumentScene extends React.Component<Props> {
|
||||
`Document updated by ${document.updatedBy.name}`,
|
||||
{
|
||||
timeout: 30 * 1000,
|
||||
type: "warning",
|
||||
action: {
|
||||
text: "Reload",
|
||||
onClick: () => {
|
||||
@ -239,7 +240,7 @@ class DocumentScene extends React.Component<Props> {
|
||||
this.props.ui.setActiveDocument(savedDocument);
|
||||
}
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
this.isPublishing = false;
|
||||
|
@ -86,7 +86,7 @@ class DocumentMove extends React.Component<Props> {
|
||||
}
|
||||
|
||||
handleSuccess = () => {
|
||||
this.props.ui.showToast("Document moved");
|
||||
this.props.ui.showToast("Document moved", { type: "info" });
|
||||
this.props.onRequestClose();
|
||||
};
|
||||
|
||||
|
@ -48,7 +48,7 @@ class DocumentDelete extends React.Component<Props> {
|
||||
}
|
||||
this.props.onSubmit();
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
} finally {
|
||||
this.isDeleting = false;
|
||||
}
|
||||
|
@ -37,7 +37,9 @@ class DocumentNew extends React.Component<Props> {
|
||||
});
|
||||
this.props.history.replace(editDocumentUrl(document));
|
||||
} catch (err) {
|
||||
this.props.ui.showToast("Couldn’t create the document, try again?");
|
||||
this.props.ui.showToast("Couldn’t create the document, try again?", {
|
||||
type: "error",
|
||||
});
|
||||
this.props.history.goBack();
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ class DocumentShare extends React.Component<Props> {
|
||||
try {
|
||||
await share.save({ published: event.target.checked });
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
}
|
||||
|
@ -28,10 +28,12 @@ class DocumentTemplatize extends React.Component<Props> {
|
||||
try {
|
||||
const template = await this.props.document.templatize();
|
||||
this.props.history.push(documentUrl(template));
|
||||
this.props.ui.showToast("Template created, go ahead and customize it");
|
||||
this.props.ui.showToast("Template created, go ahead and customize it", {
|
||||
type: "info",
|
||||
});
|
||||
this.props.onSubmit();
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ class GroupDelete extends React.Component<Props> {
|
||||
this.props.history.push(groupSettings());
|
||||
this.props.onSubmit();
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
} finally {
|
||||
this.isDeleting = false;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ class GroupEdit extends React.Component<Props> {
|
||||
await this.props.group.save({ name: this.name });
|
||||
this.props.onSubmit();
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
}
|
||||
|
@ -62,10 +62,11 @@ class AddPeopleToGroup extends React.Component<Props> {
|
||||
userId: user.id,
|
||||
});
|
||||
this.props.ui.showToast(
|
||||
t(`{{userName}} was added to the group`, { userName: user.name })
|
||||
t(`{{userName}} was added to the group`, { userName: user.name }),
|
||||
{ type: "success" }
|
||||
);
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(t("Could not add user"));
|
||||
this.props.ui.showToast(t("Could not add user"), { type: "error" });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -52,10 +52,11 @@ class GroupMembers extends React.Component<Props> {
|
||||
userId: user.id,
|
||||
});
|
||||
this.props.ui.showToast(
|
||||
t(`{{userName}} was removed from the group`, { userName: user.name })
|
||||
t(`{{userName}} was removed from the group`, { userName: user.name }),
|
||||
{ type: "success" }
|
||||
);
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(t("Could not remove user"));
|
||||
this.props.ui.showToast(t("Could not remove user"), { type: "error" });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -39,7 +39,7 @@ class GroupNew extends React.Component<Props> {
|
||||
try {
|
||||
this.group = await group.save();
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
}
|
||||
|
@ -51,9 +51,9 @@ class Invite extends React.Component<Props> {
|
||||
try {
|
||||
await this.props.users.invite(this.invites);
|
||||
this.props.onSubmit();
|
||||
this.props.ui.showToast("We sent out your invites!");
|
||||
this.props.ui.showToast("We sent out your invites!", { type: "success" });
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
}
|
||||
@ -73,7 +73,8 @@ class Invite extends React.Component<Props> {
|
||||
handleAdd = () => {
|
||||
if (this.invites.length >= MAX_INVITES) {
|
||||
this.props.ui.showToast(
|
||||
`Sorry, you can only send ${MAX_INVITES} invites at a time`
|
||||
`Sorry, you can only send ${MAX_INVITES} invites at a time`,
|
||||
{ type: "warning" }
|
||||
);
|
||||
}
|
||||
|
||||
@ -88,7 +89,9 @@ class Invite extends React.Component<Props> {
|
||||
|
||||
handleCopy = () => {
|
||||
this.linkCopied = true;
|
||||
this.props.ui.showToast("A link was copied to your clipboard");
|
||||
this.props.ui.showToast("Share link copied", {
|
||||
type: "success",
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -52,9 +52,9 @@ class Details extends React.Component<Props> {
|
||||
avatarUrl: this.avatarUrl,
|
||||
subdomain: this.subdomain,
|
||||
});
|
||||
this.props.ui.showToast("Settings saved");
|
||||
this.props.ui.showToast("Settings saved", { type: "success" });
|
||||
} catch (err) {
|
||||
this.props.ui.showToast(err.message);
|
||||
this.props.ui.showToast(err.message, { type: "error" });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -29,7 +29,7 @@ class Export extends React.Component<Props> {
|
||||
try {
|
||||
await this.props.collections.export();
|
||||
this.isExporting = true;
|
||||
this.props.ui.showToast("Export in progress…");
|
||||
this.props.ui.showToast("Export in progress…", { type: "info" });
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ class Notifications extends React.Component<Props> {
|
||||
};
|
||||
|
||||
showSuccessMessage = debounce(() => {
|
||||
this.props.ui.showToast("Notifications saved");
|
||||
this.props.ui.showToast("Notifications saved", { type: "success" });
|
||||
}, 500);
|
||||
|
||||
render() {
|
||||
|
@ -55,7 +55,7 @@ class Profile extends React.Component<Props> {
|
||||
language: this.language,
|
||||
});
|
||||
|
||||
this.props.ui.showToast(t("Profile saved"));
|
||||
this.props.ui.showToast(t("Profile saved"), { type: "success" });
|
||||
};
|
||||
|
||||
handleNameChange = (ev: SyntheticInputEvent<*>) => {
|
||||
@ -69,12 +69,15 @@ class Profile extends React.Component<Props> {
|
||||
await this.props.auth.updateUser({
|
||||
avatarUrl: this.avatarUrl,
|
||||
});
|
||||
this.props.ui.showToast(t("Profile picture updated"));
|
||||
this.props.ui.showToast(t("Profile picture updated"), { type: "success" });
|
||||
};
|
||||
|
||||
handleAvatarError = (error: ?string) => {
|
||||
const { t } = this.props;
|
||||
this.props.ui.showToast(error || t("Unable to upload new profile picture"));
|
||||
this.props.ui.showToast(
|
||||
error || t("Unable to upload new profile picture"),
|
||||
{ type: "error" }
|
||||
);
|
||||
};
|
||||
|
||||
handleLanguageChange = (ev: SyntheticInputEvent<*>) => {
|
||||
|
@ -56,7 +56,7 @@ class Security extends React.Component<Props> {
|
||||
};
|
||||
|
||||
showSuccessMessage = debounce(() => {
|
||||
this.props.ui.showToast("Settings saved");
|
||||
this.props.ui.showToast("Settings saved", { type: "success" });
|
||||
}, 500);
|
||||
|
||||
render() {
|
||||
|
@ -27,7 +27,7 @@ class UserDelete extends React.Component<Props> {
|
||||
await this.props.auth.deleteUser();
|
||||
this.props.auth.logout();
|
||||
} catch (error) {
|
||||
this.props.ui.showToast(error.message);
|
||||
this.props.ui.showToast(error.message, { type: "error" });
|
||||
} finally {
|
||||
this.isDeleting = false;
|
||||
}
|
||||
|
Reference in New Issue
Block a user