Skip to content

Commit

Permalink
CE-798 - Mobile Refactor for Attachments Interfaces (#482)
Browse files Browse the repository at this point in the history
Co-authored-by: afwilcox <[email protected]>
  • Loading branch information
jeznorth and afwilcox authored Jun 24, 2024
1 parent a61a4df commit b6cd859
Show file tree
Hide file tree
Showing 8 changed files with 252 additions and 194 deletions.
4 changes: 2 additions & 2 deletions frontend/cypress/e2e/complaint-attachments.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ describe("Complaint Attachments", () => {
}

// should be able to upload on details view
cy.get("button.coms-carousel-upload-container").should("exist");
cy.get("button.comp-attachment-upload-btn").should("exist");
});
});

it("Verifies that upload option exists on the create page", () => {
cy.navigateToCreateScreen();
cy.get("button.coms-carousel-upload-container").should("exist");
cy.get("button.comp-attachment-upload-btn").should("exist");
});
});
13 changes: 4 additions & 9 deletions frontend/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,20 +178,15 @@ Cypress.Commands.add("verifyAttachmentsCarousel", (uploadable: boolean, divId: s
cy.get("h3").contains("attachments");

// verify the carousel exists (since 23-000076, 23-006888 are known to have attachments)
cy.get("div.carousel.coms-carousel").should("exist");

// verify that the previous/next buttons exist (but not visibe)
cy.get('button[aria-label="previous"]').should("exist").and("not.be.visible");

cy.get('button[aria-label="next"]').should("exist").and("not.be.visible");
cy.get("div.comp-carousel").should("exist");

if (!uploadable) {
cy.get("button.coms-carousel-upload-container").should("not.exist");
cy.get("button.comp-attachment-upload-btn").should("not.exist");

cy.get(".coms-carousel-actions").first().invoke("attr", "style", "display: block");
cy.get(".comp-attachment-slide-actions").first().invoke("attr", "style", "display: block");

// cypress can't verify things that happen in other tabs, so don't open attachments in another tab
cy.get(".download-icon").should("exist");
cy.get(".comp-slide-download-btn").should("exist");
}
});
});
Expand Down
38 changes: 22 additions & 16 deletions frontend/src/app/components/common/attachment-slide.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import "pure-react-carousel/dist/react-carousel.es.css";
import { useAppDispatch } from "../../hooks/hooks";
import { generateApiParameters, get } from "../../common/api";
import { formatDateTime } from "../../common/methods";
import { BsCloudDownload, BsTrash } from "react-icons/bs";
import { COMSObject } from "../../types/coms/object";
import config from "../../../config";
import AttachmentIcon from "./attachment-icon";
import { Button } from "react-bootstrap";

type Props = {
index: number;
Expand Down Expand Up @@ -38,9 +38,9 @@ export const AttachmentSlide: FC<Props> = ({ index, attachment, allowDelete, onF
let className = "";

if (attachment.errorMesage) {
className = "error-slide";
className = "comp-attachment-slide-error";
} else if (attachment.pendingUpload) {
className = "pending-slide";
className = "comp-attachment-slide-pending";
}

return className;
Expand All @@ -51,35 +51,41 @@ export const AttachmentSlide: FC<Props> = ({ index, attachment, allowDelete, onF
index={index}
key={index}
>
<div className={`coms-carousel-slide ${getSlideClass()}`}>
<div className="coms-carousel-actions">
<div className={`comp-attachment-slide ${getSlideClass()}`}>
<div className="comp-attachment-slide-actions">
{!attachment.pendingUpload && (
<BsCloudDownload
<Button
variant="light"
className="icon-btn comp-slide-download-btn"
tabIndex={index}
className="download-icon"
onClick={() => handleAttachmentClick(`${attachment.id}`, `${attachment.name}`)}
/>
>
<i className="bi bi-cloud-arrow-down"></i>
</Button>
)}
{allowDelete && (
<BsTrash
className="delete-icon"
<Button
variant="light"
className="icon-btn"
tabIndex={index}
onClick={() => onFileRemove(attachment)}
/>
>
<i className="bi bi-trash3"></i>
</Button>
)}
</div>
<div className="top-section">
<div className="comp-attachment-slide-top">
<AttachmentIcon
filename={attachment.name}
imageIconString={attachment.imageIconString}
/>
</div>
<div className="bottom-section">
<div className="slide_text slide_file_name">{decodeURIComponent(attachment.name)}</div>
<div className="comp-attachment-slide-bottom">
<div className="comp-attachment-slide-name">{decodeURIComponent(attachment.name)}</div>
{attachment?.pendingUpload && attachment?.errorMesage ? (
<div>{attachment?.errorMesage}</div>
<div className="comp-attachment-slide-meta">{attachment?.errorMesage}</div>
) : (
<div className="slide_text">
<div className="comp-attachment-slide-meta">
{attachment?.pendingUpload
? "Save to upload attachment(s)"
: formatDateTime(attachment.createdAt?.toString())}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/components/common/attachment-upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const AttachmentUpload: FC<Props> = ({ onFileSelect }) => {
style={{ display: "none" }}
/>
<button
className="coms-carousel-upload-container"
className="comp-attachment-upload-btn"
tabIndex={0}
onClick={handleDivClick}
>
Expand Down
18 changes: 4 additions & 14 deletions frontend/src/app/components/common/attachments-carousel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FC, useEffect, useState, useRef } from "react";
import { CarouselProvider, Slider, ButtonBack, ButtonNext } from "pure-react-carousel";
import { CarouselProvider, Slider } from "pure-react-carousel";
import "pure-react-carousel/dist/react-carousel.es.css";
import { useAppDispatch, useAppSelector } from "../../hooks/hooks";
import {
Expand All @@ -8,7 +8,6 @@ import {
setAttachments,
setOutcomeAttachments,
} from "../../store/reducers/attachments";
import { BsArrowLeftShort, BsArrowRightShort } from "react-icons/bs";
import { AttachmentSlide } from "./attachment-slide";
import { AttachmentUpload } from "./attachment-upload";
import { COMSObject } from "../../types/coms/object";
Expand Down Expand Up @@ -203,26 +202,17 @@ export const AttachmentsCarousel: FC<Props> = ({
}, [allowUpload]);

return (
<div
className="comp-complaint-details-block"
ref={carouselContainerRef}
>
<div ref={carouselContainerRef}>
{(allowUpload || (slides && slides?.length > 0)) && (
<CarouselProvider
naturalSlideWidth={SLIDE_WIDTH}
naturalSlideHeight={SLIDE_HEIGHT}
totalSlides={slides ? slides.length : 0}
visibleSlides={visibleSlides}
className="coms-carousel"
className="comp-carousel"
>
<ButtonBack className="back-icon">
<BsArrowLeftShort />
</ButtonBack>
<ButtonNext className="next-icon">
<BsArrowRightShort />
</ButtonNext>
{allowUpload && <AttachmentUpload onFileSelect={onFileSelect} />}
<Slider className="coms-slider">
{allowUpload && <AttachmentUpload onFileSelect={onFileSelect} />}
{slides?.map((item, index) => (
<AttachmentSlide
key={item.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,7 @@ export const ComplaintDetailsEdit: FC = () => {
{/* Attachments */}
<fieldset>
<legend>Complainant attachments ({complaintAttachmentCount})</legend>
<div className="comp-details-attachments">
<div>
<AttachmentsCarousel
attachmentType={AttachmentEnum.COMPLAINT_ATTACHMENT}
complaintIdentifier={id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import { useAppDispatch, useAppSelector } from "../../../../hooks/hooks";
import { ToggleError } from "../../../../common/toast";
import { openModal } from "../../../../store/reducers/app";
import { useParams } from "react-router-dom";
import { Button } from "react-bootstrap";
import { Button, Card } from "react-bootstrap";
import AttachmentEnum from "../../../../constants/attachment-enum";
import { clearAttachments, getAttachments, selectAttachments } from "../../../../store/reducers/attachments";
import { CompTextIconButton } from "../../../common/comp-text-icon-button";
import { BsExclamationCircleFill, BsPencil } from "react-icons/bs";
import { BsExclamationCircleFill } from "react-icons/bs";
import { setIsInEdit } from "../../../../store/reducers/cases";

export const HWCRFileAttachments: FC = () => {
Expand Down Expand Up @@ -141,77 +140,70 @@ export const HWCRFileAttachments: FC = () => {
};

return (
<div
className="comp-outcome-report-block"
<section
className="comp-details-section"
id="outcome-attachments"
>
<h3>Outcome attachments ({outcomeAttachmentCount})</h3>
{showSectionErrors && (
<div className="section-error-message">
<BsExclamationCircleFill />
<span>Save section before closing the complaint.</span>
</div>
)}
<div className={`comp-outcome-report-complaint-attachments ${showSectionErrors ? "section-error" : ""}`}>
<div className="comp-details-edit-container">
<div
className="comp-details-edit-column"
style={{ marginRight: "0px" }}
>
<AttachmentsCarousel
attachmentType={AttachmentEnum.OUTCOME_ATTACHMENT}
complaintIdentifier={id}
allowUpload={componentState === EDIT_STATE}
allowDelete={componentState === EDIT_STATE}
cancelPendingUpload={cancelPendingUpload}
setCancelPendingUpload={setCancelPendingUpload}
onFilesSelected={onHandleAddAttachments}
onFileDeleted={onHandleDeleteAttachment}
onSlideCountChange={handleSlideCountChange}
/>
</div>
{componentState === DISPLAY_STATE && (
<div
className="comp-details-right-column"
style={{ marginTop: "24px" }}
<div className="comp-details-section-header">
<h3>Outcome attachments ({outcomeAttachmentCount})</h3>

{componentState === DISPLAY_STATE && (
<div className="comp-details-section-header-actions">
<Button
variant="outline-primary"
size="sm"
onClick={(e) => {
setComponentState(EDIT_STATE);
}}
>
<CompTextIconButton
buttonClasses="button-text"
text="Edit"
icon={BsPencil}
click={(e) => {
setComponentState(EDIT_STATE);
}}
/>
<i className="bi bi-pencil"></i>
<span>Edit</span>
</Button>
</div>
)}
</div>

<Card border={showSectionErrors ? "danger" : "default"}>
<Card.Body>
{showSectionErrors && (
<div className="section-error-message mb-4">
<BsExclamationCircleFill />
<span>Save section before closing the complaint.</span>
</div>
)}
</div>
{componentState === EDIT_STATE && (
<div
className="comp-outcome-report-container"
style={{ marginBottom: "24px" }}
>
<div className="comp-outcome-report-actions">
<AttachmentsCarousel
attachmentType={AttachmentEnum.OUTCOME_ATTACHMENT}
complaintIdentifier={id}
allowUpload={componentState === EDIT_STATE}
allowDelete={componentState === EDIT_STATE}
cancelPendingUpload={cancelPendingUpload}
setCancelPendingUpload={setCancelPendingUpload}
onFilesSelected={onHandleAddAttachments}
onFileDeleted={onHandleDeleteAttachment}
onSlideCountChange={handleSlideCountChange}
/>
{componentState === EDIT_STATE && (
<div className="comp-details-form-buttons">
<Button
variant="outline-primary"
id="outcome-cancel-button"
title="Cancel Outcome"
className="comp-outcome-cancel"
onClick={cancelButtonClick}
>
Cancel
</Button>
<Button
variant="primary"
id="outcome-save-button"
title="Save Outcome"
className="comp-outcome-save"
onClick={saveButtonClick}
>
Save
</Button>
</div>
</div>
)}
</div>
</div>
)}
</Card.Body>
</Card>
</section>
);
};
Loading

0 comments on commit b6cd859

Please sign in to comment.