Advertisement
Levii_Valenok

Untitled

Mar 6th, 2023
1,160
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import React, { useEffect, useState } from 'react';
  2. import {
  3.   Autocomplete,
  4.   FormControl,
  5.   FormControlProps,
  6.   InputLabel,
  7.   InputLabelProps,
  8.   ListItemText,
  9.   ListItemTextProps,
  10.   MenuItem,
  11.   MenuItemProps,
  12.   MenuProps,
  13.   OutlinedInput,
  14.   Select,
  15.   SelectChangeEvent,
  16.   TextField,
  17. } from '@mui/material';
  18.  
  19. import styled, { ThemeProps, useTheme } from 'styled-components';
  20. import { CustomTheme } from '../../style/themes/themes';
  21. import Checkbox from './Checkbox';
  22. import SelectButton from './SelectButton';
  23. import { KeyValuePair } from '../types';
  24.  
  25. interface MultiSelectProps {
  26.   isVisible: boolean;
  27.   placement?: Placement;
  28.   disabled?: boolean;
  29.   label?: string;
  30.   options: KeyValuePair[];
  31.   initiallySelectedOptions?: string[];
  32.   onClick: () => void;
  33.   onChangeHandler: (selectedValues: KeyValuePair[]) => void;
  34.   isAbsolute?: boolean;
  35.   renderInput?: () => void;
  36. }
  37.  
  38. interface AutocompleteMultipleProps {
  39.   renderInput?: ()=> void;
  40.   multiply?: boolean;
  41. }
  42.  
  43. export enum Placement {
  44.   left = 'left',
  45.   right = 'right',
  46. }
  47.  
  48. const definePlacement = (placement?: string) => {
  49.   switch (placement) {
  50.     case Placement.right:
  51.       return '0';
  52.     case Placement.left:
  53.     default:
  54.       return 'unset';
  55.   }
  56. };
  57.  
  58. const MultiSelectWithAutocomplete = ({
  59.   isVisible,
  60.   placement,
  61.   options,
  62.   onClick,
  63.   onChangeHandler,
  64.   label,
  65.   initiallySelectedOptions = [],
  66.   isAbsolute = true,
  67.   renderInput,
  68. }: MultiSelectProps) => {
  69.   const currentTheme = useTheme();
  70.  
  71.   const CustomMenuProps: Partial<MenuProps> = {
  72.     PaperProps: {
  73.       style: {
  74.         maxHeight: '365px',
  75.         backgroundColor: currentTheme.lightAccentBackground,
  76.         boxShadow: 'none',
  77.         width: '360px',
  78.         display: isVisible ? 'block' : 'none',
  79.         padding: '0 16px',
  80.       },
  81.     },
  82.     disablePortal: true,
  83.     variant: 'menu',
  84.     disableAutoFocusItem: true,
  85.   };
  86.  
  87.   const [selectedValue, setSelectedValue] = useState<KeyValuePair[]>(
  88.     options.filter((option) => initiallySelectedOptions?.indexOf(option.key) !== -1)
  89.   );
  90.   const [isCollapsed, setIsCollapsed] = useState<boolean>(false);
  91.  
  92.   const handleChange = (event: SelectChangeEvent<string[]>) => {
  93.     const values = event.target.value as string[];
  94.     const selectedItems: KeyValuePair[] = [];
  95.  
  96.     for (let i = 0; i < values.length; ++i) {
  97.       const item = options.find((x) => x.value === values.at(i));
  98.       if (item) {
  99.         selectedItems.push(item);
  100.       }
  101.     }
  102.  
  103.     setSelectedValue(selectedItems);
  104.     onChangeHandler(selectedItems);
  105.   };
  106.  
  107.   const collapseClickHandler = (e: React.MouseEvent) => {
  108.     const target = e.target as HTMLButtonElement;
  109.     if (!target.closest('.MuiPaper-root')) {
  110.       setIsCollapsed(!isCollapsed);
  111.     }
  112.   };
  113.  
  114.   const applyButtonClickHandler = () => {
  115.     setIsCollapsed(false);
  116.     onClick();
  117.   };
  118.  
  119.   useEffect(() => {
  120.     setIsCollapsed(isVisible);
  121.   }, [isVisible]);
  122.  
  123.   useEffect(() => {
  124.     setSelectedValue(options.filter((option) => initiallySelectedOptions?.indexOf(option.key) !== -1));
  125.   }, [initiallySelectedOptions]);
  126.  
  127.   useEffect(() => {
  128.     const trackCollapseHandler = (e: MouseEvent): void => {
  129.       const target = e.target as HTMLButtonElement;
  130.       if (target) {
  131.         if (!target.closest('.MuiPaper-root') && !target.closest('.selectRootWrapper')) {
  132.           if (isCollapsed) {
  133.             setIsCollapsed(false);
  134.           }
  135.         }
  136.       }
  137.     };
  138.     document.addEventListener('click', trackCollapseHandler);
  139.     return function cleanup() {
  140.       document.removeEventListener('click', trackCollapseHandler);
  141.     };
  142.   }, [isCollapsed]);
  143.  
  144.   return (
  145.     <MultiSelectWrapper
  146.       isCollapsed={isCollapsed}
  147.       className="selectRootWrapper"
  148.       isVisible={isVisible}
  149.       placement={placement}
  150.       isAbsolute={isAbsolute}
  151.     >
  152.       <CustomFormControl onClick={collapseClickHandler}>
  153.         <CustomInputLabel id="demo-multiple-checkbox-label">{label}</CustomInputLabel>
  154.         <Autocomplete
  155.           multiple
  156.           renderInput={(params) => <TextField {...params} label="Players" />}
  157.           options={options}
  158.           getOptionLabel={(option: KeyValuePair) => option.value}
  159.         />
  160.         {/*<Select*/}
  161.         {/*  labelId="demo-multiple-checkbox-label"*/}
  162.         {/*  id="demo-multiple-checkbox"*/}
  163.         {/*  multiple*/}
  164.         {/*  value={selectedValue.map((x) => x.value)}*/}
  165.         {/*  onChange={handleChange}*/}
  166.         {/*  renderValue={params => <TextField {...params} label="Players"/>}*/}
  167.         {/*  MenuProps={CustomMenuProps}*/}
  168.         {/*  open={isCollapsed}*/}
  169.         {/*>*/}
  170.         {/*  {options.map((option) => (*/}
  171.         {/*    <CustomMenuItem key={option.key} value={option.value}>*/}
  172.         {/*      <Checkbox*/}
  173.         {/*        onChange={() => {*/}
  174.         {/*          return null;*/}
  175.         {/*        }}*/}
  176.         {/*        checked={selectedValue.findIndex((item) => item.key === option.key) !== -1}*/}
  177.         {/*      />*/}
  178.         {/*      <CustomListItemText primary={option.value} />*/}
  179.         {/*    </CustomMenuItem>*/}
  180.         {/*  ))}*/}
  181.         {/*</Select>*/}
  182.       </CustomFormControl>
  183.       <SelectButton isVisible={isCollapsed} onClick={applyButtonClickHandler} disabled={false}>
  184.         Apply
  185.       </SelectButton>
  186.     </MultiSelectWrapper>
  187.   );
  188. };
  189.  
  190. export const SelectWrapper = styled.div<{
  191.   theme: ThemeProps<CustomTheme>;
  192.   placement?: string;
  193. }>`
  194.   padding: 0;
  195.   width: 360px;
  196.   background: ${(props) => props.theme.lightAccentBackground};
  197.   border-radius: 8px;
  198.   transition: height 3s linear;
  199.   right: ${(props) => definePlacement(props.placement)};
  200.   flex-direction: column;
  201.   justify-content: space-between;
  202. `;
  203.  
  204. export const MultiSelectWrapper = styled(SelectWrapper)<{
  205.   theme: ThemeProps<CustomTheme>;
  206.   isVisible?: boolean;
  207.   placement?: string;
  208.   isCollapsed?: boolean;
  209.   isAbsolute?: boolean;
  210. }>`
  211.   position: ${(props) => (props.isAbsolute ? 'absolute' : 'unset')};
  212.   padding: ${(props) => (props.isAbsolute ? '16px;' : '0')};
  213.   background: ${(props) => props.theme.lightAccentBackground};
  214.   display: ${(props) => (props.isVisible ? 'flex' : 'none')};
  215.   top: 115%;
  216.   z-index: 500;
  217.   height: ${(props) => (props.isCollapsed ? '495px' : 'unset')};
  218. `;
  219.  
  220. export const CustomFormControl = styled(FormControl)<FormControlProps>(({ theme }: ThemeProps<CustomTheme>) => ({
  221.   width: '100%',
  222.   '& .MuiInputBase-root': {
  223.     maxHeight: 56,
  224.     '& .MuiOutlinedInput-notchedOutline': {
  225.       borderColor: theme.addColor,
  226.       borderRadius: 8,
  227.       '& legend': {
  228.         width: '35%',
  229.       },
  230.     },
  231.     '&:hover': {
  232.       '& .MuiOutlinedInput-notchedOutline': {
  233.         borderColor: theme.addColor,
  234.       },
  235.     },
  236.     '&.Mui-focused': {
  237.       '& .MuiOutlinedInput-notchedOutline': {
  238.         borderColor: theme.addColor,
  239.         '& legend': {
  240.           width: '35%',
  241.         },
  242.       },
  243.     },
  244.     '& .MuiSelect-icon': {
  245.       color: theme.addColor,
  246.     },
  247.   },
  248.   '.MuiOutlinedInput-input': {
  249.     color: theme.basicColor,
  250.   },
  251.   '& .MuiPopover-root': {
  252.     bottom: '65%',
  253.     '& .MuiBackdrop-root': {
  254.       bottom: '65%',
  255.     },
  256.   },
  257. }));
  258.  
  259. export const CustomInputLabel = styled(InputLabel)<InputLabelProps>(({ theme }: ThemeProps<CustomTheme>) => ({
  260.   '&.MuiInputLabel-root': {
  261.     color: theme.addColor,
  262.     '&.Mui-focused': {
  263.       color: theme.addColor,
  264.     },
  265.   },
  266. }));
  267.  
  268. export const CustomMenuItem = styled(MenuItem)<MenuItemProps>(({ theme }: ThemeProps<CustomTheme>) => ({
  269.   '&.MuiMenuItem-root': {
  270.     backgroundColor: 'inherit',
  271.     paddingLeft: 3,
  272.     '&.Mui-selected': {
  273.       backgroundColor: 'inherit',
  274.     },
  275.     '&:hover': {
  276.       backgroundColor: theme.selectItemHover,
  277.     },
  278.   },
  279. }));
  280.  
  281. export const CustomListItemText = styled(ListItemText)<ListItemTextProps>(({ theme }: ThemeProps<CustomTheme>) => ({
  282.   '&.MuiListItemText-root': {
  283.     color: theme.basicColor,
  284.     fontFamily: 'Quicksand',
  285.     '& .MuiTypography-root': {
  286.       fontFamily: 'Quicksand',
  287.     },
  288.   },
  289. }));
  290.  
  291. export default MultiSelectWithAutocomplete;
  292.  
Advertisement
Comments
Add Comment
Please, Sign In to add comment
Advertisement