remove duplicate ConnectServiceSelect code

This commit is contained in:
Sidney Alcantara
2021-11-01 17:00:13 +11:00
parent b0d403478f
commit b4c154e6c0
3 changed files with 0 additions and 360 deletions

View File

@@ -1,204 +0,0 @@
import React, { useEffect, useState } from "react";
import clsx from "clsx";
import { useDebouncedCallback } from "use-debounce";
import _get from "lodash/get";
import {
Button,
Checkbox,
Divider,
Grid,
InputAdornment,
List,
ListItemIcon,
ListItemText,
MenuItem,
TextField,
Typography,
Radio,
} from "@mui/material";
import SearchIcon from "@mui/icons-material/Search";
import { IConnectServiceSelectProps } from ".";
import useStyles from "./styles";
import Loading from "@src/components/Loading";
export interface IPopupContentsProps
extends Omit<IConnectServiceSelectProps, "className" | "TextFieldProps"> {}
// TODO: Implement infinite scroll here
export default function PopupContents({
value = [],
onChange,
config,
docRef,
}: IPopupContentsProps) {
const url = config.url;
const titleKey = config.titleKey ?? config.primaryKey;
const subtitleKey = config.subtitleKey;
const resultsKey = config.resultsKey;
const primaryKey = config.primaryKey;
const multiple = Boolean(config.multiple);
const classes = useStyles();
// Webservice search query
const [query, setQuery] = useState("");
// Webservice response
const [response, setResponse] = useState<any | null>(null);
const [docData, setDocData] = useState<any | null>(null);
useEffect(() => {
docRef.get().then((d) => setDocData(d.data()));
}, []);
const hits: any["hits"] = _get(response, resultsKey) ?? [];
const [search] = useDebouncedCallback(
async (query: string) => {
if (!docData) return;
if (!url) return;
const uri = new URL(url),
params = { q: query };
Object.keys(params).forEach((key) =>
uri.searchParams.append(key, params[key])
);
const resp = await fetch(uri.toString(), {
method: "POST",
body: JSON.stringify(docData),
headers: { "content-type": "application/json" },
});
const jsonBody = await resp.json();
setResponse(jsonBody);
},
1000,
{ leading: true }
);
useEffect(() => {
search(query);
}, [query, docData]);
if (!response) return <Loading />;
const select = (hit: any) => () => {
if (multiple) onChange([...value, hit]);
else onChange([hit]);
};
const deselect = (hit: any) => () => {
if (multiple)
onChange(value.filter((v) => v[primaryKey] !== hit[primaryKey]));
else onChange([]);
};
const selectedValues = value?.map((item) => _get(item, primaryKey));
const clearSelection = () => onChange([]);
return (
<Grid container direction="column" className={classes.grid}>
<Grid item className={classes.searchRow}>
<TextField
value={query}
onChange={(e) => setQuery(e.target.value)}
fullWidth
variant="filled"
margin="dense"
label="Search items"
className={classes.noMargins}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<SearchIcon />
</InputAdornment>
),
}}
onClick={(e) => e.stopPropagation()}
onKeyDown={(e) => e.stopPropagation()}
/>
</Grid>
<Grid item xs className={classes.listRow}>
<List className={classes.list}>
{hits.map((hit) => {
const isSelected =
selectedValues.indexOf(_get(hit, primaryKey)) !== -1;
console.log(`Selected Values: ${selectedValues}`);
return (
<React.Fragment key={_get(hit, primaryKey)}>
<MenuItem
dense
onClick={isSelected ? deselect(hit) : select(hit)}
>
<ListItemIcon className={classes.checkboxContainer}>
{multiple ? (
<Checkbox
edge="start"
checked={isSelected}
tabIndex={-1}
color="secondary"
className={classes.checkbox}
disableRipple
inputProps={{
"aria-labelledby": `label-${_get(hit, primaryKey)}`,
}}
/>
) : (
<Radio
edge="start"
checked={isSelected}
tabIndex={-1}
color="secondary"
className={classes.checkbox}
disableRipple
inputProps={{
"aria-labelledby": `label-${_get(hit, primaryKey)}`,
}}
/>
)}
</ListItemIcon>
<ListItemText
id={`label-${_get(hit, primaryKey)}`}
primary={_get(hit, titleKey)}
secondary={!subtitleKey ? "" : _get(hit, subtitleKey)}
/>
</MenuItem>
<Divider className={classes.divider} />
</React.Fragment>
);
})}
</List>
</Grid>
{multiple && (
<Grid item className={clsx(classes.footerRow, classes.selectedRow)}>
<Grid
container
direction="row"
justifyContent="space-between"
alignItems="center"
>
<Typography
variant="button"
color="textSecondary"
className={classes.selectedNum}
>
{value?.length} of {hits?.length}
</Typography>
<Button
disabled={!value || value.length === 0}
onClick={clearSelection}
color="primary"
className={classes.selectAllButton}
>
Clear selection
</Button>
</Grid>
</Grid>
)}
</Grid>
);
}

View File

@@ -1,73 +0,0 @@
import { lazy, Suspense } from "react";
import clsx from "clsx";
import { TextField, TextFieldProps } from "@mui/material";
import useStyles from "./styles";
import Loading from "@src/components/Loading";
import ErrorBoundary from "@src/components/ErrorBoundary";
const PopupContents = lazy(
() => import("./PopupContents" /* webpackChunkName: "PopupContents" */)
);
export type ServiceValue = { value: string; [prop: string]: any };
export interface IConnectServiceSelectProps {
value: ServiceValue[];
onChange: (value: ServiceValue[]) => void;
row: any;
config: {
displayKey: string;
[key: string]: any;
};
editable?: boolean;
/** Optional style overrides for root MUI `TextField` component */
className?: string;
/** Override any props of the root MUI `TextField` component */
TextFieldProps?: Partial<TextFieldProps>;
docRef: firebase.default.firestore.DocumentReference;
}
export default function ConnectServiceSelect({
value = [],
className,
TextFieldProps = {},
...props
}: IConnectServiceSelectProps) {
const classes = useStyles();
const sanitisedValue = Array.isArray(value) ? value : [];
return (
<TextField
label=""
hiddenLabel
variant={"filled" as any}
select
value={sanitisedValue}
className={clsx(classes.root, className)}
{...TextFieldProps}
SelectProps={{
renderValue: (value) => `${(value as any[]).length} selected`,
displayEmpty: true,
classes: { root: classes.selectRoot },
...TextFieldProps.SelectProps,
// Must have this set to prevent MUI transforming `value`
// prop for this component to a comma-separated string
MenuProps: {
classes: { paper: classes.paper, list: classes.menuChild },
MenuListProps: { disablePadding: true },
anchorOrigin: { vertical: "bottom", horizontal: "center" },
transformOrigin: { vertical: "top", horizontal: "center" },
...TextFieldProps.SelectProps?.MenuProps,
},
}}
>
<ErrorBoundary>
<Suspense fallback={<Loading />}>
<PopupContents value={sanitisedValue} {...props} />
</Suspense>
</ErrorBoundary>
</TextField>
);
}

View File

@@ -1,83 +0,0 @@
import { makeStyles, createStyles } from "@mui/styles";
export const useStyles = makeStyles((theme) =>
createStyles({
root: { minWidth: 200 },
selectRoot: { paddingRight: theme.spacing(4) },
paper: { overflow: "hidden", maxHeight: "calc(100% - 48px)" },
menuChild: {
padding: `0 ${theme.spacing(2)}`,
minWidth: 340,
// Need to set fixed height here so popup is positioned correctly
height: 340,
},
grid: { outline: 0 },
noMargins: { margin: 0 },
searchRow: { marginTop: theme.spacing(2) },
listRow: {
background: `${theme.palette.background.paper} no-repeat`,
position: "relative",
margin: theme.spacing(0, -2),
maxWidth: `calc(100% + ${theme.spacing(4)})`,
"&::before, &::after": {
content: '""',
position: "absolute",
top: 0,
left: 0,
right: 0,
zIndex: 9,
display: "block",
height: 16,
background: `linear-gradient(to bottom, #fff, rgba(255, 255, 255, 0))`,
},
"&::after": {
top: "auto",
bottom: 0,
background: `linear-gradient(to top, #fff, rgba(255, 255, 255, 0))`,
},
},
list: () => {
let maxHeightDeductions = 0;
maxHeightDeductions -= 64; // search box
maxHeightDeductions -= 48; // multiple
maxHeightDeductions += 8; // footer padding
return {
padding: theme.spacing(2, 0),
overflowY: "auto" as "auto",
// height: `calc(340px - ${-maxHeightDeductions}px)`,
height: 340 + maxHeightDeductions,
};
},
checkboxContainer: { minWidth: theme.spacing(36 / 8) },
checkbox: {
padding: theme.spacing(6 / 8, 9 / 8),
"&:hover": { background: "transparent" },
},
divider: { margin: theme.spacing(0, 2, 0, 6.5) },
footerRow: { marginBottom: theme.spacing(2) },
selectedRow: {
"$listRow + &": { marginTop: -theme.spacing(1) },
"$footerRow + &": { marginTop: -theme.spacing(2) },
marginBottom: 0,
"& > div": { height: 48 },
},
selectAllButton: { marginRight: -theme.spacing(1) },
selectedNum: { fontFeatureSettings: '"tnum"' },
})
);
export default useStyles;