bcgov/citz-imb-staff-purchasing-reimbursement

View on GitHub
app/src/components/custom/modals/UserReport.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import { modalStyles } from './modalStyles';
import ActionButton from '../../bcgov/ActionButton';
import { buttonStyles } from '../../bcgov/ButtonStyles';
import axios from 'axios';
import { CSSProperties, useContext, useState } from 'react';
import { ErrorContext, errorStyles } from '../notifications/ErrorWrapper';
import Constants from '../../../constants/Constants';
import { useAuthService } from '../../../keycloak';
import { FormControl, FormLabel, TextField } from '@mui/material';
import { normalFont } from '../../../constants/fonts';

/**
 * @description A component to handle users sending in reports.
 * @returns A React component.
 */
export const UserReport = () => {
  const { BACKEND_URL } = Constants;
  const [issueData, setIssueData] = useState({
    title: '',
    description: '',
  });
  const { state: authState } = useAuthService();
  const user = authState.userInfo;

  const maxDescCharacters = 300;
  const maxTitleCharacters = 100;
  const minCharacters = 10;
  const id = 'user-issue';

  // Error reporting
  const { setErrorState } = useContext(ErrorContext);

  /**
   * @description Sends an API request with the form data. Should create a JIRA issue with that info.
   */
  const sendReportToJIRA = async () => {
    try {
      const axiosReqConfig = {
        url: `${BACKEND_URL}/api/jira/create`,
        method: `post`,
        headers: {
          Authorization: `Bearer ${authState.accessToken}`,
        },
        data: {
          title: issueData.title,
          description: `\
          ${issueData.description}\n\n \
          Submitted by ${user.given_name} ${user.family_name}\n \
          Email: ${user.email}\n \
          On ${new Date().toLocaleString()}`,
        },
      };
      const response = await axios(axiosReqConfig);

      if (response.status === 201) {
        // Success! Close popup and alert user.
        const thisDialog: HTMLDialogElement = document.querySelector(`#${id}`)!;
        thisDialog.close();
        setIssueData({ title: '', description: '' });
        setErrorState({
          text: 'Issue reported successfully.',
          open: true,
          style: errorStyles.success,
        });
      }
    } catch (e) {
      console.warn(e);
      if (axios.isAxiosError(e) && e.code === '401') {
        setErrorState({
          text: 'User is unauthenticated. Redirecting to login.',
          open: true,
        });
        window.location.reload();
      } else {
        // Request failed. Report error to user.
        setErrorState({
          text: 'Issue could not be submitted.',
          open: true,
          style: errorStyles.error,
        });
      }
    }
  };

  // General styling for form elements.
  const formControlStyle: CSSProperties = {
    width: '100%',
    marginBottom: '1em',
    ...normalFont,
  };

  return (
    <dialog id={id} style={modalStyles.standardModalStyle}>
      <h4
        style={{
          marginBottom: '1em',
        }}
      >
        Submit Issue
      </h4>
      {/* Text box goes here. */}
      <form>
        <FormControl sx={formControlStyle}>
          <FormLabel htmlFor='issueTitle'>Issue Title</FormLabel>
          <TextField
            id='issueTitle'
            name='issueTitle'
            value={issueData.title}
            onChange={(e: any) => {
              if (e.target.value.length <= maxTitleCharacters) {
                setIssueData({ ...issueData, title: e.target.value });
              }
            }}
            onKeyDown={(e) => {
              if (e.key === 'Enter') {
                e.preventDefault();
              }
            }}
            placeholder='e.g. Submit button not working'
            error={issueData.title.length < minCharacters && issueData.title.length !== 0}
            helperText={`Minimum of ${minCharacters} characters.`}
          />
        </FormControl>
        <FormControl sx={formControlStyle}>
          <FormLabel htmlFor='issueDescription'>Description</FormLabel>
          <TextField
            id='issueDescription'
            name='issueDescription'
            value={issueData.description}
            onChange={(e: any) => {
              if (e.target.value.length <= maxDescCharacters) {
                setIssueData({ ...issueData, description: e.target.value });
              }
            }}
            placeholder='Please mention the issue and any information leading up to that issue. Be descriptive.'
            multiline
            InputProps={{
              minRows: 4,
            }}
            error={
              issueData.description.length < minCharacters && issueData.description.length !== 0
            }
            helperText={`Minimum of ${minCharacters} characters.`}
          />
        </FormControl>
      </form>
      <p style={{ alignSelf: 'end' }}>{`${issueData.description.length}/${maxDescCharacters}`}</p>
      {/* Buttons go below. */}
      <div
        style={{
          display: 'flex',
          justifyContent: 'space-between',
          marginTop: '2em',
        }}
      >
        <ActionButton
          style={buttonStyles.secondary}
          handler={() => {
            setIssueData({ title: '', description: '' });
            const thisDialog: HTMLDialogElement = document.querySelector(`#${id}`)!;
            thisDialog.close();
          }}
        >
          Cancel
        </ActionButton>
        <ActionButton
          style={buttonStyles.primary}
          handler={() => {
            sendReportToJIRA();
          }}
          disabled={
            issueData.title.length < minCharacters || issueData.description.length < minCharacters
          }
        >
          Submit
        </ActionButton>
      </div>
    </dialog>
  );
};