@mui/material#TableContainer TypeScript Examples

The following examples show how to use @mui/material#TableContainer. 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: table.component.tsx    From master-frontend-lemoncode with MIT License 6 votes vote down vote up
TableComponent: React.FunctionComponent<Props> = (props) => {
  const { memberList, className } = props;

  return (
    <TableContainer className={className}>
      <Table>
        <HeaderComponent />
        <TableBody>
          {memberList.map((member) => (
            <RowComponent key={member.id} member={member} />
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
}
Example #2
Source File: index.tsx    From Search-Next with GNU General Public License v3.0 6 votes vote down vote up
Table: React.FC<TableProps> = (props) => {
  const { dataSource, columns, size } = props;
  return (
    <TableContainer component={Paper}>
      <MTable sx={{ minWidth: 650 }} size={size}>
        <TableHead>
          <TableRow>
            {columns.map(({ name, field, align = 'left', ...i }) => (
              <StyledTableCell key={field} align={align}>
                {name}
              </StyledTableCell>
            ))}
          </TableRow>
        </TableHead>
        <TableBody>
          {dataSource.map((row, index) => (
            <StyledTableRow
              key={row.name}
              sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
            >
              {columns.map(({ name, field, align = 'left', render, ...i }) => (
                <StyledTableCell key={field} align={align}>
                  {render ? render(row[field], row, index) : row[field]}
                </StyledTableCell>
              ))}
            </StyledTableRow>
          ))}
        </TableBody>
      </MTable>
      {dataSource.length === 0 && (
        <div className="w-full">
          <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
        </div>
      )}
    </TableContainer>
  );
}
Example #3
Source File: ClearingAccountDetail.tsx    From abrechnung with GNU Affero General Public License v3.0 5 votes vote down vote up
export default function ClearingAccountDetail({ group, account }) {
    const classes = useStyles();
    const accounts = useRecoilValue(accountsSeenByUser(group.id));
    const balances = useRecoilValue(accountBalances(group.id));

    const [showAdvanced, setShowAdvanced] = useState(false);

    useEffect(() => {
        for (const share of Object.values(account.clearing_shares)) {
            if (share !== 1) {
                setShowAdvanced(true);
                break;
            }
        }
    }, [account]);

    const clearingShareValue = (accountID) => {
        return account.clearing_shares?.hasOwnProperty(accountID) ? account.clearing_shares[accountID] : 0;
    };

    return (
        <TableContainer>
            <Table>
                <TableHead>
                    <TableRow>
                        <TableCell>Account</TableCell>
                        {showAdvanced && <TableCell>Shares</TableCell>}
                        <TableCell width="100px" align="right">
                            Shared
                        </TableCell>
                    </TableRow>
                </TableHead>
                <TableBody>
                    {accounts
                        .filter((a) => balances[account.id].clearingResolution.hasOwnProperty(a.id))
                        .map((a) => (
                            <TableRow hover key={a.id}>
                                <TableCell className={classes.tableLinkCell}>
                                    {/*TODO: proper link*/}
                                    <Link className={classes.tableLink} to={`/groups/${group.id}/accounts/${a.id}`}>
                                        <Grid container direction="row" alignItems="center">
                                            <Grid item>
                                                {a.type === "personal" ? (
                                                    <PersonalAccountIcon />
                                                ) : (
                                                    <ClearingAccountIcon />
                                                )}
                                            </Grid>
                                            <Grid item sx={{ ml: 1 }}>
                                                <Typography variant="body2" component="span">
                                                    {a.name}
                                                </Typography>
                                            </Grid>
                                        </Grid>
                                    </Link>
                                </TableCell>
                                {showAdvanced && <TableCell width="50px">{clearingShareValue(a.id)}</TableCell>}
                                <TableCell width="100px" align="right">
                                    {balances[account.id].clearingResolution[a.id].toFixed(2)} {group.currency_symbol}
                                </TableCell>
                            </TableRow>
                        ))}
                </TableBody>
            </Table>
        </TableContainer>
    );
}
Example #4
Source File: EntityPreview.tsx    From firecms with MIT License 4 votes vote down vote up
/**
 * Use this component to render a preview of a property values
 * @param entity
 * @param schema
 * @param path
 * @constructor
 * @category Components
 */
export function EntityPreview<M>(
    {
        entity,
        schema: inputSchema,
        path
    }: EntityPreviewProps<M>) {

    const classes = useStyles();

    const appConfig: FireCMSContext | undefined = useFireCMSContext();

    const schema: ResolvedEntitySchema<M> = useMemo(() => computeSchema({
        schemaOrResolver: inputSchema,
        path,
        entityId: entity.id,
        values: entity?.values,
        previousValues: entity?.values
    }), [inputSchema, path, entity]);

    const properties: Properties = schema.properties;

    return (
        <TableContainer>
            <Table aria-label="entity table">
                <TableBody>
                    <TableRow>
                        <TableCell align="right"
                                   component="td"
                                   scope="row"
                                   className={classes.titleCell}>
                            <Typography variant={"caption"}
                                        color={"textSecondary"}>
                                Id
                            </Typography>
                        </TableCell>
                        <TableCell padding="none"
                                   className={classes.iconCell}>
                            {getIdIcon("disabled", "small")}
                        </TableCell>
                        <TableCell className={classes.valuePreview}>
                            <Box display="flex" alignItems="center">
                                {entity.id}
                                {appConfig?.entityLinkBuilder &&
                                <a href={appConfig.entityLinkBuilder({ entity })}
                                   rel="noopener noreferrer"
                                   target="_blank">
                                    <IconButton
                                        aria-label="go-to-entity-datasource"
                                        size="large">
                                        <OpenInNewIcon
                                            fontSize={"small"}/>
                                    </IconButton>
                                </a>}
                            </Box>
                        </TableCell>
                    </TableRow>

                    {schema && Object.entries(properties)
                        .map(([key, property]) => {
                            const value = (entity.values as any)[key];
                            return (
                                <TableRow
                                    key={"entity_prev" + property.title + key}>
                                    <TableCell align="right"
                                               component="td"
                                               scope="row"
                                               className={classes.titleCell}>
                                        <Typography
                                            style={{ paddingLeft: "16px" }}
                                            variant={"caption"}
                                            color={"textSecondary"}>
                                            {property.title}
                                        </Typography>
                                    </TableCell>

                                    <TableCell padding="none"
                                               className={classes.iconCell}>
                                        {getIconForProperty(property, "disabled", "small")}
                                    </TableCell>

                                <TableCell
                                    className={classes.valuePreview}>
                                    <ErrorBoundary>
                                        <PreviewComponent
                                            name={key}
                                            value={value}
                                            property={property as AnyProperty}
                                            size={"regular"}/>
                                    </ErrorBoundary>
                                </TableCell>

                            </TableRow>
                        );
                    })}
                </TableBody>
            </Table>
        </TableContainer>
    );

}
Example #5
Source File: ClearingSharesFormElement.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function ClearingSharesFormElement({ group, clearingShares, setClearingShares, accountID = undefined }) {
    const accounts = useRecoilValue(accountsSeenByUser(group.id));
    const [showAdvanced, setShowAdvanced] = useState(false);
    const [searchValue, setSearchValue] = useState("");
    const [filteredAccounts, setFilteredAccounts] = useState([]);

    useEffect(() => {
        if (searchValue != null && searchValue !== "") {
            setFilteredAccounts(
                accounts.filter((acc) => {
                    return acc.name.toLowerCase().includes(searchValue.toLowerCase());
                })
            );
        } else {
            setFilteredAccounts(accounts);
        }
    }, [searchValue, accounts]);

    return (
        <>
            <Grid container direction="row" justifyContent="space-between">
                <Typography variant="subtitle1">Allocation to</Typography>
                <FormControlLabel
                    control={<Checkbox name={`show-advanced`} />}
                    checked={showAdvanced}
                    onChange={(event: React.ChangeEvent<HTMLInputElement>) => setShowAdvanced(event.target.checked)}
                    label="Advanced"
                />
            </Grid>
            <TableContainer sx={{ maxHeight: 400 }}>
                <Table size="small" stickyHeader>
                    <TableHead>
                        <TableRow>
                            <TableCell>
                                <TextField
                                    placeholder="Search ..."
                                    margin="none"
                                    size="small"
                                    value={searchValue}
                                    onChange={(e) => setSearchValue(e.target.value)}
                                    variant="standard"
                                    InputProps={{
                                        startAdornment: (
                                            <InputAdornment position="start">
                                                <SearchIcon />
                                            </InputAdornment>
                                        ),
                                    }}
                                />
                            </TableCell>
                            <TableCell width="100px">Shares</TableCell>
                        </TableRow>
                    </TableHead>
                    <TableBody>
                        {filteredAccounts.map(
                            (account) =>
                                (accountID === undefined || account.id !== accountID) && (
                                    <TableRow hover key={account.id}>
                                        <TableCell>
                                            <Grid container direction="row" alignItems="center">
                                                <Grid item>
                                                    {account.type === "personal" ? <Person /> : <CompareArrows />}
                                                </Grid>
                                                <Grid item sx={{ ml: 1 }}>
                                                    <Typography variant="body2" component="span">
                                                        {account.name}
                                                    </Typography>
                                                </Grid>
                                            </Grid>
                                        </TableCell>
                                        <TableCell width="100px">
                                            {showAdvanced ? (
                                                <ShareInput
                                                    onChange={(value) =>
                                                        setClearingShares({
                                                            ...(clearingShares !== undefined ? clearingShares : {}),
                                                            [account.id]: value,
                                                        })
                                                    }
                                                    value={
                                                        clearingShares && clearingShares.hasOwnProperty(account.id)
                                                            ? clearingShares[account.id]
                                                            : 0.0
                                                    }
                                                />
                                            ) : (
                                                <Checkbox
                                                    name={`${account.name}-checked`}
                                                    checked={
                                                        clearingShares &&
                                                        clearingShares.hasOwnProperty(account.id) &&
                                                        clearingShares[account.id] !== 0
                                                    }
                                                    onChange={(event) =>
                                                        setClearingShares({
                                                            ...(clearingShares !== undefined ? clearingShares : {}),
                                                            [account.id]: event.target.checked ? 1.0 : 0.0,
                                                        })
                                                    }
                                                />
                                            )}
                                        </TableCell>
                                    </TableRow>
                                )
                        )}
                    </TableBody>
                </Table>
            </TableContainer>
        </>
    );
}
Example #6
Source File: PurchaseDebitorShares.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function PurchaseDebitorShares({ group, transaction, showPositions = false }) {
    const classes = useStyles();
    const isSmallScreen = useMediaQuery((theme: Theme) => theme.breakpoints.down("sm"));

    const accounts = useRecoilValue(accountsSeenByUser(group.id));

    const [searchValue, setSearchValue] = useState("");
    const [filteredAccounts, setFilteredAccounts] = useState([]);

    const [showAdvanced, setShowAdvanced] = useState(false);

    const transactionHasPositions =
        transaction.positions != null && transaction.positions.find((item) => !item.deleted) !== undefined;
    const setLocalTransactionDetails = useSetRecoilState(pendingTransactionDetailChanges(transaction.id));

    useEffect(() => {
        for (const share of Object.values(transaction.debitor_shares)) {
            if (share !== 1) {
                setShowAdvanced(true);
                break;
            }
        }
    }, [transaction]);

    useEffect(() => {
        if (searchValue != null && searchValue !== "") {
            setFilteredAccounts(
                accounts.filter((acc) => {
                    return acc.name.toLowerCase().includes(searchValue.toLowerCase());
                })
            );
        } else {
            setFilteredAccounts(accounts);
        }
    }, [searchValue, accounts]);

    const debitorShareValueForAccount = (accountID) => {
        return transaction.debitor_shares && transaction.debitor_shares.hasOwnProperty(accountID)
            ? transaction.debitor_shares[accountID]
            : 0;
    };

    const debitorValueForAccount = (accountID) => {
        if (!transaction.account_balances.hasOwnProperty(accountID)) {
            return 0.0;
        }
        return transaction.account_balances[accountID].common_debitors;
    };

    const positionValueForAccount = (accountID) => {
        if (!transaction.account_balances.hasOwnProperty(accountID)) {
            return 0.0;
        }
        return transaction.account_balances[accountID].positions;
    };

    const updateDebShare = (accountID, value) => {
        if (value === 0) {
            setLocalTransactionDetails((currState) => {
                let newDebitorShares;
                if (currState.debitor_shares === undefined) {
                    newDebitorShares = {
                        ...transaction.debitor_shares,
                    };
                } else {
                    newDebitorShares = {
                        ...currState.debitor_shares,
                    };
                }
                delete newDebitorShares[accountID];
                return {
                    ...currState,
                    debitor_shares: newDebitorShares,
                };
            });
        } else {
            setLocalTransactionDetails((currState) => {
                let newDebitorShares;
                if (currState.debitor_shares === undefined) {
                    newDebitorShares = {
                        ...transaction.debitor_shares,
                        [accountID]: value,
                    };
                } else {
                    newDebitorShares = {
                        ...currState.debitor_shares,
                        [accountID]: value,
                    };
                }
                return {
                    ...currState,
                    debitor_shares: newDebitorShares,
                };
            });
        }
    };

    return (
        <div>
            <Box className={classes.listItem}>
                <Grid container direction="row" justifyContent="space-between">
                    <Typography variant="subtitle1" className={classes.checkboxLabel}>
                        <Box sx={{ display: "flex", alignItems: "flex-end" }}>For whom</Box>
                    </Typography>
                    {transaction.is_wip && (
                        <FormControlLabel
                            control={<Checkbox name={`show-advanced`} />}
                            checked={showAdvanced}
                            onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
                                setShowAdvanced(event.target.checked)
                            }
                            label="Advanced"
                        />
                    )}
                </Grid>
            </Box>
            <Divider variant="middle" className={classes.divider} />
            <TableContainer sx={{ maxHeight: { md: 400 } }}>
                <Table size="small" stickyHeader>
                    <TableHead>
                        <TableRow>
                            <TableCell>
                                {isSmallScreen ? (
                                    "Account"
                                ) : (
                                    <TextField
                                        placeholder="Search ..."
                                        margin="none"
                                        size="small"
                                        value={searchValue}
                                        onChange={(e) => setSearchValue(e.target.value)}
                                        variant="standard"
                                        InputProps={{
                                            startAdornment: (
                                                <InputAdornment position="start">
                                                    <SearchIcon />
                                                </InputAdornment>
                                            ),
                                            endAdornment: (
                                                <InputAdornment position="end">
                                                    <IconButton
                                                        aria-label="clear search input"
                                                        onClick={(e) => setSearchValue("")}
                                                        edge="end"
                                                    >
                                                        <Clear />
                                                    </IconButton>
                                                </InputAdornment>
                                            ),
                                        }}
                                    />
                                )}
                            </TableCell>
                            <TableCell width="100px">Shares</TableCell>
                            {showPositions || transactionHasPositions ? (
                                <>
                                    <TableCell width="100px" align="right">
                                        Positions
                                    </TableCell>
                                    <TableCell width="3px" align="center">
                                        +
                                    </TableCell>
                                    <TableCell width="100px" align="right">
                                        Shared + Rest
                                    </TableCell>
                                    <TableCell width="3px" align="center">
                                        =
                                    </TableCell>
                                    <TableCell width="100px" align="right">
                                        Total
                                    </TableCell>
                                </>
                            ) : (
                                <TableCell width="100px" align="right">
                                    Shared
                                </TableCell>
                            )}
                        </TableRow>
                    </TableHead>
                    <TableBody>
                        {filteredAccounts.map((account) => (
                            <AccountTableRow
                                key={account.id}
                                transaction={transaction}
                                account={account}
                                debitorValueForAccount={debitorValueForAccount}
                                debitorShareValueForAccount={debitorShareValueForAccount}
                                positionValueForAccount={positionValueForAccount}
                                showAdvanced={showAdvanced}
                                showPositions={showPositions}
                                updateDebShare={updateDebShare}
                            />
                        ))}
                    </TableBody>
                </Table>
            </TableContainer>
        </div>
    );
}
Example #7
Source File: PurchaseDebitorSharesReadOnly.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function PurchaseDebitorSharesReadOnly({ group, transaction }) {
    const classes = useStyles();

    const accounts = useRecoilValue(accountsSeenByUser(group.id));

    const [debitorShareValues, setDebitorShareValues] = useState({});
    const [showAdvanced, setShowAdvanced] = useState(false);

    const transactionHasPositions =
        transaction.positions != null && transaction.positions.find((item) => !item.deleted) !== undefined;

    useEffect(() => {
        setDebitorShareValues(transaction.debitor_shares);
        for (const share of Object.values(transaction.debitor_shares)) {
            if (share !== 1) {
                setShowAdvanced(true);
                break;
            }
        }
    }, [transaction]);

    const debitorShareValueForAccount = (accountID) => {
        return debitorShareValues.hasOwnProperty(accountID) ? debitorShareValues[accountID] : 0;
    };

    return (
        <List>
            <ListItem className={classes.listItem}>
                <Grid container direction="row" justifyContent="space-between">
                    <Typography variant="subtitle1" className={classes.checkboxLabel}>
                        <Box sx={{ display: "flex", alignItems: "flex-end" }}>For whom</Box>
                    </Typography>
                </Grid>
            </ListItem>
            <Divider variant="middle" className={classes.divider} />

            <TableContainer>
                <Table>
                    <TableHead>
                        <TableRow>
                            <TableCell>Account</TableCell>
                            {showAdvanced && <TableCell>Shares</TableCell>}
                            {transactionHasPositions ? (
                                <>
                                    <TableCell width="100px" align="right">
                                        Positions
                                    </TableCell>
                                    <TableCell width="3px" align="center">
                                        +
                                    </TableCell>
                                    <TableCell width="100px" align="right">
                                        Shared Rest
                                    </TableCell>
                                    <TableCell width="3px" align="center">
                                        =
                                    </TableCell>
                                    <TableCell width="100px" align="right">
                                        Total
                                    </TableCell>
                                </>
                            ) : (
                                <TableCell width="100px" align="right">
                                    Shared
                                </TableCell>
                            )}
                        </TableRow>
                    </TableHead>
                    <TableBody>
                        {accounts
                            .filter(
                                (account) =>
                                    transaction.account_balances.hasOwnProperty(account.id) &&
                                    (transaction.account_balances[account.id].common_debitors !== 0 ||
                                        transaction.account_balances[account.id].positions)
                            )
                            .map((account) => (
                                <TableRow hover key={account.id}>
                                    <TableCell className={classes.tableLinkCell}>
                                        {/*TODO: proper link*/}
                                        <Link
                                            className={classes.tableLink}
                                            to={`/groups/${group.id}/accounts/${account.id}`}
                                        >
                                            <Grid container direction="row" alignItems="center">
                                                <Grid item>
                                                    {account.type === "personal" ? (
                                                        <PersonalAccountIcon />
                                                    ) : (
                                                        <ClearingAccountIcon />
                                                    )}
                                                </Grid>
                                                <Grid item sx={{ ml: 1 }}>
                                                    <Typography variant="body2" component="span">
                                                        {account.name}
                                                    </Typography>
                                                </Grid>
                                            </Grid>
                                        </Link>
                                    </TableCell>
                                    {showAdvanced && (
                                        <TableCell width="50px">{debitorShareValueForAccount(account.id)}</TableCell>
                                    )}
                                    {transactionHasPositions ? (
                                        <>
                                            <TableCell align="right">
                                                {transaction.account_balances[account.id].positions.toFixed(2)}{" "}
                                                {transaction.currency_symbol}
                                            </TableCell>
                                            <TableCell></TableCell>
                                            <TableCell align="right">
                                                {transaction.account_balances[account.id].common_debitors.toFixed(2)}{" "}
                                                {transaction.currency_symbol}
                                            </TableCell>
                                            <TableCell></TableCell>
                                            <TableCell width="100px" align="right">
                                                {(
                                                    transaction.account_balances[account.id].common_debitors +
                                                    transaction.account_balances[account.id].positions
                                                ).toFixed(2)}{" "}
                                                {transaction.currency_symbol}
                                            </TableCell>
                                        </>
                                    ) : (
                                        <TableCell width="100px" align="right">
                                            {transaction.account_balances[account.id].common_debitors.toFixed(2)}{" "}
                                            {transaction.currency_symbol}
                                        </TableCell>
                                    )}
                                </TableRow>
                            ))}
                    </TableBody>
                </Table>
            </TableContainer>
        </List>
    );
}
Example #8
Source File: TransactionPositions.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function TransactionPositions({ group, transaction }: PropTypes) {
    const classes = useStyles();
    const accounts = useRecoilValue(accountsSeenByUser(group.id));
    const [localPositionChanges, setLocalPositionChanges] = useRecoilState(
        pendingTransactionPositionChanges(transaction.id)
    );
    const [showAdvanced, setShowAdvanced] = useState(false);

    const [positions, setPositions] = useState([]);

    useEffect(() => {
        setPositions(
            transaction.positions
                .map((p) => ({ ...p, is_empty: false }))
                .concat([
                    {
                        ...localPositionChanges.empty,
                        is_empty: true,
                    },
                ])
        );
    }, [transaction, setPositions, localPositionChanges]);

    // find all accounts that take part in the transaction, either via debitor shares or purchase items
    // TODO: should we add creditor accounts as well?
    const positionAccounts: Array<number> = Array.from(
        new Set<number>(
            positions
                .map((item) => Object.keys(item.usages))
                .flat()
                .map((id) => parseInt(id))
        )
    );

    const [additionalPurchaseItemAccounts, setAdditionalPurchaseItemAccounts] = useState([]);
    const transactionAccounts: Array<number> = Array.from(
        new Set<number>(
            Object.keys(transaction.debitor_shares)
                .map((id) => parseInt(id))
                .concat(positionAccounts)
                .concat(additionalPurchaseItemAccounts)
        )
    );

    const showAddAccount = transactionAccounts.length < accounts.length;

    const [showAccountSelect, setShowAccountSelect] = useState(false);

    const totalPositionValue = positions.reduce((acc, curr) => acc + curr.price, 0);
    const sharedTransactionValue = transaction.value - totalPositionValue;

    const purchaseItemSumForAccount = (accountID) => {
        return transaction.account_balances.hasOwnProperty(accountID)
            ? transaction.account_balances[accountID].positions
            : 0;
    };

    const updatePosition = (position, name, price, communistShares) => {
        if (position.is_empty) {
            return updateEmptyPosition(position, name, price, communistShares);
        }
        if (position.only_local) {
            setLocalPositionChanges((currPositions) => {
                let mappedAdded = { ...currPositions.added };
                mappedAdded[position.id] = {
                    ...position,
                    name: name,
                    price: price,
                    communist_shares: communistShares,
                };
                return {
                    modified: currPositions.modified,
                    added: mappedAdded,
                    empty: currPositions.empty,
                };
            });
        } else {
            setLocalPositionChanges((currPositions) => {
                let mappedModified = { ...currPositions.modified };
                mappedModified[position.id] = {
                    ...position,
                    name: name,
                    price: price,
                    communist_shares: communistShares,
                };
                return {
                    modified: mappedModified,
                    empty: currPositions.empty,
                    added: currPositions.added,
                };
            });
        }
    };

    const updatePositionUsage = (position, accountID, shares) => {
        if (position.is_empty) {
            return updateEmptyPositionUsage(position, accountID, shares);
        }
        if (position.only_local) {
            setLocalPositionChanges((currPositions) => {
                let mappedAdded = { ...currPositions.added };
                let usages = { ...currPositions.added[position.id].usages };
                if (shares === 0) {
                    delete usages[accountID];
                } else {
                    usages[accountID] = shares;
                }
                mappedAdded[position.id] = {
                    ...currPositions.added[position.id],
                    usages: usages,
                };
                return {
                    modified: currPositions.modified,
                    added: mappedAdded,
                    empty: currPositions.empty,
                };
            });
        } else {
            setLocalPositionChanges((currPositions) => {
                let mappedModified = { ...currPositions.modified };
                let usages;
                if (mappedModified.hasOwnProperty(position.id)) {
                    // we already did change something locally
                    usages = { ...currPositions.modified[position.id].usages };
                } else {
                    // we first need to copy
                    usages = { ...position.usages };
                }

                if (shares === 0) {
                    delete usages[accountID];
                } else {
                    usages[accountID] = shares;
                }
                mappedModified[position.id] = {
                    ...position,
                    ...currPositions.modified[position.id],
                    usages: usages,
                };
                return {
                    modified: mappedModified,
                    added: currPositions.added,
                    empty: currPositions.empty,
                };
            });
        }
    };

    const deletePosition = (position) => {
        if (position.is_empty) {
            return resetEmptyPosition();
        }

        if (position.only_local) {
            setLocalPositionChanges((currPositions) => {
                let mappedAdded = { ...currPositions.added };
                delete mappedAdded[position.id];
                return {
                    modified: currPositions.modified,
                    added: mappedAdded,
                    empty: currPositions.empty,
                };
            });
        } else {
            setLocalPositionChanges((currPositions) => {
                let mappedModified = { ...currPositions.modified };
                mappedModified[position.id] = {
                    ...position,
                    deleted: true,
                };
                return {
                    modified: mappedModified,
                    added: currPositions.added,
                    empty: currPositions.empty,
                };
            });
        }
    };

    const nextEmptyPositionID = (localPositions: LocalPositionChanges) => {
        return Math.min(...Object.values(localPositions.added).map((p) => p.id), -1, localPositions.empty.id) - 1;
    };

    const resetEmptyPosition = () => {
        setLocalPositionChanges((currValue) => ({
            modified: currValue.modified,
            added: currValue.added,
            empty: {
                id: nextEmptyPositionID(currValue),
                name: "",
                price: 0,
                communist_shares: 0,
                usages: {},
                deleted: false,
            },
        }));
    };

    const updateEmptyPosition = (position, name, price, communistShares) => {
        if (name !== "" && name != null) {
            const copyOfEmpty = { ...position, name: name, price: price, communist_shares: communistShares };
            setLocalPositionChanges((currPositions) => {
                let mappedAdded = { ...currPositions.added };
                mappedAdded[position.id] = copyOfEmpty;
                return {
                    modified: currPositions.modified,
                    added: mappedAdded,
                    empty: {
                        id: nextEmptyPositionID(currPositions),
                        name: "",
                        price: 0,
                        communist_shares: 0,
                        usages: {},
                        deleted: false,
                    },
                };
            });
        } else {
            setLocalPositionChanges((currPositions) => {
                return {
                    modified: currPositions.modified,
                    added: currPositions.added,
                    empty: {
                        ...position,
                        name: name,
                        price: price,
                        communist_shares: communistShares,
                    },
                };
            });
        }
    };

    const updateEmptyPositionUsage = (position, accountID, value) => {
        setLocalPositionChanges((currPositions) => {
            let newUsages = { ...position.usages };
            if (value === 0) {
                delete newUsages[accountID];
            } else {
                newUsages[accountID] = value;
            }
            return {
                modified: currPositions.modified,
                added: currPositions.added,
                empty: {
                    ...position,
                    usages: newUsages,
                },
            };
        });
    };

    const copyPosition = (position) => {
        setLocalPositionChanges((currPositions) => {
            const newPosition = {
                ...position,
                id: nextEmptyPositionID(currPositions),
            };
            let mappedAdded = { ...currPositions.added };
            mappedAdded[newPosition.id] = newPosition;
            return {
                modified: currPositions.modified,
                added: mappedAdded,
                empty: currPositions.empty,
            };
        });
    };

    const addPurchaseItemAccount = (account) => {
        setShowAccountSelect(false);
        setAdditionalPurchaseItemAccounts((currAdditionalAccounts) =>
            Array.from(new Set<number>([...currAdditionalAccounts, parseInt(account.id)]))
        );
    };

    return (
        <MobilePaper sx={{ marginTop: 2 }}>
            <Grid container direction="row" justifyContent="space-between">
                <Typography>Positions</Typography>
                {transaction.is_wip && (
                    <FormControlLabel
                        control={<Checkbox name={`show-advanced`} />}
                        checked={showAdvanced}
                        onChange={(event: React.ChangeEvent<HTMLInputElement>) => setShowAdvanced(event.target.checked)}
                        label="Advanced"
                    />
                )}
            </Grid>
            <TableContainer>
                <Table className={classes.table} stickyHeader aria-label="purchase items" size="small">
                    <TableHead>
                        <TableRow>
                            <TableCell>Name</TableCell>
                            <TableCell align="right">Price</TableCell>
                            {(transaction.is_wip ? transactionAccounts : positionAccounts).map((accountID) => (
                                <TableCell align="right" sx={{ minWidth: 80 }} key={accountID}>
                                    {accounts.find((account) => account.id === accountID).name}
                                </TableCell>
                            ))}
                            {transaction.is_wip && (
                                <>
                                    {showAccountSelect && (
                                        <TableCell align="right">
                                            <AccountSelect
                                                group={group}
                                                exclude={transactionAccounts}
                                                onChange={addPurchaseItemAccount}
                                            />
                                        </TableCell>
                                    )}
                                    {showAddAccount && (
                                        <TableCell align="right">
                                            <IconButton onClick={() => setShowAccountSelect(true)}>
                                                <Add />
                                            </IconButton>
                                        </TableCell>
                                    )}
                                </>
                            )}
                            <TableCell align="right">Shared</TableCell>
                            {transaction.is_wip && <TableCell></TableCell>}
                        </TableRow>
                    </TableHead>
                    <TableBody>
                        {transaction.is_wip
                            ? positions.map((position, idx) => (
                                  <TableRow hover key={position.id}>
                                      <PositionTableRow
                                          position={position}
                                          deletePosition={deletePosition}
                                          transactionAccounts={transactionAccounts}
                                          copyPosition={copyPosition}
                                          updatePosition={updatePosition}
                                          updatePositionUsage={updatePositionUsage}
                                          showAdvanced={showAdvanced}
                                          showAccountSelect={showAccountSelect}
                                          showAddAccount={showAddAccount}
                                      />
                                  </TableRow>
                              ))
                            : positions.map(
                                  (position) =>
                                      !position.is_empty && (
                                          <TableRow hover key={position.id}>
                                              <TableCell>{position.name}</TableCell>
                                              <TableCell align="right" style={{ minWidth: 80 }}>
                                                  {position.price.toFixed(2)} {transaction.currency_symbol}
                                              </TableCell>
                                              {positionAccounts.map((accountID) => (
                                                  <TableCell align="right" key={accountID}>
                                                      {position.usages.hasOwnProperty(String(accountID))
                                                          ? position.usages[String(accountID)]
                                                          : 0}
                                                  </TableCell>
                                              ))}
                                              <TableCell align="right">{position.communist_shares}</TableCell>
                                          </TableRow>
                                      )
                              )}
                        <TableRow hover>
                            <TableCell>
                                <Typography sx={{ fontWeight: "bold" }}>Total:</Typography>
                            </TableCell>
                            <TableCell align="right">
                                {totalPositionValue.toFixed(2)} {transaction.currency_symbol}
                            </TableCell>
                            {(transaction.is_wip ? transactionAccounts : positionAccounts).map((accountID) => (
                                <TableCell align="right" key={accountID}>
                                    {purchaseItemSumForAccount(accountID).toFixed(2)} {transaction.currency_symbol}
                                </TableCell>
                            ))}
                            <TableCell align="right" colSpan={showAddAccount ? 2 : 1}>
                                {(
                                    positions.reduce((acc, curr) => acc + curr.price, 0) -
                                    Object.values(transaction.account_balances).reduce(
                                        (acc, curr) => acc + curr.positions,
                                        0
                                    )
                                ).toFixed(2)}{" "}
                                {transaction.currency_symbol}
                            </TableCell>
                            {transaction.is_wip && <TableCell></TableCell>}
                        </TableRow>
                        <TableRow hover>
                            <TableCell>
                                <Typography sx={{ fontWeight: "bold" }}>Remaining:</Typography>
                            </TableCell>
                            <TableCell align="right">
                                {sharedTransactionValue.toFixed(2)} {transaction.currency_symbol}
                            </TableCell>
                            {(transaction.is_wip ? transactionAccounts : positionAccounts).map((accountID) => (
                                <TableCell align="right" key={accountID}></TableCell>
                            ))}
                            <TableCell align="right" colSpan={showAddAccount ? 2 : 1}></TableCell>
                            {transaction.is_wip && <TableCell></TableCell>}
                        </TableRow>
                    </TableBody>
                </Table>
            </TableContainer>
        </MobilePaper>
    );
}
Example #9
Source File: PlayerList.tsx    From NekoMaid with MIT License 4 votes vote down vote up
Players: React.FC = () => {
  const his = useHistory()
  const plugin = usePlugin()
  const [page, setPage] = useState(0)
  const [loading, setLoading] = useState(true)
  const [state, setState] = useState<number | null>(null)
  const [activedPlayer, setActivedPlayer] = useState<PlayerData | null>(null)
  const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null)
  const [data, setData] = useState<{ count: number, players: PlayerData[] }>(() => ({ count: 0, players: [] }))
  const globalData = useGlobalData()
  const { hasWhitelist } = globalData
  const refresh = () => {
    setLoading(true)
    plugin.emit('playerList:fetchPage', (it: any) => {
      if (it.players == null) it.players = []
      setData(it)
      setLoading(false)
    }, page, state === 1 || state === 2 ? state : 0, null)
  }
  useMemo(refresh, [page, state])
  const close = () => {
    setAnchorEl(null)
    setActivedPlayer(null)
  }

  return <Card>
    <CardHeader
      title={lang.playerList.title}
      action={
        <ToggleButtonGroup
          size='small'
          color={(state === 1 ? 'warning' : state === 2 ? 'error' : undefined) as any}
          value={state}
          exclusive
          onChange={(_, it) => {
            if (it === 3) return
            setState(it)
            if (state === 3) refresh()
          }}
        >
          <ToggleButton disabled={loading} value={1}><Star /></ToggleButton>
          <ToggleButton disabled={loading} value={2}><Block /></ToggleButton>
          <ToggleButton disabled={loading} value={3} onClick={() => state !== 3 && dialog(lang.playerList.nameToSearch, lang.username)
            .then(filter => {
              if (filter == null) return
              his.push('/NekoMaid/playerList/' + filter)
              setState(3)
              setLoading(true)
              plugin.emit('playerList:fetchPage', (it: any) => {
                if (it.players == null) it.players = []
                setPage(0)
                setData(it)
                setLoading(false)
              }, page, 0, filter.toLowerCase())
            })}><Search /></ToggleButton>
        </ToggleButtonGroup>
      }
    />
    <Divider />
    <Box sx={{ position: 'relative' }}>
      <CircularLoading loading={loading} />
      <TableContainer>
        <Table>
          <TableHead>
            <TableRow>
              <TableCell padding='checkbox' />
              <TableCell>{lang.username}</TableCell>
              <TableCell align='right'>{minecraft['stat.minecraft.play_time']}</TableCell>
              <TableCell align='right'>{lang.playerList.lastPlay}</TableCell>
              <TableCell align='right'>{lang.operations}</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {data.players.map(it => <TableRow key={it.name}>
              <TableCell sx={{ cursor: 'pointer', padding: theme => theme.spacing(1, 1, 1, 2) }} onClick={() => his.push('/NekoMaid/playerList/' + it.name)}>
                <Avatar src={getSkin(globalData, it.name, true)} imgProps={{ crossOrigin: 'anonymous', style: { width: 40, height: 40 } }} variant='rounded' />
              </TableCell>
              <TableCell>{it.name}</TableCell>
              <TableCell align='right'>{dayjs.duration(it.playTime / 20, 'seconds').humanize()}</TableCell>
              <TableCell align='right'>{dayjs(it.lastOnline).fromNow()}</TableCell>
              <TableCell align='right'>
                {(state === 1 || hasWhitelist) && <Tooltip title={lang.playerList[it.whitelisted ? 'clickToRemoveWhitelist' : 'clickToAddWhitelist']}>
                  <IconButton onClick={() => whitelist(it.name, plugin, refresh, !it.whitelisted)}>
                    {it.whitelisted ? <Star color='warning' /> : <StarBorder />}
                  </IconButton>
                </Tooltip>}
                <Tooltip title={it.ban == null ? lang.playerList.clickToBan : lang.playerList.banned + ': ' + it.ban}>
                  <IconButton onClick={() => banPlayer(it.name, plugin, refresh, it.ban == null)}>
                    <Block color={it.ban == null ? undefined : 'error'} />
                  </IconButton>
                </Tooltip>
                {actions.length
                  ? <IconButton onClick={e => {
                    setActivedPlayer(anchorEl ? null : it)
                    setAnchorEl(anchorEl ? null : e.currentTarget)
                  }}><MoreHoriz /></IconButton>
                  : null}
              </TableCell>
            </TableRow>)}
          </TableBody>
        </Table>
      </TableContainer>
      <TablePagination
        rowsPerPageOptions={[]}
        component='div'
        count={data.count}
        rowsPerPage={10}
        page={page}
        onPageChange={(_, it) => !loading && setPage(it)}
      />
    </Box>
    <Menu
      anchorEl={anchorEl}
      open={Boolean(anchorEl)}
      onClose={() => setAnchorEl(null)}
    >{actions.map((It, i) => <It key={i} onClose={close} player={activedPlayer} />)}</Menu>
  </Card>
}
Example #10
Source File: Plugins.tsx    From NekoMaid with MIT License 4 votes vote down vote up
Plugins: React.FC = () => {
  const plugin = usePlugin()
  const theme = useTheme()
  const { canLoadPlugin } = useGlobalData()
  const [plugins, setPlugins] = useState<Plugin[]>([])
  useEffect(() => {
    const offList = plugin.on('plugins:list', (plugins: Plugin[]) => {
      const arr: Plugin[] = []
      setPlugins(plugins.filter(it => {
        const res = canPluginBeDisabled(it.name)
        if (res) arr.push(it)
        return !res
      }).concat(arr))
    })
    plugin.emit('plugins:fetch')
    return () => {
      offList()
    }
  }, [])

  const map: Record<string, number> = { }
  let id = 0
  const data = plugins.map(it => {
    map[it.name] = id
    return { id: id++, name: it.name, category: 1 - (it.enabled as any) }
  })
  const links: Array<{ source: number, target: number }> = []
  plugins.forEach(it => {
    const source = map[it.name]
    it.depends.forEach(dep => {
      if (!(dep in map)) {
        map[dep] = id
        data.push({ id: id++, name: dep, category: 3 })
      }
      links.push({ source, target: map[dep] })
    })
    it.softDepends.forEach(dep => {
      if (!(dep in map)) {
        map[dep] = id
        data.push({ id: id++, name: dep, category: 2 })
      }
      links.push({ source, target: map[dep] })
    })
  })
  return <Box sx={{ minHeight: '100%', py: 3 }}>
    <Toolbar />
    <Container maxWidth={false}>
      <Grid container spacing={3}>
        <Grid item xs={12}>
          <Card>
            <CardHeader title={lang.plugins.title} />
            <Divider />
            <TableContainer>
              <Table>
                <TableHead>
                  <TableRow>
                    <TableCell sx={{ paddingRight: 0 }}>{lang.plugins.enable}</TableCell>
                    <TableCell>{lang.plugins.name}</TableCell>
                    <TableCell>{lang.plugins.version}</TableCell>
                    <TableCell>{lang.plugins.author}</TableCell>
                    <TableCell>{lang.plugins.description}</TableCell>
                    <TableCell align='right'>{lang.operations}</TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {plugins.map(it => {
                    const canBeDisabled = canPluginBeDisabled(it.name)
                    const disabledForever = it.file.endsWith('.disabled')
                    return <TableRow key={it.name}>
                      <TableCell padding='checkbox'>
                        <Checkbox
                          color='primary'
                          checked={it.enabled}
                          disabled={disabledForever || canBeDisabled}
                          onChange={() => plugin.emit('plugins:enable', it.file, it.name, action)
                        } />
                      </TableCell>
                      <TableCell><Tooltip title={it.file}><span>{it.name}</span></Tooltip></TableCell>
                      <TableCell>{it.website
                        ? <Link underline='hover' rel='noopener' target='_blank' href={it.website}>{it.version}</Link>
                        : it.version
                      }</TableCell>
                      <TableCell>{it.author}</TableCell>
                      <TableCell>{it.description}</TableCell>
                      <TableCell align='right' sx={{ whiteSpace: 'nowrap' }}>
                        <Tooltip title={lang.plugins[disabledForever ? 'enablePlugin' : 'disableForever']}><span>
                          <IconButton
                            disabled={it.enabled || (it.loaded && !canLoadPlugin)}
                            onClick={() => plugin.emit('plugins:disableForever', it.file, action)}
                          >{disabledForever ? <LockOpen /> : <Lock />}</IconButton>
                        </span></Tooltip>
                        {disabledForever && <Tooltip title={lang.plugins.delete}><span>
                            <IconButton
                              color='error'
                              disabled={canBeDisabled}
                              onClick={() => dialog({
                                okButton: { color: 'error' },
                                content: <>{lang.plugins.confirmDelete(<span className='bold'>{it.file.replace(/\.disabled$/, '')}</span>)}&nbsp;
                                  <span className='bold' style={{ color: theme.palette.error.main }}>({lang.unrecoverable})</span></>
                              }).then(res => res && plugin.emit('plugins:delete', it.file, action))}
                            ><DeleteForever /></IconButton>
                          </span></Tooltip>}
                      </TableCell>
                    </TableRow>
                  })}
                </TableBody>
              </Table>
            </TableContainer>
          </Card>
        </Grid>
        <Grid item xs={12}>
          <Card>
            <CardHeader title={lang.plugins.dependency} />
            <Divider />
            <ReactECharts style={{ marginTop: theme.spacing(1), height: 450 }} theme={theme.palette.mode === 'dark' ? 'dark' : undefined} option={{
              backgroundColor: 'rgba(0, 0, 0, 0)',
              legend: { data: lang.plugins.categories },
              series: [
                {
                  edgeSymbol: ['none', 'arrow'],
                  symbolSize: 13,
                  type: 'graph',
                  layout: 'force',
                  data,
                  links,
                  categories: lang.plugins.categories.map(name => ({ name, base: name })),
                  roam: true,
                  label: {
                    show: true,
                    position: 'right',
                    formatter: '{b}'
                  },
                  labelLayout: {
                    hideOverlap: true
                  }
                }
              ]
            }} />
          </Card>
        </Grid>
      </Grid>
    </Container>
  </Box>
}
Example #11
Source File: Worlds.tsx    From NekoMaid with MIT License 4 votes vote down vote up
Worlds: React.FC = () => {
  const plugin = usePlugin()
  const globalData = useGlobalData()
  const [worlds, setWorlds] = useState<World[]>([])
  const [selected, setSelected] = useState('')
  const [open, setOpen] = useState(false)
  const update = () => plugin.emit('worlds:fetch', (data: World[]) => {
    setWorlds(data)
    if (data.length) setSelected(old => data.some(it => it.id === old) ? old : '')
  })
  useEffect(() => {
    const offUpdate = plugin.on('worlds:update', update)
    update()
    return () => { offUpdate() }
  }, [])
  const sw = worlds.find(it => it.id === selected)
  const getSwitch = (name: string, configId = name) => sw
    ? <ListItem
      secondaryAction={<Switch disabled={!globalData.hasMultiverse} checked={(sw as any)[name]}
      onChange={e => {
        plugin.emit('worlds:set', sw.id, configId, e.target.checked.toString())
        success()
      }}
    />}><ListItemText primary={(lang.worlds as any)[name]} /></ListItem>
    : null

  return <Box sx={{ minHeight: '100%', py: 3 }}>
    <Toolbar />
    <Container maxWidth={false}>
      <Grid container spacing={3}>
        <Grid item lg={8} md={12} xl={9} xs={12}>
        <Card>
          <CardHeader title={lang.worlds.title} />
          <Divider />
          <Box sx={{ position: 'relative' }}>
            <TableContainer>
              <Table>
                <TableHead>
                  <TableRow>
                    <TableCell padding='checkbox' />
                    <TableCell>{lang.worlds.name}</TableCell>
                    {globalData.hasMultiverse && <TableCell>{lang.worlds.alias}</TableCell>}
                    <TableCell>{lang.worlds.players}</TableCell>
                    <TableCell>{lang.worlds.chunks}</TableCell>
                    <TableCell>{lang.worlds.entities}</TableCell>
                    <TableCell>{lang.worlds.tiles}</TableCell>
                    <TableCell>{lang.worlds.time}</TableCell>
                    <TableCell>{lang.worlds.weather}</TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {worlds.map(it => <TableRow key={it.id}>
                    <TableCell padding='checkbox'><Checkbox checked={selected === it.id} onClick={() => setSelected(it.id)} /></TableCell>
                    <TableCell><Tooltip title={it.id}><span>{it.name}</span></Tooltip></TableCell>
                    {globalData.hasMultiverse && <TableCell>{it.alias}
                      <IconButton size='small' onClick={() => dialog(lang.inputValue, lang.worlds.alias).then(res => {
                        if (res == null) return
                        plugin.emit('worlds:set', it.id, 'alias', res)
                        success()
                      })}><Edit fontSize='small' /></IconButton>
                      </TableCell>}
                    <TableCell>{it.players}</TableCell>
                    <TableCell>{it.chunks}</TableCell>
                    <TableCell>{it.entities}</TableCell>
                    <TableCell>{it.tiles}</TableCell>
                    <TableCell><Countdown time={it.time} max={24000} interval={50} /></TableCell>
                    <TableCell><IconButton size='small' onClick={() => {
                      plugin.emit('worlds:weather', it.id)
                      success()
                    }}>
                      {React.createElement((it.weather === 1 ? WeatherRainy : it.weather === 2 ? WeatherLightningRainy : WbSunny) as any)}
                    </IconButton></TableCell>
                  </TableRow>)}
                </TableBody>
              </Table>
            </TableContainer>
          </Box>
        </Card>
        </Grid>
        <Grid item lg={4} md={6} xl={3} xs={12}>
          <Card>
            <CardHeader
              title={lang.operations}
              sx={{ position: 'relative' }}
              action={<Tooltip title={lang.worlds.save} placement='left'>
                <IconButton
                  size='small'
                  onClick={() => {
                    if (!sw) return
                    plugin.emit('worlds:save', sw.id)
                    success()
                  }}
                  sx={cardActionStyles}
                ><Save /></IconButton>
              </Tooltip>}
            />
            <Divider />
            <Box sx={{ position: 'relative' }}>
              {sw
                ? <List sx={{ width: '100%' }} component='nav'>
                  <ListItem secondaryAction={<ToggleButtonGroup
                    exclusive
                    color='primary'
                    size='small'
                    value={sw.difficulty}
                    onChange={(_, value) => {
                      plugin.emit('worlds:difficulty', sw.id, value)
                      success()
                    }}
                  >
                    {difficulties.map(it => <ToggleButton value={it.toUpperCase()} key={it}>{minecraft['options.difficulty.' + it]}</ToggleButton>)}
                  </ToggleButtonGroup>}><ListItemText primary={minecraft['options.difficulty']} /></ListItem>
                  <ListItem secondaryAction={<Switch checked={sw.pvp} onChange={e => {
                    plugin.emit('worlds:pvp', sw.id, e.target.checked)
                    success()
                  }} />}><ListItemText primary='PVP' /></ListItem>
                  {getSwitch('allowAnimals', 'spawning.animals.spawn')}
                  {getSwitch('allowMonsters', 'spawning.monsters.spawn')}
                  {globalData.hasMultiverse && <>
                    {getSwitch('allowFlight')}
                    {getSwitch('autoHeal')}
                    {getSwitch('hunger')}
                  </>}
                  <ListItem secondaryAction={globalData.canSetViewDistance
                    ? <IconButton
                      onClick={() => dialog({
                        content: lang.inputValue,
                        input: {
                          error: true,
                          type: 'number',
                          helperText: lang.invalidValue,
                          validator: (it: string) => /^\d+$/.test(it) && +it > 1 && +it < 33
                        }
                      }).then(res => {
                        if (!res) return
                        plugin.emit('worlds:viewDistance', sw.id, parseInt(res as any))
                        success()
                      })}
                    ><Edit /></IconButton>
                    : undefined}>
                    <ListItemText primary={lang.worlds.viewDistance + ': ' + sw.viewDistance} />
                  </ListItem>
                  <ListItem><ListItemText primary={minecraft['selectWorld.enterSeed']} secondary={sw.seed} /></ListItem>
                  <ListItemButton onClick={() => setOpen(!open)}>
                    <ListItemText primary={minecraft['selectWorld.gameRules']} />
                    {open ? <ExpandLess /> : <ExpandMore />}
                  </ListItemButton>
                  <Collapse in={open} timeout="auto" unmountOnExit>
                    <List component='div' dense disablePadding>
                      {sw.rules.map(([key, value]) => {
                        const isTrue = value === 'true'
                        const isBoolean = isTrue || value === 'false'
                        const isNumber = /^\d+$/.test(value)
                        return <ListItem
                          key={key}
                          sx={{ pl: 4 }}
                          secondaryAction={isBoolean
                            ? <Switch
                              checked={isTrue}
                              onChange={e => {
                                plugin.emit('worlds:rule', sw.id, key, e.target.checked.toString())
                                success()
                              }}
                            />
                            : <IconButton
                              onClick={() => dialog({
                                content: lang.inputValue,
                                input: isNumber
                                  ? {
                                      error: true,
                                      type: 'number',
                                      helperText: lang.invalidValue,
                                      validator: (it: string) => /^\d+$/.test(it)
                                    }
                                  : { }
                              }).then(res => {
                                if (res == null) return
                                plugin.emit('worlds:rule', sw.id, key, res)
                                success()
                              })}
                            ><Edit /></IconButton>}
                        >
                          <ListItemText primary={(minecraft['gamerule.' + key] || key) + (isBoolean ? '' : ': ' + value)} />
                        </ListItem>
                      })}
                    </List>
                  </Collapse>
                </List>
                : <CardContent><Empty /></CardContent>
              }
            </Box>
          </Card>
        </Grid>
      </Grid>
    </Container>
  </Box>
}
Example #12
Source File: CertificatesTab.tsx    From frontend with MIT License 4 votes vote down vote up
export default function CertificatesTab() {
  const { data = { donations: [], total: 0 } } = useUserDonations()
  const [fromDate, setFromDate] = React.useState(new Date())
  const [toDate, setToDate] = React.useState(new Date())

  return (
    <Root>
      <Box className={classes.boxTitle}>
        <Typography className={classes.h3}>История на сертификати</Typography>
      </Box>
      <ProfileTab name={ProfileTabs.certificates}>
        <Box>
          <Box sx={{ mt: 4 }}>
            <h3 className={classes.thinFont}>Онлайн дарения</h3>
          </Box>
          <Box
            sx={{
              display: 'flex',
              alignItems: 'baseline',
              justifyContent: 'space-between',
              mt: 2,
            }}>
            <span className={classes.smallText}>Покажи:</span>
            <Box>
              <Checkbox defaultChecked />
              <span className={classes.smallText}>еднократни</span>
            </Box>
            <Box>
              <Checkbox defaultChecked />
              <span className={classes.smallText}>месечни</span>
            </Box>
            <LocalizationProvider dateAdapter={AdapterDateFns}>
              <span className={classes.smallText}>от дата</span>
              <DesktopDatePicker
                label="от дата"
                inputFormat="MM/dd/yyyy"
                value={fromDate}
                onChange={(date) => setFromDate(date as Date)}
                renderInput={(params) => <TextField {...params} />}
              />
              <span className={classes.smallText}>до дата</span>
              <DesktopDatePicker
                label="до дата"
                inputFormat="MM/dd/yyyy"
                value={toDate}
                onChange={(date) => setToDate(date as Date)}
                renderInput={(params) => <TextField {...params} />}
              />
            </LocalizationProvider>
          </Box>
          {data.donations.length ? (
            <TableContainer>
              <Table sx={{ minWidth: 650, backgroundColor: 'white' }} aria-label="simple table">
                <TableHead>
                  <TableRow>
                    <TableCell>№</TableCell>
                    <TableCell>Дата</TableCell>
                    <TableCell>Вид</TableCell>
                    <TableCell>Кауза</TableCell>
                    <TableCell>стойност</TableCell>
                    <TableCell>сертификат</TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {data.donations.map((donation, index) => (
                    <TableRow
                      key={index}
                      sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>
                      <TableCell component="th" scope="row">
                        {index + 1}
                      </TableCell>
                      <TableCell>{formatDateString(donation.createdAt)}</TableCell>
                      <TableCell>
                        <Avatar sx={{ background: '#F6992B' }}>
                          <StarIcon />
                        </Avatar>
                      </TableCell>
                      <TableCell>{donation.targetVault.campaign.title}</TableCell>
                      <TableCell>
                        {donation.amount} {donation.currency}
                      </TableCell>
                      <TableCell>
                        <Button variant="outlined">
                          Свали <ArrowForwardIcon />
                        </Button>
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </TableContainer>
          ) : (
            <Box sx={{ fontSize: 20, mt: 4 }}>Към момента няма направени дарения</Box>
          )}
        </Box>
      </ProfileTab>
    </Root>
  )
}
Example #13
Source File: DonationTable.tsx    From frontend with MIT License 4 votes vote down vote up
function DonationTable({ donations }: DonationTableProps) {
  const { t, i18n } = useTranslation()
  const [fromDate, setFromDate] = React.useState<Date | null>(null)
  const [toDate, setToDate] = React.useState<Date | null>(null)
  const [monthly, setMonthly] = React.useState(true)
  const [oneTime, setOneTime] = React.useState(true)
  const filteredByTypeDonations = useMemo(() => {
    if (monthly && oneTime) {
      return donations
    }
    if (!monthly && !oneTime) {
      return []
    }
    if (monthly) {
      return donations?.filter((d) => d.type !== 'donation')
    }
    if (oneTime) {
      return donations?.filter((d) => d.type === 'donation')
    }
    return donations
  }, [donations, monthly, oneTime])
  const filteredDonations = useMemo(() => {
    if (!fromDate && !toDate) {
      return filteredByTypeDonations
    }
    if (fromDate && toDate) {
      return filteredByTypeDonations?.filter((d) => {
        const createdAtDate = parseISO(d.createdAt)
        return isAfter(createdAtDate, fromDate) && isBefore(createdAtDate, toDate)
      })
    }
    if (fromDate) {
      return filteredByTypeDonations?.filter((d) => {
        const createdAtDate = parseISO(d.createdAt)
        return isAfter(createdAtDate, fromDate)
      })
    }
    if (toDate) {
      return filteredByTypeDonations?.filter((d) => {
        const createdAtDate = parseISO(d.createdAt)
        return isBefore(createdAtDate, toDate)
      })
    }
  }, [filteredByTypeDonations, fromDate, toDate])
  return (
    <Card sx={{ padding: theme.spacing(2) }}>
      <Grid container alignItems={'flex-start'} spacing={theme.spacing(2)}>
        <Grid item xs={6} sm={3}>
          <CheckboxLabel>{t('profile:donations.oneTime')}</CheckboxLabel>
          <Checkbox
            onChange={(e, checked) => setOneTime(checked)}
            checked={oneTime}
            name="oneTime"
          />
        </Grid>
        <Grid item xs={6} sm={3}>
          <CheckboxLabel>{t('profile:donations.monthly')}</CheckboxLabel>
          <Checkbox
            onChange={(e, checked) => setMonthly(checked)}
            checked={monthly}
            name="monthly"
          />
        </Grid>
        <LocalizationProvider
          locale={i18n.language === 'bg' ? bg : enUS}
          dateAdapter={AdapterDateFns}>
          <Grid item xs={12} sm={3}>
            <DatePicker
              label={t('profile:donations.fromDate')}
              value={fromDate}
              onChange={setFromDate}
              renderInput={(params) => <TextField size="small" {...params} />}
            />
          </Grid>
          <Grid item xs={12} sm={3}>
            <DatePicker
              label={t('profile:donations.toDate')}
              value={toDate}
              onChange={setToDate}
              renderInput={(params) => <TextField size="small" {...params} />}
            />
          </Grid>
        </LocalizationProvider>
      </Grid>
      {filteredDonations?.length ? (
        <TableContainer>
          <Table sx={{ minWidth: 650, backgroundColor: 'white' }} aria-label="simple table">
            <TableHead>
              <TableRow>
                <TableCell>№</TableCell>
                <TableCell>{t('profile:donations.date')}</TableCell>
                <TableCell>{t('profile:donations.type')}</TableCell>
                <TableCell>{t('profile:donations.cause')}</TableCell>
                <TableCell>{t('profile:donations.amount')}</TableCell>
                <TableCell>{t('profile:donations.certificate')}</TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {filteredDonations.map((donation, index) => (
                <TableRow key={index} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>
                  <TableCell component="th" scope="row">
                    {index + 1}
                  </TableCell>
                  <TableCell>
                    {format(parseISO(donation.createdAt), 'd.LL.yyyy', {
                      locale: i18n.language === 'bg' ? bg : enUS,
                    })}
                  </TableCell>
                  <TableCell>
                    <Avatar sx={{ background: darken(theme.palette.secondary.main, 0.175) }}>
                      <StarIcon />
                    </Avatar>
                  </TableCell>
                  <TableCell>{donation.targetVault.campaign.title}</TableCell>
                  <TableCell>{money(donation.amount)}</TableCell>
                  <TableCell>
                    <Button variant="outlined" disabled={donation.status != 'succeeded'}>
                      <Link target="_blank" href={routes.donation.viewCertificate(donation.id)}>
                        {t('profile:donations.download')} <ArrowForwardIcon />
                      </Link>
                    </Button>
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </TableContainer>
      ) : (
        <Box sx={{ fontSize: 20, mt: 4 }}>Към момента няма направени дарения</Box>
      )}
    </Card>
  )
}
Example #14
Source File: index.tsx    From yearn-watch-legacy with GNU Affero General Public License v3.0 4 votes vote down vote up
GenericList = <T extends GenericListItem>(
    props: GenericListProps<T>
) => {
    const {
        defaultRowsPerPage = 10,
        defaultOrder = 'asc',
        defaultOrderBy = 'id',
    } = props;
    const classes = useStyles();
    const [order, setOrder] = React.useState<Order>(defaultOrder);
    const [orderBy, setOrderBy] =
        React.useState<keyof GenericListItem>(defaultOrderBy);
    const [page, setPage] = React.useState(0);
    const [rowsPerPage, setRowsPerPage] = React.useState(defaultRowsPerPage);
    const { items, title, headCells, displayPagination = true } = props;

    const shouldCollapse = props.collapse !== undefined;

    const handleRequestSort = (
        event: React.MouseEvent<unknown>,
        property: keyof GenericListItem
    ) => {
        const isAsc = orderBy === property && order === 'asc';
        setOrder(isAsc ? 'desc' : 'asc');
        setOrderBy(property);
    };

    const handleChangePage = (event: unknown, newPage: number) => {
        setPage(newPage);
    };

    const handleChangeRowsPerPage = (
        event: React.ChangeEvent<HTMLInputElement>
    ) => {
        setRowsPerPage(parseInt(event.target.value, 10));
        setPage(0);
    };

    const emptyRows =
        rowsPerPage - Math.min(rowsPerPage, items.length - page * rowsPerPage);
    return (
        <div className={classes.root}>
            <Paper className={classes.paper}>
                <EnhancedTableToolbar title={title} />
                <TableContainer>
                    <Table
                        className={classes.table}
                        aria-labelledby="tableTitle"
                        size="small"
                        aria-label="enhanced table"
                    >
                        <EnhancedTableHead
                            classes={classes}
                            order={order}
                            orderBy={orderBy.toString()}
                            headCells={props.headCells}
                            onRequestSort={handleRequestSort}
                            shouldCollapse={shouldCollapse}
                        />
                        <TableBody>
                            {stableSort(items, getComparator(order, orderBy))
                                .slice(
                                    page * rowsPerPage,
                                    page * rowsPerPage + rowsPerPage
                                )
                                .map((row, index) => {
                                    const labelId = `enhanced-table-checkbox-${index}`;
                                    return (
                                        <ItemRow
                                            headCells={headCells}
                                            item={row}
                                            index={index}
                                            key={labelId}
                                            collapse={props.collapse}
                                            getRowStyle={props.getRowStyle}
                                        />
                                    );
                                })}
                            {emptyRows > 0 && (
                                <TableRow
                                    style={{
                                        height: 33 * emptyRows,
                                    }}
                                >
                                    <TableCell colSpan={6} />
                                </TableRow>
                            )}
                        </TableBody>
                    </Table>
                </TableContainer>
                {displayPagination ? (
                    <TablePagination
                        rowsPerPageOptions={[5, 10, 20, 40, 60, 75, 100]}
                        component="div"
                        count={items.length}
                        rowsPerPage={rowsPerPage}
                        page={page}
                        onPageChange={handleChangePage}
                        onRowsPerPageChange={handleChangeRowsPerPage}
                    />
                ) : (
                    ''
                )}
            </Paper>
        </div>
    );
}