clientProgressSelector

 avatar
unknown
plain_text
2 years ago
4.1 kB
2
Indexable
import { Box, Button, ButtonGroup, Menu, MenuItem, Skeleton, Typography } from '@mui/material';
import { Client } from '../../common/types/client';
import {
  ClientProcess,
  monitorFakeProcess,
  PROCESS_NOT_STARTED_ID,
} from '../../common/types/clientProcess';
import { Icon } from '@iconify/react';
import { LoadingButton } from '@mui/lab';
import { STATE_BUSY_ID, STATE_DONE_ID } from '../../common/types/clientState';
import { useIsClientUnderMonitoring } from '../../common/hooks/useIsClientUnderMonitoring';
import { useQueryProcesses } from '../../common/hooks/useQueryProcesses';
import { useState } from 'react';
import { useUpdateClientProcessMutation } from '../../ops/mutations';

interface ClientProcessSelectorProps {
  client: Client;
  onChange: (value: ClientProcess, openNotes?: boolean) => void;
}

/**
 * Dropdown to select next client process
 */
const ClientProcessSelector = ({ client, onChange }: ClientProcessSelectorProps) => {
  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
  const open = Boolean(anchorEl);
  const { data: clientProcesses, isLoading } = useQueryProcesses();
  const isMonitoring = useIsClientUnderMonitoring(client);
  const mutation = useUpdateClientProcessMutation();

  if (isLoading || !clientProcesses)
    return <Skeleton variant="rounded" height={36} sx={{ width: 1 }} />;

  // Ignore client "not started" process and display the next one.
  // Also show the next step if current step is done.
  let currentPosition = clientProcesses.findIndex(({ id }) => id === client.processID);
  if (
    clientProcesses[currentPosition]?.id === PROCESS_NOT_STARTED_ID ||
    (client.stateID === STATE_DONE_ID && clientProcesses[currentPosition + 1])
  ) {
    currentPosition = currentPosition + 1;
  }

  const currentProcess = clientProcesses[currentPosition];

  const handleChange = (selectedProcess: ClientProcess, openNotes?: boolean) => {
    setAnchorEl(null);

    // If user open next process that is not active, then activate it
    if (
      client.processID !== selectedProcess.id &&
      selectedProcess.id > client.processID &&
      !mutation.isLoading
    ) {
      mutation.mutate(
        { ID: client.id, stateID: STATE_BUSY_ID, processID: selectedProcess.id },
        {
          onSuccess: () => {
            onChange(selectedProcess, openNotes);
          },
        },
      );
    } else {
      onChange(selectedProcess, openNotes);
    }
  };

  if (isMonitoring) {
    return (
      <Button
        fullWidth
        variant="outlined"
        color="gray"
        sx={{ fontSize: 15 }}
        onClick={() => onChange(monitorFakeProcess)}
      >
        Monitoring
      </Button>
    );
  }

  return (
    <Box>
      <ButtonGroup variant="outlined" color="gray">
        <LoadingButton
          variant="outlined"
          sx={{ fontSize: 15, width: 108 }}
          loading={mutation.isLoading}
          onClick={() => currentProcess && handleChange(currentProcess)}
        >
          Open
        </LoadingButton>
        <Button
          sx={{ width: 40, p: 0, ml: 1 }}
          size="small"
          onClick={(event) => setAnchorEl(event.currentTarget)}
        >
          <Icon icon="gridicons:dropdown" width={24} />
        </Button>
      </ButtonGroup>
      <Button
        key="history"
        sx={{ minWidth: 40, height: 37, px: 0, ml: 1 }}
        color="gray"
        onClick={() => handleChange(currentProcess, true)}
      >
        <Icon icon="ic:baseline-history" width={24} />
      </Button>
      <Menu open={open} anchorEl={anchorEl} onClose={() => setAnchorEl(null)}>
        {clientProcesses.map((process, index) =>
          process.id === PROCESS_NOT_STARTED_ID ? null : (
            <MenuItem
              key={process.id}
              onClick={() => handleChange(process)}
              disabled={index > currentPosition}
            >
              <Typography variant="caption">{process.note}</Typography>
            </MenuItem>
          ),
        )}
      </Menu>
    </Box>
  );
};

export default ClientProcessSelector;