mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-23 00:51:32 +03:00
Merge pull request #742 from filecoin-project/@jason-leyser/confirmation-modals
Confirmation popup components
This commit is contained in:
commit
a01c262f6b
@ -69,11 +69,6 @@ export const signOut = async ({ viewer }) => {
|
|||||||
|
|
||||||
// NOTE(jim): Permanently deletes you, forever.
|
// NOTE(jim): Permanently deletes you, forever.
|
||||||
export const deleteMe = async ({ viewer }) => {
|
export const deleteMe = async ({ viewer }) => {
|
||||||
const message = "Do you really want to delete your account? It will be permanently removed";
|
|
||||||
if (!window.confirm(message)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Actions.updateSearch("delete-user");
|
await Actions.updateSearch("delete-user");
|
||||||
|
|
||||||
let response = await Actions.deleteViewer();
|
let response = await Actions.deleteViewer();
|
||||||
|
@ -51,13 +51,11 @@ const STYLES_CONTENT = css`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const STYLES_SIDEBAR = css`
|
const STYLES_SIDEBAR_ELEMENTS = css`
|
||||||
z-index: ${Constants.zindex.sidebar};
|
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: ${Constants.sizes.sidebar}px;
|
width: ${Constants.sizes.sidebar}px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
position: fixed;
|
|
||||||
background-color: rgba(195, 195, 196, 1);
|
background-color: rgba(195, 195, 196, 1);
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
@ -66,12 +64,20 @@ const STYLES_SIDEBAR = css`
|
|||||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
@supports ((-webkit-backdrop-filter: blur(25px)) or (backdrop-filter: blur(25px))) {
|
@supports ((-webkit-backdrop-filter: blur(25px)) or (backdrop-filter: blur(25px))) {
|
||||||
-webkit-backdrop-filter: blur(25px);
|
-webkit-backdrop-filter: blur(25px);
|
||||||
backdrop-filter: blur(25px);
|
backdrop-filter: blur(25px);
|
||||||
background-color: rgba(195, 195, 196, 0.6);
|
background-color: rgba(195, 195, 196, 0.6);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
`;
|
||||||
|
|
||||||
|
const STYLES_SIDEBAR = css`
|
||||||
|
position: fixed;
|
||||||
|
top: 0; right: 0;
|
||||||
|
margin: auto;
|
||||||
|
z-index: ${Constants.zindex.sidebar};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const STYLES_SIDEBAR_HEADER = css`
|
const STYLES_SIDEBAR_HEADER = css`
|
||||||
@ -202,13 +208,15 @@ export default class ApplicationLayout extends React.Component {
|
|||||||
enabled
|
enabled
|
||||||
onOutsideRectEvent={this._handleDismiss}
|
onOutsideRectEvent={this._handleDismiss}
|
||||||
>
|
>
|
||||||
<div
|
<div css={STYLES_SIDEBAR}>
|
||||||
css={STYLES_SIDEBAR}
|
<div
|
||||||
ref={(c) => {
|
css={STYLES_SIDEBAR_ELEMENTS}
|
||||||
this._sidebar = c;
|
ref={(c) => {
|
||||||
}}
|
this._sidebar = c;
|
||||||
>
|
}}
|
||||||
{sidebarElements}
|
>
|
||||||
|
{sidebarElements}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Boundary>
|
</Boundary>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -21,6 +21,7 @@ import { Tag } from "~/components/system/components/Tag";
|
|||||||
import isEqual from "lodash/isEqual";
|
import isEqual from "lodash/isEqual";
|
||||||
import cloneDeep from "lodash/cloneDeep";
|
import cloneDeep from "lodash/cloneDeep";
|
||||||
import ProcessedText from "~/components/core/ProcessedText";
|
import ProcessedText from "~/components/core/ProcessedText";
|
||||||
|
import { ConfirmationModal } from "~/components/core/ConfirmationModal";
|
||||||
|
|
||||||
const DEFAULT_BOOK =
|
const DEFAULT_BOOK =
|
||||||
"https://slate.textile.io/ipfs/bafkreibk32sw7arspy5kw3p5gkuidfcwjbwqyjdktd5wkqqxahvkm2qlyi";
|
"https://slate.textile.io/ipfs/bafkreibk32sw7arspy5kw3p5gkuidfcwjbwqyjdktd5wkqqxahvkm2qlyi";
|
||||||
@ -38,7 +39,6 @@ const STYLES_NO_VISIBLE_SCROLL = css`
|
|||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
-ms-overflow-style: -ms-autohiding-scrollbar;
|
-ms-overflow-style: -ms-autohiding-scrollbar;
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 0px;
|
width: 0px;
|
||||||
display: none;
|
display: none;
|
||||||
@ -77,13 +77,11 @@ const STYLES_SIDEBAR = css`
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background-color: rgba(20, 20, 20, 0.8);
|
background-color: rgba(20, 20, 20, 0.8);
|
||||||
${STYLES_NO_VISIBLE_SCROLL}
|
${STYLES_NO_VISIBLE_SCROLL}
|
||||||
|
|
||||||
@supports ((-webkit-backdrop-filter: blur(75px)) or (backdrop-filter: blur(75px))) {
|
@supports ((-webkit-backdrop-filter: blur(75px)) or (backdrop-filter: blur(75px))) {
|
||||||
-webkit-backdrop-filter: blur(75px);
|
-webkit-backdrop-filter: blur(75px);
|
||||||
backdrop-filter: blur(75px);
|
backdrop-filter: blur(75px);
|
||||||
background-color: rgba(150, 150, 150, 0.2);
|
background-color: rgba(150, 150, 150, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -95,7 +93,6 @@ const STYLES_DISMISS_BOX = css`
|
|||||||
right: 16px;
|
right: 16px;
|
||||||
color: ${Constants.system.darkGray};
|
color: ${Constants.system.darkGray};
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
color: ${Constants.system.white};
|
color: ${Constants.system.white};
|
||||||
}
|
}
|
||||||
@ -123,7 +120,6 @@ const STYLES_META_TITLE = css`
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
color: ${Constants.system.blue};
|
color: ${Constants.system.blue};
|
||||||
}
|
}
|
||||||
@ -173,11 +169,9 @@ const STYLES_ACTION = css`
|
|||||||
border-bottom: 1px solid #3c3c3c;
|
border-bottom: 1px solid #3c3c3c;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
color: ${Constants.system.brand};
|
color: ${Constants.system.brand};
|
||||||
}
|
}
|
||||||
|
|
||||||
:last-child {
|
:last-child {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
@ -243,7 +237,6 @@ const STYLES_AUTOSAVE = css`
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 24px;
|
top: 24px;
|
||||||
left: 16px;
|
left: 16px;
|
||||||
|
|
||||||
@keyframes slate-animations-autosave {
|
@keyframes slate-animations-autosave {
|
||||||
0% {
|
0% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@ -300,6 +293,7 @@ class CarouselSidebar extends React.Component {
|
|||||||
showSavedMessage: false,
|
showSavedMessage: false,
|
||||||
showConnectedSection: false,
|
showConnectedSection: false,
|
||||||
showFileSection: true,
|
showFileSection: true,
|
||||||
|
modalShow: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
@ -449,11 +443,11 @@ class CarouselSidebar extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleDelete = () => {
|
_handleDelete = (res) => {
|
||||||
if (this.props.external || !this.props.isOwner) return;
|
if (this.props.external || !this.props.isOwner) return;
|
||||||
const message =
|
|
||||||
"Are you sure you want to delete this? It will be removed from your collections as well";
|
if (!res) {
|
||||||
if (!window.confirm(message)) {
|
this.setState({ modalShow: false });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const id = this.props.data.id;
|
const id = this.props.data.id;
|
||||||
@ -745,7 +739,7 @@ class CarouselSidebar extends React.Component {
|
|||||||
|
|
||||||
if (editingAllowed) {
|
if (editingAllowed) {
|
||||||
actions.push(
|
actions.push(
|
||||||
<div key="delete" css={STYLES_ACTION} onClick={this._handleDelete}>
|
<div key="delete" css={STYLES_ACTION} onClick={() => this.setState({ modalShow: true })}>
|
||||||
<SVG.Trash height="24px" />
|
<SVG.Trash height="24px" />
|
||||||
<span style={{ marginLeft: 16 }}>Delete</span>
|
<span style={{ marginLeft: 16 }}>Delete</span>
|
||||||
</div>
|
</div>
|
||||||
@ -847,70 +841,81 @@ class CarouselSidebar extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div css={STYLES_SIDEBAR} style={{ display: this.props.display }}>
|
<>
|
||||||
{this.state.showSavedMessage && (
|
{this.state.modalShow && (
|
||||||
<div css={STYLES_AUTOSAVE}>
|
<ConfirmationModal
|
||||||
<SVG.Check height="14px" style={{ marginRight: 4 }} />
|
type={"DELETE"}
|
||||||
Changes saved
|
withValidation={false}
|
||||||
</div>
|
callback={this._handleDelete}
|
||||||
|
header={`Are you sure you want to delete the file “${this.state.name}”?`}
|
||||||
|
subHeader={`This file will be deleted from all connected collections and your file library. You can’t undo this action.`}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<div key="s-1" css={STYLES_DISMISS_BOX} onClick={this.props.onClose}>
|
<div css={STYLES_SIDEBAR} style={{ display: this.props.display }}>
|
||||||
<SVG.Dismiss height="24px" />
|
{this.state.showSavedMessage && (
|
||||||
</div>
|
<div css={STYLES_AUTOSAVE}>
|
||||||
|
<SVG.Check height="14px" style={{ marginRight: 4 }} />
|
||||||
<div key="s-2" style={{ marginBottom: 80 }}>
|
Changes saved
|
||||||
{elements}
|
</div>
|
||||||
|
|
||||||
{!this.props.external && <div css={STYLES_ACTIONS}>{actions}</div>}
|
|
||||||
{privacy}
|
|
||||||
{uploadCoverImage}
|
|
||||||
{!this.props.external && (
|
|
||||||
<>
|
|
||||||
<div
|
|
||||||
css={STYLES_SECTION_HEADER}
|
|
||||||
style={{ cursor: "pointer", marginTop: 48 }}
|
|
||||||
onClick={() => this._handleToggleAccordion("showConnectedSection")}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
marginRight: 8,
|
|
||||||
transform: this.state.showConnectedSection ? "none" : "rotate(-90deg)",
|
|
||||||
transition: "100ms ease transform",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SVG.ChevronDown height="24px" display="block" />
|
|
||||||
</span>
|
|
||||||
<span>Add to collection</span>
|
|
||||||
</div>
|
|
||||||
{this.state.showConnectedSection && (
|
|
||||||
<div style={{ width: "100%", margin: "24px 0 44px 0" }}>
|
|
||||||
<SlatePicker
|
|
||||||
dark
|
|
||||||
slates={this.props.viewer.slates}
|
|
||||||
onCreateSlate={this._handleCreateSlate}
|
|
||||||
selectedColor={Constants.system.white}
|
|
||||||
files={[this.props.data]}
|
|
||||||
selected={this.state.selected}
|
|
||||||
onAdd={this._handleAdd}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
|
<div key="s-1" css={STYLES_DISMISS_BOX} onClick={this.props.onClose}>
|
||||||
|
<SVG.Dismiss height="24px" />
|
||||||
|
</div>
|
||||||
|
|
||||||
{this.props.data.filename.endsWith(".md") ? (
|
<div key="s-2" style={{ marginBottom: 80 }}>
|
||||||
<>
|
{elements}
|
||||||
<div css={STYLES_SECTION_HEADER} style={{ margin: "48px 0px 8px 0px" }}>
|
|
||||||
Settings
|
{!this.props.external && <div css={STYLES_ACTIONS}>{actions}</div>}
|
||||||
</div>
|
{privacy}
|
||||||
<div css={STYLES_OPTIONS_SECTION}>
|
{uploadCoverImage}
|
||||||
<div css={STYLES_TEXT}>Dark mode</div>
|
{!this.props.external && (
|
||||||
<Toggle dark active={this.props?.theme?.darkmode} onChange={this._handleDarkMode} />
|
<>
|
||||||
</div>
|
<div
|
||||||
</>
|
css={STYLES_SECTION_HEADER}
|
||||||
) : null}
|
style={{ cursor: "pointer", marginTop: 48 }}
|
||||||
|
onClick={() => this._handleToggleAccordion("showConnectedSection")}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
marginRight: 8,
|
||||||
|
transform: this.state.showConnectedSection ? "none" : "rotate(-90deg)",
|
||||||
|
transition: "100ms ease transform",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SVG.ChevronDown height="24px" display="block" />
|
||||||
|
</span>
|
||||||
|
<span>Add to collection</span>
|
||||||
|
</div>
|
||||||
|
{this.state.showConnectedSection && (
|
||||||
|
<div style={{ width: "100%", margin: "24px 0 44px 0" }}>
|
||||||
|
<SlatePicker
|
||||||
|
dark
|
||||||
|
slates={this.props.viewer.slates}
|
||||||
|
onCreateSlate={this._handleCreateSlate}
|
||||||
|
selectedColor={Constants.system.white}
|
||||||
|
files={[this.props.data]}
|
||||||
|
selected={this.state.selected}
|
||||||
|
onAdd={this._handleAdd}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.props.data.filename.endsWith(".md") ? (
|
||||||
|
<>
|
||||||
|
<div css={STYLES_SECTION_HEADER} style={{ margin: "48px 0px 8px 0px" }}>
|
||||||
|
Settings
|
||||||
|
</div>
|
||||||
|
<div css={STYLES_OPTIONS_SECTION}>
|
||||||
|
<div css={STYLES_TEXT}>Dark mode</div>
|
||||||
|
<Toggle dark active={this.props?.theme?.darkmode} onChange={this._handleDarkMode} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
128
components/core/ConfirmationModal.js
Normal file
128
components/core/ConfirmationModal.js
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import * as Constants from "~/common/constants";
|
||||||
|
|
||||||
|
import { css } from "@emotion/react";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import { ButtonPrimaryFull, ButtonSecondaryFull, ButtonWarningFull } from "~/components/system/components/Buttons.js";
|
||||||
|
import { Input } from "~/components/system/components/Input.js";
|
||||||
|
import { Boundary } from "~/components/system/components/fragments/Boundary.js";
|
||||||
|
|
||||||
|
const STYLES_TRANSPARENT_BG = css `
|
||||||
|
background-color: ${Constants.system.bgBlurGrayBlack};
|
||||||
|
z-index: ${Constants.zindex.modal};
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const STYLES_MAIN_MODAL = css `
|
||||||
|
background-color: ${Constants.system.white};
|
||||||
|
width: 380px;
|
||||||
|
height: auto;
|
||||||
|
position: fixed;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 24px;
|
||||||
|
text-align: left;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const STYLES_HEADER = css `
|
||||||
|
color: ${Constants.system.black};
|
||||||
|
font-size: ${Constants.typescale.lvl1};
|
||||||
|
font-family: ${Constants.font.semiBold};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const STYLES_SUB_HEADER = css `
|
||||||
|
color: ${Constants.system.textGray};
|
||||||
|
font-size: ${Constants.typescale.lvl0};
|
||||||
|
font-family: ${Constants.font.text};
|
||||||
|
margin-top: 16px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const STYLES_INPUT_HEADER = css `
|
||||||
|
color: ${Constants.system.black};
|
||||||
|
font-size: ${Constants.typescale.lvlN1};
|
||||||
|
font-family: ${Constants.font.semiBold};
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 24px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ConfirmationModal = (props) => {
|
||||||
|
const [isEnabled, setIsEnabled] = useState(false);
|
||||||
|
|
||||||
|
const lang = {
|
||||||
|
deleteText: 'Delete',
|
||||||
|
confirmText: 'Confirm',
|
||||||
|
cancelText: 'Cancel'
|
||||||
|
}
|
||||||
|
|
||||||
|
const _handleChange = (e) => {
|
||||||
|
if (e.target.value === props.matchValue) {
|
||||||
|
setIsEnabled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let deleteButton = <ButtonWarningFull disabled={true}>{props.buttonText || lang.deleteText}</ButtonWarningFull>;
|
||||||
|
if (isEnabled) {
|
||||||
|
deleteButton = <ButtonWarningFull onClick={() => props.callback(true)}>{props.buttonText || lang.deleteText}</ButtonWarningFull>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let confirmButton = <ButtonPrimaryFull disabled={true}>{props.buttonText || lang.confirmText}</ButtonPrimaryFull>;
|
||||||
|
if (isEnabled) {
|
||||||
|
confirmButton = <ButtonPrimaryFull onClick={() => props.callback(true)}>{props.buttonText || lang.confirmText}</ButtonPrimaryFull>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div css={STYLES_TRANSPARENT_BG}>
|
||||||
|
<Boundary enabled={true} onOutsideRectEvent={() => props.callback(false)}>
|
||||||
|
<div css={STYLES_MAIN_MODAL}>
|
||||||
|
<div css={STYLES_HEADER}>{props.header}</div>
|
||||||
|
<div css={STYLES_SUB_HEADER}>{props.subHeader}</div>
|
||||||
|
{props.type === "DELETE" &&
|
||||||
|
<>
|
||||||
|
{props.withValidation ? (
|
||||||
|
<>
|
||||||
|
<div css={STYLES_INPUT_HEADER}>{props.inputHeader}</div>
|
||||||
|
<Input placeholder={props.inputPlaceholder} onChange={_handleChange} />
|
||||||
|
<ButtonSecondaryFull onClick={() => props.callback(false)} style={{margin: '24px 0px 8px'}}>{lang.cancelText}</ButtonSecondaryFull>
|
||||||
|
{deleteButton}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ButtonSecondaryFull onClick={() => props.callback(false)} style={{ margin: '24px 0px 8px' }}>{lang.cancelText}</ButtonSecondaryFull>
|
||||||
|
<ButtonWarningFull onClick={() => props.callback(true)}>{props.buttonText || lang.deleteText}</ButtonWarningFull>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
{props.type === "CONFIRM" &&
|
||||||
|
<>
|
||||||
|
{props.withValidation ? (
|
||||||
|
<>
|
||||||
|
<div css={STYLES_INPUT_HEADER}>{props.inputHeader}</div>
|
||||||
|
<Input placeholder={props.inputPlaceholder} onChange={_handleChange} />
|
||||||
|
<ButtonSecondaryFull onClick={() => props.callback(false)} style={{ margin: '24px 0px 8px' }}>{lang.cancelText}</ButtonSecondaryFull>
|
||||||
|
{confirmButton}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ButtonSecondaryFull onClick={() => props.callback(false)} style={{ margin: '24px 0px 8px' }}>{lang.cancelText}</ButtonSecondaryFull>
|
||||||
|
<ButtonPrimaryFull onClick={() => props.callback(true)}>{props.buttonText || lang.confirmText}</ButtonPrimaryFull>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Boundary>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -20,10 +20,10 @@ import { GroupSelectable, Selectable } from "~/components/core/Selectable/";
|
|||||||
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
|
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
|
||||||
import FilePreviewBubble from "~/components/core/FilePreviewBubble";
|
import FilePreviewBubble from "~/components/core/FilePreviewBubble";
|
||||||
import isEqual from "lodash/isEqual";
|
import isEqual from "lodash/isEqual";
|
||||||
|
import { ConfirmationModal } from "~/components/core/ConfirmationModal";
|
||||||
|
|
||||||
const STYLES_CONTAINER_HOVER = css`
|
const STYLES_CONTAINER_HOVER = css`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
color: ${Constants.system.brand};
|
color: ${Constants.system.brand};
|
||||||
}
|
}
|
||||||
@ -67,7 +67,6 @@ const STYLES_LINK = css`
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
max-width: 320px;
|
max-width: 320px;
|
||||||
|
|
||||||
@media (max-width: ${Constants.sizes.tablet}px) {
|
@media (max-width: ${Constants.sizes.tablet}px) {
|
||||||
max-width: 120px;
|
max-width: 120px;
|
||||||
}
|
}
|
||||||
@ -86,7 +85,6 @@ const STYLES_ICON_BOX_HOVER = css`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
color: ${Constants.system.brand};
|
color: ${Constants.system.brand};
|
||||||
}
|
}
|
||||||
@ -117,7 +115,6 @@ const STYLES_ACTION_BAR = css`
|
|||||||
width: 90vw;
|
width: 90vw;
|
||||||
max-width: 878px;
|
max-width: 878px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
|
|
||||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -131,7 +128,6 @@ const STYLES_ACTION_BAR_CONTAINER = css`
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: ${Constants.zindex.header};
|
z-index: ${Constants.zindex.header};
|
||||||
|
|
||||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -153,7 +149,6 @@ const STYLES_LEFT = css`
|
|||||||
const STYLES_FILES_SELECTED = css`
|
const STYLES_FILES_SELECTED = css`
|
||||||
font-family: ${Constants.font.semiBold};
|
font-family: ${Constants.font.semiBold};
|
||||||
color: ${Constants.system.white};
|
color: ${Constants.system.white};
|
||||||
|
|
||||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -171,7 +166,6 @@ const STYLES_IMAGE_GRID = css`
|
|||||||
grid-column-gap: 20px;
|
grid-column-gap: 20px;
|
||||||
grid-row-gap: 20px;
|
grid-row-gap: 20px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
}
|
||||||
@ -185,11 +179,9 @@ const STYLES_IMAGE_BOX = css`
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||||
margin: 12px auto;
|
margin: 12px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
box-shadow: 0px 0px 0px 1px ${Constants.system.lightBorder} inset,
|
box-shadow: 0px 0px 0px 1px ${Constants.system.lightBorder} inset,
|
||||||
0 0 40px 0 ${Constants.system.shadow};
|
0 0 40px 0 ${Constants.system.shadow};
|
||||||
@ -223,12 +215,10 @@ const STYLES_TAG = css`
|
|||||||
font-family: ${Constants.font.text};
|
font-family: ${Constants.font.text};
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
margin: 8px 8px 0 0;
|
margin: 8px 8px 0 0;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: ${Constants.system.gray30};
|
background: ${Constants.system.gray30};
|
||||||
}
|
}
|
||||||
@ -307,6 +297,7 @@ export default class DataView extends React.Component {
|
|||||||
viewLimit: 40,
|
viewLimit: 40,
|
||||||
scrollDebounce: false,
|
scrollDebounce: false,
|
||||||
imageSize: 100,
|
imageSize: 100,
|
||||||
|
modalShow: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
isShiftDown = false;
|
isShiftDown = false;
|
||||||
@ -474,9 +465,9 @@ export default class DataView extends React.Component {
|
|||||||
this.setState({ checked: {} });
|
this.setState({ checked: {} });
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleDelete = (id) => {
|
_handleDelete = (res, id) => {
|
||||||
const message = `Are you sure you want to delete these files? They will be deleted from your collections as well`;
|
if (!res) {
|
||||||
if (!window.confirm(message)) {
|
this.setState({ modalShow: false });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,7 +486,7 @@ export default class DataView extends React.Component {
|
|||||||
this.props.onUpdateViewer({ library });
|
this.props.onUpdateViewer({ library });
|
||||||
|
|
||||||
UserBehaviors.deleteFiles(ids);
|
UserBehaviors.deleteFiles(ids);
|
||||||
this.setState({ checked: {} });
|
this.setState({ checked: {}, modalShow: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleSelect = (index) => {
|
_handleSelect = (index) => {
|
||||||
@ -600,7 +591,6 @@ export default class DataView extends React.Component {
|
|||||||
|
|
||||||
return commonTags;
|
return commonTags;
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let numChecked = Object.keys(this.state.checked).length || 0;
|
let numChecked = Object.keys(this.state.checked).length || 0;
|
||||||
// const header = (
|
// const header = (
|
||||||
@ -637,6 +627,7 @@ export default class DataView extends React.Component {
|
|||||||
// </span>
|
// </span>
|
||||||
// </div>
|
// </div>
|
||||||
// );
|
// );
|
||||||
|
|
||||||
const footer = (
|
const footer = (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{numChecked ? (
|
{numChecked ? (
|
||||||
@ -684,11 +675,20 @@ export default class DataView extends React.Component {
|
|||||||
<ButtonWarning
|
<ButtonWarning
|
||||||
transparent
|
transparent
|
||||||
style={{ marginLeft: 8, color: Constants.system.white }}
|
style={{ marginLeft: 8, color: Constants.system.white }}
|
||||||
onClick={() => this._handleDelete()}
|
onClick={() => this.setState({ modalShow: true })}
|
||||||
>
|
>
|
||||||
{Strings.pluralize("Delete file", numChecked)}
|
{Strings.pluralize("Delete file", numChecked)}
|
||||||
</ButtonWarning>
|
</ButtonWarning>
|
||||||
)}
|
)}
|
||||||
|
{this.state.modalShow && (
|
||||||
|
<ConfirmationModal
|
||||||
|
type={"DELETE"}
|
||||||
|
withValidation={false}
|
||||||
|
callback={this._handleDelete}
|
||||||
|
header={`Are you sure you want to delete the selected files?`}
|
||||||
|
subHeader={`These files will be deleted from all connected collections and your file library. You can’t undo this action.`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
css={STYLES_ICON_BOX}
|
css={STYLES_ICON_BOX}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -969,7 +969,7 @@ export default class DataView extends React.Component {
|
|||||||
text: "Delete",
|
text: "Delete",
|
||||||
onClick: (e) => {
|
onClick: (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.setState({ menu: null }, () => this._handleDelete(each.id));
|
this.setState({ menu: null, modalShow: true });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
ButtonWarning,
|
ButtonWarning,
|
||||||
} from "~/components/system/components/Buttons";
|
} from "~/components/system/components/Buttons";
|
||||||
import { GroupSelectable, Selectable } from "~/components/core/Selectable/";
|
import { GroupSelectable, Selectable } from "~/components/core/Selectable/";
|
||||||
|
import { ConfirmationModal } from "~/components/core/ConfirmationModal";
|
||||||
|
|
||||||
//NOTE(martina): sets 200px as the standard width for a 1080px wide layout with 20px margin btwn images.
|
//NOTE(martina): sets 200px as the standard width for a 1080px wide layout with 20px margin btwn images.
|
||||||
//If the container is larger or smaller, it scales accordingly by that factor
|
//If the container is larger or smaller, it scales accordingly by that factor
|
||||||
@ -328,6 +329,7 @@ export class SlateLayout extends React.Component {
|
|||||||
tooltip: null,
|
tooltip: null,
|
||||||
keyboardTooltip: false,
|
keyboardTooltip: false,
|
||||||
signInModal: false,
|
signInModal: false,
|
||||||
|
modalShowDeleteFiles: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount = async () => {
|
componentDidMount = async () => {
|
||||||
@ -887,10 +889,9 @@ export class SlateLayout extends React.Component {
|
|||||||
this.setState(state);
|
this.setState(state);
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleResetLayout = async () => {
|
_handleResetLayout = async (res) => {
|
||||||
if (
|
if (!res) {
|
||||||
!window.confirm("Are you sure you want to reset your layout to the default column layout?")
|
this.setState({ modalShowResetLayout: false });
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let prevLayout = this.cloneLayout(this.state.layout);
|
let prevLayout = this.cloneLayout(this.state.layout);
|
||||||
@ -907,6 +908,7 @@ export class SlateLayout extends React.Component {
|
|||||||
],
|
],
|
||||||
layout,
|
layout,
|
||||||
zIndexMax: 1,
|
zIndexMax: 1,
|
||||||
|
modalShowResetLayout: false,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1049,14 +1051,15 @@ export class SlateLayout extends React.Component {
|
|||||||
e.dataTransfer.setData("DownloadURL", `${type}:${title}:${url}`);
|
e.dataTransfer.setData("DownloadURL", `${type}:${title}:${url}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleDeleteFiles = async (e, i) => {
|
_handleDeleteModal = () => {
|
||||||
const message = `Are you sure you want to delete these files? They will be deleted from your data and collections.`;
|
this.setState({ modalShowDeleteFiles: true })
|
||||||
if (!window.confirm(message)) {
|
}
|
||||||
|
|
||||||
|
_handleDeleteFiles = async (res, i) => {
|
||||||
|
if (!res) {
|
||||||
|
this.setState({ modalShowDeleteFiles: false });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
let ids = [];
|
let ids = [];
|
||||||
if (i !== undefined) {
|
if (i !== undefined) {
|
||||||
ids = [this.state.items[i].id.replace("data-", "")];
|
ids = [this.state.items[i].id.replace("data-", "")];
|
||||||
@ -1078,7 +1081,7 @@ export class SlateLayout extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await UserBehaviors.deleteFiles(ids);
|
await UserBehaviors.deleteFiles(ids);
|
||||||
this.setState({ checked: {} });
|
this.setState({ checked: {}, modalShowDeleteFiles: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
_stopProp = (e) => {
|
_stopProp = (e) => {
|
||||||
@ -1134,10 +1137,19 @@ export class SlateLayout extends React.Component {
|
|||||||
Reset layout
|
Reset layout
|
||||||
</ButtonDisabled>
|
</ButtonDisabled>
|
||||||
) : (
|
) : (
|
||||||
<ButtonSecondary onClick={this._handleResetLayout} style={{ marginRight: 16 }}>
|
<ButtonSecondary onClick={() => { this.setState({ modalShowResetLayout: true }) }} style={{ marginRight: 16 }}>
|
||||||
Reset layout
|
Reset layout
|
||||||
</ButtonSecondary>
|
</ButtonSecondary>
|
||||||
)}
|
)}
|
||||||
|
{this.state.modalShowResetLayout && (
|
||||||
|
<ConfirmationModal
|
||||||
|
type={"CONFIRM"}
|
||||||
|
withValidation={false}
|
||||||
|
callback={this._handleResetLayout}
|
||||||
|
header={`Are you sure you want to reset your layout to the default column layout?`}
|
||||||
|
subHeader={`You can’t undo this action.`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{this.state.prevLayouts.length ? (
|
{this.state.prevLayouts.length ? (
|
||||||
<ButtonSecondary style={{ marginRight: 16 }} onClick={this._handleUndo}>
|
<ButtonSecondary style={{ marginRight: 16 }} onClick={this._handleUndo}>
|
||||||
Undo
|
Undo
|
||||||
@ -1453,8 +1465,8 @@ export class SlateLayout extends React.Component {
|
|||||||
onMouseLeave={() => this.setState({ tooltip: null })}
|
onMouseLeave={() => this.setState({ tooltip: null })}
|
||||||
onClick={
|
onClick={
|
||||||
this.state.items[i].ownerId === this.props.viewer.id
|
this.state.items[i].ownerId === this.props.viewer.id
|
||||||
? (e) => {
|
? () => {
|
||||||
this._handleDeleteFiles(e, i);
|
this.setState({ modalShowDeleteFiles: true })
|
||||||
}
|
}
|
||||||
: () => {}
|
: () => {}
|
||||||
}
|
}
|
||||||
@ -1475,6 +1487,7 @@ export class SlateLayout extends React.Component {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
) : (
|
) : (
|
||||||
@ -1674,6 +1687,15 @@ export class SlateLayout extends React.Component {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{this.state.modalShowDeleteFiles && (
|
||||||
|
<ConfirmationModal
|
||||||
|
type={"DELETE"}
|
||||||
|
withValidation={false}
|
||||||
|
callback={this._handleDeleteFiles}
|
||||||
|
header={`Are you sure you want to delete the selected files?`}
|
||||||
|
subHeader={`These files will be deleted from all connected collections and your file library. You can’t undo this action.`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{numChecked ? (
|
{numChecked ? (
|
||||||
<div css={STYLES_ACTION_BAR_CONTAINER}>
|
<div css={STYLES_ACTION_BAR_CONTAINER}>
|
||||||
<div css={STYLES_ACTION_BAR}>
|
<div css={STYLES_ACTION_BAR}>
|
||||||
@ -1710,7 +1732,7 @@ export class SlateLayout extends React.Component {
|
|||||||
<ButtonWarning
|
<ButtonWarning
|
||||||
transparent
|
transparent
|
||||||
style={{ marginLeft: 8, color: Constants.system.white }}
|
style={{ marginLeft: 8, color: Constants.system.white }}
|
||||||
onClick={this._handleDeleteFiles}
|
onClick={this._handleDeleteModal}
|
||||||
>
|
>
|
||||||
{Strings.pluralize("Delete file", numChecked)}
|
{Strings.pluralize("Delete file", numChecked)}
|
||||||
</ButtonWarning>
|
</ButtonWarning>
|
||||||
|
@ -10,6 +10,7 @@ import * as UserBehaviors from "~/common/user-behaviors";
|
|||||||
|
|
||||||
import { RadioGroup } from "~/components/system/components/RadioGroup";
|
import { RadioGroup } from "~/components/system/components/RadioGroup";
|
||||||
import { css } from "@emotion/react";
|
import { css } from "@emotion/react";
|
||||||
|
import { ConfirmationModal } from "~/components/core/ConfirmationModal";
|
||||||
|
|
||||||
const SIZE_LIMIT = 1000000;
|
const SIZE_LIMIT = 1000000;
|
||||||
const DEFAULT_IMAGE =
|
const DEFAULT_IMAGE =
|
||||||
@ -52,6 +53,7 @@ export default class SidebarSingleSlateSettings extends React.Component {
|
|||||||
name: this.props.data.data.name,
|
name: this.props.data.data.name,
|
||||||
tags: this.props.data.data?.tags || [],
|
tags: this.props.data.data?.tags || [],
|
||||||
suggestions: this.props.viewer?.tags || [],
|
suggestions: this.props.viewer?.tags || [],
|
||||||
|
modalShow: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
@ -107,12 +109,9 @@ export default class SidebarSingleSlateSettings extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleDelete = async (e) => {
|
_handleDelete = async (res) => {
|
||||||
if (
|
if (!res) {
|
||||||
!window.confirm(
|
this.setState({ modalShow: false })
|
||||||
"Are you sure you want to delete this Collection? This action is irreversible."
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +129,8 @@ export default class SidebarSingleSlateSettings extends React.Component {
|
|||||||
if (Events.hasError(response)) {
|
if (Events.hasError(response)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setState({ modalShow: false })
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -303,11 +304,20 @@ export default class SidebarSingleSlateSettings extends React.Component {
|
|||||||
</System.ButtonPrimary>
|
</System.ButtonPrimary>
|
||||||
|
|
||||||
<div style={{ marginTop: 16 }}>
|
<div style={{ marginTop: 16 }}>
|
||||||
<System.ButtonWarning full onClick={this._handleDelete} style={{ overflow: "hidden" }}>
|
<System.ButtonWarning full onClick={() => this.setState({ modalShow: true })} style={{ overflow: "hidden" }}>
|
||||||
Delete collection
|
Delete collection
|
||||||
</System.ButtonWarning>
|
</System.ButtonWarning>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{this.state.modalShow && (
|
||||||
|
<ConfirmationModal
|
||||||
|
type={"DELETE"}
|
||||||
|
withValidation={false}
|
||||||
|
callback={this._handleDelete}
|
||||||
|
header={`Are you sure you want to delete the collection “${this.state.slatename}”?`}
|
||||||
|
subHeader={`This collection will be deleted but all your files will remain in your file library. You can’t undo this action.`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,13 @@ const STYLES_BUTTON_PRIMARY = css`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const STYLES_BUTTON_PRIMARY_DISABLED = css`
|
||||||
|
${STYLES_BUTTON}
|
||||||
|
cursor: not-allowed;
|
||||||
|
background-color: ${Constants.system.bgBlue};
|
||||||
|
color: ${Constants.system.white};
|
||||||
|
`;
|
||||||
|
|
||||||
const STYLES_BUTTON_PRIMARY_TRANSPARENT = css`
|
const STYLES_BUTTON_PRIMARY_TRANSPARENT = css`
|
||||||
${STYLES_BUTTON}
|
${STYLES_BUTTON}
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -71,6 +78,17 @@ export const ButtonPrimary = (props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (props.disabled) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
css={STYLES_BUTTON_PRIMARY_DISABLED}
|
||||||
|
style={{ width: props.full ? "100%" : "auto", ...props.style }}
|
||||||
|
onClick={props.onClick}
|
||||||
|
children={props.children}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
css={props.transparent ? STYLES_BUTTON_PRIMARY_TRANSPARENT : STYLES_BUTTON_PRIMARY}
|
css={props.transparent ? STYLES_BUTTON_PRIMARY_TRANSPARENT : STYLES_BUTTON_PRIMARY}
|
||||||
@ -88,12 +106,12 @@ export const ButtonPrimaryFull = (props) => {
|
|||||||
const STYLES_BUTTON_SECONDARY = css`
|
const STYLES_BUTTON_SECONDARY = css`
|
||||||
${STYLES_BUTTON}
|
${STYLES_BUTTON}
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: ${Constants.system.brand};
|
color: ${Constants.system.black};
|
||||||
background-color: ${Constants.system.white};
|
background-color: ${Constants.system.gray20};
|
||||||
box-shadow: 0 0 0 1px ${Constants.system.bgGray} inset;
|
box-shadow: 0 0 0 1px ${Constants.system.bgGray} inset;
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
background-color: #fcfcfc;
|
background-color: ${Constants.system.gray30};
|
||||||
}
|
}
|
||||||
|
|
||||||
:focus {
|
:focus {
|
||||||
@ -251,12 +269,11 @@ export const ButtonDisabledFull = (props) => {
|
|||||||
const STYLES_BUTTON_WARNING = css`
|
const STYLES_BUTTON_WARNING = css`
|
||||||
${STYLES_BUTTON}
|
${STYLES_BUTTON}
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: ${Constants.system.red};
|
color: ${Constants.system.white};
|
||||||
background-color: ${Constants.system.white};
|
background-color: ${Constants.system.red};
|
||||||
box-shadow: 0 0 0 1px ${Constants.system.bgGray} inset;
|
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
background-color: #fcfcfc;
|
background-color: #b51111;
|
||||||
}
|
}
|
||||||
|
|
||||||
:focus {
|
:focus {
|
||||||
@ -265,6 +282,14 @@ const STYLES_BUTTON_WARNING = css`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const STYLES_BUTTON_WARNING_DISABLED = css`
|
||||||
|
${STYLES_BUTTON}
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: ${Constants.system.white};
|
||||||
|
background-color: ${Constants.system.bgRed};
|
||||||
|
box-shadow: 0 0 0 1px ${Constants.system.bgGray} inset;
|
||||||
|
`;
|
||||||
|
|
||||||
const STYLES_BUTTON_WARNING_TRANSPARENT = css`
|
const STYLES_BUTTON_WARNING_TRANSPARENT = css`
|
||||||
${STYLES_BUTTON}
|
${STYLES_BUTTON}
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -297,6 +322,17 @@ export const ButtonWarning = (props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (props.disabled) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
css={STYLES_BUTTON_WARNING_DISABLED}
|
||||||
|
style={{ width: props.full ? "100%" : "auto", ...props.style }}
|
||||||
|
onClick={props.onClick}
|
||||||
|
children={props.children}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
css={props.transparent ? STYLES_BUTTON_WARNING_TRANSPARENT : STYLES_BUTTON_WARNING}
|
css={props.transparent ? STYLES_BUTTON_WARNING_TRANSPARENT : STYLES_BUTTON_WARNING}
|
||||||
@ -306,3 +342,7 @@ export const ButtonWarning = (props) => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ButtonWarningFull = (props) => {
|
||||||
|
return <ButtonWarning full {...props} />;
|
||||||
|
};
|
||||||
|
@ -15,6 +15,7 @@ import { SecondaryTabGroup } from "~/components/core/TabGroup";
|
|||||||
import ScenePage from "~/components/core/ScenePage";
|
import ScenePage from "~/components/core/ScenePage";
|
||||||
import ScenePageHeader from "~/components/core/ScenePageHeader";
|
import ScenePageHeader from "~/components/core/ScenePageHeader";
|
||||||
import Avatar from "~/components/core/Avatar";
|
import Avatar from "~/components/core/Avatar";
|
||||||
|
import { ConfirmationModal } from "~/components/core/ConfirmationModal";
|
||||||
|
|
||||||
const STYLES_FILE_HIDDEN = css`
|
const STYLES_FILE_HIDDEN = css`
|
||||||
height: 1px;
|
height: 1px;
|
||||||
@ -56,6 +57,7 @@ export default class SceneEditAccount extends React.Component {
|
|||||||
savingNameBio: false,
|
savingNameBio: false,
|
||||||
changingFilecoin: false,
|
changingFilecoin: false,
|
||||||
tab: 0,
|
tab: 0,
|
||||||
|
modalShow: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleUpload = async (e) => {
|
_handleUpload = async (e) => {
|
||||||
@ -151,13 +153,19 @@ export default class SceneEditAccount extends React.Component {
|
|||||||
this.setState({ changingPassword: false, password: "", confirm: "" });
|
this.setState({ changingPassword: false, password: "", confirm: "" });
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleDelete = async (e) => {
|
_handleDelete = async (res) => {
|
||||||
|
if (!res) {
|
||||||
|
this.setState({ modalShow: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.setState({ deleting: true });
|
this.setState({ deleting: true });
|
||||||
|
this.setState({ modalShow: false });
|
||||||
|
|
||||||
await Window.delay(100);
|
await Window.delay(100);
|
||||||
|
|
||||||
await UserBehaviors.deleteMe({ viewer: this.props.viewer });
|
await UserBehaviors.deleteMe({ viewer: this.props.viewer });
|
||||||
this.setState({ deleting: false });
|
this.setState({ deleting: false });
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleChange = (e) => {
|
_handleChange = (e) => {
|
||||||
@ -333,7 +341,7 @@ export default class SceneEditAccount extends React.Component {
|
|||||||
|
|
||||||
<div style={{ marginTop: 24 }}>
|
<div style={{ marginTop: 24 }}>
|
||||||
<System.ButtonWarning
|
<System.ButtonWarning
|
||||||
onClick={this._handleDelete}
|
onClick={() => this.setState({ modalShow: true })}
|
||||||
loading={this.state.deleting}
|
loading={this.state.deleting}
|
||||||
style={{ width: "200px" }}
|
style={{ width: "200px" }}
|
||||||
>
|
>
|
||||||
@ -351,6 +359,19 @@ export default class SceneEditAccount extends React.Component {
|
|||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
css={STYLES_COPY_INPUT}
|
css={STYLES_COPY_INPUT}
|
||||||
/>{" "}
|
/>{" "}
|
||||||
|
|
||||||
|
{this.state.modalShow && (
|
||||||
|
<ConfirmationModal
|
||||||
|
type={"DELETE"}
|
||||||
|
withValidation={true}
|
||||||
|
matchValue={this.state.username}
|
||||||
|
callback={this._handleDelete}
|
||||||
|
header={`Are you sure you want to delete your account @${this.state.username}?`}
|
||||||
|
subHeader={`You will lose all your files and collections. You can’t undo this action.`}
|
||||||
|
inputHeader={`Please type your username to confirm`}
|
||||||
|
inputPlaceholder={`username`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</ScenePage>
|
</ScenePage>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ import APIDocsUpdateSlateV2 from "~/components/api-docs/v2/update-slate.js";
|
|||||||
import APIDocsUpdateFileV2 from "~/components/api-docs/v2/update-file.js";
|
import APIDocsUpdateFileV2 from "~/components/api-docs/v2/update-file.js";
|
||||||
import APIDocsUploadToSlateV2 from "~/components/api-docs/v2/upload.js";
|
import APIDocsUploadToSlateV2 from "~/components/api-docs/v2/upload.js";
|
||||||
|
|
||||||
|
import { ConfirmationModal } from "~/components/core/ConfirmationModal";
|
||||||
|
|
||||||
const STYLES_API_KEY = css`
|
const STYLES_API_KEY = css`
|
||||||
height: 40px;
|
height: 40px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@ -49,10 +51,15 @@ const STYLES_KEY_CONTAINER = css`
|
|||||||
class Key extends React.Component {
|
class Key extends React.Component {
|
||||||
_input;
|
_input;
|
||||||
|
|
||||||
state = { visible: false, copying: false };
|
state = { visible: false, copying: false, modalShow: false };
|
||||||
|
|
||||||
_handleDelete = async (id) => {
|
_handleDelete = async (res, id) => {
|
||||||
|
if (!res) {
|
||||||
|
this.setState({ modalShow: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
await this.props.onDelete(id);
|
await this.props.onDelete(id);
|
||||||
|
this.setState({ modalShow: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleCopy = async () => {
|
_handleCopy = async () => {
|
||||||
@ -79,13 +86,24 @@ class Key extends React.Component {
|
|||||||
onMouseLeave={() => this.setState({ visible: false })}
|
onMouseLeave={() => this.setState({ visible: false })}
|
||||||
/>
|
/>
|
||||||
<SquareButtonGray
|
<SquareButtonGray
|
||||||
onClick={() => this._handleDelete(this.props.data.id)}
|
onClick={() => this.setState({ modalShow: true })}
|
||||||
style={{
|
style={{
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SVG.Trash height="16px" />
|
<SVG.Trash height="16px" />
|
||||||
</SquareButtonGray>
|
</SquareButtonGray>
|
||||||
|
|
||||||
|
{this.state.modalShow && (
|
||||||
|
<ConfirmationModal
|
||||||
|
type={"DELETE"}
|
||||||
|
withValidation={false}
|
||||||
|
callback={(e) => this._handleDelete(e, this.props.data.id)}
|
||||||
|
header={`Are you sure you want to revoke this API key?`}
|
||||||
|
subHeader={`Any services using it will no longer be able to access your Slate account.`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -100,6 +118,7 @@ export default class SceneSettingsDeveloper extends React.Component {
|
|||||||
docs: "GET",
|
docs: "GET",
|
||||||
copying: false,
|
copying: false,
|
||||||
tab: 0,
|
tab: 0,
|
||||||
|
modalShow: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
_handleCopy = async () => {
|
_handleCopy = async () => {
|
||||||
@ -121,16 +140,7 @@ export default class SceneSettingsDeveloper extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_handleDelete = async (id) => {
|
_handleDelete = async (id) => {
|
||||||
this.setState({ loading: true });
|
this.setState({ loading: true, modalShow: false });
|
||||||
|
|
||||||
if (
|
|
||||||
!window.confirm(
|
|
||||||
"Are you sure you want to revoke this API key? Any services using it will no longer be able to access your Slate account"
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
this.setState({ loading: false });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await Actions.deleteAPIKey({ id });
|
const response = await Actions.deleteAPIKey({ id });
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user