diff --git a/src/helpers/AccountHelper.ts b/src/helpers/AccountHelper.ts
index 3947137..567a012 100644
--- a/src/helpers/AccountHelper.ts
+++ b/src/helpers/AccountHelper.ts
@@ -17,6 +17,12 @@ export interface AdminAccount {
time_create: number;
}
+export interface NewAdminGeneralSettings {
+ id: number;
+ name: string;
+ email: string;
+}
+
const SESSION_STORAGE_TOKEN = "auth_token";
let currentAccount: AdminAccount | null = null;
@@ -114,4 +120,17 @@ export class AccountHelper {
sessionStorage.removeItem(SESSION_STORAGE_TOKEN);
document.location.href = document.location.href + "";
}
+
+ /**
+ * Update an admin's settings
+ *
+ * @param a New settings
+ */
+ static async UpdateGeneralSettings(s: NewAdminGeneralSettings) {
+ await serverRequest("admins/update_general_settings", {
+ id: s.id,
+ name: s.name,
+ email: s.email,
+ });
+ }
}
diff --git a/src/ui/routes/AccountSettingsRoute.tsx b/src/ui/routes/AccountSettingsRoute.tsx
index 8b5d4d8..43adf86 100644
--- a/src/ui/routes/AccountSettingsRoute.tsx
+++ b/src/ui/routes/AccountSettingsRoute.tsx
@@ -4,10 +4,19 @@
* @author Pierre Hubert
*/
+import {
+ Button,
+ Divider,
+ Grid,
+ Paper,
+ TextField,
+ Typography,
+} from "@material-ui/core";
import React from "react";
import { useParams } from "react-router-dom";
import { AccountHelper, AdminAccount } from "../../helpers/AccountHelper";
import { AsyncWidget } from "../widgets/AsyncWidget";
+import { matAlert, snackbar } from "../widgets/DialogsProvider";
export function AccountSettingsRoute() {
let params: any = useParams();
@@ -52,6 +61,110 @@ class AccountSettingsRouteInner extends React.Component<
}
build() {
- return
{this.state.account.email}
;
+ return (
+
+
+
+ );
}
}
+
+class GeneralSettings extends React.Component<
+ { admin: AdminAccount },
+ { newName: string; newEmail: string }
+> {
+ constructor(p: any) {
+ super(p);
+
+ this.state = {
+ newName: this.props.admin.name,
+ newEmail: this.props.admin.email,
+ };
+
+ this.changedName = this.changedName.bind(this);
+ this.changedEmail = this.changedEmail.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+ }
+
+ changedName(e: React.ChangeEvent) {
+ this.setState({ newName: e.target.value });
+ }
+
+ changedEmail(e: React.ChangeEvent) {
+ this.setState({ newEmail: e.target.value });
+ }
+
+ get isValid(): boolean {
+ return this.state.newEmail.length > 2 && this.state.newName.length > 2;
+ }
+
+ async handleSubmit() {
+ try {
+ if (!this.isValid) return;
+
+ await AccountHelper.UpdateGeneralSettings({
+ id: this.props.admin.id,
+ name: this.state.newName,
+ email: this.state.newEmail,
+ });
+
+ snackbar("Successfully updated admin settings!");
+ } catch (e) {
+ console.error(e);
+ matAlert("Failed to update admin settings!");
+ }
+ }
+
+ render() {
+ return (
+
+
+
+
+
+
+
+ );
+ }
+}
+
+function SettingsSection(p: { title: string; children?: React.ReactNode }) {
+ return (
+
+
+
+ General settings
+
+
+
+ {p.children}
+
+
+
+ );
+}
diff --git a/src/ui/routes/MainRoute.tsx b/src/ui/routes/MainRoute.tsx
index 5cab5ac..ead154c 100644
--- a/src/ui/routes/MainRoute.tsx
+++ b/src/ui/routes/MainRoute.tsx
@@ -155,20 +155,28 @@ export function MainRoute() {
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
+
diff --git a/src/ui/widgets/AsyncWidget.tsx b/src/ui/widgets/AsyncWidget.tsx
index 9a6f251..9591370 100644
--- a/src/ui/widgets/AsyncWidget.tsx
+++ b/src/ui/widgets/AsyncWidget.tsx
@@ -59,7 +59,7 @@ export class AsyncWidget extends React.Component<
}
componentDidUpdate() {
- if (this.state.key != this.props.key) {
+ if (this.state.key !== this.props.key) {
this.setState({ key: this.props.key });
this.reload();
}
diff --git a/src/ui/widgets/DialogsProvider.tsx b/src/ui/widgets/DialogsProvider.tsx
index 188d5f8..a4231c8 100644
--- a/src/ui/widgets/DialogsProvider.tsx
+++ b/src/ui/widgets/DialogsProvider.tsx
@@ -1,242 +1,324 @@
/**
* Application dialogs provider
- *
+ *
* @author Pierre Hubert
*/
-import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Button, TextField } from "@material-ui/core";
+import {
+ Dialog,
+ DialogTitle,
+ DialogContent,
+ DialogContentText,
+ DialogActions,
+ Button,
+ TextField,
+ Snackbar,
+ IconButton,
+} from "@material-ui/core";
+import { Close } from "@material-ui/icons";
import React from "react";
-let cache : ApplicationDialogsProvider;
+let cache: ApplicationDialogsProvider;
export interface TextInputOptions {
- title ?: string,
- message ?: string,
- initialValue ?: string,
- minLength ?: number,
- maxLength ?: number,
- label : string,
+ title?: string;
+ message?: string;
+ initialValue?: string;
+ minLength?: number;
+ maxLength?: number;
+ label: string;
}
interface AppDiagProvState {
+ // Alert dialog
+ alertMessage: string;
+ showAlert: boolean;
- // Alert dialog
- alertMessage : string,
- showAlert : boolean,
+ // Simple snackbar
+ snackBarMessage: string;
+ showSnackBar: boolean;
- // Confirm dialog
- confirmMessage: string,
- showConfirm: boolean,
- resolveConfirm ?: (confirmed: boolean) => void,
-
- // Text input dialog
- showInputDialog: boolean,
- inputValue: string,
- inputOptions: TextInputOptions,
- resolveInput ?: (text: string) => void,
+ // Confirm dialog
+ confirmMessage: string;
+ showConfirm: boolean;
+ resolveConfirm?: (confirmed: boolean) => void;
+ // Text input dialog
+ showInputDialog: boolean;
+ inputValue: string;
+ inputOptions: TextInputOptions;
+ resolveInput?: (text: string) => void;
}
-export class ApplicationDialogsProvider extends React.Component<{}, AppDiagProvState> {
- private acceptConfirm: () => void;
- private rejectConfirm: () => void;
- private cancelInput: () => void;
- private confirmInput: () => void;
+export class ApplicationDialogsProvider extends React.Component<
+ {},
+ AppDiagProvState
+> {
+ private acceptConfirm: () => void;
+ private rejectConfirm: () => void;
+ private cancelInput: () => void;
+ private confirmInput: () => void;
- constructor(props: any) {
- super(props);
+ constructor(props: any) {
+ super(props);
- this.state = {
+ this.state = {
+ // Alert dialog
+ alertMessage: "",
+ showAlert: false,
- // Alert dialog
- alertMessage: "",
- showAlert: false,
+ // Simple snackbar
+ snackBarMessage: "",
+ showSnackBar: false,
- // Confirm dialog
- showConfirm: false,
- confirmMessage: "",
- resolveConfirm: undefined,
+ // Confirm dialog
+ showConfirm: false,
+ confirmMessage: "",
+ resolveConfirm: undefined,
- // Text input dialog
- showInputDialog: false,
- inputValue: "",
- inputOptions: {
- label: ""
- },
- resolveInput: undefined,
- };
+ // Text input dialog
+ showInputDialog: false,
+ inputValue: "",
+ inputOptions: {
+ label: "",
+ },
+ resolveInput: undefined,
+ };
- this.handleCloseAlert = this.handleCloseAlert.bind(this);
+ this.handleCloseAlert = this.handleCloseAlert.bind(this);
- this.acceptConfirm = this.handleCloseConfirm.bind(this, true);
- this.rejectConfirm = this.handleCloseConfirm.bind(this, false);
+ this.handleCloseSnackbar = this.handleCloseSnackbar.bind(this);
- this.handleInputValueChanged = this.handleInputValueChanged.bind(this);
- this.cancelInput = this.handleCloseInput.bind(this, true);
- this.confirmInput = this.handleCloseInput.bind(this, false);
- }
+ this.acceptConfirm = this.handleCloseConfirm.bind(this, true);
+ this.rejectConfirm = this.handleCloseConfirm.bind(this, false);
- showAlert(message: string) {
- this.setState({
- showAlert: true,
- alertMessage: message,
- })
- }
+ this.handleInputValueChanged = this.handleInputValueChanged.bind(this);
+ this.cancelInput = this.handleCloseInput.bind(this, true);
+ this.confirmInput = this.handleCloseInput.bind(this, false);
+ }
- handleCloseAlert() {
- this.setState({showAlert: false});
- }
+ showAlert(message: string) {
+ this.setState({
+ showAlert: true,
+ alertMessage: message,
+ });
+ }
- showConfirm(message: string) : Promise {
- return new Promise((res, _rej) => {
- this.setState({
- showConfirm: true,
- confirmMessage: message,
- resolveConfirm: res
- });
- });
- }
+ handleCloseAlert() {
+ this.setState({ showAlert: false });
+ }
- handleCloseConfirm(accept: boolean) {
- this.setState({
- showConfirm: false
- });
+ showSnackbar(message: string) {
+ this.setState({ showSnackBar: true, snackBarMessage: message });
+ }
- this.state.resolveConfirm && this.state.resolveConfirm(accept);
- }
+ handleCloseSnackbar(
+ _event: React.SyntheticEvent | React.MouseEvent,
+ reason?: string
+ ) {
+ if (reason === "clickaway") {
+ return;
+ }
- showInput(options: TextInputOptions) : Promise {
- return new Promise((res, _rej) => {
- this.setState({
- showInputDialog: true,
- inputOptions: options,
- resolveInput: res,
- inputValue: options.initialValue || ""
- });
- });
- }
+ this.setState({ showSnackBar: false });
+ }
- handleInputValueChanged(e: React.ChangeEvent){
- this.setState({inputValue: e.target.value});
- }
+ showConfirm(message: string): Promise {
+ return new Promise((res, _rej) => {
+ this.setState({
+ showConfirm: true,
+ confirmMessage: message,
+ resolveConfirm: res,
+ });
+ });
+ }
- handleCloseInput(cancel: boolean) {
- this.setState({
- showInputDialog: false
- });
+ handleCloseConfirm(accept: boolean) {
+ this.setState({
+ showConfirm: false,
+ });
- if (!cancel)
- this.state.resolveInput && this.state.resolveInput(this.state.inputValue);
- }
-
- get isInputValid() : boolean {
- const options = this.state.inputOptions;
- const value = this.state.inputValue;
+ this.state.resolveConfirm && this.state.resolveConfirm(accept);
+ }
- if (options.minLength && value.length < options.minLength)
- return false;
+ showInput(options: TextInputOptions): Promise {
+ return new Promise((res, _rej) => {
+ this.setState({
+ showInputDialog: true,
+ inputOptions: options,
+ resolveInput: res,
+ inputValue: options.initialValue || "",
+ });
+ });
+ }
- if (options.maxLength && value.length > options.maxLength)
- return false;
+ handleInputValueChanged(e: React.ChangeEvent) {
+ this.setState({ inputValue: e.target.value });
+ }
- return true;
- }
+ handleCloseInput(cancel: boolean) {
+ this.setState({
+ showInputDialog: false,
+ });
- render() {
- cache = this;
+ if (!cancel)
+ this.state.resolveInput &&
+ this.state.resolveInput(this.state.inputValue);
+ }
- if(this.state == null)
- return();
+ get isInputValid(): boolean {
+ const options = this.state.inputOptions;
+ const value = this.state.inputValue;
- return (
-
- {/* Simple alert dialog */}
-
+ if (options.minLength && value.length < options.minLength) return false;
- {/* Confirm dialog */}
-
+ if (options.maxLength && value.length > options.maxLength) return false;
- {/* Text input dialog */}
-
-
)
- }
+ render() {
+ cache = this;
+
+ if (this.state == null) return ;
+
+ return (
+
+ {/* Simple alert dialog */}
+
+
+ {/* Simple snackbar */}
+
+
+
+
+
+ }
+ />
+
+ {/* Confirm dialog */}
+
+
+ {/* Text input dialog */}
+
+
+ );
+ }
}
export function matAlert(msg: string) {
- cache.showAlert(msg);
+ cache.showAlert(msg);
}
-export function matConfirm(msg: string) : Promise {
- return cache.showConfirm(msg);
+export function snackbar(msg: string) {
+ cache.showSnackbar(msg);
}
-export function input(options: TextInputOptions) : Promise {
- return cache.showInput(options);
-}
\ No newline at end of file
+export function matConfirm(msg: string): Promise {
+ return cache.showConfirm(msg);
+}
+
+export function input(options: TextInputOptions): Promise {
+ return cache.showInput(options);
+}