diff options
-rw-r--r-- | src/client/util/GroupManager.scss | 45 | ||||
-rw-r--r-- | src/client/util/GroupManager.tsx | 120 |
2 files changed, 97 insertions, 68 deletions
diff --git a/src/client/util/GroupManager.scss b/src/client/util/GroupManager.scss index 4df1b4758..dea22703b 100644 --- a/src/client/util/GroupManager.scss +++ b/src/client/util/GroupManager.scss @@ -50,7 +50,6 @@ } } - .editing-contents { overflow-y: auto; // max-height: 67%; @@ -169,57 +168,13 @@ margin: 2px 0; } - .error-text { - color: #C40233; - } - - .success-text { - color: #009F6B; - } - - p { - padding: 0 0 .1em .2em; - } - } } - .focus-span { - text-decoration: underline; - } - h1 { color: $dark-color; text-transform: uppercase; letter-spacing: 2px; font-size: 120%; } - - .container { - display: block; - position: relative; - margin-top: 10px; - margin-bottom: 10px; - font-size: 22px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: 700px; - min-width: 700px; - max-width: 700px; - text-align: left; - font-style: normal; - font-size: 15; - font-weight: normal; - padding: 0; - - .padding { - padding: 0 0 0 20px; - color: black; - } - - - - } }
\ No newline at end of file diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 290f0e026..7f48ca014 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -1,18 +1,18 @@ import * as React from "react"; -import { observable, action, runInAction, computed } from "mobx"; +import { observable, action, runInAction, computed, Lambda, reaction } from "mobx"; import { SelectionManager } from "./SelectionManager"; import MainViewModal from "../views/MainViewModal"; import { observer } from "mobx-react"; import { Doc, DocListCast, Opt } from "../../fields/Doc"; -import { List } from "../../fields/List"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as fa from '@fortawesome/free-solid-svg-icons'; import { library } from "@fortawesome/fontawesome-svg-core"; -import SharingManager, { User } from "./SharingManager"; +import { User } from "./SharingManager"; import { Utils } from "../../Utils"; import * as RequestPromise from "request-promise"; import Select from 'react-select'; import "./GroupManager.scss"; +import { StrCast } from "../../fields/Types"; library.add(fa.faWindowClose); @@ -25,19 +25,27 @@ interface UserOptions { export default class GroupManager extends React.Component<{}> { static Instance: GroupManager; - @observable private isOpen: boolean = false; // whether the menu is open or not - @observable private dialogueBoxOpacity: number = 1; - @observable private overlayOpacity: number = 0.4; - @observable private users: string[] = []; - @observable private selectedUsers: UserOptions[] | null = null; - @observable private currentGroup: Opt<Doc>; - private inputRef: React.RefObject<HTMLInputElement> = React.createRef(); + @observable private isOpen: boolean = false; // whether the GroupManager is to be displayed or not. + @observable private dialogueBoxOpacity: number = 1; // opacity of the dialogue box div of the MainViewModal. + @observable private overlayOpacity: number = 0.4; // opacity of the overlay div of the MainViewModal. + @observable private users: string[] = []; // list of users populated from the database. + @observable private selectedUsers: UserOptions[] | null = null; // list of users selected in the "Select users" dropdown. + @observable private currentGroup: Opt<Doc>; // the currently selected group. + private inputRef: React.RefObject<HTMLInputElement> = React.createRef(); // the ref for the input box. constructor(props: Readonly<{}>) { super(props); GroupManager.Instance = this; } + // sets up the list of users + componentDidMount() { + this.populateUsers().then(resolved => runInAction(() => this.users = resolved)); + } + + /** + * Fetches the list of users stored on the database and @returns a list of the emails. + */ populateUsers = async () => { const userList: User[] = JSON.parse(await RequestPromise.get(Utils.prepend("/getUsers"))); const currentUserIndex = userList.findIndex(user => user.email === Doc.CurrentUserEmail); @@ -45,45 +53,77 @@ export default class GroupManager extends React.Component<{}> { return userList.map(user => user.email); } + /** + * @returns the options to be rendered in the dropdown menu to add users and create a group. + */ @computed get options() { return this.users.map(user => ({ label: user, value: user })); } - open = action(() => { + /** + * Makes the GroupManager visible. + */ + @action + open = () => { SelectionManager.DeselectAll(); this.isOpen = true; - this.populateUsers().then(resolved => runInAction(() => this.users = resolved)); - }); + } - close = action(() => { + /** + * Hides the GroupManager. + */ + @action + close = () => { this.isOpen = false; this.currentGroup = undefined; - }); + } + /** + * @returns the database of groups. + */ get GroupManagerDoc(): Doc | undefined { return Doc.UserDoc().globalGroupDatabase as Doc; } + /** + * @returns a list of all group documents. + */ getAllGroups(): Doc[] { const groupDoc = this.GroupManagerDoc; return groupDoc ? DocListCast(groupDoc.data) : []; } + /** + * @returns a group document based on the group name. + * @param groupName + */ getGroup(groupName: string): Doc | undefined { const groupDoc = this.getAllGroups().find(group => group.groupName === groupName); return groupDoc; } + /** + * @returns the members of the admin group. + */ get adminGroupMembers(): string[] { - return this.getGroup("admin") ? JSON.parse(this.getGroup("admin")!.members as string) : ""; + return this.getGroup("admin") ? JSON.parse(StrCast(this.getGroup("admin")!.members)) : ""; } + /** + * @returns a boolean indicating whether the current user has access to edit group documents. + * @param groupDoc + */ hasEditAccess(groupDoc: Doc): boolean { if (!groupDoc) return false; - const accessList: string[] = JSON.parse(groupDoc.owners as string); + const accessList: string[] = JSON.parse(StrCast(groupDoc.owners)); return accessList.includes(Doc.CurrentUserEmail) || this.adminGroupMembers?.includes(Doc.CurrentUserEmail); } + /** + * Helper method that sets up the group document. + * @param groupName + * @param memberEmails + */ createGroupDoc(groupName: string, memberEmails: string[]) { const groupDoc = new Doc; groupDoc.groupName = groupName; @@ -92,6 +132,10 @@ export default class GroupManager extends React.Component<{}> { this.addGroup(groupDoc); } + /** + * Helper method that adds a group document to the database of group documents and @returns whether it was successfully added or not. + * @param groupDoc + */ addGroup(groupDoc: Doc): boolean { if (this.GroupManagerDoc) { Doc.AddDocToList(this.GroupManagerDoc, "data", groupDoc); @@ -100,6 +144,10 @@ export default class GroupManager extends React.Component<{}> { return false; } + /** + * Deletes a group from the database of group documents and @returns whether the group was deleted or not. + * @param group + */ deleteGroup(group: Doc): boolean { if (group) { if (this.GroupManagerDoc && this.hasEditAccess(group)) { @@ -113,33 +161,54 @@ export default class GroupManager extends React.Component<{}> { return false; } + /** + * Adds a member to a group. + * @param groupDoc + * @param email + */ addMemberToGroup(groupDoc: Doc, email: string) { if (this.hasEditAccess(groupDoc)) { - const memberList: string[] = JSON.parse(groupDoc.members as string); + const memberList: string[] = JSON.parse(StrCast(groupDoc.members)); !memberList.includes(email) && memberList.push(email); groupDoc.members = JSON.stringify(memberList); } } + /** + * Removes a member from the group. + * @param groupDoc + * @param email + */ removeMemberFromGroup(groupDoc: Doc, email: string) { if (this.hasEditAccess(groupDoc)) { - const memberList: string[] = JSON.parse(groupDoc.members as string); + const memberList: string[] = JSON.parse(StrCast(groupDoc.members)); const index = memberList.indexOf(email); index !== -1 && memberList.splice(index, 1); groupDoc.members = JSON.stringify(memberList); } } + /** + * Handles changes in the users selected in the "Select users" dropdown. + * @param selectedOptions + */ @action handleChange = (selectedOptions: any) => { console.log(selectedOptions); this.selectedUsers = selectedOptions as UserOptions[]; } + /** + * Creates the group when the enter key has been pressed (when in the input). + * @param e + */ handleKeyDown = (e: React.KeyboardEvent) => { e.key === "Enter" && this.createGroup(); } + /** + * Handles the input of required fields in the setup of a group and resets the relevant variables. + */ @action createGroup = () => { if (!this.inputRef.current?.value) { @@ -159,9 +228,12 @@ export default class GroupManager extends React.Component<{}> { this.inputRef.current.value = ""; } + /** + * A getter that @returns the interface rendered to view an individual group. + */ private get editingInterface() { - const members: string[] = this.currentGroup ? JSON.parse(this.currentGroup.members as string) : []; - const options: UserOptions[] = this.currentGroup ? this.options.filter(option => !(JSON.parse(this.currentGroup!.members as string) as string[]).includes(option.value)) : []; + const members: string[] = this.currentGroup ? JSON.parse(StrCast(this.currentGroup.members)) : []; + const options: UserOptions[] = this.currentGroup ? this.options.filter(option => !(JSON.parse(StrCast(this.currentGroup!.members)) as string[]).includes(option.value)) : []; return (!this.currentGroup ? null : <div className="editing-interface"> <div className="editing-header"> @@ -202,7 +274,9 @@ export default class GroupManager extends React.Component<{}> { } - + /** + * A getter that @returns the main interface for the GroupManager. + */ private get groupInterface() { return ( <div className="group-interface"> @@ -238,7 +312,7 @@ export default class GroupManager extends React.Component<{}> { <div className="group-row"> <div className="group-name">{group.groupName}</div> <button onClick={action(() => this.currentGroup = group)}> - {this.hasEditAccess(this.getGroup(group.groupName as string) as Doc) ? "Edit" : "View"} + {this.hasEditAccess(this.getGroup(StrCast(group.groupName)) as Doc) ? "Edit" : "View"} </button> </div> )} |