feat: refine subject visits and project workflows
Add early termination visit workflow with ordering, non-applicable visit handling, visit window display, and medication adherence support. Extend monitoring visit issue template fields, site scoping, setup draft project info handling, login security UI, attachment behavior, and related tests/migrations.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const apiGet = vi.fn();
|
||||
const apiPost = vi.fn();
|
||||
const apiDelete = vi.fn();
|
||||
|
||||
vi.mock("./axios", () => ({
|
||||
apiGet,
|
||||
apiPost,
|
||||
apiDelete,
|
||||
}));
|
||||
|
||||
describe("attachments api", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("uses canonical collection URLs with trailing slash", async () => {
|
||||
const { fetchAttachments, uploadAttachment } = await import("./attachments");
|
||||
const file = new File(["x"], "x.txt", { type: "text/plain" });
|
||||
|
||||
fetchAttachments("study-1", "startup_feasibility", "entity-1");
|
||||
uploadAttachment("study-1", "startup_feasibility", "entity-1", file);
|
||||
|
||||
expect(apiGet).toHaveBeenCalledWith("/api/v1/studies/study-1/startup_feasibility/entity-1/attachments/");
|
||||
expect(apiPost).toHaveBeenCalledWith(
|
||||
"/api/v1/studies/study-1/startup_feasibility/entity-1/attachments/",
|
||||
expect.any(FormData),
|
||||
expect.objectContaining({ headers: { "Content-Type": "multipart/form-data" } })
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { apiGet, apiPost, apiDelete } from "./axios";
|
||||
|
||||
export const fetchAttachments = (studyId: string, entityType: string, entityId: string) =>
|
||||
apiGet(`/api/v1/studies/${studyId}/${entityType}/${entityId}/attachments`);
|
||||
apiGet(`/api/v1/studies/${studyId}/${entityType}/${entityId}/attachments/`);
|
||||
|
||||
export const uploadAttachment = (
|
||||
studyId: string,
|
||||
@@ -12,7 +12,7 @@ export const uploadAttachment = (
|
||||
) => {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
return apiPost(`/api/v1/studies/${studyId}/${entityType}/${entityId}/attachments`, formData, {
|
||||
return apiPost(`/api/v1/studies/${studyId}/${entityType}/${entityId}/attachments/`, formData, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
...options,
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { apiDelete, apiGet, apiPatch, apiPost } from "./axios";
|
||||
import { apiDelete, apiGet, apiPatch, apiPost, type ApiRequestConfig } from "./axios";
|
||||
|
||||
export const fetchVisits = (studyId: string, subjectId: string) =>
|
||||
apiGet(`/api/v1/studies/${studyId}/subjects/${subjectId}/visits/`);
|
||||
@@ -6,6 +6,13 @@ export const fetchVisits = (studyId: string, subjectId: string) =>
|
||||
export const createVisit = (studyId: string, subjectId: string, payload: Record<string, any>) =>
|
||||
apiPost(`/api/v1/studies/${studyId}/subjects/${subjectId}/visits/`, payload);
|
||||
|
||||
export const createEarlyTerminationVisit = (
|
||||
studyId: string,
|
||||
subjectId: string,
|
||||
payload: Record<string, any>,
|
||||
config?: ApiRequestConfig
|
||||
) => apiPost(`/api/v1/studies/${studyId}/subjects/${subjectId}/visits/early-termination`, payload, config);
|
||||
|
||||
export const updateVisit = (studyId: string, subjectId: string, visitId: string, payload: Record<string, any>) =>
|
||||
apiPatch(`/api/v1/studies/${studyId}/subjects/${subjectId}/visits/${visitId}`, payload);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user