Skip to content

Commit

Permalink
Feature: email revalidation (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
bobhageman authored Jul 12, 2023
1 parent b1a57d9 commit ae5f91a
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 6 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added
- E-mail address 'being revalidated' indicator icon with tooltip
- E-mail address 'being deleted' indicator icon with tooltip
- Custom warnings when and invalid e-mail address is marked for revalidation while deleting e-mail address or account

## [3.0.0] - 2023-03-23
### Added
- New Yivi look & feel
Expand Down
4 changes: 4 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import LoadingSpinner from './widgets/loading_spinner';
import AccountOverview from './components/account_overview';
import RegistrationVerified from './components/registration_verified';
import TokenInvalid from './components/token_invalid';
import WarningMessage from './components/warning_message';
import ErrorMessage from './components/error_message';

const mapStateToProps = (state) => {
Expand All @@ -13,6 +14,7 @@ const mapStateToProps = (state) => {
loggedIn: state.login.sessionState === 'loggedIn',
registrationVerified: state.login.sessionState === 'showPostRegistration',
tokenInvalid: state.login.sessionState === 'tokenInvalid',
warningRaised: state.login.sessionState === 'warningRaised',
errorRaised: state.login.error !== '',
};
};
Expand All @@ -29,6 +31,8 @@ const App = (props) => {
return <RegistrationVerified dispatch={props.dispatch} />;
} else if (props.tokenInvalid) {
return <TokenInvalid dispatch={props.dispatch} />;
} else if (props.warningRaised) {
return <WarningMessage />;
} else {
return <Login />;
}
Expand Down
18 changes: 17 additions & 1 deletion src/components/emails/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,23 @@ class Emails extends React.Component {
<td>{address.email}</td>
<td className={styles.deleteColumn}>
{address.delete_in_progress ? (
this.t('delete-in-progress')
<a
role="button"
tabIndex="0"
className={styles.tooltip}
data-title={this.t('delete-in-progress-explanation')}
>
{this.t('delete-in-progress')}
</a>
) : address.revalidate_in_progress ? (
<a
role="button"
tabIndex="0"
className={styles.tooltip}
data-title={this.t('revalidate-in-progress-explanation')}
>
{this.t('revalidate-in-progress')}
</a>
) : (
<YiviButton theme={'ghost'} onClick={() => this.onDeleteEmail(address.email)}>
<CrossIcon />
Expand Down
40 changes: 40 additions & 0 deletions src/components/emails/index.module.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,43 @@
.deleteColumn > * {
float: right;
}

.tooltip {
position: relative;
text-decoration: none;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" viewBox="0 0 24 24"><path d="M12,2A10,10,0,1,0,22,12,10,10,0,0,0,12,2Zm1,15a1,1,0,0,1-2,0V11a1,1,0,0,1,2,0ZM12,8a1.5,1.5,0,1,1,1.5-1.5A1.5,1.5,0,0,1,12,8Z"/></svg>')
no-repeat;
background-position: right top;
padding-right: 18px;
cursor: pointer;
}

.tooltip:hover::before,
.tooltip.active::before,
.tooltip:focus::before {
position: absolute;
width: 0;
height: 0;
right: 0;
bottom: 15px;
content: '';
border-style: solid;
border-width: 10px;
border-color: #000 transparent transparent transparent;
}

.tooltip:hover::after,
.tooltip.active::after,
.tooltip:focus::after {
position: absolute;
right: -10px;
bottom: 35px;
width: 200px;
padding: 12px;
content: attr(data-title);
font-size: 0.9em;
border-radius: 8px;
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1);
background: #000;
color: #fff;
}
36 changes: 36 additions & 0 deletions src/components/warning_message/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import { withTranslation } from 'react-i18next';
import { connect } from 'react-redux';

import YiviAppBar from '../../widgets/yivi_app_bar';
import YiviButton from '../../widgets/yivi_button';
import Column from '../../widgets/column';
import Spacer from '../../widgets/spacer';

const mapStateToProps = (state) => {
return {
explanation: state.login.explanation,
details: state.login.details,
};
};

const WarningMessage = (props) => {
const onReturn = () => {
props.dispatch({ type: 'resolveError' });
};

return (
<>
<YiviAppBar title={props.t('header')} />
<Column>
<Spacer />
<p>{props.t(props.explanation)}</p>
<p>{props.t(props.details)}</p>
<YiviButton theme={'primary'} onClick={onReturn}>
{props.t('return')}
</YiviButton>
</Column>
</>
);
};
export default connect(mapStateToProps)(withTranslation('warning-message')(WarningMessage));
25 changes: 20 additions & 5 deletions src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createStore, applyMiddleware, combineReducers } from 'redux';

import login from './loginstate';
import logs from './logs';
import userdata from './userdata';
Expand Down Expand Up @@ -64,9 +63,15 @@ function handleEmail({ dispatch }) {
body: action.email,
credentials: 'include',
})
.then((res) => res.json())
.then((res) => {
if (res.status !== 204) throw res.status;
dispatch({ type: 'emailRemoved' });
if (res.status === 204) {
dispatch({ type: 'emailRemoved' });
} else if (res.status === 500 && res.error === 'REVALIDATE_EMAIL') {
dispatch({ type: 'raiseWarning', explanation: 'delete-mail-explanation', details: 'delete-mail-details' });
} else {
throw res.status;
}
})
.catch((err) => {
dispatch({ type: 'raiseError', errorMessage: `Error while removing email: ${err}` });
Expand All @@ -83,9 +88,19 @@ function handleDeleteAccount({ dispatch }) {
method: 'POST',
credentials: 'include',
})
.then((res) => res.json())
.then((res) => {
if (res.status !== 204) throw res.status;
dispatch({ type: 'logout' });
if (res.status === 204) {
dispatch({ type: 'logout' });
} else if (res.status === 500 && res.error === 'REVALIDATE_EMAIL') {
dispatch({
type: 'raiseWarning',
explanation: 'delete-account-mail-explanation',
details: 'delete-account-mail-details',
});
} else {
throw res.status;
}
})
.catch((err) => {
dispatch({ type: 'raiseError', errorMessage: `Error while deleting account: ${err}` });
Expand Down
7 changes: 7 additions & 0 deletions src/store/loginstate.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ export default function login(state = initialState, action) {
...state,
sessionState: 'tokenInvalid',
};
case 'raiseWarning':
return {
...state,
sessionState: 'warningRaised',
explanation: action.explanation,
details: action.details,
};
case 'raiseError':
return state.error
? state
Expand Down
1 change: 1 addition & 0 deletions src/store/userdata.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default function userdata(state = initialState, action) {
...state,
username: action.data.username,
deleting: action.data.delete_in_progress,
revalidating: action.data.revalidate_in_progress,
emails: action.data.emails,
fetching: false,
};
Expand Down
11 changes: 11 additions & 0 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
"emailaddress": "E-mail",
"delete": "Delete",
"delete-in-progress": "Being deleted",
"delete-in-progress-explanation": "Your e-mail address is marked for deletion and will be deleted within a few days.",
"revalidate-in-progress": "Being revalidated",
"revalidate-in-progress-explanation": "Your e-mail address is marked invalid because it was unreachable. Does it still exist? We will check again within 5 days. If it works, your e-mail address will be active again. If not, we will delete it for you.",
"add-email": "Add e-mail address",
"delete-confirm-header": "Confirm",
"delete-confirm-explanation": "Are you sure you want to delete {{email}}?"
Expand Down Expand Up @@ -98,6 +101,14 @@
"point-4":"Click on 'Add e-mail address' and follow the instructions to add your e-mail address to MyYivi.",
"retry": "Go to MyYivi"
},
"warning-message": {
"header": "Something went wrong",
"return": "Go back",
"delete-account-mail-explanation": "We could not send an e-mail to one or more of your registered e-mail addresses.",
"delete-account-mail-details": "Please check if your e-mail addresses are still valid and working properly. Since sending the email failed, we will revalidate your e-mail address in 5 days and delete it if the issue persists. Until then, access to your Yivi app and MyYivi is blocked. Afterwards you can proceed deleting your account.",
"delete-mail-explanation": "We could not mark your e-mail address for deletion.",
"delete-mail-details": "It seems that your e-mail address does not work or is no longer active, so we have temporarily marked it as invalid. Does it still exist? We will revalidate your e-mail address in 5 days and will delete it if the issue persists. If it does work by then, your e-mail address will be active again."
},
"error-message": {
"header": "Something went wrong",
"explanation": "The requested action could not be processed. Please check your internet connection and try again. If the problem keeps occurring, please contact Yivi.",
Expand Down
11 changes: 11 additions & 0 deletions src/translations/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
"emailaddress": "E-mail",
"delete": "Verwijder",
"delete-in-progress": "Wordt verwijderd",
"delete-in-progress-explanation": "Je e-mailadres is gemarkeerd voor verwijdering en wordt binnen enkele dagen verwijderd.",
"revalidate-in-progress": "Wordt gevalideerd",
"revalidate-in-progress-explanation": "Je e-mailadres is gemarkeerd als ongeldig omdat het niet bereikbaar was. Bestaat het nog wel? We controleren het nogmaals binnen 5 dagen. Werkt het dan wel, dan wordt je e-mailadres weer vrijgegeven. Zo niet, dan zullen we het voor je verwijderen.",
"add-email": "Voeg e-mailadres toe",
"delete-confirm-header": "Bevestigen",
"delete-confirm-explanation": "Weet je zeker dat je {{email}} wilt verwijderen?"
Expand Down Expand Up @@ -98,6 +101,14 @@
"point-4":"Klik op 'Voeg e-mailadres toe' en volg de instructies om je e-mailadres toe toe voegen aan MijnYivi.",
"retry": "Ga naar MijnYivi"
},
"warning-message": {
"header": "Er ging iets mis",
"return": "Ga terug",
"delete-account-mail-explanation": "We konden geen e-mail sturen aan één of meerdere van jouw geregistreerde e-mailadressen.",
"delete-account-mail-details": "Controleer of jouw e-mailadresssen nog werken. Omdat het verzenden van de e-mail niet lukte, valideren we jouw e-mailadres over 5 dagen opnieuw en zullen we het verwijderen als het probleem zich nog steeds voordoet. Tot die tijd is toegang tot jouw Yivi app en MijnYivi geblokkeerd. Daarna kan je jouw account alsnog verwijderen.",
"delete-mail-explanation": "We konden jouw e-mailadres niet markeren voor verwijdering.",
"delete-mail-details": "Het lijkt erop dat je e-mail adres niet werkt of niet meer actief is en daarom hebben we het tijdelijk als ongeldig gemarkeerd. Bestaat het nog? We valideren jouw e-mailadres over 5 dagen opnieuw en zullen het verwijderen als het probleem zich nog steeds voordoet. Werkt het wel, dan wordt je e-mailadres weer actief."
},
"error-message": {
"header": "Er ging iets mis",
"explanation": "De gevraagde actie kon niet worden verwerkt. Controleer je internetverbinding en probeer het opnieuw. Als de fout blijft aanhouden, neem dan contact op met Yivi.",
Expand Down

0 comments on commit ae5f91a

Please sign in to comment.