mirror of
https://github.com/wassname/talk.git
synced 2026-08-02 13:10:23 +08:00
Merge branch 'master' into gdpr-email
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
.container {
|
||||
border: 1px solid #f26563;
|
||||
border-radius: 2px;
|
||||
color: #3b4a53;
|
||||
padding: 20px 10px;
|
||||
background-color: rgba(242, 101, 99, 0.1);
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.button {
|
||||
color: #787D80;
|
||||
border-radius: 2px;
|
||||
background-color: transparent;
|
||||
height: 30px;
|
||||
font-size: 0.9em;
|
||||
line-height: normal;
|
||||
|
||||
&:hover {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
background-color: #787D80;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
i.icon {
|
||||
font-size: 1em;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 0;
|
||||
padding-left: 22px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
text-align: center;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cn from 'classnames';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
import moment from 'moment';
|
||||
import { Button, Icon } from 'plugin-api/beta/client/components/ui';
|
||||
import styles from './AccountDeletionRequestedSign.css';
|
||||
import { getErrorMessages } from 'coral-framework/utils';
|
||||
import { scheduledDeletionDelayHours } from '../../config';
|
||||
|
||||
class AccountDeletionRequestedSign extends React.Component {
|
||||
cancelAccountDeletion = async () => {
|
||||
const { cancelAccountDeletion, notify } = this.props;
|
||||
try {
|
||||
await cancelAccountDeletion();
|
||||
notify('success', t('delete_request.account_deletion_cancelled'));
|
||||
} catch (err) {
|
||||
notify('error', getErrorMessages(err));
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { me: { scheduledDeletionDate } } = this.props.root;
|
||||
|
||||
const deletionScheduledFor = moment(scheduledDeletionDate).format(
|
||||
'MMM Do YYYY, h:mm a'
|
||||
);
|
||||
const deletionScheduledOn = moment(scheduledDeletionDate)
|
||||
.subtract(scheduledDeletionDelayHours, 'hours')
|
||||
.format('MMM Do YYYY, h:mm a');
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<h4 className={styles.title}>
|
||||
<Icon name="warning" className={styles.icon} />{' '}
|
||||
{t('delete_request.account_deletion_requested')}
|
||||
</h4>
|
||||
<p className={styles.description}>
|
||||
{t('delete_request.received_on')}
|
||||
{deletionScheduledFor}.
|
||||
</p>
|
||||
<p className={styles.description}>
|
||||
{t('delete_request.cancel_request_description')}
|
||||
<b>
|
||||
{' '}
|
||||
{t('delete_request.before')} {deletionScheduledOn}
|
||||
</b>.
|
||||
</p>
|
||||
<div className={styles.actions}>
|
||||
<Button
|
||||
className={cn(styles.button, styles.secondary)}
|
||||
onClick={this.cancelAccountDeletion}
|
||||
>
|
||||
{t('delete_request.cancel_account_deletion_request')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AccountDeletionRequestedSign.propTypes = {
|
||||
cancelAccountDeletion: PropTypes.func.isRequired,
|
||||
notify: PropTypes.func.isRequired,
|
||||
root: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default AccountDeletionRequestedSign;
|
||||
@@ -0,0 +1,23 @@
|
||||
.button {
|
||||
color: #787D80;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #787d80;
|
||||
background-color: transparent;
|
||||
height: 30px;
|
||||
font-size: 0.9em;
|
||||
line-height: normal;
|
||||
|
||||
&:hover {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
background-color: #787D80;
|
||||
color: white;
|
||||
}
|
||||
|
||||
> i {
|
||||
font-size: 1.2em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cn from 'classnames';
|
||||
import moment from 'moment';
|
||||
import styles from './DeleteMyAccount.css';
|
||||
import { Button } from 'plugin-api/beta/client/components/ui';
|
||||
import DeleteMyAccountDialog from './DeleteMyAccountDialog';
|
||||
import { getErrorMessages } from 'coral-framework/utils';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
|
||||
const initialState = { showDialog: false };
|
||||
|
||||
class DeleteMyAccount extends React.Component {
|
||||
state = initialState;
|
||||
|
||||
showDialog = () => {
|
||||
this.setState({
|
||||
showDialog: true,
|
||||
});
|
||||
};
|
||||
|
||||
closeDialog = () => {
|
||||
this.setState({
|
||||
showDialog: false,
|
||||
});
|
||||
};
|
||||
|
||||
cancelAccountDeletion = async () => {
|
||||
const { cancelAccountDeletion, notify } = this.props;
|
||||
try {
|
||||
await cancelAccountDeletion();
|
||||
notify('success', t('delete_request.account_deletion_requested'));
|
||||
} catch (err) {
|
||||
notify('error', getErrorMessages(err));
|
||||
}
|
||||
};
|
||||
|
||||
requestAccountDeletion = async () => {
|
||||
const { requestAccountDeletion, notify } = this.props;
|
||||
try {
|
||||
await requestAccountDeletion();
|
||||
notify('success', t('delete_request.account_deletion_requested'));
|
||||
} catch (err) {
|
||||
notify('error', getErrorMessages(err));
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
me: { scheduledDeletionDate },
|
||||
settings: { organizationContactEmail },
|
||||
} = this.props.root;
|
||||
return (
|
||||
<div className="talk-plugin-auth--delete-my-account">
|
||||
<DeleteMyAccountDialog
|
||||
requestAccountDeletion={this.requestAccountDeletion}
|
||||
showDialog={this.state.showDialog}
|
||||
closeDialog={this.closeDialog}
|
||||
scheduledDeletionDate={scheduledDeletionDate}
|
||||
organizationContactEmail={organizationContactEmail}
|
||||
/>
|
||||
<h3
|
||||
className={cn(
|
||||
styles.title,
|
||||
'talk-plugin-auth--delete-my-account-description'
|
||||
)}
|
||||
>
|
||||
{t('delete_request.delete_my_account')}
|
||||
</h3>
|
||||
<p
|
||||
className={cn(
|
||||
styles.description,
|
||||
'talk-plugin-auth--delete-my-account-description'
|
||||
)}
|
||||
>
|
||||
{t('delete_request.delete_my_account_description')}
|
||||
</p>
|
||||
<p
|
||||
className={cn(
|
||||
styles.description,
|
||||
'talk-plugin-auth--delete-my-account-description'
|
||||
)}
|
||||
>
|
||||
{scheduledDeletionDate &&
|
||||
t(
|
||||
'delete_request.already_submitted_request_description',
|
||||
moment(scheduledDeletionDate).format('MMM Do YYYY, h:mm:ss a')
|
||||
)}
|
||||
</p>
|
||||
{scheduledDeletionDate ? (
|
||||
<Button
|
||||
className={cn(styles.button, styles.secondary)}
|
||||
onClick={this.cancelAccountDeletion}
|
||||
>
|
||||
{t('delete_request.cancel_account_deletion_request')}
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
className={cn(styles.button)}
|
||||
icon="delete"
|
||||
onClick={this.showDialog}
|
||||
>
|
||||
{t('delete_request.delete_my_account')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteMyAccount.propTypes = {
|
||||
requestAccountDeletion: PropTypes.func.isRequired,
|
||||
cancelAccountDeletion: PropTypes.func.isRequired,
|
||||
notify: PropTypes.func.isRequired,
|
||||
root: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default DeleteMyAccount;
|
||||
@@ -0,0 +1,38 @@
|
||||
.dialog {
|
||||
border: none;
|
||||
box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2);
|
||||
width: 380px;
|
||||
top: 10px;
|
||||
font-family: Helvetica, 'Helvetica Neue', Verdana, sans-serif;
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.close {
|
||||
font-size: 20px;
|
||||
line-height: 14px;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
position: absolute;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
color: #363636;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #6b6b6b;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.2em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1em;
|
||||
line-height: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './DeleteMyAccountDialog.css';
|
||||
import { Dialog } from 'plugin-api/beta/client/components/ui';
|
||||
import StepProgress from './StepProgress';
|
||||
import DeleteMyAccountStep0 from './DeleteMyAccountStep0';
|
||||
import DeleteMyAccountStep1 from './DeleteMyAccountStep1';
|
||||
import DeleteMyAccountStep2 from './DeleteMyAccountStep2';
|
||||
import DeleteMyAccountStep3 from './DeleteMyAccountStep3';
|
||||
import DeleteMyAccountFinalStep from './DeleteMyAccountFinalStep';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
|
||||
const initialState = { step: 0, formData: {} };
|
||||
|
||||
class DeleteMyAccountDialog extends React.Component {
|
||||
state = initialState;
|
||||
|
||||
goToNextStep = () => {
|
||||
this.setState(state => ({
|
||||
step: state.step + 1,
|
||||
}));
|
||||
};
|
||||
|
||||
clear = () => {
|
||||
this.setState(initialState);
|
||||
};
|
||||
|
||||
cancel = () => {
|
||||
this.clear();
|
||||
this.props.closeDialog();
|
||||
};
|
||||
|
||||
onChange = e => {
|
||||
const { name, value } = e.target;
|
||||
|
||||
this.setState(state => ({
|
||||
formData: {
|
||||
...state.formData,
|
||||
[name]: value,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
render() {
|
||||
const { step } = this.state;
|
||||
const { scheduledDeletionDate, organizationContactEmail } = this.props;
|
||||
|
||||
return (
|
||||
<Dialog open={this.props.showDialog} className={styles.dialog}>
|
||||
<span className={styles.close} onClick={this.cancel}>
|
||||
×
|
||||
</span>
|
||||
<h3 className={styles.title}>
|
||||
{t('delete_request.delete_my_account')}
|
||||
</h3>
|
||||
<StepProgress currentStep={this.state.step} totalSteps={4} />
|
||||
{step === 0 && (
|
||||
<DeleteMyAccountStep0
|
||||
goToNextStep={this.goToNextStep}
|
||||
cancel={this.cancel}
|
||||
/>
|
||||
)}
|
||||
{step === 1 && (
|
||||
<DeleteMyAccountStep1
|
||||
goToNextStep={this.goToNextStep}
|
||||
cancel={this.cancel}
|
||||
/>
|
||||
)}
|
||||
{step === 2 && (
|
||||
<DeleteMyAccountStep2
|
||||
goToNextStep={this.goToNextStep}
|
||||
cancel={this.cancel}
|
||||
/>
|
||||
)}
|
||||
{step === 3 && (
|
||||
<DeleteMyAccountStep3
|
||||
formData={this.state.formData}
|
||||
goToNextStep={this.goToNextStep}
|
||||
cancel={this.cancel}
|
||||
requestAccountDeletion={this.props.requestAccountDeletion}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
)}
|
||||
{step === 4 && (
|
||||
<DeleteMyAccountFinalStep
|
||||
scheduledDeletionDate={scheduledDeletionDate}
|
||||
organizationContactEmail={organizationContactEmail}
|
||||
finish={this.cancel}
|
||||
/>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteMyAccountDialog.propTypes = {
|
||||
showDialog: PropTypes.bool.isRequired,
|
||||
closeDialog: PropTypes.func.isRequired,
|
||||
requestAccountDeletion: PropTypes.func.isRequired,
|
||||
scheduledDeletionDate: PropTypes.any.isRequired,
|
||||
organizationContactEmail: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DeleteMyAccountDialog;
|
||||
@@ -0,0 +1,60 @@
|
||||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Icon } from 'plugin-api/beta/client/components/ui';
|
||||
import styles from './DeleteMyAccountStep.css';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
import moment from 'moment';
|
||||
|
||||
const DeleteMyAccountFinalStep = props => (
|
||||
<div className={styles.step}>
|
||||
<p className={styles.description}>
|
||||
{t('delete_request.your_request_submitted_description')}
|
||||
</p>
|
||||
|
||||
<div className={cn(styles.box, styles.scheduledDeletion)}>
|
||||
<strong className={styles.block}>
|
||||
{t('delete_request.your_account_deletion_scheduled')}
|
||||
</strong>
|
||||
<strong className={styles.block}>
|
||||
<Icon name="access_time" className={styles.timeIcon} />
|
||||
<span>
|
||||
{moment(props.scheduledDeletionDate).format('MMM Do YYYY, h:mm a')}
|
||||
</span>
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<p className={styles.description}>
|
||||
<strong> {t('delete_request.changed_your_mind')}</strong>{' '}
|
||||
{t('delete_request.simply_go_to')} “<strong>
|
||||
{t('delete_request.cancel_account_deletion_request')}.
|
||||
</strong>”
|
||||
</p>
|
||||
|
||||
<p className={styles.description}>
|
||||
<strong>{t('delete_request.tell_us_why')}.</strong>{' '}
|
||||
{t('delete_request.feedback_copy')}{' '}
|
||||
<a href={`mailto:${props.organizationContactEmail}`}>
|
||||
{props.organizationContactEmail}
|
||||
</a>.
|
||||
</p>
|
||||
|
||||
<div className={cn(styles.actions, styles.columnView)}>
|
||||
<Button
|
||||
className={cn(styles.button, styles.proceed)}
|
||||
onClick={props.finish}
|
||||
full
|
||||
>
|
||||
{t('delete_request.done')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
DeleteMyAccountFinalStep.propTypes = {
|
||||
finish: PropTypes.func.isRequired,
|
||||
scheduledDeletionDate: PropTypes.any.isRequired,
|
||||
organizationContactEmail: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DeleteMyAccountFinalStep;
|
||||
@@ -0,0 +1,116 @@
|
||||
.list {
|
||||
padding: 0;
|
||||
margin: 20px 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.itemIcon {
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.text {
|
||||
flex-grow: 1;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
> i.itemIcon {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
color: #787D80;
|
||||
border-radius: 2px;
|
||||
background-color: transparent;
|
||||
height: 30px;
|
||||
font-size: 0.9em;
|
||||
line-height: normal;
|
||||
|
||||
&:hover {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
|
||||
&.cancel {
|
||||
background-color: transparent;
|
||||
color: #787D80;
|
||||
}
|
||||
|
||||
&.proceed {
|
||||
background-color: #3498DB;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.danger {
|
||||
background-color: #FA4643;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
text-align: right;
|
||||
padding-top: 20px;
|
||||
|
||||
&.columnView {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1em;
|
||||
line-height: 20px;
|
||||
margin: 0;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.note {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
font-size: 1em;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.textBox {
|
||||
background-color: #F1F2F2;
|
||||
border: none;
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
color: #3B4A53;
|
||||
font-size: 1em;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.step {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.scheduledDeletion {
|
||||
i.timeIcon {
|
||||
font-size: 1.2em;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cn from 'classnames';
|
||||
import { Button, Icon } from 'plugin-api/beta/client/components/ui';
|
||||
import styles from './DeleteMyAccountStep.css';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
|
||||
const DeleteMyAccountStep0 = props => (
|
||||
<div className={styles.step}>
|
||||
<p className={styles.description}>
|
||||
{t('delete_request.step_0.you_are_attempting')}
|
||||
</p>
|
||||
<ul className={styles.list}>
|
||||
<li className={styles.item}>
|
||||
<Icon name="done" className={styles.itemIcon} />
|
||||
<span className={styles.text}>{t('delete_request.step_0.item_1')}</span>
|
||||
</li>
|
||||
<li className={styles.item}>
|
||||
<Icon name="done" className={styles.itemIcon} />
|
||||
<span className={styles.text}>{t('delete_request.step_0.item_2')}</span>
|
||||
</li>
|
||||
<li className={styles.item}>
|
||||
<Icon name="done" className={styles.itemIcon} />
|
||||
<span className={styles.text}>{t('delete_request.step_0.item_3')}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div className={cn(styles.actions)}>
|
||||
<Button
|
||||
className={cn(styles.button, styles.cancel)}
|
||||
onClick={props.cancel}
|
||||
>
|
||||
{t('delete_request.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
className={cn(styles.button, styles.proceed)}
|
||||
onClick={props.goToNextStep}
|
||||
>
|
||||
{t('delete_request.proceed')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
DeleteMyAccountStep0.propTypes = {
|
||||
goToNextStep: PropTypes.func.isRequired,
|
||||
cancel: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default DeleteMyAccountStep0;
|
||||
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cn from 'classnames';
|
||||
import { Button } from 'plugin-api/beta/client/components/ui';
|
||||
import styles from './DeleteMyAccountStep.css';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
import { scheduledDeletionDelayHours } from '../../config';
|
||||
|
||||
const DeleteMyAccountStep1 = props => (
|
||||
<div className={styles.step}>
|
||||
<h4 className={styles.subTitle}>{t('delete_request.step_1.subtitle')}</h4>
|
||||
<p className={styles.description}>
|
||||
{t('delete_request.step_1.description', scheduledDeletionDelayHours)}
|
||||
</p>
|
||||
<h4 className={styles.subTitle}>{t('delete_request.step_1.subtitle_2')}</h4>
|
||||
<p className={styles.description}>
|
||||
{t('delete_request.step_1.description_2', scheduledDeletionDelayHours)}
|
||||
</p>
|
||||
<div className={cn(styles.actions)}>
|
||||
<Button
|
||||
className={cn(styles.button, styles.cancel)}
|
||||
onClick={props.cancel}
|
||||
>
|
||||
{t('delete_request.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
className={cn(styles.button, styles.proceed)}
|
||||
onClick={props.goToNextStep}
|
||||
>
|
||||
{t('delete_request.proceed')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
DeleteMyAccountStep1.propTypes = {
|
||||
goToNextStep: PropTypes.func.isRequired,
|
||||
cancel: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default DeleteMyAccountStep1;
|
||||
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cn from 'classnames';
|
||||
import { Button } from 'plugin-api/beta/client/components/ui';
|
||||
import styles from './DeleteMyAccountStep.css';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
|
||||
const DeleteMyAccountStep2 = props => (
|
||||
<div className={styles.step}>
|
||||
<p className={styles.description}>
|
||||
{t('delete_request.step_2.description')}
|
||||
</p>
|
||||
<p className={styles.description}>
|
||||
{t('delete_request.step_2.to_download')}
|
||||
<strong className={styles.block}>
|
||||
{t('delete_request.step_2.path')}
|
||||
</strong>
|
||||
</p>
|
||||
<div className={cn(styles.actions)}>
|
||||
<Button
|
||||
className={cn(styles.button, styles.cancel)}
|
||||
onClick={props.cancel}
|
||||
>
|
||||
{t('delete_request.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
className={cn(styles.button, styles.proceed)}
|
||||
onClick={props.goToNextStep}
|
||||
>
|
||||
{t('delete_request.proceed')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
DeleteMyAccountStep2.propTypes = {
|
||||
goToNextStep: PropTypes.func.isRequired,
|
||||
cancel: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default DeleteMyAccountStep2;
|
||||
@@ -0,0 +1,96 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cn from 'classnames';
|
||||
import { Button } from 'plugin-api/beta/client/components/ui';
|
||||
import styles from './DeleteMyAccountStep.css';
|
||||
import InputField from './InputField';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
|
||||
const initialState = {
|
||||
showError: false,
|
||||
};
|
||||
|
||||
class DeleteMyAccountStep3 extends React.Component {
|
||||
state = initialState;
|
||||
phrase = 'delete';
|
||||
|
||||
showError = () => {
|
||||
this.setState({
|
||||
showError: true,
|
||||
});
|
||||
};
|
||||
|
||||
clear = () => {
|
||||
this.setState(initialState);
|
||||
};
|
||||
|
||||
deleteAndContinue = async () => {
|
||||
if (this.formHasError()) {
|
||||
this.showError();
|
||||
return;
|
||||
}
|
||||
|
||||
await this.props.requestAccountDeletion();
|
||||
this.clear();
|
||||
this.props.goToNextStep();
|
||||
};
|
||||
|
||||
formHasError = () =>
|
||||
!this.props.formData.confirmPhrase ||
|
||||
this.props.formData.confirmPhrase !== this.phrase;
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.step}>
|
||||
<h4 className={styles.subTitle}>
|
||||
{t('delete_request.step_3.subtitle')}
|
||||
</h4>
|
||||
<p className={styles.description}>
|
||||
{t('delete_request.step_3.description')}
|
||||
</p>
|
||||
<input
|
||||
className={styles.textBox}
|
||||
disabled={true}
|
||||
readOnly={true}
|
||||
value={this.phrase}
|
||||
/>
|
||||
<InputField
|
||||
id="confirmPhrase"
|
||||
label={t('delete_request.step_3.type_to_confirm')}
|
||||
name="confirmPhrase"
|
||||
type="text"
|
||||
onChange={this.props.onChange}
|
||||
defaultValue=""
|
||||
hasError={this.formHasError()}
|
||||
errorMsg={t('delete_request.input_is_not_correct')}
|
||||
showError={this.state.showError}
|
||||
columnDisplay
|
||||
/>
|
||||
<div className={cn(styles.actions)}>
|
||||
<Button
|
||||
className={cn(styles.button, styles.cancel)}
|
||||
onClick={this.props.cancel}
|
||||
>
|
||||
{t('delete_request.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
className={cn(styles.button, styles.danger)}
|
||||
onClick={this.deleteAndContinue}
|
||||
>
|
||||
{t('delete_request.delete_my_account')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteMyAccountStep3.propTypes = {
|
||||
goToNextStep: PropTypes.func.isRequired,
|
||||
requestAccountDeletion: PropTypes.func.isRequired,
|
||||
cancel: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
formData: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default DeleteMyAccountStep3;
|
||||
@@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
import { Button } from 'plugin-api/beta/client/components/ui';
|
||||
import styles from './DownloadCommentHistory.css';
|
||||
import { getErrorMessages } from 'coral-framework/utils';
|
||||
import { downloadRateLimitDays } from '../../config';
|
||||
|
||||
export const readableDuration = durAsHours => {
|
||||
const durAsDays = Math.ceil(durAsHours / 24);
|
||||
@@ -19,21 +21,30 @@ export const readableDuration = durAsHours => {
|
||||
class DownloadCommentHistory extends Component {
|
||||
static propTypes = {
|
||||
requestDownloadLink: PropTypes.func.isRequired,
|
||||
notify: PropTypes.func.isRequired,
|
||||
root: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
requestDownloadLink = async () => {
|
||||
const { requestDownloadLink, notify } = this.props;
|
||||
try {
|
||||
await requestDownloadLink();
|
||||
notify('success', t('download_request.download_preparing'));
|
||||
} catch (err) {
|
||||
notify('error', getErrorMessages(err));
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
root: { me: { lastAccountDownload } },
|
||||
requestDownloadLink,
|
||||
} = this.props;
|
||||
const { root: { me: { lastAccountDownload } } } = this.props;
|
||||
|
||||
const now = new Date();
|
||||
const lastAccountDownloadDate =
|
||||
lastAccountDownload && new Date(lastAccountDownload);
|
||||
const hoursLeft = lastAccountDownloadDate
|
||||
? Math.ceil(
|
||||
7 * 24 - (now.getTime() - lastAccountDownloadDate.getTime()) / 3.6e6
|
||||
downloadRateLimitDays * 24 -
|
||||
(now.getTime() - lastAccountDownloadDate.getTime()) / 3.6e6
|
||||
)
|
||||
: 0;
|
||||
const canRequestDownload = !lastAccountDownloadDate || hoursLeft <= 0;
|
||||
@@ -43,7 +54,7 @@ class DownloadCommentHistory extends Component {
|
||||
<h3>{t('download_request.section_title')}</h3>
|
||||
<p>
|
||||
{t('download_request.you_will_get_a_copy')}{' '}
|
||||
<b>{t('download_request.download_rate')}</b>.
|
||||
<b>{t('download_request.download_rate', downloadRateLimitDays)}</b>.
|
||||
</p>
|
||||
{lastAccountDownloadDate && (
|
||||
<p className={styles.most_recent}>
|
||||
@@ -52,7 +63,7 @@ class DownloadCommentHistory extends Component {
|
||||
</p>
|
||||
)}
|
||||
{canRequestDownload ? (
|
||||
<Button className={styles.button} onClick={requestDownloadLink}>
|
||||
<Button className={styles.button} onClick={this.requestDownloadLink}>
|
||||
<i className="material-icons" aria-hidden={true}>
|
||||
file_download
|
||||
</i>{' '}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
.errorMsg {
|
||||
color: #FA4643;
|
||||
font-size: 0.9em;
|
||||
|
||||
i.warningIcon {
|
||||
font-size: 17px;
|
||||
}
|
||||
}
|
||||
|
||||
.warningIcon {
|
||||
color: #FA4643;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './ErrorMessage.css';
|
||||
import { Icon } from 'plugin-api/beta/client/components/ui';
|
||||
|
||||
const ErrorMessage = ({ children }) => (
|
||||
<div className={styles.errorMsg}>
|
||||
<Icon className={styles.warningIcon} name="warning" />
|
||||
<span>{children}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
ErrorMessage.propTypes = {
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
export default ErrorMessage;
|
||||
@@ -0,0 +1,85 @@
|
||||
|
||||
.detailItem {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.detailItemContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.columnDisplay {
|
||||
flex-direction: column;
|
||||
|
||||
.detailItemMessage {
|
||||
padding: 4px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.detailItemContent {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.detailInput {
|
||||
border: solid 1px #787D80;
|
||||
border-radius: 2px;
|
||||
background-color: white;
|
||||
height: 30px;
|
||||
display: inline-block;
|
||||
width: 230px;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
|
||||
> .detailIcon {
|
||||
font-size: 1.2em;
|
||||
padding: 0 5px;
|
||||
color: #787D80;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
&.error {
|
||||
border: solid 2px #FA4643;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background-color: #E0E0E0;
|
||||
}
|
||||
}
|
||||
|
||||
.detailLabel {
|
||||
color: #4C4C4D;
|
||||
font-size: 1em;
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.detailValue {
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 1em;
|
||||
color: #000;
|
||||
outline: none;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
.detailItemMessage {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 6px;
|
||||
|
||||
.warningIcon, .checkIcon {
|
||||
font-size: 17px;
|
||||
}
|
||||
}
|
||||
|
||||
.checkIcon {
|
||||
color: #00CD73;
|
||||
}
|
||||
|
||||
.warningIcon {
|
||||
color: #FA4643;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cn from 'classnames';
|
||||
import styles from './InputField.css';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import { Icon } from 'plugin-api/beta/client/components/ui';
|
||||
|
||||
const InputField = ({
|
||||
id = '',
|
||||
label = '',
|
||||
type = 'text',
|
||||
name = '',
|
||||
onChange = () => {},
|
||||
showError = true,
|
||||
hasError = false,
|
||||
errorMsg = '',
|
||||
children,
|
||||
columnDisplay = false,
|
||||
showSuccess = false,
|
||||
validationType = '',
|
||||
icon = '',
|
||||
value = '',
|
||||
defaultValue = '',
|
||||
disabled = false,
|
||||
}) => {
|
||||
const inputValue = {
|
||||
...(value ? { value } : {}),
|
||||
...(defaultValue ? { defaultValue } : {}),
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.detailItem}>
|
||||
<div className={cn(styles.detailItemContainer)}>
|
||||
{label && (
|
||||
<label className={styles.detailLabel} id={id}>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
<div
|
||||
className={cn(styles.detailItemContent, {
|
||||
[styles.columnDisplay]: columnDisplay,
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
styles.detailInput,
|
||||
{ [styles.error]: hasError && showError },
|
||||
{ [styles.disabled]: disabled }
|
||||
)}
|
||||
>
|
||||
{icon && <Icon name={icon} className={styles.detailIcon} />}
|
||||
<input
|
||||
id={id}
|
||||
type={type}
|
||||
name={name}
|
||||
className={styles.detailValue}
|
||||
onChange={onChange}
|
||||
autoComplete="off"
|
||||
data-validation-type={validationType}
|
||||
disabled={disabled}
|
||||
{...inputValue}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.detailItemMessage}>
|
||||
{!hasError &&
|
||||
showSuccess &&
|
||||
value && (
|
||||
<Icon className={styles.checkIcon} name="check_circle" />
|
||||
)}
|
||||
{hasError && showError && <ErrorMessage>{errorMsg}</ErrorMessage>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
InputField.propTypes = {
|
||||
id: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
label: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
name: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func,
|
||||
value: PropTypes.string,
|
||||
defaultValue: PropTypes.string,
|
||||
icon: PropTypes.string,
|
||||
showError: PropTypes.bool,
|
||||
hasError: PropTypes.bool,
|
||||
errorMsg: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
columnDisplay: PropTypes.bool,
|
||||
showSuccess: PropTypes.bool,
|
||||
validationType: PropTypes.string,
|
||||
};
|
||||
|
||||
export default InputField;
|
||||
@@ -0,0 +1,36 @@
|
||||
.step {
|
||||
color: #BBBEBF;
|
||||
background-color: white;
|
||||
padding: 6px;
|
||||
z-index: 10;
|
||||
|
||||
> .icon {
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
&.current {
|
||||
color: rgba(0, 205, 115, 0.3);
|
||||
}
|
||||
|
||||
&.completed {
|
||||
color: #00CD73;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
position: absolute;
|
||||
border: solid 2px #BBBEBF;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
position: relative;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
margin: 0 20px;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './StepProgress.css';
|
||||
import { Icon } from 'plugin-api/beta/client/components/ui';
|
||||
|
||||
const CheckItem = ({ current = false, completed = false }) => (
|
||||
<span
|
||||
className={cn(styles.step, {
|
||||
[styles.current]: current,
|
||||
[styles.completed]: completed,
|
||||
})}
|
||||
>
|
||||
<Icon name="check_circle" className={styles.icon} />
|
||||
</span>
|
||||
);
|
||||
|
||||
CheckItem.propTypes = {
|
||||
current: PropTypes.bool.isRequired,
|
||||
completed: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const Line = () => <hr className={styles.line} />;
|
||||
|
||||
class StepProgress extends React.Component {
|
||||
render() {
|
||||
const { currentStep, totalSteps } = this.props;
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
{Array.from({ length: totalSteps }).map((_, i) => (
|
||||
<CheckItem
|
||||
key={`step_${i}`}
|
||||
completed={i < currentStep}
|
||||
current={currentStep === i}
|
||||
/>
|
||||
))}
|
||||
<Line />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
StepProgress.propTypes = {
|
||||
currentStep: PropTypes.number.isRequired,
|
||||
totalSteps: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
export default StepProgress;
|
||||
@@ -0,0 +1,25 @@
|
||||
import { compose, gql } from 'react-apollo';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect, withFragments, excludeIf } from 'plugin-api/beta/client/hocs';
|
||||
import AccountDeletionRequestedSign from '../components/AccountDeletionRequestedSign';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { withCancelAccountDeletion } from '../hocs';
|
||||
|
||||
const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch);
|
||||
|
||||
const withData = withFragments({
|
||||
root: gql`
|
||||
fragment Talk_AccountDeletionRequestedSignIn_root on RootQuery {
|
||||
me {
|
||||
scheduledDeletionDate
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
export default compose(
|
||||
connect(null, mapDispatchToProps),
|
||||
withCancelAccountDeletion,
|
||||
withData,
|
||||
excludeIf(({ root: { me } }) => !me || !me.scheduledDeletionDate)
|
||||
)(AccountDeletionRequestedSign);
|
||||
@@ -0,0 +1,28 @@
|
||||
import { compose, gql } from 'react-apollo';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect, withFragments } from 'plugin-api/beta/client/hocs';
|
||||
import DeleteMyAccount from '../components/DeleteMyAccount';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { withRequestAccountDeletion, withCancelAccountDeletion } from '../hocs';
|
||||
|
||||
const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch);
|
||||
|
||||
const withData = withFragments({
|
||||
root: gql`
|
||||
fragment Talk_DeleteMyAccount_root on RootQuery {
|
||||
me {
|
||||
scheduledDeletionDate
|
||||
}
|
||||
settings {
|
||||
organizationContactEmail
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
export default compose(
|
||||
connect(null, mapDispatchToProps),
|
||||
withRequestAccountDeletion,
|
||||
withCancelAccountDeletion,
|
||||
withData
|
||||
)(DeleteMyAccount);
|
||||
@@ -1,27 +1,36 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { compose, gql } from 'react-apollo';
|
||||
import DownloadCommentHistory from '../components/DownloadCommentHistory';
|
||||
import { withFragments } from 'plugin-api/beta/client/hocs';
|
||||
import { withRequestDownloadLink } from '../hocs';
|
||||
import { connect, withFragments } from 'plugin-api/beta/client/hocs';
|
||||
import { withRequestDownloadLink } from '../hocs';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
|
||||
class DownloadCommentHistoryContainer extends Component {
|
||||
static propTypes = {
|
||||
requestDownloadLink: PropTypes.func.isRequired,
|
||||
root: PropTypes.object.isRequired,
|
||||
notify: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<DownloadCommentHistory
|
||||
root={this.props.root}
|
||||
notify={this.props.notify}
|
||||
requestDownloadLink={this.props.requestDownloadLink}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch);
|
||||
|
||||
const enhance = compose(
|
||||
connect(null, mapDispatchToProps),
|
||||
withFragments({
|
||||
root: gql`
|
||||
fragment TalkDownloadCommentHistory_DownloadCommentHistorySection_root on RootQuery {
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
import update from 'immutability-helper';
|
||||
import { createDefaultResponseFragments } from 'coral-framework/utils';
|
||||
|
||||
export default {
|
||||
fragments: {
|
||||
...createDefaultResponseFragments(
|
||||
'RequestAccountDeletionResponse',
|
||||
'RequestDownloadLinkResponse',
|
||||
'CancelAccountDeletionResponse'
|
||||
),
|
||||
},
|
||||
mutations: {
|
||||
DownloadCommentHistory: () => ({
|
||||
RequestDownloadLink: () => ({
|
||||
updateQueries: {
|
||||
CoralEmbedStream_Profile: previousData =>
|
||||
update(previousData, {
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import DownloadCommentHistory from './containers/DownloadCommentHistory';
|
||||
import DeleteMyAccount from './containers/DeleteMyAccount';
|
||||
import AccountDeletionRequestedSign from './containers/AccountDeletionRequestedSign';
|
||||
import translations from './translations.yml';
|
||||
import graphql from './graphql';
|
||||
|
||||
export default {
|
||||
slots: {
|
||||
profileSettings: [DownloadCommentHistory],
|
||||
stream: [AccountDeletionRequestedSign],
|
||||
profileSettings: [DownloadCommentHistory, DeleteMyAccount],
|
||||
},
|
||||
translations,
|
||||
...graphql,
|
||||
|
||||
@@ -2,7 +2,7 @@ en:
|
||||
download_request:
|
||||
section_title: "Download My Comment History"
|
||||
you_will_get_a_copy: "You will recieve an email with a link to download your comment history. You can make"
|
||||
download_rate: "one download request every 7 days"
|
||||
download_rate: "one download request every {0} days"
|
||||
most_recent_request: "Your most recent request"
|
||||
request: "Request Comment History"
|
||||
rate_limit: "You can submit another Comment History request in {0}"
|
||||
@@ -10,3 +10,42 @@ en:
|
||||
days: "{0} days"
|
||||
hour: "{0} hour"
|
||||
day: "{0} day"
|
||||
download_preparing: "Account Download Preparing - Check your email shortly for a download link"
|
||||
delete_request:
|
||||
account_deletion_cancelled: 'Account Deletion Request Cancelled - Your request to delete your account has been cancelled.'
|
||||
account_deletion_requested: 'Account Deletion Requested'
|
||||
received_on: "A request to delete your account was received on "
|
||||
cancel_request_description: "If you would like to reactivate your account, you may cancel your request to delete your account below"
|
||||
before: "before"
|
||||
cancel_account_deletion_request: "Cancel Account Deletion Request"
|
||||
delete_my_account: "Delete My Account"
|
||||
delete_my_account_description: "Deleting your account will permanently erase your profile and remove all your comments from this site."
|
||||
already_submitted_request_description: "You have already submitted a request to delete your account. Your account will be deleted on {0}. You may cancel the request until that time"
|
||||
your_request_submitted_description: "Your request has been submitted and confirmation has been sent to the email address associated with your account."
|
||||
your_account_deletion_scheduled: "Your account is scheduled to be deleted at:"
|
||||
changed_your_mind: "Changed your mind?"
|
||||
simply_go_to: "Simply go to your account again before this time and click"
|
||||
tell_us_why: "Tell us why"
|
||||
feedback_copy: "We would like to know why you chose to delete your account. Send us feedback on our comment system by emailing"
|
||||
done: "Done"
|
||||
cancel: "Cancel"
|
||||
proceed: "Proceed"
|
||||
input_is_not_correct: "The input is not correct"
|
||||
step_0:
|
||||
you_are_attempting: "You are attempting to delete your account. This means:"
|
||||
item_1: "All of your comments are removed from this site"
|
||||
item_2: "All of your comments are deleted from our database"
|
||||
item_3: "Your username and email address are removed from our system"
|
||||
step_1:
|
||||
subtitle: "When will my account be deleted?"
|
||||
description: "Your account will be deleted {0} hours after your request has been submitted."
|
||||
subtitle_2: "Can I still write comments until my account is deleted?"
|
||||
description_2: "Yes, you can still comment, reply, and react to comments until the {0} hours expires."
|
||||
step_2:
|
||||
description: "Before your account is deleted, we recommend you download your comment history for your records. After your account is deleted, you will be unable to request your comment history."
|
||||
to_download: "To download your comment history go to:"
|
||||
path: "My Profile > Download My Comment History"
|
||||
step_3:
|
||||
subtitle: "Are you sure you want to delete your account?"
|
||||
description: "To confirm you would like to delete your account please type in the following phrase into the text box below:"
|
||||
type_to_confirm: "Type phrase below to confirm"
|
||||
|
||||
Reference in New Issue
Block a user