• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CBIIT / crdc-datahub-ui / 17132131774

21 Aug 2025 03:52PM UTC coverage: 77.592% (+1.7%) from 75.941%
17132131774

Pull #806

github

web-flow
Merge 6b88b37d9 into c10ceac73
Pull Request #806: Submission Request Excel Import & Export CRDCDH-3033, CRDCDH-3045, CRDCDH-3063

4841 of 5322 branches covered (90.96%)

Branch coverage included in aggregate %.

3122 of 3394 new or added lines in 32 files covered. (91.99%)

7 existing lines in 3 files now uncovered.

28996 of 38287 relevant lines covered (75.73%)

1856.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.59
/src/components/ImportApplicationButton/index.tsx
1
import { Button, ButtonProps, Stack, styled, Typography } from "@mui/material";
1✔
2
import { useState } from "react";
1✔
3

4
import ImportIconSvg from "@/assets/icons/import_icon.svg?react";
1✔
5
import useFormMode from "@/hooks/useFormMode";
1✔
6
import { Logger } from "@/utils";
1✔
7

8
import { useFormContext } from "../Contexts/FormContext";
1✔
9
import StyledFormTooltip from "../StyledFormComponents/StyledTooltip";
1✔
10

11
import ImportDialog from "./ImportDialog";
1✔
12

13
const StyledImportIcon = styled(ImportIconSvg)({
1✔
14
  width: "27px",
1✔
15
  display: "flex",
1✔
16
  alignItems: "center",
1✔
17
  justifyContent: "center",
1✔
18
  marginRight: "16px",
1✔
19
  color: "currentColor",
1✔
20
});
1✔
21

22
const StyledText = styled(Typography)({
1✔
23
  fontFamily: "'Nunito Sans', 'Rubik', sans-serif",
1✔
24
  letterSpacing: "-0.25px",
1✔
25
  fontWeight: 600,
1✔
26
  fontSize: "16px",
1✔
27
  lineHeight: "150%",
1✔
28
  color: "inherit",
1✔
29
  paddingLeft: "14px",
1✔
30
});
1✔
31

32
const StyledStack = styled(Stack)({
1✔
33
  margin: "0 !important",
1✔
34
  width: "100%",
1✔
35
});
1✔
36

37
const StyledImportButton = styled(Button)({
1✔
38
  justifyContent: "flex-start",
1✔
39
  padding: "12px 14px",
1✔
40
  marginRight: "auto",
1✔
41
  color: "#136071",
1✔
42
  "&:hover": {
1✔
43
    color: "#00819E",
1✔
44
    background: "transparent",
1✔
45
  },
1✔
46
  "&.Mui-disabled": {
1✔
47
    color: "#BBBBBB",
1✔
48
    opacity: 1,
1✔
49
  },
1✔
50
  "& .MuiButton-startIcon": {
1✔
51
    marginRight: "0px !important",
1✔
52
  },
1✔
53
});
1✔
54

55
const StyledTooltip = styled(StyledFormTooltip)({
1✔
56
  marginLeft: "0 !important",
1✔
57
  "& .MuiTooltip-tooltip": {
1✔
58
    color: "#000000",
1✔
59
  },
1✔
60
});
1✔
61

62
const disableImportStatuses: ApplicationStatus[] = [
1✔
63
  "Submitted",
1✔
64
  "Approved",
1✔
65
  "Rejected",
1✔
66
  "Canceled",
1✔
67
  "Deleted",
1✔
68
];
69

70
type Props = Omit<ButtonProps, "onClick">;
71

72
/**
73
 * ImportApplicationButton component for handling the import of application data
74
 * from an Excel file.
75
 *
76
 * @param param Props for the button component.
77
 * @returns JSX.Element
78
 */
79
const ImportApplicationButton = ({ disabled = false, ...rest }: Props) => {
1✔
80
  const { data, setData } = useFormContext();
30✔
81
  const { readOnlyInputs } = useFormMode();
30✔
82
  const [openDialog, setOpenDialog] = useState<boolean>(false);
30✔
83
  const [isUploading, setIsUploading] = useState<boolean>(false);
30✔
84
  const shouldDisable = disabled || disableImportStatuses.includes(data?.status) || readOnlyInputs;
30✔
85

86
  /**
87
   * Triggers the file input dialog.
88
   *
89
   * @returns void
90
   */
91
  const onImportClick = () => {
30✔
92
    if (shouldDisable) {
4!
NEW
93
      return;
×
NEW
94
    }
×
95

96
    setOpenDialog(true);
4✔
97
  };
4✔
98

99
  /**
100
   * Handles the import of the selected file and uses middleware
101
   * to parse only the valid values from the Excel file. Finally,
102
   * it updates the form data to the new imported data.
103
   *
104
   * @param file The file to import.
105
   * @returns void
106
   */
107
  const handleImport = async (file: File) => {
30✔
108
    if (!file) {
2!
NEW
109
      return;
×
NEW
110
    }
×
111

112
    setIsUploading(true);
2✔
113
    const { QuestionnaireExcelMiddleware } = await import("@/classes/QuestionnaireExcelMiddleware");
2✔
114

115
    // Add the file back to a FileList
116
    const dataTransfer = new DataTransfer();
2✔
117
    dataTransfer?.items?.add(file);
2✔
118

119
    const dataTransferFile = dataTransfer?.files?.[0];
2✔
120
    if (typeof dataTransferFile?.arrayBuffer !== "function") {
2✔
121
      Logger.error(
1✔
122
        `ImportApplicationButton: File does not have arrayBuffer method`,
1✔
123
        dataTransferFile
1✔
124
      );
1✔
125
      return;
1✔
126
    }
1✔
127

128
    const newData = await QuestionnaireExcelMiddleware.parse(
1✔
129
      await dataTransferFile?.arrayBuffer(),
2✔
130
      {
1✔
131
        application: data,
1✔
132
      }
1✔
133
    );
1✔
134

135
    await setData(newData as QuestionnaireData, { skipSave: true });
1✔
136

137
    setOpenDialog(false);
1✔
138
    setIsUploading(false);
1✔
139
  };
2✔
140

141
  return (
30✔
142
    <>
30✔
143
      <StyledStack direction="row" alignItems="center" justifyContent="center">
30✔
144
        <StyledImportButton
30✔
145
          variant="text"
30✔
146
          onClick={onImportClick}
30✔
147
          disabled={shouldDisable}
30✔
148
          startIcon={<StyledImportIcon />}
30✔
149
          aria-label="Import application from Excel button"
30✔
150
          data-testid="import-application-excel-button"
30✔
151
          disableTouchRipple
30✔
152
          {...rest}
30✔
153
        >
154
          <StyledTooltip
30✔
155
            title="Import the Submission Request from Excel."
30✔
156
            placement="top"
30✔
157
            data-testid="import-application-excel-tooltip"
30✔
158
            disableInteractive
30✔
159
            arrow
30✔
160
          >
161
            <StyledText variant="body2" data-testid="import-application-excel-tooltip-text">
30✔
162
              Import
163
            </StyledText>
30✔
164
          </StyledTooltip>
30✔
165
        </StyledImportButton>
30✔
166
      </StyledStack>
30✔
167

168
      <ImportDialog
30✔
169
        open={openDialog}
30✔
170
        onClose={() => setOpenDialog(false)}
30✔
171
        onConfirm={handleImport}
30✔
172
        disabled={isUploading}
30✔
173
      />
174
    </>
30✔
175
  );
176
};
30✔
177

178
export default ImportApplicationButton;
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc