Advertisement
Guest User

Untitled

a guest
Dec 29th, 2020
325
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { useQuery } from '@apollo/react-hooks';
  2. import {
  3.   Button,
  4.   Checkbox,
  5.   Dialog,
  6.   DialogActions,
  7.   DialogContent,
  8.   DialogTitle,
  9.   FormControl,
  10.   Grid,
  11.   InputLabel,
  12.   ListItemText,
  13.   makeStyles,
  14.   MenuItem,
  15.   Select,
  16. } from '@material-ui/core';
  17. import Tooltip from '@material-ui/core/Tooltip';
  18. import ActiveIcon from '@material-ui/icons/Brightness1';
  19. import gql from 'graphql-tag';
  20. import { get } from 'lodash';
  21. import MuiDataTable from 'mui-datatables';
  22. import { func, shape, string } from 'prop-types';
  23. import { useEffect, useMemo, useState } from 'react';
  24. import { FormattedMessage, useIntl } from 'react-intl';
  25. import { useParams } from 'react-router-dom';
  26. import PropTypes from '../../helpers/propTypes';
  27. import { useDisclosure } from '../../utils/hooks';
  28. import { sortSiteSelection } from '../../utils/sites';
  29. import AutocompletePlaces from '../AutocompletePlacesAPI';
  30. import ConfirmDialog from '../Dialogs/ConfirmDialog';
  31. import calculateNearestSites from '../../utils/sitesUtil';
  32.  
  33. const useStyle = makeStyles(theme => ({
  34.   dialogTitle: {
  35.     marginTop: theme.spacing(2),
  36.   },
  37.   flag: {
  38.     height: 12,
  39.     marginRight: theme.spacing(1),
  40.   },
  41.   button: {
  42.     marginRight: theme.spacing(4),
  43.     height: 40,
  44.   },
  45.   active: {
  46.     color: '#4caf50',
  47.     fontSize: 15,
  48.   },
  49.   notActive: {
  50.     color: '#ff1259',
  51.     fontSize: 15,
  52.   },
  53. }));
  54.  
  55. const getStudySiteChoicesQuery = gql`
  56.   query getStudySiteChoices($studyId: ID!) {
  57.     sites(studyId: $studyId, statuses: [ACTIVE, INACTIVE]) {
  58.       siteId
  59.       name
  60.       city
  61.       state
  62.       address
  63.       status
  64.       countryCode
  65.       country {
  66.         code
  67.         englishName
  68.         flagIconUrl
  69.       }
  70.       coordinates {
  71.         latitude
  72.         longitude
  73.       }
  74.     }
  75.   }
  76. `;
  77.  
  78. const useStudySiteChoices = () => {
  79.   const { studyId } = useParams();
  80.   const { data, ...rest } = useQuery(getStudySiteChoicesQuery, {
  81.     variables: { studyId },
  82.     fetchPolicy: 'network-only',
  83.   });
  84.   return { sites: data?.sites ?? [], ...rest };
  85. };
  86.  
  87. const CustomCheckbox = props => {
  88.   const newProps = { ...props };
  89.   newProps.color =
  90.     newProps['data-description'] === 'row-select' ? 'secondary' : 'primary';
  91.   const i = newProps['data-index'] === null ? 0 : newProps['data-index'];
  92.  
  93.   if (newProps.sites[i][0] === newProps.defaultsite.siteId)
  94.     newProps.checked = true;
  95.  
  96.   return <Checkbox {...newProps} color="primary" />;
  97. };
  98.  
  99. const Flag = siteCountry => {
  100.   return (
  101.     <Tooltip title={get(siteCountry, 'siteCountry.englishName')}>
  102.       <img
  103.         className={useStyle().flag}
  104.         src={get(siteCountry, 'siteCountry.flagIconUrl')}
  105.         alt={get(siteCountry, 'siteCountry.englishName')}
  106.       />
  107.     </Tooltip>
  108.   );
  109. };
  110.  
  111. const Sites = ({
  112.   isOpen,
  113.   onClose,
  114.   site,
  115.   onChange: onChangeSelectedSite = () => {},
  116. }) => {
  117.   const intl = useIntl();
  118.   const classes = useStyle();
  119.   const { sites } = useStudySiteChoices();
  120.   const [selectedSiteId, selectSite] = useState('');
  121.   const { isOpen: isConfirmOpen, onToggle: onConfirmToggle } = useDisclosure();
  122.   const [usingLocation, setLocation] = useState(null);
  123.  
  124.   const nearestSites = calculateNearestSites(usingLocation, sites);
  125.   const selectedSite = sites.find(s => s.siteId === selectedSiteId);
  126.   const preparedSites = useMemo(
  127.     () =>
  128.       sites.sort(sortSiteSelection(site)).map(elm => {
  129.         const arr = [
  130.           elm.siteId,
  131.           elm.city,
  132.           elm.state,
  133.           elm.country,
  134.           elm.address,
  135.           elm.status,
  136.         ];
  137.         if (nearestSites.length)
  138.           arr.push(
  139.             nearestSites.find(s => s.closestSiteId === elm.siteId).distance,
  140.           );
  141.         return arr;
  142.       }),
  143.     [sites, nearestSites],
  144.   );
  145.  
  146.   const onFieldChangeConfirm = () => {
  147.     onChangeSelectedSite('siteId', selectedSiteId);
  148.     onClose();
  149.   };
  150.  
  151.   console.log('LOCATION', usingLocation);
  152.  
  153.   const isLocation = usingLocation !== null;
  154.  
  155.   const isDisplay = () => {
  156.     if (usingLocation !== null) return true;
  157.     else return false;
  158.   };
  159.  
  160.   console.log(isDisplay());
  161.  
  162.   const DISTANCE_MEASURE = 'Km';
  163.  
  164.   const columns = useMemo(
  165.     () => [
  166.       'Id',
  167.  
  168.       {
  169.         name: intl.formatMessage({
  170.           id: 'SitesColumn.city',
  171.           defaultMessage: 'City',
  172.         }),
  173.       },
  174.       {
  175.         name: intl.formatMessage({
  176.           id: 'SitesColumn.state',
  177.           defaultMessage: 'State',
  178.         }),
  179.       },
  180.       {
  181.         name: intl.formatMessage({
  182.           id: 'SitesColumn.country',
  183.           defaultMessage: 'Country',
  184.         }),
  185.         options: {
  186.           filter: true,
  187.           filterList: [site.countryCode],
  188.           filterType: 'custom',
  189.           filterOptions: {
  190.             logic(country, filters) {
  191.               if (filters.length) return filters[0] !== country.code;
  192.               return false;
  193.             },
  194.             display: (filterList, onChange, index, column) => (
  195.               <MuiTableForm
  196.                 preparedSites={preparedSites}
  197.                 filterList={filterList}
  198.                 onChange={onChange}
  199.                 index={index}
  200.                 column={column}
  201.               />
  202.             ),
  203.           },
  204.           customBodyRender: value => <Flag siteCountry={value} />,
  205.         },
  206.       },
  207.       {
  208.         name: intl.formatMessage({
  209.           id: 'SitesColumn.address',
  210.           defaultMessage: 'Address',
  211.         }),
  212.       },
  213.       {
  214.         name: intl.formatMessage({
  215.           id: 'SitesColumn.status',
  216.           defaultMessage: 'Status',
  217.         }),
  218.         options: {
  219.           customBodyRender: value => {
  220.             if (value === 'ACTIVE')
  221.               return (
  222.                 <Tooltip
  223.                   title={intl.formatMessage({
  224.                     id: 'SitesColumn.active',
  225.                     defaultMessage: 'ACTIVE',
  226.                   })}
  227.                 >
  228.                   <ActiveIcon className={classes.active} />
  229.                 </Tooltip>
  230.               );
  231.             else
  232.               return (
  233.                 <Tooltip
  234.                   title={intl.formatMessage({
  235.                     id: 'SitesColumn.inactive',
  236.                     defaultMessage: 'INACTIVE',
  237.                   })}
  238.                 >
  239.                   <ActiveIcon className={classes.notActive} />
  240.                 </Tooltip>
  241.               );
  242.           },
  243.           filter: true,
  244.           filterList: ['ACTIVE'],
  245.         },
  246.       },
  247.       {
  248.         name: 'Distance',
  249.         options: {
  250.           display: isDisplay(),
  251.           filter: false,
  252.           customBodyRender: value => {
  253.             return !value ? 'N/A' : `${value} ${DISTANCE_MEASURE}`;
  254.           },
  255.         },
  256.       },
  257.     ],
  258.     [sites, site],
  259.   );
  260.  
  261.   const options = useMemo(
  262.     () => ({
  263.       filter: true,
  264.       filterType: 'dropdown',
  265.       responsive: 'standard',
  266.       tableBodyHeight: '90%',
  267.       tableBodyWith: '100%',
  268.       tableBodyMaxHeight: '100%',
  269.       selectableRowsOnClick: true,
  270.       selectableRows: 'single',
  271.       search: false,
  272.       viewColumns: false,
  273.       download: false,
  274.       print: false,
  275.       sortOrder: {
  276.         name: 'Distance',
  277.         direction: 'asc',
  278.       },
  279.       customToolbarSelect: () => {},
  280.       isRowSelectable: dataIndex => {
  281.         if (
  282.           preparedSites[dataIndex][5] === 'INACTIVE' ||
  283.           preparedSites[dataIndex][0] === site.siteId
  284.         ) {
  285.           return false;
  286.         }
  287.         return true;
  288.       },
  289.       setRowProps: (row, dataIndex) => {
  290.         if (preparedSites[dataIndex][0] === site.siteId)
  291.           return {
  292.             style: { backgroundColor: 'rgba(0, 168, 238, .1)' },
  293.           };
  294.         else if (preparedSites[dataIndex][5] === 'INACTIVE')
  295.           return {
  296.             style: {
  297.               opacity: '.5',
  298.             },
  299.           };
  300.         return '';
  301.       },
  302.       setFilterChipProps: () => {
  303.         return {
  304.           color: 'primary',
  305.           variant: 'outlined',
  306.         };
  307.       },
  308.       onRowSelectionChange: rowsSelectedData => {
  309.         const id = preparedSites[rowsSelectedData[0].dataIndex][0];
  310.         const status = preparedSites[rowsSelectedData[0].dataIndex][5];
  311.         if (status === 'ACTIVE') selectSite(id);
  312.       },
  313.     }),
  314.     [sites, site],
  315.   );
  316.  
  317.   return (
  318.     <>
  319.       <Dialog open={isOpen} fullWidth maxWidth="md">
  320.         <DialogTitle className={classes.dialogTitle}>
  321.           <FormattedMessage
  322.             id="Candidate.selectClinicTitle"
  323.             defaultMessage="Select a clinic"
  324.           />
  325.           <br />
  326.           <FormattedMessage
  327.             id="Candidate.currentSite"
  328.             defaultMessage="Current site: "
  329.           />
  330.           {site.name} {site.city}
  331.         </DialogTitle>
  332.         <DialogContent>
  333.           <AutocompletePlaces onSelect={setLocation} />
  334.           <MuiDataTable
  335.             data={preparedSites}
  336.             columns={columns}
  337.             options={options}
  338.             components={{
  339.               Checkbox: props => (
  340.                 <CustomCheckbox
  341.                   {...{ ...props, defaultsite: site, sites: preparedSites }}
  342.                 />
  343.               ),
  344.             }}
  345.           />
  346.         </DialogContent>
  347.  
  348.         <DialogActions>
  349.           <Grid
  350.             container
  351.             direction="row"
  352.             justify="flex-end"
  353.             alignItems="center"
  354.           >
  355.             {' '}
  356.             <Grid item>
  357.               <Button
  358.                 color="primary"
  359.                 variant="outlined"
  360.                 onClick={onClose}
  361.                 className={classes.button}
  362.               >
  363.                 <FormattedMessage id="Candidate.close" defaultMessage="Close" />
  364.               </Button>
  365.             </Grid>
  366.             <Grid item>
  367.               <Button
  368.                 color="primary"
  369.                 variant="contained"
  370.                 disabled={!selectedSite}
  371.                 onClick={onConfirmToggle}
  372.                 className={classes.button}
  373.               >
  374.                 <FormattedMessage
  375.                   id="Candidate.saveClinic"
  376.                   defaultMessage="Save clinic selection"
  377.                 />
  378.               </Button>
  379.             </Grid>
  380.           </Grid>
  381.         </DialogActions>
  382.       </Dialog>
  383.  
  384.       <ConfirmDialog
  385.         open={isConfirmOpen}
  386.         title={intl.formatMessage({
  387.           id: 'Candidate.confirmChangeTitle',
  388.           defaultMessage: 'Confirm the change',
  389.         })}
  390.         content={intl.formatMessage(
  391.           {
  392.             id: 'Candidate.confirmChangeMessage',
  393.             defaultMessage: 'Change from {oldValue} to {newValue}?',
  394.           },
  395.           {
  396.             oldValue: `${site.name} ${site.city} ${site.state}`,
  397.             newValue: `${selectedSite?.name} ${selectedSite?.city} ${selectedSite?.state}`,
  398.           },
  399.         )}
  400.         close={onConfirmToggle}
  401.         confirm={onFieldChangeConfirm}
  402.       />
  403.     </>
  404.   );
  405. };
  406.  
  407. const MuiTableForm = ({
  408.   preparedSites,
  409.   filterList,
  410.   onChange,
  411.   index,
  412.   column,
  413. }) => {
  414.   // Eslint saying .reduce has a missing proptypes seems a bug
  415.   // eslint-disable-next-line react/prop-types
  416.   const optionValues = preparedSites.reduce((acc, val) => {
  417.     const exists = acc.find(country => country.code === val[3].code);
  418.     if (!exists) acc.push(val[3]);
  419.     return acc;
  420.   }, []);
  421.   return (
  422.     <FormControl>
  423.       <InputLabel htmlFor="select-multiple-chip">Country</InputLabel>
  424.       <Select
  425.         value={filterList[index]}
  426.         renderValue={selected => selected.join(' ')}
  427.         onChange={event => {
  428.           onChange([event.target.value], index, column);
  429.         }}
  430.       >
  431.         {optionValues.map(item => (
  432.           <MenuItem key={item.code} value={item.code}>
  433.             <Flag siteCountry={item} />
  434.             <ListItemText primary={item.code} />
  435.           </MenuItem>
  436.         ))}
  437.       </Select>
  438.     </FormControl>
  439.   );
  440. };
  441.  
  442. Sites.propTypes = {
  443.   isOpen: PropTypes.bool,
  444.   onClose: func,
  445.   site: shape({ id: string, name: string, siteId: string }).isRequired,
  446.   onChange: func,
  447. };
  448.  
  449. MuiTableForm.propTypes = {
  450.   onChange: func,
  451.   preparedSites: PropTypes.shape({}).isRequired,
  452.   filterList: PropTypes.arrayOf(),
  453.   index: PropTypes.number,
  454.   column: PropTypes.shape(),
  455. };
  456.  
  457. export default Sites;
  458.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement