diff --git a/src/helpers/ComunicUsersHelper.ts b/src/helpers/ComunicUsersHelper.ts index 515b3a4..757ffeb 100644 --- a/src/helpers/ComunicUsersHelper.ts +++ b/src/helpers/ComunicUsersHelper.ts @@ -61,4 +61,14 @@ export class ComunicUsersHelper { user_id: id, }); } + + /** + * Change the email address of a user + */ + static async ChangeEmail(id: number, newEmail: string): Promise { + await serverRequest("users/change_email_address", { + user_id: id, + new_mail: newEmail, + }); + } } diff --git a/src/ui/routes/ComunicUserRoute.tsx b/src/ui/routes/ComunicUserRoute.tsx index 80797ed..d9846a0 100644 --- a/src/ui/routes/ComunicUserRoute.tsx +++ b/src/ui/routes/ComunicUserRoute.tsx @@ -1,21 +1,24 @@ import { Avatar, + Button, Grid, Table, TableBody, TableCell, TableRow, } from "@material-ui/core"; +import EmailIcon from "@material-ui/icons/Email"; import React from "react"; import { ComunicUser, ComunicUsersHelper, } from "../../helpers/ComunicUsersHelper"; +import { validateEmail } from "../../utils/StringsUtils"; import { AsyncWidget } from "../widgets/AsyncWidget"; import { CustomCard } from "../widgets/CustomCard"; +import { input, matAlert } from "../widgets/DialogsProvider"; import { PageTitle } from "../widgets/PageTitle"; import { TimestampWidget } from "../widgets/TimestampWidget"; - interface UserProperty { name: string; value?: string | number; @@ -37,6 +40,7 @@ export class ComunicUserRoute extends React.Component< this.load = this.load.bind(this); this.build = this.build.bind(this); + this.changeEmailAddress = this.changeEmailAddress.bind(this); } get user(): ComunicUser { @@ -101,6 +105,42 @@ export class ComunicUserRoute extends React.Component< ]; } + get userID(): number { + return this.props.userID; + } + + get fullName(): string { + return this.user.first_name + " " + this.user.last_name; + } + + async changeEmailAddress() { + try { + const newEmail = await input({ + title: "Change user email address", + label: "New email address", + message: + "Please input the new email address for " + + this.fullName + + ":", + type: "email", + minLength: 5, + validateInput: validateEmail, + }); + + if (!newEmail || newEmail.length === 0) return; + + await ComunicUsersHelper.ChangeEmail(this.userID, newEmail); + + this.setState((s) => { + s.user.email = newEmail; + return s; + }); + } catch (e) { + console.error(e); + matAlert("Failed to update user email address!"); + } + } + build() { const properties = this.userProperties.map((p) => { return ( @@ -158,6 +198,21 @@ export class ComunicUserRoute extends React.Component< + + +
+ +
+
+
); diff --git a/src/ui/widgets/DialogsProvider.tsx b/src/ui/widgets/DialogsProvider.tsx index 8309c53..f036469 100644 --- a/src/ui/widgets/DialogsProvider.tsx +++ b/src/ui/widgets/DialogsProvider.tsx @@ -28,6 +28,7 @@ export interface TextInputOptions { maxLength?: number; label: string; type?: string; + validateInput?: (value: string) => boolean; } interface AppDiagProvState { @@ -175,6 +176,9 @@ export class ApplicationDialogsProvider extends React.Component< if (options.maxLength && value.length > options.maxLength) return false; + if (options.validateInput && !options.validateInput(value)) + return false; + return true; } diff --git a/src/utils/StringsUtils.ts b/src/utils/StringsUtils.ts new file mode 100644 index 0000000..ea38f07 --- /dev/null +++ b/src/utils/StringsUtils.ts @@ -0,0 +1,11 @@ +/** + * String utilities + * + * @author Pierre Hubert + */ + +export function validateEmail(email: string) { + const re = + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(String(email).toLowerCase()); +}