@mui/material#ListItemSecondaryAction TypeScript Examples

The following examples show how to use @mui/material#ListItemSecondaryAction. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx    From ExpressLRS-Configurator with GNU General Public License v3.0 4 votes vote down vote up
UserDefinesList: FunctionComponent<UserDefinesListProps> = (props) => {
  const { options, onChange, firmwareVersionData } = props;
  const onChecked = (data: UserDefineKey) => {
    const opt = options.find(({ key }) => key === data);
    if (opt !== undefined) {
      onChange({
        ...opt,
        enabled: !opt.enabled,
      });
    } else {
      throw new Error(`user define key ${data} not found`);
    }
  };

  const onUserDefineValueChange = (data: UserDefineKey) => (
    event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
  ) => {
    const opt = options.find(({ key }) => key === data);
    if (opt !== undefined) {
      const update = {
        ...opt,
        value: event.target.value,
      };
      onChange(update);
    } else {
      throw new Error(`user define key ${data} not found`);
    }
  };

  const onEnumValueChange = (data: UserDefineKey) => (value: string | null) => {
    const opt = options.find(({ key }) => key === data);
    if (opt !== undefined) {
      const update = {
        ...opt,
        value,
      };
      onChange(update);
    } else {
      throw new Error(`user define key ${data} not found`);
    }
  };

  const inputLabel = (key: UserDefineKey): string => {
    switch (key) {
      case UserDefineKey.ARM_CHANNEL:
        return 'Arm channel';
      case UserDefineKey.BINDING_PHRASE:
        return 'Custom binding phrase';
      case UserDefineKey.MY_STARTUP_MELODY:
        return 'My startup melody';
      default:
        return 'Value';
    }
  };

  return (
    <List>
      {options.map((item) => {
        return (
          <React.Fragment key={item.key}>
            <ListItem
              dense
              selected={item.enabled}
              button
              onClick={onChecked.bind(this, item.key)}
            >
              <ListItemIcon sx={styles.icon}>
                <Checkbox
                  edge="start"
                  checked={item.enabled}
                  tabIndex={-1}
                  disableRipple
                />
              </ListItemIcon>
              <ListItemText>{item.key}</ListItemText>
              <ListItemSecondaryAction>
                <UserDefineDescription
                  userDefine={item.key}
                  firmwareVersionData={firmwareVersionData}
                />
              </ListItemSecondaryAction>
            </ListItem>
            {item.type === UserDefineKind.Text && item.enabled && (
              <>
                <ListItem sx={styles.complimentaryItem}>
                  {!item.sensitive && (
                    <TextField
                      size="small"
                      onChange={onUserDefineValueChange(item.key)}
                      value={item.value}
                      fullWidth
                      label={inputLabel(item.key)}
                    />
                  )}
                  {item.sensitive && (
                    <SensitiveTextField
                      name={item.key}
                      size="small"
                      onChange={onUserDefineValueChange(item.key)}
                      value={item.value}
                      fullWidth
                      label={inputLabel(item.key)}
                    />
                  )}
                </ListItem>
              </>
            )}
            {item.type === UserDefineKind.Enum && item.enabled && (
              <ListItem sx={styles.complimentaryItem}>
                <Omnibox
                  title={inputLabel(item.key)}
                  currentValue={{
                    value: item.value ?? '',
                    label: item.value ?? '',
                  }}
                  onChange={onEnumValueChange(item.key)}
                  options={
                    item?.enumValues?.map((opt) => ({
                      value: opt,
                      label: opt,
                    })) ?? []
                  }
                />
              </ListItem>
            )}
          </React.Fragment>
        );
      })}
    </List>
  );
}
Example #2
Source File: AccountList.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function AccountList({ group }) {
    const [speedDialOpen, setSpeedDialOpen] = useState(false);
    const toggleSpeedDial = () => setSpeedDialOpen((currValue) => !currValue);

    const [showPersonalAccountCreationModal, setShowPersonalAccountCreationModal] = useState(false);
    const [showClearingAccountCreationModal, setShowClearingAccountCreationModal] = useState(false);

    const [activeTab, setActiveTab] = useState("personal");
    const [searchValuePersonal, setSearchValuePersonal] = useState("");
    const [searchValueClearing, setSearchValueClearing] = useState("");

    const [showPersonalAccountEditModal, setShowPersonalAccountEditModal] = useState(false);
    const [showClearingAccountEditModal, setShowClearingAccountEditModal] = useState(false);
    const [clearingAccountToCopy, setClearingAccountToCopy] = useState(undefined);
    const [accountToEdit, setAccountToEdit] = useState(null);
    const [clearingAccountToEdit, setClearingAccountToEdit] = useState(null);
    const setAccounts = useSetRecoilState(groupAccounts(group.id));
    const personalAccounts = useRecoilValue(personalAccountsSeenByUser(group.id));
    const clearingAccounts = useRecoilValue(clearingAccountsSeenByUser(group.id));
    const allAccounts = useRecoilValue(accountsSeenByUser(group.id));
    const [accountToDelete, setAccountToDelete] = useState(null);
    const userPermissions = useRecoilValue(currUserPermissions(group.id));
    const currentUser = useRecoilValue(userData);
    const memberIDToUsername = useRecoilValue(groupMemberIDsToUsername(group.id));

    const [filteredPersonalAccounts, setFilteredPersonalAccounts] = useState([]);
    const [filteredClearingAccounts, setFilteredClearingAccounts] = useState([]);
    useEffect(() => {
        if (searchValuePersonal != null && searchValuePersonal !== "") {
            setFilteredPersonalAccounts(
                personalAccounts.filter((t) => {
                    return (
                        t.name.toLowerCase().includes(searchValuePersonal.toLowerCase()) ||
                        t.description.toLowerCase().includes(searchValuePersonal.toLowerCase())
                    );
                })
            );
        } else {
            return setFilteredPersonalAccounts(personalAccounts);
        }
    }, [personalAccounts, searchValuePersonal, setFilteredPersonalAccounts]);

    useEffect(() => {
        if (searchValueClearing != null && searchValueClearing !== "") {
            setFilteredClearingAccounts(
                clearingAccounts.filter((t) => {
                    return (
                        t.name.toLowerCase().includes(searchValueClearing.toLowerCase()) ||
                        t.description.toLowerCase().includes(searchValueClearing.toLowerCase())
                    );
                })
            );
        } else {
            return setFilteredClearingAccounts(clearingAccounts);
        }
    }, [clearingAccounts, searchValueClearing, setFilteredClearingAccounts]);

    useTitle(`${group.name} - Accounts`);

    const openAccountEdit = (account) => {
        setAccountToEdit(account);
        setShowPersonalAccountEditModal(true);
    };

    const closeAccountEdit = (evt, reason) => {
        if (reason !== "backdropClick") {
            setShowPersonalAccountEditModal(false);
            setAccountToEdit(null);
        }
    };

    const openClearingAccountEdit = (account) => {
        setClearingAccountToEdit(account);
        setShowClearingAccountEditModal(true);
    };

    const closeClearingAccountEdit = (evt, reason) => {
        if (reason !== "backdropClick") {
            setShowClearingAccountEditModal(false);
            setClearingAccountToEdit(null);
        }
    };

    const confirmDeleteAccount = () => {
        if (accountToDelete !== null) {
            deleteAccount({ accountID: accountToDelete })
                .then((account) => {
                    updateAccount(account, setAccounts);
                    setAccountToDelete(null);
                })
                .catch((err) => {
                    toast.error(err);
                });
        }
    };

    const openCreateDialog = () => {
        setClearingAccountToCopy(undefined);
        setShowClearingAccountCreationModal(true);
    };

    const copyClearingAccount = (account) => {
        setClearingAccountToCopy(account);
        setShowClearingAccountCreationModal(true);
    };

    return (
        <>
            <MobilePaper>
                <TabContext value={activeTab}>
                    <Box sx={{ borderBottom: 1, borderColor: "divider" }}>
                        <TabList onChange={(e, newValue) => setActiveTab(newValue)} centered>
                            <Tab
                                value="personal"
                                label={
                                    <TextBadge badgeContent={personalAccounts.length} color="primary">
                                        <span>Personal Accounts</span>
                                    </TextBadge>
                                }
                            />
                            <Tab
                                label={
                                    <TextBadge badgeContent={clearingAccounts.length} color="primary">
                                        <span>Clearing Accounts</span>
                                    </TextBadge>
                                }
                                value="clearing"
                            />
                        </TabList>
                    </Box>
                    <TabPanel value="personal">
                        <List>
                            {personalAccounts.length === 0 ? (
                                <Alert severity="info">No Accounts</Alert>
                            ) : (
                                <>
                                    <ListItem>
                                        <Input
                                            value={searchValuePersonal}
                                            onChange={(e) => setSearchValuePersonal(e.target.value)}
                                            placeholder="Search…"
                                            inputProps={{
                                                "aria-label": "search",
                                            }}
                                            endAdornment={
                                                <InputAdornment position="end">
                                                    <IconButton
                                                        aria-label="clear search input"
                                                        onClick={(e) => setSearchValuePersonal("")}
                                                        edge="end"
                                                    >
                                                        <Clear />
                                                    </IconButton>
                                                </InputAdornment>
                                            }
                                        />
                                    </ListItem>
                                    <Divider />
                                    {filteredPersonalAccounts.map((account) => (
                                        <ListItem sx={{ padding: 0 }} key={account.id}>
                                            <ListItemLink to={`/groups/${group.id}/accounts/${account.id}`}>
                                                <ListItemText
                                                    primary={
                                                        <div>
                                                            <span>{account.name}</span>
                                                            {account.owning_user_id === currentUser.id ? (
                                                                <span>
                                                                    , owned by{" "}
                                                                    <Chip
                                                                        size="small"
                                                                        component="span"
                                                                        color="primary"
                                                                        label="you"
                                                                    />
                                                                </span>
                                                            ) : (
                                                                account.owning_user_id !== null && (
                                                                    <span>
                                                                        , owned by{" "}
                                                                        <Chip
                                                                            size="small"
                                                                            component="span"
                                                                            color="secondary"
                                                                            label={
                                                                                memberIDToUsername[
                                                                                    account.owning_user_id
                                                                                ]
                                                                            }
                                                                        />
                                                                    </span>
                                                                )
                                                            )}
                                                        </div>
                                                    }
                                                    secondary={account.description}
                                                />
                                            </ListItemLink>
                                            {userPermissions.can_write && (
                                                <ListItemSecondaryAction>
                                                    <IconButton
                                                        color="primary"
                                                        onClick={() => openAccountEdit(account)}
                                                    >
                                                        <Edit />
                                                    </IconButton>
                                                    <IconButton
                                                        color="error"
                                                        onClick={() => setAccountToDelete(account.id)}
                                                    >
                                                        <Delete />
                                                    </IconButton>
                                                </ListItemSecondaryAction>
                                            )}
                                        </ListItem>
                                    ))}
                                </>
                            )}
                        </List>
                        {userPermissions.can_write && (
                            <>
                                <Grid container justifyContent="center">
                                    <Tooltip title="Create Personal Account">
                                        <IconButton
                                            color="primary"
                                            onClick={() => setShowPersonalAccountCreationModal(true)}
                                        >
                                            <Add />
                                        </IconButton>
                                    </Tooltip>
                                </Grid>
                                <CreateAccountModal
                                    show={showPersonalAccountCreationModal}
                                    onClose={(evt, reason) => {
                                        if (reason !== "backdropClick") {
                                            setShowPersonalAccountCreationModal(false);
                                        }
                                    }}
                                    group={group}
                                />
                                <EditAccountModal
                                    show={showPersonalAccountEditModal}
                                    onClose={closeAccountEdit}
                                    account={accountToEdit}
                                    group={group}
                                />
                            </>
                        )}
                    </TabPanel>
                    <TabPanel value="clearing">
                        <List>
                            {clearingAccounts.length === 0 ? (
                                <Alert severity="info">No Accounts</Alert>
                            ) : (
                                <>
                                    <ListItem>
                                        <Input
                                            value={searchValueClearing}
                                            onChange={(e) => setSearchValueClearing(e.target.value)}
                                            placeholder="Search…"
                                            inputProps={{
                                                "aria-label": "search",
                                            }}
                                            endAdornment={
                                                <InputAdornment position="end">
                                                    <IconButton
                                                        aria-label="clear search input"
                                                        onClick={(e) => setSearchValueClearing("")}
                                                        edge="end"
                                                    >
                                                        <Clear />
                                                    </IconButton>
                                                </InputAdornment>
                                            }
                                        />
                                    </ListItem>
                                    <Divider />
                                    {filteredClearingAccounts.map((account) => (
                                        <ListItem sx={{ padding: 0 }} key={account.id}>
                                            <ListItemLink to={`/groups/${group.id}/accounts/${account.id}`}>
                                                <ListItemText primary={account.name} secondary={account.description} />
                                            </ListItemLink>
                                            {userPermissions.can_write && (
                                                <ListItemSecondaryAction>
                                                    <IconButton
                                                        color="primary"
                                                        onClick={() => openClearingAccountEdit(account)}
                                                    >
                                                        <Edit />
                                                    </IconButton>
                                                    <IconButton
                                                        color="primary"
                                                        onClick={() => copyClearingAccount(account)}
                                                    >
                                                        <ContentCopy />
                                                    </IconButton>
                                                    <IconButton
                                                        color="error"
                                                        onClick={() => setAccountToDelete(account.id)}
                                                    >
                                                        <Delete />
                                                    </IconButton>
                                                </ListItemSecondaryAction>
                                            )}
                                        </ListItem>
                                    ))}
                                </>
                            )}
                        </List>
                        {userPermissions.can_write && (
                            <>
                                <Grid container justifyContent="center">
                                    <Tooltip title="Create Clearing Account">
                                        <IconButton color="primary" onClick={openCreateDialog}>
                                            <Add />
                                        </IconButton>
                                    </Tooltip>
                                </Grid>
                                <CreateClearingAccountModal
                                    show={showClearingAccountCreationModal}
                                    onClose={(evt, reason) => {
                                        if (reason !== "backdropClick") {
                                            setShowClearingAccountCreationModal(false);
                                        }
                                    }}
                                    initialValues={clearingAccountToCopy}
                                    group={group}
                                />
                                <EditClearingAccountModal
                                    show={showClearingAccountEditModal}
                                    onClose={closeClearingAccountEdit}
                                    account={clearingAccountToEdit}
                                    group={group}
                                />
                            </>
                        )}
                    </TabPanel>
                </TabContext>
            </MobilePaper>
            {userPermissions.can_write && (
                <>
                    <SpeedDial
                        ariaLabel="Create Account"
                        sx={{ position: "fixed", bottom: 20, right: 20 }}
                        icon={<SpeedDialIcon />}
                        // onClose={() => setSpeedDialOpen(false)}
                        // onOpen={() => setSpeedDialOpen(true)}
                        onClick={toggleSpeedDial}
                        open={speedDialOpen}
                    >
                        <SpeedDialAction
                            icon={<PersonalAccountIcon />}
                            tooltipTitle="Personal"
                            tooltipOpen
                            onClick={() => setShowPersonalAccountCreationModal(true)}
                        />
                        <SpeedDialAction
                            icon={<ClearingAccountIcon />}
                            tooltipTitle="Clearing"
                            tooltipOpen
                            onClick={openCreateDialog}
                        />
                    </SpeedDial>

                    <Dialog maxWidth="xs" aria-labelledby="confirmation-dialog-title" open={accountToDelete !== null}>
                        <DialogTitle id="confirmation-dialog-title">Confirm delete account</DialogTitle>
                        <DialogContent dividers>
                            Are you sure you want to delete the account "
                            {allAccounts.find((acc) => acc.id === accountToDelete)?.name}"
                        </DialogContent>
                        <DialogActions>
                            <Button autoFocus onClick={() => setAccountToDelete(null)} color="primary">
                                Cancel
                            </Button>
                            <Button onClick={confirmDeleteAccount} color="error">
                                Ok
                            </Button>
                        </DialogActions>
                    </Dialog>
                </>
            )}
        </>
    );
}
Example #3
Source File: GroupInvites.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function GroupInvites({ group }) {
    const [showModal, setShowModal] = useState(false);
    const invites = useRecoilValue(groupInvites(group.id));
    const members = useRecoilValue(groupMembers(group.id));
    const userPermissions = useRecoilValue(currUserPermissions(group.id));

    const isGuest = useRecoilValue(isGuestUser);

    useTitle(`${group.name} - Invite Links`);

    const deleteToken = (id) => {
        deleteGroupInvite({ groupID: group.id, inviteID: id }).catch((err) => {
            toast.error(err);
        });
    };

    const getMemberUsername = (member_id) => {
        const member = members.find((member) => member.user_id === member_id);
        if (member === undefined) {
            return "unknown";
        }
        return member.username;
    };

    const selectLink = (event) => {
        const node = event.target;
        const selection = window.getSelection();
        const range = document.createRange();
        range.selectNodeContents(node);
        selection.removeAllRanges();
        selection.addRange(range);
    };

    const copyToClipboard = (content) => {
        navigator.clipboard.writeText(content);
        toast.info("Link copied to clipboard!");
    };

    return (
        <MobilePaper>
            <Typography component="h3" variant="h5">
                Active Invite Links
            </Typography>
            {isGuest && (
                <Alert severity="info">
                    You are a guest user on this Abrechnung and therefore not permitted to create group invites.
                </Alert>
            )}
            <List>
                {invites.length === 0 ? (
                    <ListItem>
                        <ListItemText primary="No Links" />
                    </ListItem>
                ) : (
                    invites.map((invite) => (
                        <ListItem key={invite.id}>
                            <ListItemText
                                primary={
                                    invite.token === null ? (
                                        <span>token hidden, was created by another member</span>
                                    ) : (
                                        <span onClick={selectLink}>
                                            {window.location.origin}/invite/
                                            {invite.token}
                                        </span>
                                    )
                                }
                                secondary={
                                    <>
                                        {invite.description}, created by {getMemberUsername(invite.created_by)}, valid
                                        until{" "}
                                        {DateTime.fromISO(invite.valid_until).toLocaleString(DateTime.DATETIME_FULL)}
                                        {invite.single_use && ", single use"}
                                        {invite.join_as_editor && ", join as editor"}
                                    </>
                                }
                            />
                            {userPermissions.can_write && (
                                <ListItemSecondaryAction>
                                    <IconButton
                                        color="primary"
                                        onClick={() =>
                                            copyToClipboard(`${window.location.origin}/invite/${invite.token}`)
                                        }
                                    >
                                        <ContentCopy />
                                    </IconButton>
                                    <IconButton color="error" onClick={() => deleteToken(invite.id)}>
                                        <Delete />
                                    </IconButton>
                                </ListItemSecondaryAction>
                            )}
                        </ListItem>
                    ))
                )}
            </List>
            {userPermissions.can_write && !isGuest && (
                <>
                    <Grid container justifyContent="center">
                        <IconButton color="primary" onClick={() => setShowModal(true)}>
                            <Add />
                        </IconButton>
                    </Grid>
                    <InviteLinkCreate show={showModal} onClose={() => setShowModal(false)} group={group} />
                </>
            )}
        </MobilePaper>
    );
}
Example #4
Source File: GroupList.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function GroupList() {
    const [showGroupCreationModal, setShowGroupCreationModal] = useState(false);
    const [showGroupDeletionModal, setShowGroupDeletionModal] = useState(false);
    const [groupToDelete, setGroupToDelete] = useState(null);
    const groups = useRecoilValue(groupList);
    const isGuest = useRecoilValue(isGuestUser);

    const openGroupDeletionModal = (groupID) => {
        setGroupToDelete(groups.find((group) => group.id === groupID));
        setShowGroupDeletionModal(true);
    };

    const closeGroupDeletionModal = () => {
        setShowGroupDeletionModal(false);
        setGroupToDelete(null);
    };

    const openGroupCreateModal = () => {
        setShowGroupCreationModal(true);
    };

    const closeGroupCreateModal = (evt, reason) => {
        if (reason !== "backdropClick") {
            setShowGroupCreationModal(false);
        }
    };

    return (
        <MobilePaper>
            <Typography component="h3" variant="h5">
                Groups
            </Typography>
            {isGuest && (
                <Alert severity="info">
                    You are a guest user on this Abrechnung and therefore not permitted to create new groups.
                </Alert>
            )}
            <List>
                {groups.length === 0 ? (
                    <ListItem key={0}>
                        <span>No Groups</span>
                    </ListItem>
                ) : (
                    groups.map((group) => {
                        return (
                            <ListItem sx={{ padding: 0 }} key={group.id}>
                                <ListItemLink to={`/groups/${group.id}`}>
                                    <ListItemText primary={group.name} secondary={group.description} />
                                </ListItemLink>
                                <ListItemSecondaryAction>
                                    <IconButton
                                        edge="end"
                                        aria-label="delete-group"
                                        onClick={() => openGroupDeletionModal(group.id)}
                                    >
                                        <Delete />
                                    </IconButton>
                                </ListItemSecondaryAction>
                            </ListItem>
                        );
                    })
                )}
            </List>
            {!isGuest && (
                <>
                    <Grid container justifyContent="center">
                        <IconButton color="primary" onClick={openGroupCreateModal}>
                            <Add />
                        </IconButton>
                    </Grid>
                    <GroupCreateModal show={showGroupCreationModal} onClose={closeGroupCreateModal} />
                </>
            )}
            <GroupDeleteModal
                show={showGroupDeletionModal}
                onClose={closeGroupDeletionModal}
                groupToDelete={groupToDelete}
            />
        </MobilePaper>
    );
}
Example #5
Source File: GroupMemberList.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function GroupMemberList({ group }) {
    const [showEditMemberDialog, setShowEditMemberDialog] = useState(false);
    const [memberToEdit, setMemberToEdit] = useState(null);
    const currentUser = useRecoilValue(userData);
    const members = useRecoilValue(groupMembers(group.id));
    const permissions = useRecoilValue(currUserPermissions(group.id));

    useTitle(`${group.name} - Members`);

    const handleEditMemberSubmit = (values, { setSubmitting }) => {
        updateGroupMemberPrivileges({
            groupID: group.id,
            userID: values.userID,
            canWrite: values.canWrite,
            isOwner: values.isOwner,
        })
            .then((result) => {
                setSubmitting(false);
                setShowEditMemberDialog(false);
                toast.success("Successfully updated group member permissions");
            })
            .catch((err) => {
                setSubmitting(false);
                toast.error(err);
            });
    };

    const getMemberUsername = (member_id) => {
        const member = members.find((member) => member.user_id === member_id);
        if (member === undefined) {
            return "unknown";
        }
        return member.username;
    };

    const closeEditMemberModal = () => {
        setShowEditMemberDialog(false);
        setMemberToEdit(null);
    };

    const openEditMemberModal = (userID) => {
        const user = members.find((member) => member.user_id === userID);
        // TODO: maybe deal with disappearing users in the list
        setMemberToEdit(user);
        setShowEditMemberDialog(true);
    };

    return (
        <MobilePaper>
            <List>
                {members.length === 0 ? (
                    <ListItem>
                        <ListItemText primary="No Members" />
                    </ListItem>
                ) : (
                    members.map((member, index) => (
                        <ListItem key={index}>
                            <ListItemText
                                primary={
                                    <>
                                        <span style={{ marginRight: 5 }}>{member.username}</span>
                                        {member.is_owner ? (
                                            <Chip
                                                size="small"
                                                sx={{ mr: 1 }}
                                                component="span"
                                                color="primary"
                                                label="owner"
                                                variant="outlined"
                                            />
                                        ) : member.can_write ? (
                                            <Chip
                                                size="small"
                                                sx={{ mr: 1 }}
                                                component="span"
                                                color="primary"
                                                label="editor"
                                                variant="outlined"
                                            />
                                        ) : null}
                                        {member.user_id === currentUser.id ? (
                                            <Chip
                                                size="small"
                                                sx={{ mr: 1 }}
                                                component="span"
                                                color="primary"
                                                label="it's you"
                                            />
                                        ) : (
                                            ""
                                        )}
                                    </>
                                }
                                secondary={
                                    <>
                                        {member.invited_by && (
                                            <small className="text-muted">
                                                invited by {getMemberUsername(member.invited_by)}
                                            </small>
                                        )}
                                        <small className="text-muted">
                                            joined{" "}
                                            {DateTime.fromISO(member.joined_at).toLocaleString(DateTime.DATETIME_FULL)}
                                        </small>
                                    </>
                                }
                            />
                            {permissions.is_owner || permissions.can_write ? (
                                <ListItemSecondaryAction>
                                    <IconButton onClick={() => openEditMemberModal(member.user_id)}>
                                        <Edit />
                                    </IconButton>
                                </ListItemSecondaryAction>
                            ) : (
                                ""
                            )}
                        </ListItem>
                    ))
                )}
            </List>
            <Dialog open={showEditMemberDialog} onClose={closeEditMemberModal}>
                <DialogTitle>Edit Group Member</DialogTitle>
                <DialogContent>
                    <Formik
                        initialValues={{
                            userID: memberToEdit ? memberToEdit.user_id : -1,
                            isOwner: memberToEdit ? memberToEdit.is_owner : false,
                            canWrite: memberToEdit ? memberToEdit.can_write : false,
                        }}
                        onSubmit={handleEditMemberSubmit}
                        enableReinitialize={true}
                    >
                        {({ values, handleBlur, handleChange, handleSubmit, isSubmitting }) => (
                            <Form>
                                <FormControlLabel
                                    control={
                                        <Checkbox
                                            name="canWrite"
                                            onBlur={handleBlur}
                                            onChange={handleChange}
                                            checked={values.canWrite}
                                        />
                                    }
                                    label="Can Write"
                                />
                                <FormControlLabel
                                    control={
                                        <Checkbox
                                            name="isOwner"
                                            onBlur={handleBlur}
                                            onChange={handleChange}
                                            checked={values.isOwner}
                                        />
                                    }
                                    label="Is Owner"
                                />

                                {isSubmitting && <LinearProgress />}
                                <DialogActions>
                                    <Button type="submit" color="primary">
                                        Save
                                    </Button>
                                    <Button color="error" onClick={closeEditMemberModal}>
                                        Close
                                    </Button>
                                </DialogActions>
                            </Form>
                        )}
                    </Formik>
                </DialogContent>
            </Dialog>
        </MobilePaper>
    );
}
Example #6
Source File: SessionList.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function SessionList() {
    // TODO: fix editing functions
    const [editedSessions, setEditedSessions] = useState({});
    const [sessionToDelete, setSessionToDelete] = useState({
        show: false,
        toDelete: null,
    });
    const user = useRecoilValue(userData);
    const sessions = user.sessions;

    useTitle("Abrechnung - Sessions");

    const editSession = (id) => {
        if (!editedSessions.hasOwnProperty(id)) {
            const newSessions = {
                ...editedSessions,
                [id]: sessions.find((session) => session.id === id)?.name,
            };
            setEditedSessions(newSessions);
        }
    };

    const stopEditSession = (id) => {
        if (editedSessions.hasOwnProperty(id)) {
            let newEditedSessions = { ...editedSessions };
            delete newEditedSessions[id];
            setEditedSessions(newEditedSessions);
        }
    };

    const closeDeleteSessionModal = () => {
        setSessionToDelete({ show: false, toDelete: null });
    };

    const performRename = (id) => {
        if (editedSessions.hasOwnProperty(id)) {
            renameSession({
                sessionID: id,
                name: editedSessions[id],
            }).catch((err) => {
                toast.error(err);
            });
            stopEditSession(id);
        }
    };

    const openDeleteSessionModal = (id) => {
        setSessionToDelete({ show: true, toDelete: id });
    };

    const confirmDeleteSession = () => {
        if (sessionToDelete.toDelete !== null) {
            deleteSession({ sessionID: sessionToDelete.toDelete }).catch((err) => {
                toast.error(err);
            });
            setSessionToDelete({ show: false, toDelete: null });
        }
    };

    const handleEditChange = (id, value) => {
        const newEditedSessions = { ...editedSessions, [id]: value };
        setEditedSessions(newEditedSessions);
    };

    const onKeyUp = (id) => (key) => {
        if (key.keyCode === 13) {
            performRename(id);
        }
    };

    return (
        <MobilePaper>
            <Typography component="h3" variant="h5">
                Login Sessions
            </Typography>
            <List>
                {sessions.map((session) => {
                    if (editedSessions.hasOwnProperty(session.id)) {
                        return (
                            <ListItem key={session.id}>
                                <TextField
                                    margin="normal"
                                    variant="standard"
                                    fullWidth
                                    onKeyUp={onKeyUp(session.id)}
                                    value={editedSessions[session.id]}
                                    onChange={(event) => handleEditChange(session.id, event.target.value)}
                                />
                                <ListItemSecondaryAction>
                                    <Button onClick={() => performRename(session.id)}>
                                        <Check />
                                    </Button>
                                    <Button onClick={() => stopEditSession(session.id)}>
                                        <Close />
                                    </Button>
                                </ListItemSecondaryAction>
                            </ListItem>
                        );
                    } else {
                        return (
                            <ListItem key={session.id}>
                                <ListItemText
                                    primary={session.name}
                                    secondary={
                                        <>
                                            <span>
                                                Valid until{" "}
                                                {DateTime.fromISO(session.valid_until).toLocaleString(
                                                    DateTime.DATETIME_FULL
                                                ) && "indefinitely"}
                                                ,{" "}
                                            </span>
                                            <span>
                                                Last seen on{" "}
                                                {DateTime.fromISO(session.last_seen).toLocaleString(
                                                    DateTime.DATETIME_FULL
                                                )}
                                            </span>
                                        </>
                                    }
                                />
                                <ListItemSecondaryAction>
                                    <IconButton onClick={() => editSession(session.id)}>
                                        <Edit />
                                    </IconButton>
                                    <IconButton onClick={() => openDeleteSessionModal(session.id)}>
                                        <Delete />
                                    </IconButton>
                                </ListItemSecondaryAction>
                            </ListItem>
                        );
                    }
                })}
            </List>
            <Dialog open={sessionToDelete.show} onClose={closeDeleteSessionModal}>
                <DialogTitle>Delete Session?</DialogTitle>

                <DialogContent>
                    <DialogContentText>
                        {sessionToDelete.toDelete !== null
                            ? `Are you sure you want to delete session ${
                                  sessions.find((session) => session.id === sessionToDelete.toDelete)?.name
                              }`
                            : null}
                    </DialogContentText>
                </DialogContent>

                <DialogActions>
                    <Button color="secondary" onClick={confirmDeleteSession}>
                        Yes pls
                    </Button>
                    <Button color="primary" onClick={closeDeleteSessionModal}>
                        No
                    </Button>
                </DialogActions>
            </Dialog>
        </MobilePaper>
    );
}
Example #7
Source File: LangSelect.tsx    From Tachidesk-WebUI with Mozilla Public License 2.0 4 votes vote down vote up
export default function LangSelect(props: IProps) {
    const {
        shownLangs, setShownLangs, allLangs, forcedLangs,
    } = props;
    // hold a copy and only sate state on parent when OK pressed, improves performance
    const [mShownLangs, setMShownLangs] = useState(
        removeAll(cloneObject(shownLangs), forcedLangs!),
    );
    const [open, setOpen] = useState<boolean>(false);

    const handleCancel = () => {
        setOpen(false);
    };

    const handleOk = () => {
        setOpen(false);
        setShownLangs(mShownLangs);
    };

    const handleChange = (event: React.ChangeEvent<HTMLInputElement>, lang: string) => {
        const { checked } = event.target as HTMLInputElement;

        if (checked) {
            setMShownLangs([...mShownLangs, lang]);
        } else {
            const clone = cloneObject(mShownLangs);
            clone.splice(clone.indexOf(lang), 1);
            setMShownLangs(clone);
        }
    };

    return (
        <>
            <IconButton
                onClick={() => setOpen(true)}
                aria-label="display more actions"
                edge="end"
                color="inherit"
                size="large"
            >
                <FilterListIcon />
            </IconButton>
            <Dialog
                sx={{
                    '.MuiDialog-paper': {
                        maxHeight: 435,
                        width: '80%',
                    },
                }}
                maxWidth="xs"
                open={open}
            >
                <DialogTitle>Enabled Languages</DialogTitle>
                <DialogContent dividers sx={{ padding: 0 }}>
                    <List>
                        {allLangs.map((lang) => (
                            <ListItem key={lang}>
                                <ListItemText primary={langCodeToName(lang)} />

                                <ListItemSecondaryAction>
                                    <Switch
                                        checked={mShownLangs.indexOf(lang) !== -1}
                                        onChange={(e) => handleChange(e, lang)}
                                    />
                                </ListItemSecondaryAction>

                            </ListItem>
                        ))}
                    </List>

                </DialogContent>
                <DialogActions>
                    <Button autoFocus onClick={handleCancel} color="primary">
                        Cancel
                    </Button>
                    <Button onClick={handleOk} color="primary">
                        Ok
                    </Button>
                </DialogActions>
            </Dialog>
        </>
    );
}