mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-02 00:23:13 +00:00
fix(vendor-portal): advertise phone photo and video types for uplift evidence
The evidence picker filtered to PDF/JPG/PNG and its label and missing-file messages said the same, while the pre-check (and the server, which applies the SH-116 allowlist and work-order counts to UpliftEvidence uploads) accepts HEIC, MP4 and MOV. On a phone the picker hid exactly the photos and clips the validator would pass. The evidence input now uses the same accept filter as the completion upload, exported once from document-validation, and the label and both missing-evidence messages name all six types.
This commit is contained in:
parent
ef6cde64c8
commit
39ee98e09b
7 changed files with 40 additions and 7 deletions
2
e2e/vendors/vendor-uplift-workflow.spec.ts
vendored
2
e2e/vendors/vendor-uplift-workflow.spec.ts
vendored
|
|
@ -97,7 +97,7 @@ test("vendor uploads scanned evidence and submits a dispatch-scoped uplift", asy
|
|||
|
||||
await page.getByLabel("New total NTE").fill("125");
|
||||
await page.getByLabel("Reason").fill("Replacement compressor");
|
||||
await page.getByLabel("Evidence (PDF/JPG/PNG)").setInputFiles({
|
||||
await page.getByLabel("Evidence (PDF, JPG, PNG, HEIC, MP4, MOV)").setInputFiles({
|
||||
name: "estimate.pdf",
|
||||
mimeType: "application/pdf",
|
||||
buffer: Buffer.from("%PDF-1.4\nmock estimate"),
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { useRef, useState } from "react";
|
|||
import { Text } from "@/components/ui/text";
|
||||
import {
|
||||
validateVendorDocument,
|
||||
VENDOR_UPLOAD_ACCEPT,
|
||||
type VendorMediaUsage,
|
||||
} from "@/domain/vendor-portal/lib/document-validation";
|
||||
import {
|
||||
|
|
@ -122,13 +123,15 @@ export function UpliftRequestForm({
|
|||
</div>
|
||||
<div className="vp-row">
|
||||
<strong>
|
||||
<label htmlFor={`uplift-evidence-${mode}`}>Evidence (PDF/JPG/PNG)</label>
|
||||
<label htmlFor={`uplift-evidence-${mode}`}>
|
||||
Evidence (PDF, JPG, PNG, HEIC, MP4, MOV)
|
||||
</label>
|
||||
</strong>
|
||||
<input
|
||||
id={`uplift-evidence-${mode}`}
|
||||
type="file"
|
||||
className="vp-input"
|
||||
accept=".pdf,.jpg,.jpeg,.png,application/pdf,image/jpeg,image/png"
|
||||
accept={VENDOR_UPLOAD_ACCEPT}
|
||||
onChange={(event) => void chooseFile(event.target.files?.[0])}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ function useVendorUpliftActions({
|
|||
if (requiresApproval) {
|
||||
if (!values.evidenceFile) {
|
||||
setFormError(
|
||||
"Attach PDF, JPG, or PNG evidence — approval-required requests need evidence.",
|
||||
"Attach PDF, JPG, PNG, HEIC, MP4, or MOV evidence — approval-required requests need evidence.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { VendorPortalFeedback } from "@/app/v/_components/vendor-portal-feedback
|
|||
import { vendorPortalApi } from "@/domain/vendor-portal/api/vendor-portal-api";
|
||||
import {
|
||||
validateVendorDocument,
|
||||
VENDOR_UPLOAD_ACCEPT,
|
||||
vendorMediaUsage,
|
||||
} from "@/domain/vendor-portal/lib/document-validation";
|
||||
import type {
|
||||
|
|
@ -160,7 +161,7 @@ export function VendorPortalDocuments({
|
|||
ref={inputRef}
|
||||
type="file"
|
||||
aria-label="Choose completion document"
|
||||
accept=".pdf,.jpg,.jpeg,.png,.heic,.mp4,.mov,application/pdf,image/jpeg,image/png,image/heic,video/mp4,video/quicktime"
|
||||
accept={VENDOR_UPLOAD_ACCEPT}
|
||||
hidden
|
||||
onChange={(event) => void uploadSelectedFile(event.target.files?.[0])}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ const MAX_VIDEO_DURATION_SECONDS = 90;
|
|||
|
||||
const UNSUPPORTED_TYPE_MESSAGE = "Only PDF, JPG, PNG, HEIC, MP4, and MOV files are allowed.";
|
||||
|
||||
/** File-picker filter for every vendor portal upload, matching the allowlist below. */
|
||||
export const VENDOR_UPLOAD_ACCEPT =
|
||||
".pdf,.jpg,.jpeg,.png,.heic,.mp4,.mov,application/pdf,image/jpeg,image/png,image/heic,video/mp4,video/quicktime";
|
||||
|
||||
type VendorUploadKind = "document" | "photo" | "video";
|
||||
|
||||
// Mirrors the server allowlist: an allowlisted browser type wins, otherwise the
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export function validateUpliftAmount(
|
|||
return "Please include a reason for the uplift request.";
|
||||
}
|
||||
if (!options.file && !options.hasExisting) {
|
||||
return "Attach PDF, JPG, or PNG evidence — approval-required requests need evidence.";
|
||||
return "Attach PDF, JPG, PNG, HEIC, MP4, or MOV evidence — approval-required requests need evidence.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { UpliftRequestForm } from "@/app/v/[token]/dispatch/_components/uplift-request-form";
|
||||
|
||||
|
|
@ -48,6 +48,31 @@ describe("UpliftRequestForm revise mode", () => {
|
|||
expect(await screen.findByText("A work order can have at most 10 photos.")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("offers and accepts the same phone photo and video types as the upload allowlist", async () => {
|
||||
renderForm();
|
||||
|
||||
const input = screen.getByLabelText("Evidence (PDF, JPG, PNG, HEIC, MP4, MOV)");
|
||||
expect(input.getAttribute("accept")?.split(",")).toEqual(
|
||||
expect.arrayContaining([".pdf", ".jpg", ".png", ".heic", ".mp4", ".mov"]),
|
||||
);
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { files: [new File(["gif"], "clip.gif", { type: "image/gif" })] },
|
||||
});
|
||||
expect(
|
||||
await screen.findByText("Only PDF, JPG, PNG, HEIC, MP4, and MOV files are allowed."),
|
||||
).toBeInTheDocument();
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { files: [new File(["heic"], "site.heic", { type: "" })] },
|
||||
});
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
screen.queryByText("Only PDF, JPG, PNG, HEIC, MP4, and MOV files are allowed."),
|
||||
).not.toBeInTheDocument(),
|
||||
);
|
||||
});
|
||||
|
||||
it("reports the current NTE threshold in the actionable error", () => {
|
||||
renderForm({ initialRequested: "900", currentNte: 1000 });
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue