@mui/material#Stack JavaScript Examples
The following examples show how to use
@mui/material#Stack.
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: AppForm.jsx From matx-react with MIT License | 6 votes |
AppForm = () => {
return (
<Container>
<Box className="breadcrumb">
<Breadcrumb routeSegments={[{ name: "Material", path: "/material" }, { name: "Form" }]} />
</Box>
<Stack spacing={3}>
<SimpleCard title="Simple Form">
<SimpleForm />
</SimpleCard>
<SimpleCard title="stepper form">
<StepperForm />
</SimpleCard>
</Stack>
</Container>
);
}
Example #2
Source File: DashboardNavbar.js From Django-REST-Framework-React-BoilerPlate with MIT License | 6 votes |
export default function DashboardNavbar({ onOpenSidebar }) {
return (
<RootStyle>
<ToolbarStyle>
<IconButton onClick={onOpenSidebar} sx={{ mr: 1, color: 'text.primary', display: { lg: 'none' } }}>
<Iconify icon="eva:menu-2-fill" />
</IconButton>
<Searchbar />
<Box sx={{ flexGrow: 1 }} />
<Stack direction="row" alignItems="center" spacing={{ xs: 0.5, sm: 1.5 }}>
<AccountPopover />
</Stack>
</ToolbarStyle>
</RootStyle>
);
}
Example #3
Source File: AuthSocial.js From Django-REST-Framework-React-BoilerPlate with MIT License | 6 votes |
// ----------------------------------------------------------------------
export default function AuthSocial() {
return (
<>
<Stack direction="row" spacing={2}>
<Button fullWidth size="large" color="inherit" variant="outlined">
<Iconify icon="eva:google-fill" color="#DF3E30" width={22} height={22} />
</Button>
<Button fullWidth size="large" color="inherit" variant="outlined">
<Iconify icon="eva:facebook-fill" color="#1877F2" width={22} height={22} />
</Button>
<Button fullWidth size="large" color="inherit" variant="outlined">
<Iconify icon="eva:twitter-fill" color="#1C9CEA" width={22} height={22} />
</Button>
</Stack>
<Divider sx={{ my: 3 }}>
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
OR
</Typography>
</Divider>
</>
);
}
Example #4
Source File: ImageList.js From fireact with MIT License | 6 votes |
ActionButtons = ({id, handleDeletion}) => {
const history = useHistory();
const { userData } = useContext(AuthContext);
const url = '/account/'+userData.currentAccount.id+'/images/edit/'+id;
return (
<Stack direction="row" spacing={1} mt={2}>
<Button variant="contained" onClick={() => history.push(url)}>Edit</Button>
<DataDelete id={id} handleDeletion={handleDeletion} />
</Stack>
)
}
Example #5
Source File: AppExpansionPanel.jsx From matx-react with MIT License | 6 votes |
AppExpansionPanel = () => {
return (
<Container>
<Box className="breadcrumb">
<Breadcrumb
routeSegments={[{ name: "Material", path: "/material" }, { name: "Expansion Panel" }]}
/>
</Box>
<Stack spacing={3}>
<SimpleCard title="simple expansion panel">
<SimpleExpansionPanel />
</SimpleCard>
<SimpleCard title="Controlled Accordion">
<ControlledExpansionPanels />
</SimpleCard>
<SimpleCard title="Secondary heading and Columns">
<DetailedExpansionPanel />
</SimpleCard>
<SimpleCard title="Customized expansion panels">
<CustomizedExpansionPanels />
</SimpleCard>
</Stack>
</Container>
);
}
Example #6
Source File: AppMenu.jsx From matx-react with MIT License | 6 votes |
AppMenu = () => {
return (
<Container>
<Box className="breadcrumb">
<Breadcrumb routeSegments={[{ name: "Material", path: "/material" }, { name: "Menu" }]} />
</Box>
<Stack spacing={3}>
<SimpleCard title="simple menu">
<SimpleMenu />
</SimpleCard>
<SimpleCard title="selected menu">
<SelectedMenu />
</SimpleCard>
<SimpleCard title="customized menu">
<CustomizedMenu />
</SimpleCard>
<SimpleCard title="max height menu">
<MaxHeightMenu />
</SimpleCard>
</Stack>
</Container>
);
}
Example #7
Source File: AppRadio.jsx From matx-react with MIT License | 6 votes |
AppRadio = () => {
return (
<Container>
<Box className="breadcrumb">
<Breadcrumb routeSegments={[{ name: "Material", path: "/material" }, { name: "Radio" }]} />
</Box>
<Stack spacing={3}>
<SimpleCard title="Simple Radio Button">
<SimpleRadio />
</SimpleCard>
<SimpleCard title="Standalone Radio Button">
<StandaloneRadio />
</SimpleCard>
<SimpleCard title="Label Placement">
<PlacingRadioLabel />
</SimpleCard>
</Stack>
</Container>
);
}
Example #8
Source File: AppSlider.jsx From matx-react with MIT License | 6 votes |
AppSlider = () => {
return (
<Container>
<Box className="breadcrumb">
<Breadcrumb routeSegments={[{ name: "Material", path: "/material" }, { name: "Slider" }]} />
</Box>
<Stack spacing={3}>
<SimpleCard title="Continuous Slider">
<ContinuousSlider />
</SimpleCard>
<SimpleCard title="Discrete Slider">
<DiscreteSlider />
</SimpleCard>
<SimpleCard title="Range Slider">
<RangeSlider />
</SimpleCard>
<SimpleCard title="Slider with Input">
<InputSlider />
</SimpleCard>
<SimpleCard title="Vertical Slider">
<VerticalSlider />
</SimpleCard>
</Stack>
</Container>
);
}
Example #9
Source File: ContinuousSlider.jsx From matx-react with MIT License | 6 votes |
export default function ContinuousSlider() {
const [value, setValue] = React.useState(30);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<Box width={200}>
<Typography id="continuous-slider" gutterBottom>
Volume
</Typography>
<Stack spacing={2} direction="row" sx={{ mb: 1 }} alignItems="center">
<VolumeDown />
<Slider aria-label="Volume" value={value} onChange={handleChange} />
<VolumeUp />
</Stack>
<Slider disabled defaultValue={30} aria-label="Disabled slider" />
</Box>
);
}
Example #10
Source File: index.js From fireact with MIT License | 6 votes |
DataDelete = ({id, handleDeletion}) => {
const [open, setOpen] = useState(false);
return (
<>
<Button variant="contained" color="error" onClick={() => setOpen(true)}>
Delete
</Button>
<Dialog onClose={() => setOpen(false)} open={open}>
<DialogTitle>Delete</DialogTitle>
<Box p={3}>
Confirm deletion?
<Stack direction="row" spacing={1} mt={2}>
<Button variant="contained" color="error" onClick={() => handleDeletion(id)}>Yes</Button>
<Button variant="contained" color="secondary" onClick={() => setOpen(false)}>Cancel</Button>
</Stack>
</Box>
</Dialog>
</>
)
}
Example #11
Source File: AppSwitch.jsx From matx-react with MIT License | 6 votes |
AppSwitch = () => {
return (
<Container>
<Box className="mb-sm-30">
<Breadcrumb routeSegments={[{ name: "Material", path: "/material" }, { name: "Switch" }]} />
</Box>
<Stack spacing={3}>
<SimpleCard title="Simple Switch">
<SimpleSwitch />
</SimpleCard>
<SimpleCard title="Switch with Label">
<LabelledSwitch />
</SimpleCard>
<SimpleCard title="Switch with Form Group">
<FormGroupSwitch />
</SimpleCard>
<SimpleCard title="Customized Switch">
<CustomizedSwitch />
</SimpleCard>
<SimpleCard title="Switch with Different Label Placement">
<PlacingSwitchLabel />
</SimpleCard>
</Stack>
</Container>
);
}
Example #12
Source File: index.js From fireact with MIT License | 5 votes |
DataCreate = ({schema, validation, handleCreation, success, children}) => {
const mountedRef = useRef(true);
const [inSubmit, setInSubmit] = useState(false);
const [result, setResult] = useState({
response: null,
error: null
});
useEffect(() => {
return () => {
mountedRef.current = false
}
},[]);
return (
<form onSubmit={e => {
e.preventDefault();
setInSubmit(true);
if(validation()){
let data = {};
schema.forEach(field => {
data[field.name] = e.target.elements[field.name][field.prop]
});
handleCreation(data).then(res => {
if (!mountedRef.current) return null
setResult({
response: true,
error: null
});
setInSubmit(false);
}).catch(err => {
if (!mountedRef.current) return null
setResult({
response: false,
error: err
});
setInSubmit(false);
})
}else{
setResult({
response: false,
error: 'Please fill in the form in the correct format.'
})
setInSubmit(false);
}
}}>
<Paper>
<Box p={2}>
<Stack spacing={3}>
{result.response?(
<>{success}</>
):(
<>
{result.response === false &&
<Alert severity="error">{result.error}</Alert>
}
{children}
<Stack direction="row" spacing={1} mt={2}>
<Button variant="contained" type="submit" disabled={inSubmit}>{inSubmit && <Loader />} Create</Button>
</Stack>
</>
)}
</Stack>
</Box>
</Paper>
</form>
)
}
Example #13
Source File: AppDialog.jsx From matx-react with MIT License | 5 votes |
AppDialog = () => {
return (
<Container>
<Box className="breadcrumb">
<Breadcrumb routeSegments={[{ name: 'Material', path: '/material' }, { name: 'Dialog' }]} />
</Box>
<Stack spacing={3}>
<SimpleCard title="simple Dialog">
<SimpleDialogDemo />
</SimpleCard>
<SimpleCard title="alert dialog">
<AlertDialog />
</SimpleCard>
<SimpleCard title="transition">
<AlertDialogSlide />
</SimpleCard>
<SimpleCard title="form dialog">
<FormDialog />
</SimpleCard>
<SimpleCard title="customized dialog">
<CustomizedDialogs />
</SimpleCard>
<SimpleCard title="full-screen dialog">
<FullScreenDialog />
</SimpleCard>
<SimpleCard title="optimized size dialog">
<MaxWidthDialog />
</SimpleCard>
<SimpleCard title="responsive dialog">
<ResponsiveDialog />
</SimpleCard>
<SimpleCard title="confirmation dialog">
<ConfirmationDialog />
</SimpleCard>
</Stack>
</Container>
);
}
Example #14
Source File: search.js From react-table-library with MIT License | 5 votes |
Component = () => {
let data = { nodes };
const materialTheme = getTheme(DEFAULT_OPTIONS);
const theme = useTheme(materialTheme);
const [search, setSearch] = React.useState('');
const handleSearch = (event) => {
setSearch(event.target.value);
};
data = {
nodes: data.nodes.filter((item) => item.name.toLowerCase().includes(search.toLowerCase())),
};
const COLUMNS = [
{ label: 'Task', renderCell: (item) => item.name },
{
label: 'Deadline',
renderCell: (item) =>
item.deadline.toLocaleDateString('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
}),
},
{ label: 'Type', renderCell: (item) => item.type },
{
label: 'Complete',
renderCell: (item) => item.isComplete.toString(),
},
{ label: 'Tasks', renderCell: (item) => item.nodes?.length },
];
return (
<>
<Stack spacing={10}>
<TextField label="Search Task" value={search} icon={<FaSearch />} onChange={handleSearch} />
</Stack>
<br />
<CompactTable columns={COLUMNS} data={data} theme={theme} />
<br />
<DocumentationSee anchor={'Features/' + key} />
</>
);
}
Example #15
Source File: AppSnackbar.jsx From matx-react with MIT License | 5 votes |
AppSnackbar = () => {
return (
<Container>
<Box className="breadcrumb">
<Breadcrumb
routeSegments={[{ name: "Material", path: "/material" }, { name: "Snackbar" }]}
/>
</Box>
<Stack spacing={3}>
<SimpleCard title="simple snackbar">
<SimpleSnackbar />
</SimpleCard>
<SimpleCard title="customized snackbar">
<CustomizedSnackbars />
</SimpleCard>
<SimpleCard title="positioned snackbar">
<PositionedSnackbar />
</SimpleCard>
<SimpleCard title="message length">
<LongTextSnackbar />
</SimpleCard>
<SimpleCard title="transition">
<TransitionsSnackbar />
</SimpleCard>
<SimpleCard title="consecutive snackbar">
<ConsecutiveSnackbar />
</SimpleCard>
<SimpleCard title="Control Slide direction">
<DirectionSnackbar />
</SimpleCard>
<SimpleCard title="complementary project">
<IntegrationNotistack />
</SimpleCard>
</Stack>
</Container>
);
}
Example #16
Source File: pagination.js From react-table-library with MIT License | 5 votes |
Component = () => {
const data = { nodes };
const materialTheme = getTheme(DEFAULT_OPTIONS);
const theme = useTheme(materialTheme);
const pagination = usePagination(data, {
state: {
page: 0,
size: 2,
},
onChange: onPaginationChange,
});
function onPaginationChange(action, state) {
console.log(action, state);
}
const COLUMNS = [
{ label: 'Task', renderCell: (item) => item.name },
{
label: 'Deadline',
renderCell: (item) =>
item.deadline.toLocaleDateString('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
}),
},
{ label: 'Type', renderCell: (item) => item.type },
{
label: 'Complete',
renderCell: (item) => item.isComplete.toString(),
},
{ label: 'Tasks', renderCell: (item) => item.nodes?.length },
];
return (
<>
<CompactTable columns={COLUMNS} data={data} theme={theme} pagination={pagination} />
<br />
<Stack spacing={10}>
<TablePagination
count={data.nodes.length}
page={pagination.state.page}
rowsPerPage={pagination.state.size}
rowsPerPageOptions={[1, 2, 5]}
onRowsPerPageChange={(event) =>
pagination.fns.onSetSize(parseInt(event.target.value, 10))
}
onPageChange={(event, page) => pagination.fns.onSetPage(page)}
/>
</Stack>
<br />
<DocumentationSee anchor={'Features/' + key} />
</>
);
}
Example #17
Source File: filter.js From react-table-library with MIT License | 5 votes |
Component = () => {
let data = { nodes };
const materialTheme = getTheme(DEFAULT_OPTIONS);
const theme = useTheme(materialTheme);
const [isHide, setHide] = React.useState(false);
data = {
nodes: isHide ? data.nodes.filter((node) => !node.isComplete) : data.nodes,
};
const COLUMNS = [
{ label: 'Task', renderCell: (item) => item.name },
{
label: 'Deadline',
renderCell: (item) =>
item.deadline.toLocaleDateString('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
}),
},
{ label: 'Type', renderCell: (item) => item.type },
{
label: 'Complete',
renderCell: (item) => item.isComplete.toString(),
},
{ label: 'Tasks', renderCell: (item) => item.nodes?.length },
];
return (
<>
<Stack spacing={10}>
<FormGroup>
<FormControlLabel
control={
<Checkbox checked={isHide} onChange={(event) => setHide(event.target.checked)} />
}
label="Hide Complete"
/>
</FormGroup>
</Stack>
<CompactTable columns={COLUMNS} data={data} theme={theme} />
<br />
<DocumentationSee anchor={'Features/' + key} />
</>
);
}
Example #18
Source File: index.js From fireact with MIT License | 5 votes |
DataEdit = ({id, schema, validation, handleEdit, success, children}) => {
const mountedRef = useRef(true);
const [inSubmit, setInSubmit] = useState(false);
const [result, setResult] = useState({
response: null,
error: null
});
useEffect(() => {
return () => {
mountedRef.current = false
}
},[]);
return (
<form onSubmit={e => {
e.preventDefault();
setInSubmit(true);
if(validation()){
let data = {};
schema.forEach(field => {
data[field.name] = e.target.elements[field.name][field.prop]
});
handleEdit(id, data).then(res => {
if (!mountedRef.current) return null
setResult({
response: true,
error: null
});
setInSubmit(false);
}).catch(err => {
if (!mountedRef.current) return null
setResult({
response: false,
error: err
});
setInSubmit(false);
})
}else{
setResult({
response: false,
error: 'Please fill in the form in the correct format.'
})
setInSubmit(false);
}
}}>
<Paper>
<Box p={2}>
<Stack spacing={3}>
{result.response?(
<>{success}</>
):(
<>
{result.response === false &&
<Alert severity="error">{result.error}</Alert>
}
{children}
<Stack direction="row" spacing={1} mt={2}>
<Button variant="contained" type="submit" disabled={inSubmit}>{inSubmit && <Loader />} Save</Button>
</Stack>
</>
)}
</Stack>
</Box>
</Paper>
</form>
)
}
Example #19
Source File: index.js From fireact with MIT License | 5 votes |
DataList = ({handleFetch, schema}) => {
const mountedRef = useRef(true);
const [rows, setRows] = useState([]);
const [total, setTotal] = useState(-1);
const [page, setPage] = useState(0);
const [pageSize, setPageSize] = useState(10);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setIsLoading(true);
handleFetch(page, pageSize).then(
res => {
if (!mountedRef.current) return null
setRows(res.data);
setTotal(res.total);
setIsLoading(false);
}
)
},[handleFetch, page, pageSize]);
useEffect(() => {
return () => {
mountedRef.current = false
}
},[]);
return (
<>
{isLoading?(
<Paper>
<Box p={2}>
<Loader text="Loading..." />
</Box>
</Paper>
):(
<Stack spacing={3}>
{rows.length === 0 &&
<Alert severity="error">No data is found.</Alert>
}
<Paper>
<Box>
<DataTable
columns={schema}
rows = {rows}
totalRows = {total}
pageSize = {pageSize}
page={page}
handlePageChane = {(e, p) => {
setPage(p);
}}
handlePageSizeChange = {(e) => {
setPage(0);
setPageSize(e.target.value);
}}
/>
</Box>
</Paper>
</Stack>
)}
</>
)
}
Example #20
Source File: ButtonRow.js From fireact with MIT License | 5 votes |
ButtonRow = ({ children }) => {
return (
<Stack direction="row" spacing={1} mt={2}>
{children}
</Stack>
);
}
Example #21
Source File: User.js From Django-REST-Framework-React-BoilerPlate with MIT License | 4 votes |
export default function User() {
const userLogin = useSelector((state) => state.userLogin);
const { userInfo } = userLogin;
const listUser = useSelector((state) => state.listUser);
const { loading, error, USERLIST } = listUser;
const [page, setPage] = useState(0);
const [order, setOrder] = useState('asc');
const [selected, setSelected] = useState([]);
const [orderBy, setOrderBy] = useState('name');
const [filterName, setFilterName] = useState('');
const [rowsPerPage, setRowsPerPage] = useState(5);
const handleRequestSort = (event, property) => {
const isAsc = orderBy === property && order === 'asc';
setOrder(isAsc ? 'desc' : 'asc');
setOrderBy(property);
};
const handleSelectAllClick = (event) => {
if (event.target.checked) {
const newSelecteds = USERLIST.map((n) => n.name);
setSelected(newSelecteds);
return;
}
setSelected([]);
};
const handleClick = (event, name) => {
const selectedIndex = selected.indexOf(name);
let newSelected = [];
if (selectedIndex === -1) {
newSelected = newSelected.concat(selected, name);
} else if (selectedIndex === 0) {
newSelected = newSelected.concat(selected.slice(1));
} else if (selectedIndex === selected.length - 1) {
newSelected = newSelected.concat(selected.slice(0, -1));
} else if (selectedIndex > 0) {
newSelected = newSelected.concat(selected.slice(0, selectedIndex), selected.slice(selectedIndex + 1));
}
setSelected(newSelected);
};
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
const handleFilterByName = (event) => {
setFilterName(event.target.value);
};
const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - USERLIST.length) : 0;
const filteredUsers = applySortFilter(USERLIST, getComparator(order, orderBy), filterName);
const isUserNotFound = filteredUsers.length === 0;
return (
<Page title="User">
<Container>
{userInfo ? <UsersListCall /> : null}
<Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
<Typography variant="h4" gutterBottom>
User
</Typography>
<Button variant="contained" component={RouterLink} to="#" startIcon={<Iconify icon="eva:plus-fill" />}>
New User
</Button>
</Stack>
<Card>
<UserListToolbar numSelected={selected.length} filterName={filterName} onFilterName={handleFilterByName} />
{error ? (
<Alert severity="error">
<AlertTitle>List Loading Error</AlertTitle>
{error}
</Alert>
) : null}
{loading ? (
<Box sx={{ width: '100%' }}>
<LinearProgress />
</Box>
) : null}
<Scrollbar>
<TableContainer sx={{ minWidth: 800 }}>
<Table>
<UserListHead
order={order}
orderBy={orderBy}
headLabel={TABLE_HEAD}
rowCount={USERLIST.length}
numSelected={selected.length}
onRequestSort={handleRequestSort}
onSelectAllClick={handleSelectAllClick}
/>
<TableBody>
{filteredUsers.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row) => {
const { id, name, role, status, company, avatarUrl, isVerified } = row;
const isItemSelected = selected.indexOf(name) !== -1;
return (
<TableRow
hover
key={id}
tabIndex={-1}
role="checkbox"
selected={isItemSelected}
aria-checked={isItemSelected}
>
<TableCell padding="checkbox">
<Checkbox checked={isItemSelected} onChange={(event) => handleClick(event, name)} />
</TableCell>
<TableCell component="th" scope="row" padding="none">
<Stack direction="row" alignItems="center" spacing={2}>
<Avatar alt={name} src={avatarUrl} />
<Typography variant="subtitle2" noWrap>
{name}
</Typography>
</Stack>
</TableCell>
<TableCell align="left">{company}</TableCell>
<TableCell align="left">{role}</TableCell>
<TableCell align="left">{isVerified ? 'Yes' : 'No'}</TableCell>
<TableCell align="left">
<Label variant="ghost" color={(status === 'banned' && 'error') || 'success'}>
{sentenceCase(status)}
</Label>
</TableCell>
<TableCell align="right">
<UserMoreMenu />
</TableCell>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 53 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
{isUserNotFound && (
<TableBody>
<TableRow>
<TableCell align="center" colSpan={6} sx={{ py: 3 }}>
<SearchNotFound searchQuery={filterName} />
</TableCell>
</TableRow>
</TableBody>
)}
</Table>
</TableContainer>
</Scrollbar>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={USERLIST.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</Card>
</Container>
</Page>
);
}
Example #22
Source File: index.js From fireact with MIT License | 4 votes |
AddUser = () => {
const title = 'Add User';
const mountedRef = useRef(true);
const history = useHistory();
const { userData } = useContext(AuthContext);
const { setBreadcrumb } = useContext(BreadcrumbContext);
const [emailAddress, setEmailAddress] = useState({
hasError: false,
error: null,
value: null
});
const [error, setError] = useState(null);
const [success, setSuccess] = useState(false);
const [inSubmit, setInSubmit] = useState(false);
const [selectedRole, setSelectedRole] = useState('user');
const [inviteDialog, setInviteDialog] = useState(false);
useEffect(() => {
setBreadcrumb([
{
to: "/",
text: "Home",
active: false
},
{
to: "/account/"+userData.currentAccount.id+"/",
text: userData.currentAccount.name,
active: false
},
{
to: "/account/"+userData.currentAccount.id+"/users",
text: 'Manage Users',
active: false
},
{
to: null,
text: title,
active: true
}
]);
}, [userData, setBreadcrumb, title]);
useEffect(() => {
return () => {
mountedRef.current = false
}
},[]);
return (
<>
<Paper>
<Box p={2}>
{success?(
<>
{inviteDialog?(
<Alert severity="success">The invite is sent to the email address.</Alert>
):(
<Alert severity="success">The user is added to the account.</Alert>
)}
<Stack direction="row" spacing={1} mt={2}>
<Button variant="contained" color="primary" onClick={() => history.push("/account/"+userData.currentAccount.id+"/users")} >Back to User List</Button>
</Stack>
</>
):(
<>
{error !== null &&
<div style={{marginBottom: '20px'}}><Alert severity="error">{error}</Alert></div>
}
{inviteDialog?(
<>
<Alert severity="info">The email is not registered by any existing user. Do you want to send an invite to the user?</Alert>
<Stack direction="row" spacing={1} mt={2}>
<Button variant="contained" color="primary" disabled={inSubmit} onClick={e => {
e.preventDefault();
setInSubmit(true);
const inviteEmailToAccount = CloudFunctions.httpsCallable('inviteEmailToAccount');
inviteEmailToAccount({
accountId: userData.currentAccount.id,
email: emailAddress.value,
role: selectedRole
}).then(res => {
if (!mountedRef.current) return null
setInSubmit(false);
setSuccess(true);
}).catch(err => {
if (!mountedRef.current) return null
setError(err.message);
});
}}>{inSubmit && <Loader />}
Yes, send an invite</Button>
<Button variant="contained" color="secondary" disabled={inSubmit} onClick={() => {
history.push("/account/"+userData.currentAccount.id+"/users");
}}>No</Button>
</Stack>
</>
):(
<Form handleSubmit={e => {
e.preventDefault();
setError(null);
setSuccess(false);
setInSubmit(true);
const addUserToAccount = CloudFunctions.httpsCallable('addUserToAccount');
addUserToAccount({
accountId: userData.currentAccount.id,
email: emailAddress.value,
role: selectedRole
}).then(res => {
if (!mountedRef.current) return null
setInSubmit(false);
setSuccess(true);
}).catch(err => {
if (!mountedRef.current) return null
setInSubmit(false);
if(err.details && err.details.code === 'auth/user-not-found'){
setInviteDialog(true);
setInSubmit(false);
}else{
setError(err.message);
}
});
}}
disabled={emailAddress.hasError || emailAddress.value===null || selectedRole===null || inSubmit}
submitBtnStyle={(selectedRole!=='remove')?"primary":"danger"}
inSubmit={inSubmit}
enableDefaultButtons={true}
backToUrl={"/account/"+userData.currentAccount.id+"/users"}
>
<Input label="Email Address" type="email" name="email-address" hasError={emailAddress.hasError} error={emailAddress.error} minLen={5} maxLen={50} required={true} validRegex="^[a-zA-Z0-9-_+\.]*@[a-zA-Z0-9-_\.]*\.[a-zA-Z0-9-_\.]*$" changeHandler={setEmailAddress} fullWidth />
<FormControl fullWidth>
<InputLabel>Role</InputLabel>
<Select label="Role" value={selectedRole} onChange={e => {
setSelectedRole(e.target.value);
}}>
<MenuItem value="user">user</MenuItem>
<MenuItem value="admin">admin</MenuItem>
</Select>
</FormControl>
</Form>
)}
</>
)}
</Box>
</Paper>
</>
)
}
Example #23
Source File: index.js From fireact with MIT License | 4 votes |
DeleteAccount = () => {
const title = 'Delete Account';
const history = useHistory();
const { userData } = useContext(AuthContext);
const [error, setError] = useState(null);
const [success, setSuccess] = useState(false);
const [inSubmit, setInSubmit] = useState(false);
const { setBreadcrumb } = useContext(BreadcrumbContext);
const mountedRef = useRef(true);
const currency = currencyJSON.currency
useEffect(() => {
setBreadcrumb([
{
to: "/",
text: "Home",
active: false
},
{
to: "/account/"+userData.currentAccount.id+"/",
text: userData.currentAccount.name,
active: false
},
{
to: "/account/"+userData.currentAccount.id+"/billing",
text: 'Billing',
active: false
},
{
to: null,
text: title,
active: true
}
]);
},[userData,setBreadcrumb,title]);
useEffect(() => {
return () => {
mountedRef.current = false
}
},[]);
return (
<>
{success?(
<Redirect to="/"></Redirect>
):(
<>
<Paper>
<Box p={2}>
{error !== null &&
<Box p={3}>
<Alert severity="error">{error}</Alert>
</Box>
}
<p>Your current subscription period will end on <strong>{(new Date(userData.currentAccount.subscriptionCurrentPeriodEnd * 1000)).toLocaleDateString()}</strong>.</p>
<p>The system will charge <strong>{currency[userData.currentAccount.currency].sign}{userData.currentAccount.price}/{userData.currentAccount.paymentCycle}</strong> to renew the subscription. Deleting the account will stop the subscription and no renewal payment will be charged.</p>
<p className="text-danger">Are you sure you want to delete your account?</p>
<Stack direction="row" spacing={1} mt={2}>
<Button variant="contained" color="error" disabled={inSubmit} onClick={() => {
setInSubmit(true);
const cancelSubscription = CloudFunctions.httpsCallable('cancelSubscription');
cancelSubscription({
accountId: userData.currentAccount.id
}).then(res => {
if (!mountedRef.current) return null
setSuccess(true);
setInSubmit(false);
}).catch(err => {
if (!mountedRef.current) return null
setError(err.message);
setInSubmit(false);
})
}}>
{inSubmit &&
<Loader />
}
Yes, I want to delete the account</Button>
<Button variant="contained" color="secondary" onClick={() => history.push("/account/"+userData.currentAccount.id+"/billing")}>No, Go Back</Button>
</Stack>
</Box>
</Paper>
</>
)}
</>
)
}
Example #24
Source File: index.js From fireact with MIT License | 4 votes |
PaymentList = () => {
const title = 'Billing History';
const history = useHistory();
const currency = currencyJSON.currency
const { userData, authUser } = useContext(AuthContext);
const { setBreadcrumb } = useContext(BreadcrumbContext);
// document snapshots
const [qs, setQs] = useState(null);
const mountedRef = useRef(true);
const [total, setTotal] = useState(0);
const [pageSize, setPageSize] = useState(10);
const [page, setPage] = useState(0);
const [rows, setRows] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const getInvoices = useCallback((accountId, pageSize, direction, doc) => {
const getInvoiceCollectionCount = (accountId) => {
const accountDocRef = FirebaseAuth.firestore().collection('accounts').doc(accountId);
return accountDocRef.get().then(accountDoc => {
if(accountDoc.exists){
return accountDoc.data().invoicesColCount;
}else{
return 0;
}
}).catch(() => {
return 0;
})
}
setLoading(true);
let records = [];
const collectionRef = FirebaseAuth.firestore().collection('accounts').doc(accountId).collection('invoices');
let query = collectionRef.orderBy('created', 'desc');
if(direction && direction === 'next'){
query = query.startAfter(doc);
}
if(direction && direction === 'previous'){
query = query.endBefore(doc);
}
query = query.limit(pageSize);
Promise.all([getInvoiceCollectionCount(accountId), query.get()]).then(([invoiceCount, documentSnapshots]) => {
if (!mountedRef.current) return null
setTotal(invoiceCount);
documentSnapshots.forEach(doc => {
records.push({
'id': doc.id,
'total': (doc.data().total / 100).toFixed(2),
'subTotal': (doc.data().subTotal / 100).toFixed(2),
'tax': ((doc.data().tax || 0) / 100).toFixed(2),
'amountPaid': (Math.round(doc.data().amountPaid / 100)).toFixed(2),
'created': (new Date(doc.data().created * 1000)).toLocaleString(),
'hostedInvoiceUrl': doc.data().hostedInvoiceUrl,
'currency': doc.data().currency,
'status': doc.data().status,
'amountCol': <>{currency[doc.data().currency].sign}{(doc.data().total / 100).toFixed(2)}</>,
'statusCol': <>{doc.data().status.toUpperCase()}</>,
'urlCol': doc.data().hostedInvoiceUrl?(
<Button href={doc.data().hostedInvoiceUrl} rel="noreferrer" target="_blank" variant="contained" size="small">View Invoice</Button>
):(<></>)
});
});
if(records.length > 0){
setRows(records);
setQs(documentSnapshots);
}
setLoading(false);
}).catch(e => {
if (!mountedRef.current) return null
setError(e.message);
setLoading(false);
});
},[currency]);
useEffect(() => {
setBreadcrumb([
{
to: "/",
text: "Home",
active: false
},
{
to: "/account/"+userData.currentAccount.id+"/",
text: userData.currentAccount.name,
active: false
},
{
to: null,
text: title,
active: true
}
]);
},[userData, setBreadcrumb]);
useEffect(() => {
getInvoices(userData.currentAccount.id, pageSize);
},[pageSize, userData, getInvoices]);
useEffect(() => {
return () => {
mountedRef.current = false
}
},[]);
return (
<Stack spacing={3}>
{userData.currentAccount.owner === authUser.user.uid &&
<Stack direction="row-reverse" spacing={1} mt={2}>
<Button color="error" variant="contained" onClick={() => history.push("/account/"+userData.currentAccount.id+"/billing/delete")}>Delete Account</Button>
<Button color="info" variant="contained" onClick={() => history.push("/account/"+userData.currentAccount.id+"/billing/plan")}>Change Subscription Plan</Button>
{userData.currentAccount.price > 0 &&
<Button color="info" variant="contained" onClick={() => history.push("/account/"+userData.currentAccount.id+"/billing/payment-method")}>Update Payment Method</Button>
}
</Stack>
}
<Paper>
{loading?(
<Box p={3}>
<Loader text="Loading billing history..."></Loader>
</Box>
):(
<>
{error?(
<Box p={3}>
<Alert severity="error">{error}</Alert>
</Box>
):(
<>
{total > 0 ? (
<DataTable columns={[
{name: "Invoice ID", field: "id", style: {width: '30%'}},
{name: "Amount", field: "amountCol", style: {width: '15%'}},
{name: "Status", field: "statusCol", style: {width: '15%'}},
{name: "Invoice Date", field: "created", style: {width: '30%'}},
{name: "Invoice URL", field: "urlCol", style: {width: '10%'}}
]}
rows={rows}
totalRows={total}
pageSize={pageSize}
page={page}
handlePageChane={(e, p) => {
if(p>page){
getInvoices(userData.currentAccount.id, pageSize, 'next', qs.docs[qs.docs.length-1]);
}
if(p<page){
getInvoices(userData.currentAccount.id, pageSize, 'previous', qs.docs[0]);
}
setPage(p);
}}
handlePageSizeChange={(e) => {
setPageSize(e.target.value);
setPage(0);
}}
></DataTable>
):(
<Box p={3}>No invoice is found</Box>
)}
</>
)}
</>
)}
</Paper>
</Stack>
)
}
Example #25
Source File: index.js From fireact with MIT License | 4 votes |
PaymentMethod = () => {
const title = 'Update Payment Method';
const mountedRef = useRef(true);
const history = useHistory();
const { userData, authUser } = useContext(AuthContext);
const stripe = useStripe();
const elements = useElements();
const { setBreadcrumb } = useContext(BreadcrumbContext);
const CARD_ELEMENT_OPTIONS = {
style: {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
},
hidePostalCode: true
};
const [processing, setProcessing] = useState(false);
const [success, setSuccess] = useState(false);
const [cardError, setCardError] = useState(null);
const [errorMessage, setErrorMessage] = useState(null);
const subscribe = async(event) => {
event.preventDefault();
setProcessing(true);
setErrorMessage(null);
setSuccess(false);
let hasError = false;
let paymentMethodId = '';
setCardError(null);
if (!stripe || !elements) {
// Stripe.js has not loaded yet. Make sure to disable
// form submission until Stripe.js has loaded.
return;
}
// Get a reference to a mounted CardElement. Elements knows how
// to find your CardElement because there can only ever be one of
// each type of element.
const cardElement = elements.getElement(CardElement);
// Use your card Element with other Stripe.js APIs
const {error, paymentMethod} = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
});
if (error) {
setCardError(error.message);
hasError = true;
} else {
paymentMethodId = paymentMethod.id;
}
if(!hasError){
const updatePaymentMethod = CloudFunctions.httpsCallable('updatePaymentMethod');
updatePaymentMethod({
accountId: userData.currentAccount.id,
paymentMethodId: paymentMethodId
}).then(res => {
if (!mountedRef.current) return null
setSuccess(true);
setProcessing(false);
}).catch(err => {
if (!mountedRef.current) return null
setProcessing(false);
setErrorMessage(err.message);
});
}else{
setProcessing(false);
}
}
useEffect(() => {
setBreadcrumb([
{
to: "/",
text: "Home",
active: false
},
{
to: "/account/"+userData.currentAccount.id+"/",
text: userData.currentAccount.name,
active: false
},
{
to: "/account/"+userData.currentAccount.id+"/billing",
text: 'Billing',
active: false
},
{
to: null,
text: title,
active: true
}
]);
},[userData, setBreadcrumb, title]);
useEffect(() => {
return () => {
mountedRef.current = false
}
},[]);
return (
<>
<Paper>
<Box p={2}>
{userData.currentAccount.price > 0 ? (
<Stack spacing={3}>
{(userData.currentAccount.owner === authUser.user.uid)?(
<>
{success &&
<Alert severity="success" onClose={() => setSuccess(false)}>The payment method has been successfully updated.</Alert>
}
{errorMessage !== null &&
<Alert severity="error" onClose={() => setErrorMessage(null)}>{errorMessage}</Alert>
}
{cardError !== null &&
<Alert severity="error" onClose={() => setCardError(null)}>{cardError}</Alert>
}
<div style={{position: "relative", minHeight: '56px', padding: '15px', maxWidth: '500px'}}>
<CardElement options={CARD_ELEMENT_OPTIONS}></CardElement>
<fieldset style={{
borderColor: 'rgba(0, 0, 0, 0.23)',
borderStyle: 'solid',
borderWidth: '1px',
borderRadius: '4px',
position: 'absolute',
top: '-5px',
left: '0',
right: '0',
bottom: '0',
margin: '0',
padding: '0 8px',
overflow: 'hidden',
pointerEvents: 'none'
}}></fieldset>
</div>
<Stack direction="row" spacing={1} mt={2}>
<Button variant="contained" disabled={processing} onClick={(e) => subscribe(e)}>
{processing?(
<><Loader /> Processing...</>
):(
<>Save</>
)}
</Button>
<Button variant="contained" color="secondary" disabled={processing} onClick={() => history.push("/account/"+userData.currentAccount.id+"/billing")}>Back</Button>
</Stack>
</>
):(
<Alert type="danger" message="Access Denied." dismissible={false} ></Alert>
)}
</Stack>
):(
<Alert severity="error">The account doesn't support payment methods.</Alert>
)}
</Box>
</Paper>
</>
)
}
Example #26
Source File: index.js From fireact with MIT License | 4 votes |
Plans = () => {
const title = 'Select a Plan';
const countries = countryJSON.countries;
const { userData, authUser } = useContext(AuthContext);
const stripe = useStripe();
const elements = useElements();
const mountedRef = useRef(true);
const { setBreadcrumb } = useContext(BreadcrumbContext);
const CARD_ELEMENT_OPTIONS = {
style: {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
},
hidePostalCode: true
};
const [loading, setLoading] = useState(true);
const [processing, setProcessing] = useState(false);
const [plans, setPlans] = useState([]);
const [selectedPlan, setSelectedPlan] = useState({id: 0});
const [cardError, setCardError] = useState(null);
const [errorMessage, setErrorMessage] = useState(null);
const [country, setCountry] = useState("");
const [countryError, setCountryError] = useState(null);
const [state, setState] = useState("");
const [states, setStates] = useState([]);
const [stateError, setStateError] = useState(null);
useEffect(() => {
setBreadcrumb([
{
to: "/",
text: "Home",
active: false
},
{
to: "/account/"+userData.currentAccount.id+"/",
text: userData.currentAccount.name,
active: false
},
{
to: null,
text: title,
active: true
}
]);
setLoading(true);
const plansQuery = FirebaseAuth.firestore().collection('plans').orderBy('price', 'asc');
plansQuery.get().then(planSnapShots => {
if (!mountedRef.current) return null
let p = [];
planSnapShots.forEach(doc => {
p.push({
'id': doc.id,
'name': doc.data().name,
'price': doc.data().price,
'currency': doc.data().currency,
'paymentCycle': doc.data().paymentCycle,
'features': doc.data().features,
'stripePriceId': doc.data().stripePriceId,
'current': (userData.currentAccount.planId===doc.id)?true:false
});
});
if(p.length > 0){
const ascendingOrderPlans = p.sort((a, b) => parseFloat(a.price) - parseFloat(b.price));
setPlans(ascendingOrderPlans);
}
setLoading(false);
});
},[userData, setBreadcrumb, title]);
useEffect(() => {
return () => {
mountedRef.current = false
}
},[]);
const subscribe = async(event) => {
event.preventDefault();
setProcessing(true);
setErrorMessage(null);
let hasError = false;
let paymentMethodId = '';
if(selectedPlan.price !== 0){
if(country === ''){
setCountryError('Please select a country.');
hasError = true;
}
if(state === '' && countries[country] && countries[country].states){
setStateError('Please select a state.');
hasError = true;
}
setCardError(null);
if (!stripe || !elements) {
// Stripe.js has not loaded yet. Make sure to disable
// form submission until Stripe.js has loaded.
return;
}
// Get a reference to a mounted CardElement. Elements knows how
// to find your CardElement because there can only ever be one of
// each type of element.
const cardElement = elements.getElement(CardElement);
// Use your card Element with other Stripe.js APIs
const {error, paymentMethod} = await stripe.createPaymentMethod({
type: 'card',
card: cardElement
});
if (error) {
setCardError(error.message);
hasError = true;
} else {
paymentMethodId = paymentMethod.id;
}
}
if(!hasError){
const createSubscription = CloudFunctions.httpsCallable('createSubscription');
createSubscription({
planId: selectedPlan.id,
accountId: userData.currentAccount.id,
paymentMethodId: paymentMethodId,
billing: {
country: country,
state: state
}
}).then(res => {
// physical page load to reload the account data
if (!mountedRef.current) return null
document.location = '/account/'+userData.currentAccount.id+'/';
}).catch(err => {
if (!mountedRef.current) return null
setProcessing(false);
setErrorMessage(err.message);
});
}else{
setProcessing(false);
}
}
return (
<>
{(!loading)?(
<>{(userData.currentAccount.owner === authUser.user.uid)?(
<>{plans.length > 0 ? (
<Paper>
<Box p={3} style={{textAlign: 'center'}} >
<h2>{title}</h2>
<Grid container spacing={3}>
<>
{plans.map((plan,i) =>
<Grid container item xs={12} md={4} key={i} >
<Card style={{
width: '100%',
display: 'flex',
flexDirection: 'column',
paddingBottom: '20px',
}}>
<CardHeader title={plan.name} subheader={"$"+plan.price+"/"+plan.paymentCycle} />
<CardContent>
<Divider />
<ul style={{listStyleType: 'none', paddingLeft: '0px'}}>
{plan.features.map((feature, i) =>
<li key={i}>
<i className="fa fa-check" style={{color: "#2e7d32"}} /> {feature}
</li>
)}
</ul>
</CardContent>
<CardActions style={{
marginTop: 'auto',
justifyContent: 'center',
}}>
{plan.current?(
<Button color="success" variant="contained" disabled={true}>Current Plan</Button>
):(
<Button color="success" variant={(plan.id!==selectedPlan.id)?"outlined":"contained"} onClick={() => {
for(let i=0; i<plans.length; i++){
if(plans[i].id === plan.id){
setSelectedPlan(plan);
}
}
}}>{plan.id===selectedPlan.id && <><i className="fa fa-check" /> </>}{(plan.id!==selectedPlan.id)?"Select":"Selected"}</Button>
)}
</CardActions>
</Card>
</Grid>
)}
</>
</Grid>
{selectedPlan.id !== 0 && selectedPlan.price > 0 &&
<div style={{justifyContent: 'center', marginTop: '50px'}}>
<h2>Billing Details</h2>
<Grid container spacing={3}>
<Grid container item xs={12}>
<Card style={{
width: '100%',
paddingBottom: '20px',
}}>
<CardContent>
<Container maxWidth="sm">
<Stack spacing={3}>
{countryError !== null &&
<Alert severity="error" onClose={() => setCountryError(null)}>{countryError}</Alert>
}
<Autocomplete
value={(country !== '')?(countries.find(obj =>{
return obj.code === country
})):(null)}
options={countries}
autoHighlight
getOptionLabel={(option) => option.label}
renderOption={(props, option) => (
<Box component="li" sx={{ '& > img': { mr: 2, flexShrink: 0 } }} {...props}>
<img
loading="lazy"
width="20"
src={`https://flagcdn.com/w20/${option.code.toLowerCase()}.png`}
srcSet={`https://flagcdn.com/w40/${option.code.toLowerCase()}.png 2x`}
alt=""
/>
{option.label}
</Box>
)}
renderInput={(params) => (
<TextField
{...params}
label="Country"
inputProps={{
...params.inputProps,
autoComplete: 'new-password',
}}
/>
)}
onChange={(event, newValue) => {
if(newValue && newValue.code){
setCountry(newValue.code);
setState("");
if(newValue.states){
setStates(newValue.states);
}else{
setStates([]);
}
setCountryError(null);
}
}}
/>
{states.length > 0 &&
<>
{stateError !== null &&
<Alert severity="error" onClose={() => setStateError(null)}>{stateError}</Alert>
}
<Autocomplete
value={(state !== '')?(states.find(obj =>{
return obj.code === state
})):(null)}
options={states}
autoHighlight
getOptionLabel={(option) => option.label}
renderOption={(props, option) => (
<Box component="li" {...props}>
{option.label}
</Box>
)}
renderInput={(params) => (
<TextField
{...params}
label="State"
inputProps={{
...params.inputProps,
autoComplete: 'new-password',
}}
/>
)}
onChange={(event, newValue) => {
if(newValue && newValue.code){
setState(newValue.code);
setStateError(null);
}
}}
/>
</>
}
{cardError !== null &&
<Alert severity="error" onClose={() => setCardError(null)}>{cardError}</Alert>
}
<div style={{position: "relative", minHeight: '56px', padding: '15px'}}>
<CardElement options={CARD_ELEMENT_OPTIONS}></CardElement>
<fieldset style={{
borderColor: 'rgba(0, 0, 0, 0.23)',
borderStyle: 'solid',
borderWidth: '1px',
borderRadius: '4px',
position: 'absolute',
top: '-5px',
left: '0',
right: '0',
bottom: '0',
margin: '0',
padding: '0 8px',
overflow: 'hidden',
pointerEvents: 'none'
}}></fieldset>
</div>
</Stack>
</Container>
</CardContent>
</Card>
</Grid>
</Grid>
</div>
}
{selectedPlan.id!==0 &&
<div style={{marginTop: '50px'}}>
<Container maxWidth="sm">
<Stack spacing={3}>
{errorMessage !== null &&
<Alert severity="error" onClose={() => setErrorMessage(null)}>{errorMessage}</Alert>
}
<Button color="success" size="large" variant="contained" disabled={selectedPlan.id===0||processing?true:false} onClick={e => {
subscribe(e);
}}>{processing?(<><Loader /> Processing...</>):(<>Subscribe Now</>)}</Button>
</Stack>
</Container>
</div>
}
</Box>
</Paper>
):(
<Alert severity="warning">No plan is found.</Alert>
)}</>
):(
<Alert severity="error" >Access Denied.</Alert>
)}</>
):(
<Loader text="loading plans..." />
)}
</>
)
}
Example #27
Source File: showreel.js From react-table-library with MIT License | 4 votes |
Component = () => {
const [data, setData] = React.useState({ nodes });
//* Theme *//
const materialTheme = getTheme({
...DEFAULT_OPTIONS,
striped: true,
highlightOnHover: true,
});
const customTheme = {
Table: `
--data-table-library_grid-template-columns: 70px repeat(5, minmax(0, 1fr));
margin: 16px 0px;
`,
};
const theme = useTheme([materialTheme, customTheme]);
//* Resize *//
const resize = { resizerHighlight: '#dee2e6' };
//* Pagination *//
const pagination = usePagination(data, {
state: {
page: 0,
size: 2,
},
onChange: onPaginationChange,
});
function onPaginationChange(action, state) {
console.log(action, state);
}
//* Search *//
const [search, setSearch] = React.useState('');
useCustom('search', data, {
state: { search },
onChange: onSearchChange,
});
function onSearchChange(action, state) {
console.log(action, state);
pagination.fns.onSetPage(0);
}
//* Filter *//
const [isHide, setHide] = React.useState(false);
useCustom('filter', data, {
state: { isHide },
onChange: onFilterChange,
});
function onFilterChange(action, state) {
console.log(action, state);
pagination.fns.onSetPage(0);
}
//* Select *//
const select = useRowSelect(data, {
onChange: onSelectChange,
});
function onSelectChange(action, state) {
console.log(action, state);
}
//* Tree *//
const tree = useTree(
data,
{
onChange: onTreeChange,
},
{
clickType: TreeExpandClickTypes.ButtonClick,
treeYLevel: 1,
treeIcon: {
margin: '4px',
iconDefault: null,
iconRight: <FaChevronRight />,
iconDown: <FaChevronDown />,
},
},
);
function onTreeChange(action, state) {
console.log(action, state);
}
//* Sort *//
const sort = useSort(
data,
{
onChange: onSortChange,
},
{
sortIcon: {
iconDefault: null,
iconUp: <FaChevronUp />,
iconDown: <FaChevronDown />,
},
sortFns: {
TASK: (array) => array.sort((a, b) => a.name.localeCompare(b.name)),
DEADLINE: (array) => array.sort((a, b) => a.deadline - b.deadline),
TYPE: (array) => array.sort((a, b) => a.type.localeCompare(b.type)),
COMPLETE: (array) => array.sort((a, b) => a.isComplete - b.isComplete),
TASKS: (array) => array.sort((a, b) => (a.nodes || []).length - (b.nodes || []).length),
},
},
);
function onSortChange(action, state) {
console.log(action, state);
}
//* Drawer *//
const [drawerId, setDrawerId] = React.useState(null);
const [edited, setEdited] = React.useState('');
const handleEdit = (event) => {
setEdited(event.target.value);
};
const handleCancel = () => {
setEdited('');
setDrawerId(null);
};
const handleSave = () => {
const node = findNodeById(data.nodes, drawerId);
const editedNode = { ...node, name: edited };
const nodes = insertNode(data.nodes, editedNode);
setData({
nodes,
});
setEdited('');
setDrawerId(null);
};
//* Modal *//
const [modalOpened, setModalOpened] = React.useState(false);
//* Custom Modifiers *//
let modifiedNodes = data.nodes;
// search
modifiedNodes = modifiedNodes.filter((node) =>
node.name.toLowerCase().includes(search.toLowerCase()),
);
// filter
modifiedNodes = isHide ? modifiedNodes.filter((node) => !node.isComplete) : modifiedNodes;
//* Columns *//
const COLUMNS = [
{
label: 'Task',
renderCell: (item) => item.name,
resize,
sort: { sortKey: 'TASK' },
select: {
renderHeaderCellSelect: () => (
<Checkbox
size="small"
checked={select.state.all}
indeterminate={!select.state.all && !select.state.none}
onChange={select.fns.onToggleAll}
/>
),
renderCellSelect: (item) => (
<Checkbox
size="small"
checked={select.state.ids.includes(item.id)}
onChange={() => select.fns.onToggleById(item.id)}
/>
),
},
tree: true,
},
{
label: 'Deadline',
renderCell: (item) =>
item.deadline.toLocaleDateString('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
}),
resize,
sort: { sortKey: 'DEADLINE' },
},
{ label: 'Type', renderCell: (item) => item.type, resize, sort: { sortKey: 'TYPE' } },
{
label: 'Complete',
renderCell: (item) => item.isComplete.toString(),
resize,
sort: { sortKey: 'COMPLETE' },
},
{
label: 'Tasks',
renderCell: (item) => (
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span>{item.nodes?.length}</span>
<IconButton onClick={() => setDrawerId(item.id)}>
<FaPen size={14} />
</IconButton>
</div>
),
resize,
sort: { sortKey: 'TASKS' },
},
];
return (
<>
<Modal open={modalOpened} onClose={() => setModalOpened(false)}>
<Box
style={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 500,
backgroundColor: '#ffffff',
border: '1px solid #e0e0e0',
borderRadius: '4px',
padding: '10px',
}}
>
<Typography variant="h6" component="h2">
"Not all features included here, but we got ..."
</Typography>
<FormGroup>
<FormControlLabel control={<Checkbox checked />} label="Resize" />
<FormControlLabel control={<Checkbox checked />} label="Sort" />
<FormControlLabel control={<Checkbox checked />} label="Search" />
<FormControlLabel control={<Checkbox checked />} label="Filter" />
<FormControlLabel control={<Checkbox checked />} label="Select" />
<FormControlLabel control={<Checkbox checked />} label="Tree" />
<FormControlLabel control={<Checkbox checked />} label="Drawer on Edit" />
<FormControlLabel control={<Checkbox checked />} label="Pagination" />
</FormGroup>
</Box>
</Modal>
{/* Form */}
<Stack spacing={1} direction="row">
<Button variant="contained" onClick={() => setModalOpened(true)}>
Features?
</Button>
<TextField
label="Search Task"
value={search}
onChange={(event) => setSearch(event.target.value)}
/>
<FormControlLabel
control={
<Checkbox checked={isHide} onChange={(event) => setHide(event.target.checked)} />
}
label="Hide Complete"
/>
</Stack>
{/* Table */}
<CompactTable
columns={COLUMNS}
data={{ ...data, nodes: modifiedNodes }}
theme={theme}
layout={{ custom: true }}
select={select}
tree={tree}
sort={sort}
pagination={pagination}
/>
<br />
<Stack spacing={10}>
<TablePagination
count={modifiedNodes.length}
page={pagination.state.page}
rowsPerPage={pagination.state.size}
rowsPerPageOptions={[1, 2, 5]}
onRowsPerPageChange={(event) =>
pagination.fns.onSetSize(parseInt(event.target.value, 10))
}
onPageChange={(event, page) => pagination.fns.onSetPage(page)}
/>
</Stack>
<Drawer
open={drawerId}
onClose={handleCancel}
title="Edit"
anchor="right"
PaperProps={{
sx: { width: '50%', padding: '20px' },
}}
>
<Stack spacing={1}>
<TextField
label="Name"
value={edited || fromTreeToList(data.nodes).find((node) => node.id === drawerId)?.name}
onChange={handleEdit}
autoFocus
/>
<Button variant="outlined" onClick={handleCancel}>
Cancel
</Button>
<Button variant="contained" onClick={handleSave}>
Save
</Button>
</Stack>
</Drawer>
</>
);
}
Example #28
Source File: index.js From fireact with MIT License | 4 votes |
UserRole = () => {
const title = 'Change User Role';
const history = useHistory();
const { userData } = useContext(AuthContext);
const { userId } = useParams();
const mountedRef = useRef(true);
const { setBreadcrumb } = useContext(BreadcrumbContext);
const [user, setUser] = useState(null);
const [error, setError] = useState(null);
const [success, setSuccess] = useState(false);
const [inSubmit, setInSubmit] = useState(false);
const [selectedRole, setSelectedRole] = useState(null);
useEffect(() => {
setBreadcrumb([
{
to: "/",
text: "Home",
active: false
},
{
to: "/account/"+userData.currentAccount.id+"/",
text: userData.currentAccount.name,
active: false
},
{
to: "/account/"+userData.currentAccount.id+"/users",
text: 'Manage Users',
active: false
},
{
to: null,
text: title,
active: true
}
]);
setError(null);
const getAccountUser = CloudFunctions.httpsCallable('getAccountUser');
getAccountUser({
accountId: userData.currentAccount.id,
userId: userId
}).then(res => {
if (!mountedRef.current) return null
res.data.lastLoginTime = new Date(res.data.lastLoginTime);
setUser(res.data);
}).catch(err => {
if (!mountedRef.current) return null
setError(err.message);
});
},[userData, userId, setBreadcrumb]);
useEffect(() => {
return () => {
mountedRef.current = false
}
},[]);
return (
<Paper>
<Box p={2}>
{(userId !== userData.currentAccount.owner)?(
success?(
<>
<Alert severity="success" onClose={() => setSuccess(false)}>User role is successfully updated.</Alert>
<Stack direction="row" spacing={1} mt={2}>
<Button variant="contained" color="primary" onClick={() => history.push("/account/"+userData.currentAccount.id+"/users")} >Back to User List</Button>
</Stack>
</>
):(
<Stack spacing={3}>
{error !== null &&
<Alert severity="error">{error}</Alert>
}
{user === null ? (
<Loader text="Loading user details" />
):(
<Form handleSubmit={e => {
e.preventDefault();
setError(null);
setSuccess(false);
setInSubmit(true);
const updateAccountUserRole = CloudFunctions.httpsCallable('updateAccountUserRole');
updateAccountUserRole({
accountId: userData.currentAccount.id,
userId: userId,
role: selectedRole
}).then(res => {
setInSubmit(false);
setSuccess(true);
}).catch(err => {
setInSubmit(false);
setError(err.message);
});
}}
disabled={selectedRole===null || selectedRole===user.role || inSubmit}
submitBtnStyle={(selectedRole!=='remove')?"primary":"error"}
inSubmit={inSubmit}
enableDefaultButtons={true}
backToUrl={"/account/"+userData.currentAccount.id+"/users"}
>
<Stack spacing={1} mb={5} style={{display: 'inline-block', textAlign: 'center'}}>
<Avatar alt={user.displayName} src={user.photoUrl} sx={{width: 100, height:100, margin: 'auto'}} />
<Typography><strong style={{fontSize: '1.3rem'}}>{user.displayName}</strong></Typography>
<Typography>
Last Login:<br /> {user.lastLoginTime.toLocaleString()}
</Typography>
</Stack>
<FormControl fullWidth>
<InputLabel>Role</InputLabel>
<Select label="Role" defaultValue={user.role} onChange={e => {
setSelectedRole(e.target.value);
}}>
<MenuItem value="user">user</MenuItem>
<MenuItem value="admin">admin</MenuItem>
<MenuItem value="remove"><em>-- Remove Access --</em></MenuItem>
</Select>
</FormControl>
</Form>
)}
</Stack>
)
):(
<>
<Alert severity="error">Cannot change account owner role.</Alert>
<Stack direction="row" spacing={1} mt={2}>
<Button variant="contained" color="primary" onClick={() => history.push("/account/"+userData.currentAccount.id+"/users")} >Back to User List</Button>
</Stack>
</>
)}
</Box>
</Paper>
)
}
Example #29
Source File: ImageList.js From fireact with MIT License | 4 votes |
ImageList = () => {
const title = "Images";
const { userData } = useContext(AuthContext);
const { setBreadcrumb } = useContext(BreadcrumbContext);
const history = useHistory();
const [refreshCount, setRefreshCount] = useState(0);
const currentPage = useRef(0);
const records = useRef([]);
const useStaticData = imagesJson.useStaticData;
const listFields = imagesJson.listFields;
const handleFetch = useCallback((page, pageSize) => {
return new Promise((resolve, reject) => {
const ListImageApiFirestore = (page, pageSize) => {
const start = page * pageSize;
if(records.current.length-1>=start){
// if the page has been loaded, read from records
return new Promise((resolve, reject) => {
let docs = [];
for(let i=start; i<records.current.length; i++){
if(records.current.length<=i || i>=(start+pageSize)){
break;
}
docs.push(records.current[i]);
}
resolve({
total: -1,
data: docs
})
});
}else{
// if the page hasn't been loaded, read from Firestore
const fields = ["title", "url"];
let doc = null;
if(page > 0 && records.current.length > 0){
// find the last document if the requested page is not the first page
doc = records.current[records.current.length-1]["_doc"];
}
currentPage.current = page;
const Firestore = FirebaseAuth.firestore();
const colRef = Firestore.collection('/accounts/'+userData.currentAccount.id+'/images');
let query = colRef.orderBy('createAt', 'desc');
if(doc !== null){
query = query.startAfter(doc);
}
query = query.limit(pageSize);
return query.get().then(documentSnapshots => {
let docs = [];
if(!documentSnapshots.empty){
documentSnapshots.forEach(documentSnapshot => {
docs.push({
id: documentSnapshot.id,
_doc: documentSnapshot
});
fields.forEach(field => {
docs[docs.length-1][field] = documentSnapshot.data()[field];
})
});
records.current = records.current.concat(docs);
}
return {total: -1, data: docs}
}).catch(err => {
throw(err);
})
}
}
let ListImageApi = useStaticData?ListImageApiStatic:ListImageApiFirestore;
// apply custom filter here if you wish to pass additional parameters to the api calls
ListImageApi(page, pageSize).then(images => {
const handleDeletion = (id) => {
if(useStaticData){
DeleteImageApiStatic(id).then(() => {
setRefreshCount(refreshCount+1);
});
}else{
const Firestore = FirebaseAuth.firestore();
const DocRef = Firestore.doc('/accounts/'+userData.currentAccount.id+'/images/'+id);
DocRef.delete().then(() => {
// remove the record from records then update the list in the UI
for(let i=0; i<records.current.length; i++){
if(records.current[i].id === id){
records.current.splice(i, 1);
}
}
setRefreshCount(refreshCount+1);
})
}
}
let rows = [];
// loop through the data to add the visual components in to the list
for(let i=0; i<images.data.length; i++){
const row = {
id: images.data[i].id,
url: images.data[i].url,
title: images.data[i].title,
image: <img alt={images.data[i].title} src={images.data[i].url} width={200} />,
action: <ActionButtons id={images.data[i].id} handleDeletion={handleDeletion} />
}
rows.push(row);
}
resolve({
total: images.total,
data: rows
});
}).catch(err => {
reject(err);
});
});
},[refreshCount, userData, useStaticData]);
useEffect(() => {
setBreadcrumb([
{
to: "/",
text: "Home",
active: false
},
{
to: "/account/"+userData.currentAccount.id+"/",
text: userData.currentAccount.name,
active: false
},
{
to: null,
text: title,
active: false
}
]);
},[setBreadcrumb, title, userData]);
return (
<Stack spacing={3}>
<Alert severity="info">
This is a demo
</Alert>
<div style={{marginLeft: "auto"}}>
<Stack direction="row" spacing={1}>
<Button variant="contained" onClick={() => history.push("/account/"+userData.currentAccount.id+"/images/create")} >Create Image Link</Button>
</Stack>
</div>
<DataList handleFetch={handleFetch} schema={listFields} />
</Stack>
)
}