diff --git a/src/app/groups/GroupAction.tsx b/src/app/groups/GroupAction.tsx index b1f7e6d..372dded 100644 --- a/src/app/groups/GroupAction.tsx +++ b/src/app/groups/GroupAction.tsx @@ -23,28 +23,73 @@ async function getGroups(): Promise { ); } -export async function getGroupsFromServer(): Promise { +export async function getGroupsAction(): Promise { await actionUserRequired(); return await getGroups(); } -async function updateGroup(group: Group) { +export async function updateGroupAction(group: Group, assigendUsers: string[]) { + await actionAdminRequired(); + + console.info( + `${group.id ? 'Updating' : 'Adding'} group ${group.name} ${group.id || ''}` + ); + + let groupId: string; + if (group.id) { const doc = firestore.collection(GROUP_COLLECTION_ID).doc(group.id); await doc.set(group, { merge: true }); - return doc.id; + + groupId = group.id; } else { // new doc const result = await firestore.collection(GROUP_COLLECTION_ID).add(group); - return result.id; + groupId = result.id; } -} -export async function updateGroupFromServer(group: Group) { - await actionAdminRequired(); + const userCollection = firestore.collection(USER_COLLECTION_ID); + const users = (await userCollection.get()).docs || []; + // update assigned users + const batch = firestore.batch(); + + // users to remove + const removeUsers = users.filter( + (user) => + (user.data().groups || []).includes(groupId) && + !assigendUsers.includes(user.id) + ); + console.info( + `removing ${removeUsers.length} from group ${group.name}: ${removeUsers.map( + (u) => u.data().displayName || u.data().email + )}` + ); + removeUsers.forEach((user) => + batch.update(userCollection.doc(user.id), { + groups: (user.data().groups as string[]).filter((id) => id !== groupId), + }) + ); + + // users to add + const addUsers = users.filter( + (user) => + !(user.data().groups || []).includes(groupId) && + assigendUsers.includes(user.id) + ); + console.info( + `adding ${addUsers.length} to group ${group.name}: ${addUsers.map( + (u) => u.data().displayName || u.data().email + )}` + ); + addUsers.forEach((user) => + batch.update(userCollection.doc(user.id), { + groups: [...((user.data().groups as string[]) || []), groupId], + }) + ); - return await updateGroup(group); + await batch.commit(); + return groupId; } async function getMyGroups(userId: string): Promise { diff --git a/src/app/groups/GroupDialog.tsx b/src/app/groups/GroupDialog.tsx index e4971f2..6b66b78 100644 --- a/src/app/groups/GroupDialog.tsx +++ b/src/app/groups/GroupDialog.tsx @@ -4,14 +4,22 @@ import DialogActions from '@mui/material/DialogActions'; import DialogContent from '@mui/material/DialogContent'; import DialogContentText from '@mui/material/DialogContentText'; import DialogTitle from '@mui/material/DialogTitle'; -import { SelectChangeEvent } from '@mui/material/Select'; +import Select, { SelectChangeEvent } from '@mui/material/Select'; import TextField from '@mui/material/TextField'; -import React, { useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { Group } from './GroupAction'; +import { UserRecordExtended } from '../../common/users'; +import FormControl from '@mui/material/FormControl'; +import InputLabel from '@mui/material/InputLabel'; +import MenuItem from '@mui/material/MenuItem'; +import Checkbox from '@mui/material/Checkbox'; +import ListItemText from '@mui/material/ListItemText'; +import OutlinedInput from '@mui/material/OutlinedInput'; export interface GroupDialoggOptions { - onClose: (item?: Group) => void; + onClose: (item?: Group, assigendUsers?: string[]) => void; group: Group; + users: UserRecordExtended[]; } export const groupTextFields: { [key: string]: string } = { @@ -19,12 +27,37 @@ export const groupTextFields: { [key: string]: string } = { description: 'Zusatzinfo', }; +const ITEM_HEIGHT = 48; +const ITEM_PADDING_TOP = 8; +const MenuProps = { + PaperProps: { + style: { + maxHeight: ITEM_HEIGHT * 10 + ITEM_PADDING_TOP, + width: 250, + }, + }, +}; + export default function GroupDialogg({ onClose, group: groupDefault, + users, }: GroupDialoggOptions) { const [open, setOpen] = useState(true); const [group, setGroup] = useState(groupDefault); + const [assigendUsers, setAssigendUsers] = useState([]); + + const userMap = Object.fromEntries(users.map((user) => [user.uid, user])); + + useEffect(() => { + setAssigendUsers( + users + .filter( + (user) => group.id && user.groups && user.groups.includes(group.id) + ) + .map((user) => user.uid) + ); + }, [group.id, users]); const onChange = (field: string) => @@ -59,6 +92,46 @@ export default function GroupDialogg({ value={((group as any)[key] as string) || ''} /> ))} + + + + Benutzer der Gruppe + + +