update
This commit is contained in:
@@ -153,7 +153,7 @@ export default function Table<T>({
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
return (
|
||||
<Card>
|
||||
// <Card>
|
||||
<Grid container>
|
||||
{/* Field 1 */}
|
||||
<Grid item xs={12} paddingX="24px" paddingY="20px">
|
||||
@@ -192,20 +192,39 @@ export default function Table<T>({
|
||||
</form>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Grid item xs={12}>
|
||||
<form onSubmit={searchs.handleSearchSubmit}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
onChange={(event) => searchs.setSearchText(event.target.value)}
|
||||
value={searchs.searchText}
|
||||
fullWidth
|
||||
/>
|
||||
</form>
|
||||
</Grid>
|
||||
)}
|
||||
) : null
|
||||
// (
|
||||
// <Grid item xs={12}>
|
||||
// <form onSubmit={searchs.handleSearchSubmit}>
|
||||
// <TextField
|
||||
// id="search-input"
|
||||
// label="Search"
|
||||
// variant="outlined"
|
||||
// onChange={(event) => searchs.setSearchText(event.target.value)}
|
||||
// value={searchs.searchText}
|
||||
// fullWidth
|
||||
// />
|
||||
// </form>
|
||||
// </Grid>
|
||||
// )
|
||||
}
|
||||
|
||||
{searchs && searchs.useSearchs ? (
|
||||
<Fragment>
|
||||
<Grid item xs={12} lg={9} xl={10}>
|
||||
<form onSubmit={searchs.handleSearchSubmit}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
onChange={(event) => searchs.setSearchText(event.target.value)}
|
||||
value={searchs.searchText}
|
||||
fullWidth
|
||||
/>
|
||||
</form>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
) : null }
|
||||
</Grid>
|
||||
</Grid>
|
||||
{/* End Field 1 */}
|
||||
@@ -263,6 +282,6 @@ export default function Table<T>({
|
||||
</Grid>
|
||||
{/* End Field 2 */}
|
||||
</Grid>
|
||||
</Card>
|
||||
// </Card>
|
||||
);
|
||||
}
|
||||
|
||||
128
frontend/client-portal/src/components/UploadImage.tsx
Normal file
128
frontend/client-portal/src/components/UploadImage.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import React, { Dispatch, FunctionComponent, useCallback, useState } from 'react';
|
||||
|
||||
import { useDropzone } from 'react-dropzone';
|
||||
import { Box, Stack, Typography } from '@mui/material';
|
||||
import BlockContent from './upload/BlockContent';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { UploadIllustration } from '../assets';
|
||||
import Iconify from './Iconify';
|
||||
|
||||
const RootStyle = styled('div')(({ theme }) => ({
|
||||
width: 144,
|
||||
height: 144,
|
||||
margin: 'auto',
|
||||
borderRadius: '50%',
|
||||
padding: theme.spacing(1),
|
||||
border: `2px dashed ${theme.palette.grey[500_32]}`,
|
||||
}));
|
||||
const DropZoneStyle = styled('div')({
|
||||
zIndex: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
outline: 'none',
|
||||
display: 'flex',
|
||||
overflow: 'hidden',
|
||||
borderRadius: '50%',
|
||||
position: 'relative',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
'& > *': { width: '100%', height: '100%' },
|
||||
'&:hover': {
|
||||
cursor: 'pointer',
|
||||
'& .placeholder': {
|
||||
zIndex: 9,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const PlaceholderStyle = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
position: 'absolute',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
color: theme.palette.text.secondary,
|
||||
// backgroundColor: theme.palette.background.neutral,
|
||||
transition: theme.transitions.create('opacity', {
|
||||
easing: theme.transitions.easing.easeInOut,
|
||||
duration: theme.transitions.duration.shorter,
|
||||
}),
|
||||
'&:hover': { opacity: 0.72 },
|
||||
}));
|
||||
|
||||
const UploadImage: FunctionComponent<{
|
||||
setFile: Dispatch<any>;
|
||||
currentImage: string;
|
||||
}> = ({ setFile, currentImage, setSave, error, file, helperText, sx, ...other }) => {
|
||||
const onDrop = useCallback(
|
||||
(acceptedFiles) => {
|
||||
// Do something with the files
|
||||
console.log(acceptedFiles);
|
||||
setFile(acceptedFiles[0]);
|
||||
setImage(acceptedFiles[0]);
|
||||
},
|
||||
[setFile, setSave]
|
||||
);
|
||||
|
||||
const { getRootProps, getInputProps, isDragActive, isDragReject } = useDropzone({
|
||||
onDrop,
|
||||
multiple: false,
|
||||
});
|
||||
|
||||
const [image, setImage] = useState<File | null>(null);
|
||||
|
||||
return (
|
||||
<RootStyle
|
||||
sx={{
|
||||
...((isDragReject || error) && {
|
||||
borderColor: 'error.light',
|
||||
}),
|
||||
...sx,
|
||||
}}
|
||||
>
|
||||
<DropZoneStyle
|
||||
{...getRootProps()}
|
||||
sx={{
|
||||
...(isDragActive && { opacity: 2.72 }),
|
||||
}}
|
||||
>
|
||||
<input {...getInputProps()} />
|
||||
{/* <Stack
|
||||
spacing={2}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
direction={{ xs: 'column', md: 'row' }}
|
||||
sx={{ width: 1, textAlign: { xs: 'center', md: 'left' } }}
|
||||
> */}
|
||||
{image ? (
|
||||
<img src={URL.createObjectURL(image)} alt="preview" width={220} />
|
||||
) : currentImage ? (
|
||||
<img src={currentImage} alt="preview" width={220} />
|
||||
) : (
|
||||
<PlaceholderStyle
|
||||
className="placeholder"
|
||||
sx={{
|
||||
...((isDragReject || error) && {
|
||||
bgcolor: 'error.lighter',
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<Iconify icon={'ic:round-add-a-photo'} sx={{ width: 24, height: 24, mb: 1 }} />
|
||||
<Typography variant="caption">{image ? 'Update photo' : 'Upload photo'}</Typography>
|
||||
</PlaceholderStyle>
|
||||
)}
|
||||
|
||||
<PlaceholderStyle className="placeholder">
|
||||
<Iconify icon={'ic:round-add-a-photo'} sx={{ width: 24, height: 24, mb: 1 }} />
|
||||
<Typography variant="caption">{image ? 'Update photo' : 'Upload photo'}</Typography>
|
||||
</PlaceholderStyle>
|
||||
{/* </Stack> */}
|
||||
{/* <BlockContent file={image} /> */}
|
||||
|
||||
{isDragReject && <p>Unsupported file type...</p>}
|
||||
</DropZoneStyle>
|
||||
</RootStyle>
|
||||
);
|
||||
};
|
||||
|
||||
export default UploadImage;
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Autocomplete, TextField, TextFieldProps } from '@mui/material';
|
||||
import { useState } from 'react';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
|
||||
interface IProps {
|
||||
options: any[];
|
||||
name: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export default function RHFAutocomplete({ name, options, label, ...other }: IProps & TextFieldProps) {
|
||||
const { control } = useFormContext();
|
||||
console.log(control)
|
||||
|
||||
const [value, setValue] = useState<string | null>(options[0]);
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
|
||||
return (
|
||||
<Controller
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<Autocomplete
|
||||
{...field}
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={(event: any, newValue: string | null) => {
|
||||
// console.log('fuck', newValue)
|
||||
setValue(newValue.id);
|
||||
}}
|
||||
inputValue={inputValue}
|
||||
onInputChange={(event, newInputValue) => {
|
||||
setInputValue(newInputValue);
|
||||
}}
|
||||
renderInput={(params) => <TextField {...params} label={label ?? name} />}
|
||||
{...other}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -9,9 +9,10 @@ type IProps = Omit<FormControlLabelProps, 'control'>;
|
||||
|
||||
interface Props extends IProps {
|
||||
name: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export default function RHFSwitch({ name, ...other }: Props) {
|
||||
export default function RHFSwitch({ name, disabled = false, ...other }: Props) {
|
||||
const { control } = useFormContext();
|
||||
|
||||
return (
|
||||
@@ -20,7 +21,7 @@ export default function RHFSwitch({ name, ...other }: Props) {
|
||||
<Controller
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => <Switch {...field} checked={field.value} />}
|
||||
render={({ field }) => <Switch {...field} checked={field.value} disabled={disabled} />}
|
||||
/>
|
||||
}
|
||||
{...other}
|
||||
|
||||
1
frontend/client-portal/src/components/table/Index.ts
Normal file
1
frontend/client-portal/src/components/table/Index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as TableMoreMenu } from './TableMoreMenu';
|
||||
@@ -0,0 +1,60 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
// @mui
|
||||
import { IconButton } from '@mui/material';
|
||||
//
|
||||
import Iconify from '../Iconify';
|
||||
import MenuPopover from '../MenuPopover';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
type Props = {
|
||||
actions: React.ReactNode;
|
||||
disableRipple?: boolean;
|
||||
};
|
||||
|
||||
export default function TableMoreMenu({ actions, disableRipple }: Props) {
|
||||
const [open, setOpen] = useState<HTMLElement | null>(null);
|
||||
|
||||
// Close menu popover
|
||||
useEffect(() => {
|
||||
setOpen(null);
|
||||
}, [actions])
|
||||
|
||||
const handleOpen = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setOpen(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton onClick={handleOpen} disableRipple={disableRipple}>
|
||||
<Iconify icon={'eva:more-vertical-fill'} width={20} height={20} />
|
||||
</IconButton>
|
||||
|
||||
<MenuPopover
|
||||
open={Boolean(open)}
|
||||
anchorEl={open}
|
||||
onClose={handleClose}
|
||||
anchorOrigin={{ vertical: 'top', horizontal: 'left' }}
|
||||
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
|
||||
arrow="right-top"
|
||||
sx={{
|
||||
mt: -1,
|
||||
width: 'auto',
|
||||
minWidth: 160,
|
||||
'& .MuiMenuItem-root': {
|
||||
px: 1,
|
||||
typography: 'body2',
|
||||
borderRadius: 0.75,
|
||||
'& svg': { mr: 2, width: 20, height: 20 },
|
||||
},
|
||||
}}
|
||||
>
|
||||
{actions}
|
||||
</MenuPopover>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user