diff --git a/firestore.rules b/firestore.rules
index 44c31ca..6734209 100644
--- a/firestore.rules
+++ b/firestore.rules
@@ -94,7 +94,8 @@ service cloud.firestore {
return [requiredFields, allFields];
}
- allow read, delete: if isSignedIn() && (isSignedInUser() || getGroupRole(groupId) == "owner" || isAdmin()); // is current user's data or is owner of group or is admin
+ allow read: if isSignedIn() && (isSignedInUser() || getGroupRole(groupId) == "owner" || isAdmin()); // is current user's data or is owner of group or is admin
+ allow delete: if isSignedIn() && ((isSignedInUser() && getGroupRole(groupId) != "owner") || (!isSignedInUser() && getGroupRole(groupId) == "owner") || isAdmin())
allow create: if isSignedIn() && isSignedInUser() && (getRequestField("role", "") == "member" || (isAdmin() && verifyGroupFieldTypes())) && verifyCreateFields(getPossibleGroupFields());
allow update: if isSignedIn() &&
(getGroupRole(groupId) == "owner" || isAdmin()) &&
diff --git a/src/GroupPage.js b/src/GroupPage.js
index bd854c8..2c57362 100644
--- a/src/GroupPage.js
+++ b/src/GroupPage.js
@@ -19,608 +19,659 @@ import "./css/GroupPage.css";
import "./css/ConfirmationDialog.css";
import "./css/OptionsListOverlay.css";
-export default withRouter(class GroupPage extends Component {
- constructor(props) {
- super(props);
- this.state = {
- user: props.user,
- db: props.db,
- functions: {
- removeSetFromGroup: props.functions.httpsCallable("removeSetFromGroup"),
- getGroupMembers: props.functions.httpsCallable("getGroupMembers"),
- },
- navbarItems: [
- {
- type: "link",
- link: "/",
- icon: ,
- hideTextMobile: true,
- }
- ],
- role: null,
- groupName: "",
- sets: {},
- memberCount: null,
- joinCode: "",
- editGroupName: false,
- loading: false,
- groupUsers: {
- owners: [],
- contributors: [],
- members: [],
- },
- editingUser: null,
- showDeleteGroup: false,
- deleteGroupLoading: false,
- };
+export default withRouter(
+ class GroupPage extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ user: props.user,
+ db: props.db,
+ functions: {
+ removeSetFromGroup: props.functions.httpsCallable("removeSetFromGroup"),
+ getGroupMembers: props.functions.httpsCallable("getGroupMembers"),
+ },
+ navbarItems: [
+ {
+ type: "link",
+ link: "/",
+ icon: ,
+ hideTextMobile: true,
+ },
+ ],
+ role: null,
+ groupName: "",
+ sets: {},
+ memberCount: null,
+ joinCode: "",
+ editGroupName: false,
+ loading: false,
+ groupUsers: {
+ owners: [],
+ contributors: [],
+ members: [],
+ },
+ editingUser: null,
+ showDeleteGroup: false,
+ deleteGroupLoading: false,
+ showLeaveGroup: false,
+ leaveGroupLoading: false,
+ };
- let isMounted = true;
- Object.defineProperty(this, "isMounted", {
- get: () => isMounted,
- set: (value) => isMounted = value,
- });
- }
+ let isMounted = true;
+ Object.defineProperty(this, "isMounted", {
+ get: () => isMounted,
+ set: (value) => (isMounted = value),
+ });
+ }
- setState = (state, callback = null) => {
- if (this.isMounted) super.setState(state, callback);
- }
+ setState = (state, callback = null) => {
+ if (this.isMounted) super.setState(state, callback);
+ };
- async componentDidMount() {
- let promises = [];
- let newState = {
- sets: {},
- };
+ async componentDidMount() {
+ let promises = [];
+ let newState = {
+ sets: {},
+ };
- promises.push(
- this.state.db
- .collection("users")
- .doc(this.state.user.uid)
- .collection("groups")
- .doc(this.props.match.params.groupId)
- .get()
- .then((userGroupDoc) => {
- if (userGroupDoc.data().role === "owner") {
- return this.state.functions
- .getGroupMembers({ groupId: this.props.match.params.groupId })
- .then((response) => {
- newState.groupUsers = response.data;
- return userGroupDoc.data();
- })
- .catch((error) => {
- newState.groupUsers = {
- owners: [
- {
- displayName: this.state.user.displayName,
- uid: this.state.user.uid,
- }
- ],
- contributors: [],
- members: [],
- };
- return userGroupDoc.data();
- });
- }
- return userGroupDoc.data();
- })
- .catch((error) => {
- console.log(`Can't access user group: ${error}`);
- return {
- role: "none",
- };
- })
- );
+ promises.push(
+ this.state.db
+ .collection("users")
+ .doc(this.state.user.uid)
+ .collection("groups")
+ .doc(this.props.match.params.groupId)
+ .get()
+ .then((userGroupDoc) => {
+ if (userGroupDoc.data().role === "owner") {
+ return this.state.functions
+ .getGroupMembers({ groupId: this.props.match.params.groupId })
+ .then((response) => {
+ newState.groupUsers = response.data;
+ return userGroupDoc.data();
+ })
+ .catch((error) => {
+ newState.groupUsers = {
+ owners: [
+ {
+ displayName: this.state.user.displayName,
+ uid: this.state.user.uid,
+ },
+ ],
+ contributors: [],
+ members: [],
+ };
+ return userGroupDoc.data();
+ });
+ }
+ return userGroupDoc.data();
+ })
+ .catch((error) => {
+ console.log(`Can't access user group: ${error}`);
+ return {
+ role: "none",
+ };
+ })
+ );
- promises.push(
- this.state.db
- .collection("groups")
- .doc(this.props.match.params.groupId)
- .get()
- .then(async (groupDoc) => {
- await Promise.all(groupDoc.data().sets.map((setId) => {
- return this.state.db.collection("sets")
- .doc(setId)
- .get()
- .then((doc) => {
- newState.sets[setId] = {
- displayName: doc.data().title,
- loading: false,
- };
- });
- }));
+ promises.push(
+ this.state.db
+ .collection("groups")
+ .doc(this.props.match.params.groupId)
+ .get()
+ .then(async (groupDoc) => {
+ await Promise.all(
+ groupDoc.data().sets.map((setId) => {
+ return this.state.db
+ .collection("sets")
+ .doc(setId)
+ .get()
+ .then((doc) => {
+ newState.sets[setId] = {
+ displayName: doc.data().title,
+ loading: false,
+ };
+ });
+ })
+ );
- return groupDoc.data();
- }).catch((error) => {
- console.log(`Can't access group: ${error}`);
- return {
- display_name: "",
- users: {},
- join_code: "",
- };
- })
- );
+ return groupDoc.data();
+ })
+ .catch((error) => {
+ console.log(`Can't access group: ${error}`);
+ return {
+ display_name: "",
+ users: {},
+ join_code: "",
+ };
+ })
+ );
- const completedPromises = await Promise.all(promises);
+ const completedPromises = await Promise.all(promises);
- document.title = `${completedPromises[1].display_name} | Parandum`;
+ document.title = `${completedPromises[1].display_name} | Parandum`;
- newState.role = completedPromises[0].role;
- newState.groupName = completedPromises[1].display_name;
- newState.originalGroupName = completedPromises[1].display_name;
- newState.memberCount = Object.keys(completedPromises[1].users).length + (Object.keys(completedPromises[1].users).includes(this.state.user.uid) ? 0 : 1);
- newState.joinCode = completedPromises[0].role === "owner" ? completedPromises[1].join_code : "";
+ newState.role = completedPromises[0].role;
+ newState.groupName = completedPromises[1].display_name;
+ newState.originalGroupName = completedPromises[1].display_name;
+ newState.memberCount =
+ Object.keys(completedPromises[1].users).length +
+ (Object.keys(completedPromises[1].users).includes(this.state.user.uid) ? 0 : 1);
+ newState.joinCode = completedPromises[0].role === "owner" ? completedPromises[1].join_code : "";
- this.setState(newState);
- this.props.page.load();
+ this.setState(newState);
+ this.props.page.load();
- this.props.logEvent("select_content", {
- content_type: "group",
- item_id: this.props.match.params.groupId,
- });
- }
+ this.props.logEvent("select_content", {
+ content_type: "group",
+ item_id: this.props.match.params.groupId,
+ });
+ }
- componentWillUnmount() {
- this.isMounted = false;
- this.props.page.unload();
- }
+ componentWillUnmount() {
+ this.isMounted = false;
+ this.props.page.unload();
+ }
- editGroupName = () => {
- this.setState({
- editGroupName: true,
- }, () => this.groupNameInput.focus());
- }
+ editGroupName = () => {
+ this.setState(
+ {
+ editGroupName: true,
+ },
+ () => this.groupNameInput.focus()
+ );
+ };
- handleGroupNameChange = (event) => {
- this.setState({
- groupName: event.target.value,
- });
- }
+ handleGroupNameChange = (event) => {
+ this.setState({
+ groupName: event.target.value,
+ });
+ };
- handleInputKeypress = (event) => {
- if (event.key === "Enter") {
- this.renameGroup();
- } else if (event.key === "Escape") {
- this.cancelGroupRename();
- }
- }
+ handleInputKeypress = (event) => {
+ if (event.key === "Enter") {
+ this.renameGroup();
+ } else if (event.key === "Escape") {
+ this.cancelGroupRename();
+ }
+ };
- stopLoading = () => {
- this.setState({
- loading: false,
- editGroupName: false,
- })
- }
+ stopLoading = () => {
+ this.setState({
+ loading: false,
+ editGroupName: false,
+ });
+ };
- cancelGroupRename = () => {
- this.setState({
- editGroupName: false,
- groupName: this.state.originalGroupName,
- })
- }
+ cancelGroupRename = () => {
+ this.setState({
+ editGroupName: false,
+ groupName: this.state.originalGroupName,
+ });
+ };
- renameGroup = () => {
- if (!this.state.loading && this.state.groupName.replace(" ", "") !== "") {
- if (this.state.groupName.trim() === this.state.originalGroupName) {
- this.cancelGroupRename();
- } else {
- this.setState({
- loading: true,
- });
-
- this.state.db.collection("groups")
- .doc(this.props.match.params.groupId)
- .update({
- display_name: this.state.groupName.trim(),
- }).then(() => {
- this.stopLoading();
- }).catch((error) => {
- console.log(`Couldn't update group name: ${error}`);
- this.setState({
- loading: false,
- groupName: this.state.originalGroupName,
- editGroupName: false,
- });
- });
- }
- }
- }
+ renameGroup = () => {
+ if (!this.state.loading && this.state.groupName.replace(" ", "") !== "") {
+ if (this.state.groupName.trim() === this.state.originalGroupName) {
+ this.cancelGroupRename();
+ } else {
+ this.setState({
+ loading: true,
+ });
- removeSet = (setId) => {
- let newLoadingState = {
- sets: this.state.sets,
- };
- newLoadingState.sets[setId].loading = true;
- this.setState(newLoadingState);
+ this.state.db
+ .collection("groups")
+ .doc(this.props.match.params.groupId)
+ .update({
+ display_name: this.state.groupName.trim(),
+ })
+ .then(() => {
+ this.stopLoading();
+ })
+ .catch((error) => {
+ console.log(`Couldn't update group name: ${error}`);
+ this.setState({
+ loading: false,
+ groupName: this.state.originalGroupName,
+ editGroupName: false,
+ });
+ });
+ }
+ }
+ };
- this.state.functions.removeSetFromGroup({
- groupId: this.props.match.params.groupId,
- setId: setId,
- }).then(() => {
- let newState = {
- sets: this.state.sets,
- };
- delete newState.sets[setId];
- this.setState(newState);
- }).catch((error) => {
- console.log(`Can't remove set from group: ${error}`);
- newLoadingState.sets[setId].loading = false;
- this.setState(newLoadingState);
- });
- }
+ removeSet = (setId) => {
+ let newLoadingState = {
+ sets: this.state.sets,
+ };
+ newLoadingState.sets[setId].loading = true;
+ this.setState(newLoadingState);
- showEditUserRole = (role, index) => {
- let user;
- if (role === "owner") {
- user = this.state.groupUsers.owners[index];
- } else if (role === "contributor") {
- user = this.state.groupUsers.contributors[index];
- } else {
- user = this.state.groupUsers.members[index];
- }
- this.setState({
- editingUser: {
- uid: user.uid,
- role: role,
- index: index,
- },
- });
- }
+ this.state.functions
+ .removeSetFromGroup({
+ groupId: this.props.match.params.groupId,
+ setId: setId,
+ })
+ .then(() => {
+ let newState = {
+ sets: this.state.sets,
+ };
+ delete newState.sets[setId];
+ this.setState(newState);
+ })
+ .catch((error) => {
+ console.log(`Can't remove set from group: ${error}`);
+ newLoadingState.sets[setId].loading = false;
+ this.setState(newLoadingState);
+ });
+ };
- hideEditUserRole = () => {
- this.setState({
- editingUser: null,
- });
- }
+ showEditUserRole = (role, index) => {
+ let user;
+ if (role === "owner") {
+ user = this.state.groupUsers.owners[index];
+ } else if (role === "contributor") {
+ user = this.state.groupUsers.contributors[index];
+ } else {
+ user = this.state.groupUsers.members[index];
+ }
+ this.setState({
+ editingUser: {
+ uid: user.uid,
+ role: role,
+ index: index,
+ },
+ });
+ };
- editUserRole = (role) => {
- if (role === this.state.editingUser.role) {
- this.setState({
- editingUser: null,
- });
- } else {
- if (role === "remove") {
- this.state.db.collection("users")
- .doc(this.state.editingUser.uid)
- .collection("groups")
- .doc(this.props.match.params.groupId)
- .delete()
- .then(() => {
- let groupUsers = this.state.groupUsers;
- if (this.state.editingUser.role === "owner") {
- groupUsers.owners.splice(this.state.editingUser.index, 1);
- } else if (this.state.editingUser.role === "contributor") {
- groupUsers.contributors.splice(this.state.editingUser.index, 1);
- } else {
- groupUsers.members.splice(this.state.editingUser.index, 1);
- }
- this.setState({
- editingUser: null,
- groupUsers: groupUsers,
- });
- }).catch((error) => {
- this.setState({
- editingUser: null,
- });
- console.log(`Couldn't change user role: ${error}`)
- });
- } else {
- this.state.db.collection("users")
- .doc(this.state.editingUser.uid)
- .collection("groups")
- .doc(this.props.match.params.groupId)
- .update({
- role: role,
- }).then(() => {
- let groupUsers = this.state.groupUsers;
- let userData;
- if (this.state.editingUser.role === "owner") {
- userData = groupUsers.owners.splice(this.state.editingUser.index, 1)[0];
- } else if (this.state.editingUser.role === "contributor") {
- userData = groupUsers.contributors.splice(this.state.editingUser.index, 1)[0];
- } else {
- userData = groupUsers.members.splice(this.state.editingUser.index, 1)[0];
- }
- if (role === "owner") {
- groupUsers.owners.push(userData);
- } else if (role === "contributor") {
- groupUsers.contributors.push(userData);
- } else {
- groupUsers.members.push(userData);
- }
- this.setState({
- editingUser: null,
- groupUsers: groupUsers,
- });
- }).catch((error) => {
- this.setState({
- editingUser: null,
- });
- console.log(`Couldn't change user role: ${error}`)
- });
- }
- }
- }
+ hideEditUserRole = () => {
+ this.setState({
+ editingUser: null,
+ });
+ };
- showDeleteGroup = () => {
- this.setState({
- showDeleteGroup: true,
- });
- }
+ editUserRole = (role) => {
+ if (role === this.state.editingUser.role) {
+ this.setState({
+ editingUser: null,
+ });
+ } else {
+ if (role === "remove") {
+ this.state.db
+ .collection("users")
+ .doc(this.state.editingUser.uid)
+ .collection("groups")
+ .doc(this.props.match.params.groupId)
+ .delete()
+ .then(() => {
+ let groupUsers = this.state.groupUsers;
+ if (this.state.editingUser.role === "owner") {
+ groupUsers.owners.splice(this.state.editingUser.index, 1);
+ } else if (this.state.editingUser.role === "contributor") {
+ groupUsers.contributors.splice(this.state.editingUser.index, 1);
+ } else {
+ groupUsers.members.splice(this.state.editingUser.index, 1);
+ }
+ this.setState({
+ editingUser: null,
+ groupUsers: groupUsers,
+ });
+ })
+ .catch((error) => {
+ this.setState({
+ editingUser: null,
+ });
+ console.log(`Couldn't change user role: ${error}`);
+ });
+ } else {
+ this.state.db
+ .collection("users")
+ .doc(this.state.editingUser.uid)
+ .collection("groups")
+ .doc(this.props.match.params.groupId)
+ .update({
+ role: role,
+ })
+ .then(() => {
+ let groupUsers = this.state.groupUsers;
+ let userData;
+ if (this.state.editingUser.role === "owner") {
+ userData = groupUsers.owners.splice(this.state.editingUser.index, 1)[0];
+ } else if (this.state.editingUser.role === "contributor") {
+ userData = groupUsers.contributors.splice(this.state.editingUser.index, 1)[0];
+ } else {
+ userData = groupUsers.members.splice(this.state.editingUser.index, 1)[0];
+ }
+ if (role === "owner") {
+ groupUsers.owners.push(userData);
+ } else if (role === "contributor") {
+ groupUsers.contributors.push(userData);
+ } else {
+ groupUsers.members.push(userData);
+ }
+ this.setState({
+ editingUser: null,
+ groupUsers: groupUsers,
+ });
+ })
+ .catch((error) => {
+ this.setState({
+ editingUser: null,
+ });
+ console.log(`Couldn't change user role: ${error}`);
+ });
+ }
+ }
+ };
- hideDeleteGroup = () => {
- this.setState({
- showDeleteGroup: false,
- });
- }
+ showDeleteGroup = () => {
+ this.setState({
+ showDeleteGroup: true,
+ });
+ };
- deleteGroup = () => {
- this.setState({
- deleteGroupLoading: true,
- });
+ hideDeleteGroup = () => {
+ this.setState({
+ showDeleteGroup: false,
+ });
+ };
- this.state.db.collection("groups")
- .doc(this.props.match.params.groupId)
- .delete()
- .then(() => {
- this.props.history.push("/groups");
- }).catch((error) => {
- console.log(`Couldn't delete group: ${error}`);
- this.setState({
- deleteGroupLoading: false,
- });
- })
- }
+ deleteGroup = () => {
+ this.setState({
+ deleteGroupLoading: true,
+ });
- render() {
- return (
- (this.state.role === "none") ?
-
- :
-
-
-
- {
- !(this.state.role === null) &&
- <>
-
- {
- this.state.editGroupName && this.state.role === "owner"
- ?
-
- (this.groupNameInput = inputEl)}
- autoComplete="off"
- />
- }
- className="button--round"
- disabled={this.state.loading || this.state.groupName.replace(" ", "") === ""}
- loading={this.state.loading}
- >
-
- :
-
{}}>
- {this.state.groupName}
- {
- this.state.role === "owner" &&
-
-
-
- }
-
- }
- {
- this.state.role === "owner" &&
-
- }
- className="button--round"
- title="Group progress"
- >
- }
- className="button--round"
- title="Delete group"
- >
-
- }
-
- {
- this.state.joinCode &&
-
-
Join code
-
{this.state.joinCode}
-
- }
- {
- this.state.memberCount &&
-
-
{this.state.memberCount}
-
- member
- { this.state.memberCount !== 1 && "s" }
-
-
- }
-
-
-
Sets
- {
- Object.keys(this.state.sets).length > 0
- ?
-
- {
- Object.keys(this.state.sets)
- .sort((a, b) => {
- if (this.state.sets[a].displayName < this.state.sets[b].displayName) {
- return -1;
- }
- if (this.state.sets[a].displayName > this.state.sets[b].displayName) {
- return 1;
- }
- return 0;
- })
- .map((setId) =>
-
-
- {this.state.sets[setId].displayName}
-
- {
- this.state.role === "owner" &&
-
- }
-
- )
- }
-
- :
-
- This group doesn't have any sets yet!
-
- }
-
- {
- this.state.role === "owner" &&
- <>
-
-
Members
- {
- this.state.groupUsers && this.state.groupUsers.owners.length > 0 &&
- <>
-
Owners
-
- {
- this.state.groupUsers.owners.map((user, index) =>
-
{ } : () => this.showEditUserRole("owner", index)}
- >
- {
- user.uid === this.state.user.uid
- ?
- "You"
- :
- <>
- {user.displayName}
-
- >
- }
-
- )
- }
-
- >
- }
- {
- this.state.groupUsers && this.state.groupUsers.contributors.length > 0 &&
- <>
-
Contributors
-
- {
- this.state.groupUsers.contributors.map((user, index) =>
-
{ } : () => this.showEditUserRole("contributor", index)}
- >
- {
- user.uid === this.state.user.uid
- ?
- "You"
- :
- <>
- {user.displayName}
-
- >
- }
-
- )
- }
-
- >
- }
- {
- this.state.groupUsers && this.state.groupUsers.members.length > 0 &&
- <>
-
Members
-
- {
- this.state.groupUsers.members.map((user, index) =>
-
{ } : () => this.showEditUserRole("member", index)}
- >
- {
- user.uid === this.state.user.uid
- ?
- "You"
- :
- <>
- {user.displayName}
-
- >
- }
-
- )
- }
-
- >
- }
-
- {
- this.state.editingUser &&
- <>
-
-
- {
- ["Owner", "Contributor", "Member", "Remove"].map((role) =>
-
this.editUserRole(role.toLowerCase())}
- >
- {role}
-
- )
- }
-
-
- Cancel
-
-
- >
- }
- {
- this.state.showDeleteGroup &&
-
- }
- >
- }
- >
- }
-
-
-
- )
- }
-})
+ this.state.db
+ .collection("groups")
+ .doc(this.props.match.params.groupId)
+ .delete()
+ .then(() => {
+ this.props.history.push("/groups");
+ })
+ .catch((error) => {
+ console.log(`Couldn't delete group: ${error}`);
+ this.setState({
+ deleteGroupLoading: false,
+ });
+ });
+ };
+
+ showLeaveGroup = () => {
+ this.setState({
+ showLeaveGroup: true,
+ });
+ };
+
+ hideLeaveGroup = () => {
+ this.setState({
+ showLeaveGroup: false,
+ });
+ };
+
+ leaveGroup = () => {
+ this.setState({
+ leaveGroupLoading: true,
+ });
+
+ this.state.db
+ .collection("users")
+ .doc(this.props.user.uid)
+ .collection("groups")
+ .doc(this.props.match.params.groupId)
+ .delete()
+ .then(() => {
+ this.props.history.push("/groups");
+ })
+ .catch((error) => {
+ console.log(`Couldn't leave group: ${error}`);
+ this.setState({
+ leaveGroupLoading: false,
+ });
+ });
+ };
+
+ render() {
+ return this.state.role === "none" ? (
+
+ ) : (
+
+
+
+ {!(this.state.role === null) && (
+ <>
+
+ {this.state.editGroupName && this.state.role === "owner" ? (
+
+ (this.groupNameInput = inputEl)}
+ autoComplete="off"
+ />
+ }
+ className="button--round"
+ disabled={this.state.loading || this.state.groupName.replace(" ", "") === ""}
+ loading={this.state.loading}
+ >
+
+ ) : (
+
{}}>
+ {this.state.groupName}
+ {this.state.role === "owner" && (
+
+
+
+ )}
+
+ )}
+ {this.state.role === "owner" ? (
+
+ }
+ className="button--round"
+ title="Group progress"
+ >
+ }
+ className="button--round"
+ title="Delete group"
+ >
+
+ ) : (
+
+ }
+ className="button--round"
+ title="Leave group"
+ >
+
+ )}
+
+ {this.state.joinCode && (
+
+
Join code
+
{this.state.joinCode}
+
+ )}
+ {this.state.memberCount && (
+
+
{this.state.memberCount}
+
+ member
+ {this.state.memberCount !== 1 && "s"}
+
+
+ )}
+
+
+
Sets
+ {Object.keys(this.state.sets).length > 0 ? (
+
+ {Object.keys(this.state.sets)
+ .sort((a, b) => {
+ if (this.state.sets[a].displayName < this.state.sets[b].displayName) {
+ return -1;
+ }
+ if (this.state.sets[a].displayName > this.state.sets[b].displayName) {
+ return 1;
+ }
+ return 0;
+ })
+ .map((setId) => (
+
+ {this.state.sets[setId].displayName}
+ {this.state.role === "owner" && (
+
+ )}
+
+ ))}
+
+ ) : (
+
This group doesn't have any sets yet!
+ )}
+
+ {this.state.role === "owner" && (
+ <>
+
+
Members
+ {this.state.groupUsers && this.state.groupUsers.owners.length > 0 && (
+ <>
+
Owners
+
+ {this.state.groupUsers.owners.map((user, index) => (
+
{}
+ : () => this.showEditUserRole("owner", index)
+ }
+ >
+ {user.uid === this.state.user.uid ? (
+ "You"
+ ) : (
+ <>
+ {user.displayName}
+
+ >
+ )}
+
+ ))}
+
+ >
+ )}
+ {this.state.groupUsers && this.state.groupUsers.contributors.length > 0 && (
+ <>
+
Contributors
+
+ {this.state.groupUsers.contributors.map((user, index) => (
+
{}
+ : () => this.showEditUserRole("contributor", index)
+ }
+ >
+ {user.uid === this.state.user.uid ? (
+ "You"
+ ) : (
+ <>
+ {user.displayName}
+
+ >
+ )}
+
+ ))}
+
+ >
+ )}
+ {this.state.groupUsers && this.state.groupUsers.members.length > 0 && (
+ <>
+
Members
+
+ {this.state.groupUsers.members.map((user, index) => (
+
{}
+ : () => this.showEditUserRole("member", index)
+ }
+ >
+ {user.uid === this.state.user.uid ? (
+ "You"
+ ) : (
+ <>
+ {user.displayName}
+
+ >
+ )}
+
+ ))}
+
+ >
+ )}
+
+ {this.state.editingUser && (
+ <>
+
+
+ {["Owner", "Contributor", "Member", "Remove"].map((role) => (
+
this.editUserRole(role.toLowerCase())}>
+ {role}
+
+ ))}
+
+
Cancel
+
+ >
+ )}
+ {this.state.showDeleteGroup && (
+
+ )}
+ >
+ )}
+ {this.state.showLeaveGroup && (
+
+ )}
+ >
+ )}
+
+
+
+ );
+ }
+ }
+);
diff --git a/test/firestore.test.js b/test/firestore.test.js
index aaa4811..3aa18e0 100644
--- a/test/firestore.test.js
+++ b/test/firestore.test.js
@@ -117,18 +117,42 @@ describe("Parandum Firestore database", () => {
await firebase.assertSucceeds(testDoc.get());
});
- it("Can delete current user's groups", async () => {
+ it("Can delete current user's groups when not group owner", async () => {
+ const admin = getAdminFirestore();
+ await admin.collection("users").doc(myId).collection("groups").doc(groupOne).set({ role: "member" });
+
const db = getFirestore(myAuth);
const testDoc = db.collection("users").doc(myId).collection("groups").doc(groupOne);
await firebase.assertSucceeds(testDoc.delete());
});
- it("Can't delete other users' groups", async () => {
+ it("Can't delete current user's groups when group owner", async () => {
+ const admin = getAdminFirestore();
+ await admin.collection("users").doc(myId).collection("groups").doc(groupOne).set({ role: "owner" });
+
+ const db = getFirestore(myAuth);
+ const testDoc = db.collection("users").doc(myId).collection("groups").doc(groupOne);
+ await firebase.assertFails(testDoc.delete());
+ });
+
+ it("Can't delete other users' groups when not group owner", async () => {
+ const admin = getAdminFirestore();
+ await admin.collection("users").doc(myId).collection("groups").doc(groupOne).set({ role: "member" });
+
const db = getFirestore(myAuth);
const testDoc = db.collection("users").doc(theirId).collection("groups").doc(groupOne);
await firebase.assertFails(testDoc.delete());
});
+ it("Can delete other users' groups when group owner", async () => {
+ const admin = getAdminFirestore();
+ await admin.collection("users").doc(myId).collection("groups").doc(groupOne).set({ role: "owner" });
+
+ const db = getFirestore(myAuth);
+ const testDoc = db.collection("users").doc(theirId).collection("groups").doc(groupOne);
+ await firebase.assertSucceeds(testDoc.delete());
+ });
+
it("Can delete other users' groups when admin", async () => {
const db = getFirestore(myAdminAuth);
const testDoc = db.collection("users").doc(theirId).collection("groups").doc(groupOne);