Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

* @mdragon # project lead

/documentation/ @andycochran @btabaska @chouinar @doug-s-nava @joshtonava @mdragon @myduong-navapbc @widal001 @prasnava @jakobpederson @ErinPattisonNava # everyone
/documentation/ @andycochran @btabaska @chouinar @doug-s-nava @joshtonava @mdragon @myduong-navapbc @widal001 @prasnava @jakobpederson @ErinPattisonNava @glenblosser-nava # everyone

/analytics/ @widal001
/documentation/analytics/ @widal001

/api/ @chouinar @mdragon @joshtonava @jakobpederson
/documentation/api/ @chouinar @mdragon @joshtonava @jakobpederson

/frontend/ @andycochran @btabaska @doug-s-nava @myduong-navapbc @ErinPattisonNava
/frontend/ @andycochran @btabaska @doug-s-nava @myduong-navapbc @ErinPattisonNava @glenblosser-nava
/documentation/frontend/ @andycochran @btabaska @doug-s-nava @myduong-navapbc @ErinPattisonNava

/infra/ @mdragon @joshtonava @chouinar @prasnava @sean-navapbc
Expand Down
2 changes: 2 additions & 0 deletions MAINTAINERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This is a list of maintainers for this project. See [CODEOWNERS](/.github/CODEOW
* Prasanthreddy Arikatla
* Jakob Pederson
* Erin Pattison
* Glen Blosser

## Content and Design

Expand Down Expand Up @@ -47,5 +48,6 @@ This is a list of maintainers for this project. See [CODEOWNERS](/.github/CODEOW
* Chris Kuryak
* Eric Serrato
* Glenn Grieves
* Brian Lee


Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Metadata } from "next";
import TopLevelError from "src/app/[locale]/(base)/error/page";
import NotFound from "src/app/[locale]/(base)/not-found";
import { getSession } from "src/services/auth/session";
import withFeatureFlag from "src/services/featureFlags/withFeatureFlag";
import { getApplicationDetails } from "src/services/fetch/fetchers/applicationFetcher";
import getFormData from "src/utils/getFormData";

import { redirect } from "next/navigation";
Expand Down Expand Up @@ -43,6 +45,24 @@ interface formPageProps {
async function FormPage({ params }: formPageProps) {
const { applicationId, appFormId } = await params;
const { data, error } = await getFormData({ applicationId, appFormId });
const userSession = await getSession();

if (!userSession || !userSession.token) {
return <TopLevelError />;
}
const response = await getApplicationDetails(
applicationId,
userSession?.token,
);

if (response.status_code !== 200) {
console.error(
`Error retrieving application details for (${applicationId})`,
response,
);
return <TopLevelError />;
}
const { application_status } = response.data;

if (error || !data) {
if (error === "UnauthorizedError") return redirect("/unauthenticated");
Expand Down Expand Up @@ -98,6 +118,7 @@ async function FormPage({ params }: formPageProps) {
formId={formId}
attachments={applicationAttachments}
isBudgetForm={isBudgetForm}
applicationStatus={application_status}
/>
</GridContainer>
</>
Expand Down
37 changes: 23 additions & 14 deletions frontend/src/components/applyForm/ApplyForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const ApplyForm = ({
uiSchema,
attachments,
isBudgetForm = false,
applicationStatus,
}: {
applicationId: string;
formId: string;
Expand All @@ -65,10 +66,12 @@ const ApplyForm = ({
| null;
attachments: Attachment[];
isBudgetForm?: boolean;
applicationStatus?: string;
}) => {
const { pending } = useFormStatus();
const t = useTranslations("Application.applyForm");
const translate = t as unknown as Translator;
const isFormLocked = applicationStatus !== "in_progress";
const required = translate.rich("required", {
abr: (content) => (
<abbr
Expand Down Expand Up @@ -100,7 +103,10 @@ const ApplyForm = ({

const { error, saved } = formState;

const formObject = savedFormData || new FormData();
const formObject = useMemo(
() => savedFormData || new FormData(),
[savedFormData],
);
const navFields = useMemo(() => getFieldsForNav(uiSchema), [uiSchema]);
const formContextValue = useMemo<ApplyFormFormContext>(
() => ({
Expand Down Expand Up @@ -131,19 +137,21 @@ const ApplyForm = ({
>
<div className="display-flex flex-justify">
<div>{required}</div>
<Button
data-testid="apply-form-save"
type="submit"
name="apply-form-button"
className="margin-top-0"
value="save"
onClick={() => {
setFormChanged(false);
setAttachmentsChanged(false);
}}
>
{pending ? "Saving..." : "Save"}
</Button>
{!isFormLocked && (
<Button
data-testid="apply-form-save"
type="submit"
name="apply-form-button"
className="margin-top-0"
value="save"
onClick={() => {
setFormChanged(false);
setAttachmentsChanged(false);
}}
>
{pending ? "Saving..." : "Save"}
</Button>
)}
</div>
<div className="usa-in-page-nav-container">
<FormGroup className="order-2 width-full">
Expand All @@ -163,6 +171,7 @@ const ApplyForm = ({
schema={formSchema}
uiSchema={uiSchema}
formContext={formContextValue}
isFormLocked={isFormLocked}
/>
</AttachmentsProvider>
</FormGroup>
Expand Down
14 changes: 12 additions & 2 deletions frontend/src/components/applyForm/FormFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ export const FormFields = ({
schema,
uiSchema,
formContext,
isFormLocked,
}: {
errors: FormattedFormValidationWarning[] | null;
formData: object;
schema: RJSFSchema;
uiSchema: UiSchema;
formContext?: RootBudgetFormContext;
isFormLocked?: boolean;
}) => {
try {
let acc: JSX.Element[] = [];
Expand Down Expand Up @@ -81,7 +83,11 @@ export const FormFields = ({

const field = renderWidget({
type: widgetConfig.type,
props: { ...widgetConfig.props, formContext },
props: {
...widgetConfig.props,
formContext,
isFormLocked,
},
definition: node.definition,
});

Expand Down Expand Up @@ -120,7 +126,11 @@ export const FormFields = ({

return renderWidget({
type: widgetConfig.type,
props: { ...widgetConfig.props, formContext },
props: {
...widgetConfig.props,
formContext,
isFormLocked,
},
definition: node.definition,
});
}
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/applyForm/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ export interface UswdsWidgetProps<
maxLength?: number;
required?: boolean;
disabled?: boolean;
readonly?: boolean;
readOnly?: boolean;
isFormLocked?: boolean;
hideError?: boolean;
autofocus?: boolean;
placeholder?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const AttachmentUploadWidget = (props: UswdsWidgetProps) => {
rawErrors = [],
disabled,
options,
readOnly,
} = props;
const { contentMediaType, title, description } = schema;

Expand Down Expand Up @@ -80,7 +81,7 @@ const AttachmentUploadWidget = (props: UswdsWidgetProps) => {
deleteModalRef.current?.toggleModal();
setAttachmentsChanged(true);
}
}, [deleteState, onChange]);
}, [deleteState, onChange, setAttachmentsChanged]);

useEffect(() => {
const newAttachmentId = typeof value === "string" ? value : null;
Expand Down Expand Up @@ -143,6 +144,7 @@ const AttachmentUploadWidget = (props: UswdsWidgetProps) => {
name={id}
required={required}
disabled={disabled}
readOnly={readOnly}
ref={fileInputRef}
onChange={(e) => {
handleChange(e).catch((error) => console.error(error));
Expand All @@ -159,6 +161,7 @@ const AttachmentUploadWidget = (props: UswdsWidgetProps) => {
<Button
type="button"
unstyled
disabled={disabled}
onClick={handleDeleteClick}
className="margin-left-1"
>
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/applyForm/widgets/CheckboxWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function CheckboxWidget<
options,
value,
required,
readonly,
readOnly,
schema,
autofocus = false,
rawErrors = [],
Expand Down Expand Up @@ -88,7 +88,8 @@ function CheckboxWidget<
value="true"
defaultChecked={Boolean(value)}
required={required}
disabled={disabled || readonly}
disabled={disabled}
readOnly={readOnly}
autoFocus={autofocus}
onChange={handleChange}
onBlur={handleBlur}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import { UploadedFile } from "src/components/applyForm/types";
interface Props {
handleRemove: (index: number) => void;
uploadedFiles: UploadedFile[];
readOnly?: boolean;
}

export const MultipleAttachmentUploadList = ({
handleRemove,
uploadedFiles,
readOnly,
}: Props) => {
const { attachments } = useApplicationAttachments();
return (
Expand Down Expand Up @@ -45,6 +47,7 @@ export const MultipleAttachmentUploadList = ({
)}
<button
type="button"
disabled={readOnly}
className="usa-button usa-button--unstyled text-primary margin-left-2 display-inline-flex align-items-center"
onClick={() => handleRemove(index)}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default function MultiSelect<
>({
id,
disabled,
readonly,
readOnly,
required,
schema,
value,
Expand Down Expand Up @@ -162,7 +162,7 @@ export default function MultiSelect<
id={`${id}__combobox`}
name={`${id}__combobox_input`}
options={availableOptions}
disabled={disabled || readonly || atMaxSelection}
disabled={disabled || readOnly || atMaxSelection}
onChange={(val?: string) => {
if (!val) return;
addByLabelOrValue(val);
Expand Down Expand Up @@ -198,7 +198,7 @@ export default function MultiSelect<
<Pill
label={label}
onClose={() => {
if (disabled || readonly) return;
if (disabled || readOnly) return;
removeValue(v);
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const MultipleAttachmentUploadWidget = ({
rawErrors = [],
schema,
onChange,
readOnly,
disabled,
}: UswdsWidgetProps) => {
const { description, options, title } = schema as SchemaWithLabelOption;

Expand Down Expand Up @@ -179,6 +181,7 @@ const MultipleAttachmentUploadWidget = ({
id={id}
name={id}
ref={fileInputRef}
disabled={disabled}
type="file"
multiple
className="usa-file-input__input"
Expand All @@ -200,6 +203,7 @@ const MultipleAttachmentUploadWidget = ({
<MultipleAttachmentUploadList
uploadedFiles={uploadedFiles}
handleRemove={(index) => handleRemove(index)}
readOnly={disabled || readOnly}
/>
)}

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/applyForm/widgets/RadioWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default function RadioWidget<
options = {},
schema,
required,
readonly,
readOnly,
value,
autofocus = false,
rawErrors = [],
Expand Down Expand Up @@ -168,7 +168,7 @@ export default function RadioWidget<
key={optionId(id, index)}
name={id}
required={required}
disabled={disabled || itemDisabled || readonly}
disabled={disabled || itemDisabled || readOnly}
autoFocus={autofocus && index === 0}
aria-describedby={describedby}
checked={updateOnInput ? checked : undefined}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/applyForm/widgets/SelectWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function SelectWidget<
id,
disabled,
options = {},
readonly,
readOnly,
required,
schema,
value,
Expand Down Expand Up @@ -143,7 +143,7 @@ function SelectWidget<
defaultValue={updateOnInput ? undefined : selectValue}
value={updateOnInput ? selectValue : undefined}
required={required}
disabled={disabled || readonly}
disabled={disabled || readOnly}
autoFocus={autofocus}
onChange={updateOnInput ? handleChange : noop}
onBlur={updateOnInput ? handleBlur : undefined}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/applyForm/widgets/TextAreaWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function TextAreaWidget<
id,
disabled,
required,
readonly,
readOnly,
schema,
value,
autofocus = false,
Expand Down Expand Up @@ -84,7 +84,7 @@ function TextAreaWidget<
// update to let form validation happen on the updateOnInput
aria-required={required}
disabled={disabled}
readOnly={readonly}
readOnly={readOnly}
onChange={updateOnInput ? handleChange : undefined}
onBlur={updateOnInput ? handleBlur : undefined}
onFocus={updateOnInput ? handleFocus : undefined}
Expand Down
Loading