Skip to content

Replace native date input with USWDS DatePicker in budget team requisition#5676

Open
josbell wants to merge 12 commits into
mainfrom
OPS-1639/requisition-fields
Open

Replace native date input with USWDS DatePicker in budget team requisition#5676
josbell wants to merge 12 commits into
mainfrom
OPS-1639/requisition-fields

Conversation

@josbell
Copy link
Copy Markdown
Contributor

@josbell josbell commented May 14, 2026

What changed

Replaced native HTML5 date input with USWDS MemoizedDatePicker component in ReviewBudgetTeamRequisition page. Enhanced date validation and fixed semantic HTML violations to improve accessibility and maintain USWDS compliance.

Key changes:

  • Replaced native <input type="date"> with MemoizedDatePicker following patterns from Procurement Tracker Step Four
  • Added proper date format conversion (MM/DD/YYYY → YYYY-MM-DD) for API submission
  • Enhanced formatDateForApi validation to prevent malformed API payloads from partial/invalid dates
  • Fixed semantic HTML violations (removed unnecessary fieldset wrapper around single input)
  • Used consistent USWDS grid-col-4 for both requisition fields
  • Added proper required field indicators (required and aria-required attributes)
  • Removed fixed width-mobile-lg class from Input component globally

Issue

#1639

How to test

  1. Start the application with Docker: docker compose up --build
  2. Navigate to a pre-award requisition review page
  3. Verify both "Requisition #" and "Requisition Date" fields are properly aligned vertically
  4. Verify both input fields have matching widths (excluding the calendar icon)
  5. Test date picker functionality:
    • Click calendar icon to open date picker
    • Select a date and verify it appears in MM/DD/YYYY format
    • Verify dates in the future are disabled (maxDate validation)
  6. Test form validation:
    • Try submitting without requisition number - should be blocked
    • Try submitting without requisition date - should be blocked
    • Try submitting without attestation checkbox - should be blocked
    • Fill all fields and check attestation - approve button should be enabled
  7. Verify disabled state when requisition already processed

A11y impact

  • Accessibility changes included and validated against WCAG 2.1 AA intent
  • Replaced semantic HTML violations (removed unnecessary fieldset wrapper)
  • Added proper required field indicators with both required and aria-required="true" attributes
  • USWDS DatePicker component follows WCAG 2.1 AA standards

Screenshots

Not applicable - primarily functional changes to form inputs

Definition of Done Checklist

  • OESA: Code refactored for clarity
  • OESA: Dependency rules followed
  • Automated unit tests updated and passed (27/27 tests passing)
  • Automated integration tests updated and passed
  • Automated quality tests updated and passed (ESLint, Prettier)
  • Automated load tests updated and passed
  • Automated a11y tests updated and passed
  • Automated security tests updated and passed (pre-commit hooks passed)
  • 90%+ Code coverage achieved
  • Form validations updated (added date validation to formatDateForApi)

Links

  • Related component: /frontend/src/components/UI/USWDS/DatePicker.jsx
  • Test file: /frontend/src/pages/agreements/pre-award-approval/ReviewBudgetTeamRequisition.test.jsx

josbell and others added 8 commits May 14, 2026 14:12
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…ion field layout

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
… alignment

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…izing

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the pre-award budget team requisition review UI to use the USWDS DatePicker (instead of a native HTML date input) and adjusts date formatting for API submission, alongside a small global input styling change.

Changes:

  • Replace the requisition date field UI with the USWDS DatePicker and update field layout/alignment on ReviewBudgetTeamRequisition.
  • Format requisition dates for API submission via formatDateForApi, and harden that helper against malformed/partial inputs.
  • Update unit tests and remove the width-mobile-lg class from the shared Input component.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
frontend/src/pages/agreements/pre-award-approval/ReviewBudgetTeamRequisition.jsx Swaps requisition date to USWDS DatePicker and adjusts form layout/markup.
frontend/src/pages/agreements/pre-award-approval/ReviewBudgetTeamRequisition.hooks.js Formats requisition date for API submission and wires DatePicker into the page via the hook.
frontend/src/pages/agreements/pre-award-approval/ReviewBudgetTeamRequisition.test.jsx Updates tests to accommodate the DatePicker-based date field.
frontend/src/helpers/utils.js Strengthens formatDateForApi parsing/formatting logic.
frontend/src/components/UI/Form/Input/Input.jsx Removes fixed mobile width class from the shared input styling.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

type="date"
name="requisitionDate"
label="Requisition Date"
hint="mm/dd/yyyy"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit ece7c4c

We've addressed this by:

  1. Updated DatePicker component to pass required and aria-required attributes to the input element:

    required={isRequired || isRequiredNoShow}
    aria-required={isRequired || isRequiredNoShow}
  2. Added isRequiredNoShow={true} to the MemoizedDatePicker usage (instead of isRequired) to get the accessibility attributes without showing the "Required Information" visual label, maintaining the clean UI design.

This now properly communicates required field status to both screen readers and browser validation, fixing the WCAG 2.1 AA violation.

Comment on lines 129 to 132
data: {
requisition_number: requisitionNumber,
requisition_date: requisitionDate
requisition_date: formatDateForApi(requisitionDate)
// requisition_approved_by is server-controlled and set automatically
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit ece7c4c - Critical Issue

You correctly identified a data integrity vulnerability. We've fixed this by updating isFormValid():

// BEFORE (vulnerable)
return requisitionNumber.trim() !== "" && requisitionDate !== "" && attestationChecked;

// AFTER (fixed)
const formattedDate = formatDateForApi(requisitionDate);
return requisitionNumber.trim() !== "" && formattedDate !== null && attestationChecked;

This now properly validates the date format. Invalid dates like "1", "01/01", or "abc" that previously passed validation (because they were non-empty strings) are now correctly rejected, preventing null values from reaching the API.

We also added comprehensive unit tests for formatDateForApi (7 test cases) to prevent regressions.

Comment on lines +7 to 10
import DatePicker from "../../../components/UI/USWDS/DatePicker";
import { formatDateForApi } from "../../../helpers/utils";
import React from "react";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit ece7c4c

Consolidated the duplicate React imports into a single statement:

import React, { useState, useMemo } from "react";

Removed the duplicate import React from "react"; on line 9.

Comment on lines +450 to +456
const parts = date.split("/");
if (parts.length !== 3) return null;

const [month, day, year] = parts;
if (!month || !day || !year) return null;

return `${year}-${month.padStart(2, "0")}-${day.padStart(2, "0")}`;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit ece7c4c

Added comprehensive unit tests for formatDateForApi with 7 test cases covering:

  1. ✅ Valid MM/DD/YYYY format → YYYY-MM-DD conversion
  2. ✅ Single-digit month/day padding with leading zeros
  3. ✅ Null and undefined input handling (returns null)
  4. ✅ Empty string handling (returns null)
  5. ✅ Invalid formats: non-slash delimited (returns null)
  6. ✅ Wrong number of parts: too few or too many (returns null)
  7. ✅ Missing month, day, or year parts (returns null)

All tests pass (3,150 tests total), providing regression protection for this critical utility function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants