Skip to content

Commit

Permalink
Minor UI adjustments and ManifestActionBtns test suite
Browse files Browse the repository at this point in the history
Adjust ManifestForm test suite to accommodate multiple save buttons (one floating action button, one regular)
Minor changes to make HtSpinner for flexible and use correct profile selector in Profile Feature
  • Loading branch information
dpgraham4401 committed Dec 11, 2023
1 parent 82fa663 commit 5a63be3
Show file tree
Hide file tree
Showing 14 changed files with 258 additions and 210 deletions.
4 changes: 2 additions & 2 deletions client/src/components/Layout/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ErrorBoundary } from 'components/Error';
import { HtSpinner } from 'components/UI';
import React, { createContext, Dispatch, SetStateAction, Suspense, useState } from 'react';
import { Container } from 'react-bootstrap';
import { Outlet } from 'react-router-dom';
import { PrivateRoute } from './PrivateRoute';
import { Sidebar } from './Sidebar/Sidebar';
import { TopNav } from './TopNav/TopNav';
import { HtSpinner } from 'components/UI';

export interface NavContextProps {
showSidebar: boolean;
Expand All @@ -29,7 +29,7 @@ export function Root() {
<Suspense
fallback={
<Container fluid className="d-flex justify-content-center vh-100">
<HtSpinner size="7x" />
<HtSpinner size="6x" className="my-auto" />
</Container>
}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import '@testing-library/jest-dom';
import { ManifestActionBtns } from 'components/Manifest/ActionBtns/ManifestActionBtns';
import React from 'react';
import { cleanup, renderWithProviders, screen } from 'test-utils';
import { afterEach, describe, expect, test } from 'vitest';

afterEach(() => {
cleanup();
});

describe('ManifestActionBtns', () => {
test.each([
['Scheduled', true],
['Scheduled', false],
['NotAssigned', false],
['NotAssigned', true],
])('renders a save button when editing and {status: "%s", signAble: %s}', (status, signAble) => {
renderWithProviders(
// @ts-ignore - Status is expected to be a ManifestStatus, but we're passing a string
<ManifestActionBtns readOnly={false} manifestStatus={status} signAble={signAble} />
);
expect(screen.queryByRole('button', { name: /Save/i })).toBeInTheDocument();
});
test.each([[true, false]])(
'renders a edit button when {readOnly: %s, signAble: %s}',
(readOnly, signAble) => {
renderWithProviders(
// @ts-ignore - Status is expected to be a ManifestStatus, but we're passing a string
<ManifestActionBtns readOnly={readOnly} manifestStatus={'Scheduled'} signAble={signAble} />
);
expect(screen.queryByRole('button', { name: /Edit/i })).toBeInTheDocument();
expect(screen.queryByRole('button', { name: /Sign/i })).not.toBeInTheDocument();
expect(screen.queryByRole('button', { name: /Save/i })).not.toBeInTheDocument();
}
);
test.each([[true, true]])(
'renders a sign button when {readOnly: %s, signAble: %s}',
(readOnly, signAble) => {
renderWithProviders(
// @ts-ignore - Status is expected to be a ManifestStatus, but we're passing a string
<ManifestActionBtns readOnly={readOnly} manifestStatus={'Scheduled'} signAble={signAble} />
);
expect(screen.queryByRole('button', { name: /Sign/i })).toBeInTheDocument();
}
);
test.each([
[true, true],
[true, false],
[false, false],
[false, true],
])(
'never renders a sign button when draft status with {readOnly: %s, signAble: %s}',
(readOnly, signAble) => {
renderWithProviders(
// @ts-ignore - Status is expected to be a ManifestStatus, but we're passing a string
<ManifestActionBtns
readOnly={readOnly}
manifestStatus={'NotAssigned'}
signAble={signAble}
/>
);
expect(screen.queryByRole('button', { name: /Sign/i })).not.toBeInTheDocument();
}
);
});
44 changes: 25 additions & 19 deletions client/src/components/Manifest/ActionBtns/ManifestActionBtns.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,50 @@
import React from 'react';
import { FloatingActionBtn } from 'components/UI';
import { ManifestStatus } from 'components/Manifest/manifestSchema';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { faFloppyDisk, faPen, faPenToSquare } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { ManifestStatus } from 'components/Manifest/manifestSchema';
import { FloatingActionBtn } from 'components/UI';
import React from 'react';

interface ManifestActionBtnsProps {
manifestStatus?: ManifestStatus;
readonly?: boolean;
readOnly?: boolean;
signAble?: boolean;
}

export function ManifestActionBtns({
manifestStatus,
readonly,
readOnly,
signAble,
}: ManifestActionBtnsProps) {
let variant = 'success';
let text = '';
let icon = faFloppyDisk;
let type: 'button' | 'submit' | 'reset' | undefined = 'button';
console.log('signAble', signAble);
if (signAble) {
let variant: string | undefined = undefined;
let text: string | undefined = undefined;
let icon: IconProp | undefined = undefined;
let type: 'button' | 'submit' | 'reset' | undefined = undefined;
let name: string | undefined = undefined;
if (!readOnly || manifestStatus === 'NotAssigned') {
variant = 'success';
icon = faFloppyDisk;
text = 'Save';
type = 'submit';
name = 'saveFAB';
} else if (signAble) {
variant = 'primary';
icon = faPen;
text = 'Sign';
} else if (readonly) {
name = 'signFAB';
type = 'button';
} else if (readOnly) {
variant = 'primary';
icon = faPenToSquare;
text = 'Edit';
} else if (!readonly) {
variant = 'success';
icon = faFloppyDisk;
text = 'Save';
type = 'submit';
name = 'editFAB';
type = 'button';
} else {
return <></>;
}

return (
<FloatingActionBtn variant={variant} type={type} position="bottom-left" extended>
<FloatingActionBtn name={name} variant={variant} type={type} position="bottom-left" extended>
<span className="h5 me-3">{text}</span>
<span className="h5">
<FontAwesomeIcon icon={icon} />
Expand Down
11 changes: 4 additions & 7 deletions client/src/components/Manifest/ManifestForm.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,34 +42,31 @@ describe('ManifestForm validation', () => {
test('a generator is required', async () => {
// Arrange
renderWithProviders(<ManifestForm readOnly={false} />);
const saveBtn = screen.getByRole('button', { name: /Save/i });
const saveBtn = screen.getAllByRole('button', { name: /Save/i })[0];
// Act
await userEvent.click(saveBtn);
// Assert
expect(await screen.findByText(/Generator is required/i)).toBeInTheDocument();
});
test('at least one transporter is required', async () => {
// Arrange
renderWithProviders(<ManifestForm readOnly={false} />);
const saveBtn = screen.getByRole('button', { name: /Save/i });
// Act
const saveBtn = screen.getAllByRole('button', { name: /Save/i })[0];
await userEvent.click(saveBtn);
// Assert
expect(
await screen.findByText(/A manifest requires at least 1 transporters/i)
).toBeInTheDocument();
});
test('at least one waste line is required', async () => {
renderWithProviders(<ManifestForm readOnly={false} />);
const saveBtn = screen.getByRole('button', { name: /Save/i });
const saveBtn = screen.getAllByRole('button', { name: /Save/i })[0];
await userEvent.click(saveBtn);
expect(
await screen.findByText(/A manifest requires at least 1 waste line/i)
).toBeInTheDocument();
});
test('a TSDF is required', async () => {
renderWithProviders(<ManifestForm readOnly={false} />);
const saveBtn = screen.getByRole('button', { name: /Save/i });
const saveBtn = screen.getAllByRole('button', { name: /Save/i })[0];
await userEvent.click(saveBtn);
expect(
await screen.findByText(/Designated receiving facility is required/i)
Expand Down
10 changes: 4 additions & 6 deletions client/src/components/Manifest/ManifestForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ErrorMessage } from '@hookform/error-message';
import { zodResolver } from '@hookform/resolvers/zod';
import { ManifestActionBtns } from 'components/Manifest/ActionBtns/ManifestActionBtns';
import { AdditionalInfoForm } from 'components/Manifest/AdditionalInfo';
import { UpdateRcra } from 'components/Manifest/UpdateRcra/UpdateRcra';
import { WasteLine } from 'components/Manifest/WasteLine/wasteLineSchema';
Expand All @@ -9,6 +10,7 @@ import React, { createContext, useEffect, useState } from 'react';
import { Alert, Button, Col, Container, Form, Row, Stack } from 'react-bootstrap';
import { FormProvider, SubmitHandler, useFieldArray, useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify';
import { manifest } from 'services';
import {
selectHaztrakSiteEpaIds,
Expand All @@ -22,8 +24,6 @@ import { Manifest, manifestSchema, ManifestStatus } from './manifestSchema';
import { QuickerSignData, QuickerSignModal, QuickSignBtn } from './QuickerSign';
import { Transporter, TransporterTable } from './Transporter';
import { EditWasteModal, WasteLineTable } from './WasteLine';
import { toast } from 'react-toastify';
import { ManifestActionBtns } from 'components/Manifest/ActionBtns/ManifestActionBtns';

const defaultValues: Manifest = {
transporters: [],
Expand Down Expand Up @@ -191,9 +191,7 @@ export function ManifestForm({

const nextSigner = manifest.getNextSigner(manifestData);
const userSiteIds = useAppSelector(selectHaztrakSiteEpaIds);
console.log('userSiteIds', userSiteIds);
console.log('nextSigner', nextSigner);

// Whether the user has permissions and manifest is in a state to be signed
const signAble = userSiteIds.includes(nextSigner ?? '');

const isDraft = manifestData?.manifestTrackingNumber === undefined;
Expand Down Expand Up @@ -606,7 +604,7 @@ export function ManifestForm({
</Stack>
<ManifestActionBtns
manifestStatus={manifestStatus}
readonly={readOnly}
readOnly={readOnly}
signAble={signAble}
/>
</HtForm>
Expand Down
Loading

0 comments on commit 5a63be3

Please sign in to comment.