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

CBIIT / crdc-datahub-ui / 24157199810

08 Apr 2026 08:31PM UTC coverage: 82.981% (-0.1%) from 83.116%
24157199810

push

github

web-flow
Merge pull request #976 from CBIIT/CRDCDH-3615

CRDCDH-3615 Expand SRF Review Comment Dialog

5896 of 6467 branches covered (91.17%)

Branch coverage included in aggregate %.

160 of 226 new or added lines in 2 files covered. (70.8%)

5 existing lines in 2 files now uncovered.

34823 of 42603 relevant lines covered (81.74%)

236.85 hits per line

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

95.51
/src/components/Questionnaire/ReviewFormDialog.tsx
1
import { LoadingButton } from "@mui/lab";
1✔
2
import { Box, Button, ButtonProps, DialogProps, Typography, styled } from "@mui/material";
1✔
3
import { isEqual } from "lodash";
1✔
4
import { FC, ReactNode, memo, useMemo } from "react";
1✔
5
import { Controller, useForm } from "react-hook-form";
1✔
6

7
import Dialog from "../GenericDialog";
1✔
8
import StyledHelperText from "../StyledFormComponents/StyledHelperText";
1✔
9
import BaseOutlinedInput from "../StyledFormComponents/StyledOutlinedInput";
1✔
10

11
const StyledOutlinedInput = styled(BaseOutlinedInput)({
1✔
12
  marginTop: "24px",
1✔
13
  width: "fit-content",
1✔
14
  maxWidth: "100%",
1✔
15
  "&.MuiInputBase-multiline": {
1✔
16
    padding: "12px",
1✔
17
    alignItems: "flex-start",
1✔
18
  },
1✔
19
  "& textarea.MuiInputBase-inputMultiline": {
1✔
20
    resize: "both",
1✔
21
    overflow: "auto !important",
1✔
22
    padding: 0,
1✔
23
    lineHeight: "25px",
1✔
24
    width: "min(600px, calc(100vw - 150px))",
1✔
25
    minWidth: "min(750px, calc(100vw - 150px))",
1✔
26
    maxWidth: "min(1440px, 80vw)",
1✔
27
    height: "min(375px, calc(100vh - 340px))",
1✔
28
    minHeight: "clamp(100px, calc(100vh - 340px), 375px)",
1✔
29
    maxHeight: "min(500px, calc(100vh - 340px))",
1✔
30
    boxSizing: "border-box",
1✔
31
  },
1✔
32
});
1✔
33

34
const StyledCharacterCount = styled(Box)({
1✔
35
  display: "flex",
1✔
36
  justifyContent: "flex-end",
1✔
37
  alignItems: "flex-start",
1✔
38
  gap: "8px",
1✔
39
  marginTop: "4px",
1✔
40
  width: 0,
1✔
41
  minWidth: "100%",
1✔
42
  overflow: "hidden",
1✔
43
});
1✔
44

45
const StyledErrorText = styled(StyledHelperText)({
1✔
46
  marginTop: 0,
1✔
47
  flex: 1,
1✔
48
  minWidth: 0,
1✔
49
  wordBreak: "break-word",
1✔
50
});
1✔
51

52
const StyledCountLabel = styled(Typography)({
1✔
53
  fontSize: "12px",
1✔
54
  lineHeight: "20px",
1✔
55
  whiteSpace: "nowrap",
1✔
56
});
1✔
57

58
const StyledDialog = styled(Dialog)({
1✔
59
  "& .MuiDialog-paper": {
1✔
60
    width: "fit-content",
1✔
61
    maxWidth: "calc(100% - 64px)",
1✔
62
    maxHeight: "calc(100vh - 64px)",
1✔
63
    borderRadius: "8px",
1✔
64
    "& .MuiDialogContent-root": {
1✔
65
      overflow: "hidden",
1✔
66
    },
1✔
67
  },
1✔
68
});
1✔
69

70
const MAX_REVIEW_COMMENT_LIMIT = 10_000;
1✔
71

72
type ReviewFormFields = {
73
  reviewComment: string;
74
};
75

76
type Props = {
77
  header?: string;
78
  confirmText?: string;
79
  confirmButtonProps?: Omit<ButtonProps, "children" | "onClick">;
80
  loading?: boolean;
81
  onCancel?: () => void;
82
  onSubmit?: (reviewComment: string) => void;
83
  children?: ReactNode;
84
} & Omit<DialogProps, "onClose" | "onSubmit" | "children" | "title">;
85

86
const ReviewFormDialog: FC<Props> = ({
1✔
87
  open,
65✔
88
  header,
65✔
89
  confirmText = "Confirm",
65✔
90
  confirmButtonProps = {},
65✔
91
  loading,
65✔
92
  onCancel,
65✔
93
  onSubmit,
65✔
94
  children,
65✔
95
  ...rest
65✔
96
}) => {
65✔
97
  const {
65✔
98
    handleSubmit,
65✔
99
    watch,
65✔
100
    control,
65✔
101
    reset,
65✔
102
    formState: { errors },
65✔
103
  } = useForm<ReviewFormFields>({
65✔
104
    mode: "onSubmit",
65✔
105
    reValidateMode: "onSubmit",
65✔
106
    defaultValues: {
65✔
107
      reviewComment: "",
65✔
108
    },
65✔
109
  });
65✔
110

111
  const reviewComment = watch("reviewComment");
65✔
112
  const reviewCommentLengthLabel = useMemo(
65✔
113
    () =>
65✔
114
      Intl.NumberFormat("en-US", { maximumFractionDigits: 0 }).format(reviewComment?.length || 0),
59✔
115
    [reviewComment]
65✔
116
  );
65✔
117
  const reviewCommentLimitLabel = Intl.NumberFormat("en-US", {
65✔
118
    maximumFractionDigits: 0,
65✔
119
  }).format(MAX_REVIEW_COMMENT_LIMIT);
65✔
120

121
  const handleOnSubmit = (data: ReviewFormFields) => {
65✔
122
    onSubmit?.(data.reviewComment);
2✔
123
  };
2✔
124

125
  const handleOnCancel = () => {
65✔
126
    onCancel?.();
2✔
127
  };
2✔
128

129
  return (
65✔
130
    <StyledDialog
65✔
131
      open={open}
65✔
132
      onClose={handleOnCancel}
65✔
133
      TransitionProps={{ onExited: () => reset() }}
65✔
134
      title={header}
65✔
135
      scroll="body"
65✔
136
      actions={
65✔
137
        <>
65✔
138
          <Button
65✔
139
            data-testid="review-form-dialog-cancel-button"
65✔
140
            onClick={handleOnCancel}
65✔
141
            disabled={loading}
65✔
142
          >
143
            Cancel
144
          </Button>
65✔
145
          <LoadingButton
65✔
146
            data-testid="review-form-dialog-confirm-button"
65✔
147
            onClick={handleSubmit(handleOnSubmit)}
65✔
148
            disabled={!reviewComment?.trim()?.length || loading}
65✔
149
            loading={loading}
65✔
150
            {...confirmButtonProps}
65✔
151
          >
152
            {confirmText}
65✔
153
          </LoadingButton>
65✔
154
        </>
65✔
155
      }
156
      {...rest}
65✔
157
    >
158
      <Controller
65✔
159
        name="reviewComment"
65✔
160
        control={control}
65✔
161
        rules={{
65✔
162
          validate: {
65✔
163
            required: (v: string) => v.trim() !== "" || "This field is required",
65!
164
            maxLength: (v: string) =>
65✔
165
              v.trim().length <= MAX_REVIEW_COMMENT_LIMIT ||
2!
NEW
166
              `Maximum of ${reviewCommentLimitLabel} characters allowed`,
×
167
          },
65✔
168
        }}
65✔
169
        render={({ field }) => (
65✔
170
          <StyledOutlinedInput
64✔
171
            {...field}
64✔
172
            inputProps={{
64✔
173
              maxLength: MAX_REVIEW_COMMENT_LIMIT,
64✔
174
              "aria-label": "Review comment input",
64✔
175
            }}
64✔
176
            name="reviewComment"
64✔
177
            placeholder={`${reviewCommentLimitLabel} characters allowed`}
64✔
178
            data-testid="review-comment"
64✔
179
            sx={{ paddingY: "16px" }}
64✔
180
            required
64✔
181
            multiline
64✔
182
          />
183
        )}
65✔
184
      />
185

186
      <StyledCharacterCount>
65✔
187
        {errors?.reviewComment?.message?.length > 0 && (
65!
NEW
188
          <StyledErrorText data-testid="review-comment-dialog-error">
×
NEW
189
            {errors.reviewComment.message}
×
NEW
190
          </StyledErrorText>
×
191
        )}
192
        <StyledCountLabel data-testid="review-comment-character-count">
65✔
193
          {reviewCommentLengthLabel} / {reviewCommentLimitLabel}
65✔
194
        </StyledCountLabel>
65✔
195
      </StyledCharacterCount>
65✔
196

197
      {children}
65✔
198
    </StyledDialog>
65✔
199
  );
200
};
65✔
201

202
export default memo<Props>(ReviewFormDialog, isEqual);
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

© 2026 Coveralls, Inc