/* eslint-disable react/no-array-index-key */ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Badge, Box, Button, Chip, config, Icon, Icons, Menu, Spinner, Text } from 'folds'; import produce from 'immer'; import { SequenceCard } from '../../../components/sequence-card'; import { SequenceCardStyle } from '../styles.css'; import { SettingTile } from '../../../components/setting-tile'; import { applyPermissionPower, getPermissionPower, IPowerLevels, PermissionLocation, } from '../../../hooks/usePowerLevels'; import { PermissionGroup } from './types'; import { getPowerLevelTag, getPowers, usePowerLevelTags } from '../../../hooks/usePowerLevelTags'; import { useRoom } from '../../../hooks/useRoom'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { StateEvent } from '../../../../types/matrix/room'; import { PowerSwitcher } from '../../../components/power'; import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback'; import { useAlive } from '../../../hooks/useAlive'; const USER_DEFAULT_LOCATION: PermissionLocation = { user: true, }; type PermissionGroupsProps = { canEdit: boolean; powerLevels: IPowerLevels; permissionGroups: PermissionGroup[]; }; export function PermissionGroups({ powerLevels, permissionGroups, canEdit, }: PermissionGroupsProps) { const mx = useMatrixClient(); const room = useRoom(); const alive = useAlive(); const powerLevelTags = usePowerLevelTags(room, powerLevels); const maxPower = useMemo(() => Math.max(...getPowers(powerLevelTags)), [powerLevelTags]); const [permissionUpdate, setPermissionUpdate] = useState>( new Map() ); useEffect(() => { // reset permission update if component rerender // as permission location object reference has changed setPermissionUpdate(new Map()); }, [permissionGroups]); const handleChangePermission = ( location: PermissionLocation, newPower: number, currentPower: number ) => { setPermissionUpdate((p) => { const up: typeof p = new Map(); p.forEach((value, key) => { up.set(key, value); }); if (newPower === currentPower) { up.delete(location); } else { up.set(location, newPower); } return up; }); }; const [applyState, applyChanges] = useAsyncCallback( useCallback(async () => { const editedPowerLevels = produce(powerLevels, (draftPowerLevels) => { permissionGroups.forEach((group) => group.items.forEach((item) => { const power = getPermissionPower(powerLevels, item.location); applyPermissionPower(draftPowerLevels, item.location, power); }) ); permissionUpdate.forEach((power, location) => applyPermissionPower(draftPowerLevels, location, power) ); return draftPowerLevels; }); await mx.sendStateEvent(room.roomId, StateEvent.RoomPowerLevels as any, editedPowerLevels); }, [mx, room, powerLevels, permissionUpdate, permissionGroups]) ); const resetChanges = useCallback(() => { setPermissionUpdate(new Map()); }, []); const handleApplyChanges = () => { applyChanges().then(() => { if (alive()) { resetChanges(); } }); }; const applyingChanges = applyState.status === AsyncStatus.Loading; const hasChanges = permissionUpdate.size > 0; const renderUserGroup = () => { const power = getPermissionPower(powerLevels, USER_DEFAULT_LOCATION); const powerUpdate = permissionUpdate.get(USER_DEFAULT_LOCATION); const value = powerUpdate ?? power; const tag = getPowerLevelTag(powerLevelTags, value); const powerChanges = value !== power; return ( Users handleChangePermission(USER_DEFAULT_LOCATION, v, power)} > {(handleOpen, opened) => ( ) } before={ canEdit && ( ) } onClick={handleOpen} > {tag.name} )} } /> ); }; return ( <> {renderUserGroup()} {permissionGroups.map((group, groupIndex) => ( {group.name} {group.items.map((item, itemIndex) => { const power = getPermissionPower(powerLevels, item.location); const powerUpdate = permissionUpdate.get(item.location); const value = powerUpdate ?? power; const tag = getPowerLevelTag(powerLevelTags, value); const powerChanges = value !== power; return ( handleChangePermission(item.location, v, power)} > {(handleOpen, opened) => ( ) } before={ canEdit && ( ) } onClick={handleOpen} > {tag.name} {value < maxPower && & Above} )} } /> ); })} ))} {hasChanges && ( {applyState.status === AsyncStatus.Error ? ( Failed to apply changes! Please try again. ) : ( Changes saved! Apply when ready. )} )} ); }