Skip to content

Commit 843903e

Browse files
authored
Merge pull request #1287 from WildMeOrg/1197_new_encounter_page_react_api
1197 new encounter page react api
2 parents d077f90 + a3b8629 commit 843903e

File tree

163 files changed

+24182
-1873
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

163 files changed

+24182
-1873
lines changed

frontend/package-lock.json

Lines changed: 107 additions & 46 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
"private": true,
55
"dependencies": {
66
"@flowjs/flow.js": "^2.14.1",
7-
"@testing-library/user-event": "^13.5.0",
87
"antd": "^5.21.5",
98
"autoprefixer": "^10.4.18",
109
"axios": "^1.7.4",
1110
"bootstrap": "^5.3.2",
1211
"copy-webpack-plugin": "^12.0.2",
12+
"dompurify": "^3.2.7",
1313
"exif-js": "^2.3.0",
1414
"flow.js": "^0.2.6",
1515
"google-map-react": "^2.2.1",
@@ -35,10 +35,12 @@
3535
"react-router-bootstrap": "^0.26.2",
3636
"react-router-dom": "^6.22.0",
3737
"react-scripts": "5.0.1",
38-
"react-select": "^5.8.0",
38+
"react-select": "^5.10.2",
39+
"react-toastify": "^11.0.5",
3940
"react-window": "^1.8.11",
4041
"recharts": "^3.1.0",
4142
"sass": "^1.71.1",
43+
"swiper": "^12.0.1",
4244
"web-vitals": "^2.1.4",
4345
"webpack-merge": "^5.10.0",
4446
"webpack-version-file": "^0.1.7",
@@ -88,6 +90,7 @@
8890
"@tanstack/react-table": "^8.21.3",
8991
"@testing-library/jest-dom": "^6.5.0",
9092
"@testing-library/react": "^16.0.1",
93+
"@testing-library/user-event": "^14.6.1",
9194
"bootstrap-icons": "^1.11.3",
9295
"css-loader": "^6.10.0",
9396
"date-fns": "^4.1.0",

frontend/src/App.jsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import LocaleContext from "./IntlProvider";
1414
import FooterVisibilityContext from "./FooterVisibilityContext";
1515
import Cookies from "js-cookie";
1616
import FilterContext from "./FilterContextProvider";
17+
import { ToastContainer } from "react-toastify";
1718

1819
function App() {
1920
const messageMap = {
@@ -51,9 +52,11 @@ function App() {
5152
setFilters({});
5253
};
5354

54-
const publicUrl = process.env.PUBLIC_URL
55-
? (process.env.PUBLIC_URL.startsWith('http') ? new URL(process.env.PUBLIC_URL).pathname : process.env.PUBLIC_URL)
56-
: "/";
55+
const publicUrl = process.env.PUBLIC_URL
56+
? process.env.PUBLIC_URL.startsWith("http")
57+
? new URL(process.env.PUBLIC_URL).pathname
58+
: process.env.PUBLIC_URL
59+
: "/";
5760

5861
return (
5962
<QueryClientProvider client={queryClient}>
@@ -78,6 +81,17 @@ function App() {
7881
adminUserInitialized={true}
7982
setLocale={setLocale}
8083
/>
84+
<ToastContainer
85+
position="top-right"
86+
autoClose={3000}
87+
hideProgressBar={false}
88+
newestOnTop={false}
89+
closeOnClick
90+
rtl={false}
91+
pauseOnFocusLoss
92+
draggable
93+
pauseOnHover
94+
/>
8195
</FilterContext.Provider>
8296
</FooterVisibilityContext.Provider>
8397
</IntlProvider>

frontend/src/AuthenticatedSwitch.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ const ReportConfirm = lazy(
2323
);
2424
const ProjectList = lazy(() => import("./pages/ProjectList"));
2525
const ManualAnnotation = lazy(() => import("./pages/ManualAnnotation"));
26+
const EditAnnotation = lazy(() => import("./pages/EditAnnotation"));
2627

2728
const BulkImport = lazy(() => import("./pages/BulkImport/BulkImport"));
2829
const BulkImportTask = lazy(() => import("./pages/BulkImport/BulkImportTask"));
2930

31+
const Encounter = lazy(() => import("./pages/Encounter/Encounter"));
32+
3033
export default function AuthenticatedSwitch({
3134
showclassicsubmit,
3235
showClassicEncounterSearch,
@@ -75,9 +78,12 @@ export default function AuthenticatedSwitch({
7578
<Route path="/home" element={<Home />} />
7679
<Route path="/report" element={<ReportEncounter />} />
7780
<Route path="/reportConfirm" element={<ReportConfirm />} />
81+
<Route path="/encounter" element={<Encounter />} />
82+
7883
<Route path="/encounter-search" element={<EncounterSearch />} />
7984
<Route path="/admin/logs" element={<AdminLogs />} />
8085
<Route path="/manual-annotation" element={<ManualAnnotation />} />
86+
<Route path="/edit-annotation" element={<EditAnnotation />} />
8187
<Route path="/bulk-import" element={<BulkImport />} />
8288
<Route path="/bulk-import-task" element={<BulkImportTask />} />
8389
<Route path="/login" element={<Login />} />

frontend/src/UnAuthenticatedSwitch.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { lazy, Suspense } from "react";
22
import { Routes, Route, Navigate, useLocation } from "react-router-dom";
33
import Footer from "./components/Footer";
44
import UnAuthenticatedAppHeader from "./components/UnAuthenticatedAppHeader";
5+
import EncounterPageViewOnly from "./pages/Encounter/EncounterPageViewOnly";
56

67
// Lazy load pages
78
const Login = lazy(() => import("./pages/Login"));
@@ -53,6 +54,7 @@ export default function UnAuthenticatedSwitch({ showclassicsubmit }) {
5354
path="/home"
5455
element={<Unauthorized setHeader={setHeader} />}
5556
/>
57+
<Route path="/encounter" element={<EncounterPageViewOnly />} />
5658
<Route path="/citation" element={<Citation />} />
5759
<Route path="/report" element={<ReportEncounter />} />
5860
<Route path="/reportConfirm" element={<ReportConfirm />} />
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/* eslint-disable react/display-name */
2+
import React from "react";
3+
import { render, screen, fireEvent } from "@testing-library/react";
4+
5+
jest.mock("react-konva", () => {
6+
const React = require("react");
7+
8+
const FakeStage = ({ children, width, height }) => (
9+
<div data-testid="konva-stage" data-width={width} data-height={height}>
10+
{children}
11+
</div>
12+
);
13+
14+
const FakeRect = React.forwardRef(({ onClick, onDragEnd, ...rest }, ref) => {
15+
const fakeNode = {
16+
x: jest.fn(() => 30),
17+
y: jest.fn(() => 40),
18+
width: jest.fn(() => 100),
19+
height: jest.fn(() => 50),
20+
scaleX: jest.fn(() => 1),
21+
scaleY: jest.fn(() => 1),
22+
rotation: jest.fn(() => 15),
23+
};
24+
if (ref) {
25+
if (typeof ref === "function") {
26+
ref(fakeNode);
27+
} else {
28+
ref.current = fakeNode;
29+
}
30+
}
31+
return (
32+
<div
33+
data-testid="konva-rect"
34+
onClick={onClick}
35+
onDragEnd={onDragEnd}
36+
{...rest}
37+
>
38+
rect
39+
</div>
40+
);
41+
});
42+
43+
const FakeTransformer = React.forwardRef((props, ref) => {
44+
const fakeTransformer = {
45+
nodes: jest.fn(),
46+
getLayer: () => ({
47+
batchDraw: jest.fn(),
48+
}),
49+
};
50+
if (ref) {
51+
if (typeof ref === "function") {
52+
ref(fakeTransformer);
53+
} else {
54+
ref.current = fakeTransformer;
55+
}
56+
}
57+
return <div data-testid="konva-transformer">transformer</div>;
58+
});
59+
60+
const FakeLayer = ({ children }) => (
61+
<div data-testid="konva-layer">{children}</div>
62+
);
63+
64+
return {
65+
Stage: FakeStage,
66+
Layer: FakeLayer,
67+
Rect: FakeRect,
68+
Transformer: FakeTransformer,
69+
};
70+
});
71+
72+
import ResizableRotatableRect from "../../../src/components/ResizableRotatableRect";
73+
74+
describe("ResizableRotatableRect", () => {
75+
const baseRect = {
76+
x: 10,
77+
y: 20,
78+
width: 120,
79+
height: 80,
80+
rotation: 0,
81+
};
82+
83+
test("renders Stage and Rect with given size", () => {
84+
const setRect = jest.fn();
85+
const setValue = jest.fn();
86+
87+
render(
88+
<ResizableRotatableRect
89+
rect={baseRect}
90+
imgHeight={400}
91+
imgWidth={600}
92+
setRect={setRect}
93+
setValue={setValue}
94+
drawStatus="DRAW"
95+
/>,
96+
);
97+
98+
expect(screen.getByTestId("konva-stage")).toHaveAttribute(
99+
"data-width",
100+
"600",
101+
);
102+
expect(screen.getByTestId("konva-stage")).toHaveAttribute(
103+
"data-height",
104+
"400",
105+
);
106+
expect(screen.getByTestId("konva-rect")).toBeInTheDocument();
107+
expect(screen.getByTestId("konva-transformer")).toBeInTheDocument();
108+
});
109+
110+
test("clicking rect selects it (transformer.nodes called)", () => {
111+
const setRect = jest.fn();
112+
const setValue = jest.fn();
113+
114+
render(
115+
<ResizableRotatableRect
116+
rect={baseRect}
117+
imgHeight={400}
118+
imgWidth={600}
119+
setRect={setRect}
120+
setValue={setValue}
121+
drawStatus="DRAW"
122+
/>,
123+
);
124+
125+
const rect = screen.getByTestId("konva-rect");
126+
fireEvent.click(rect);
127+
fireEvent.dragEnd(rect);
128+
});
129+
130+
test("drag end updates rect via setRect", () => {
131+
const setRect = jest.fn();
132+
const setValue = jest.fn();
133+
134+
render(
135+
<ResizableRotatableRect
136+
rect={baseRect}
137+
imgHeight={400}
138+
imgWidth={600}
139+
setRect={setRect}
140+
setValue={setValue}
141+
drawStatus="DRAW"
142+
/>,
143+
);
144+
145+
const rect = screen.getByTestId("konva-rect");
146+
147+
fireEvent.dragEnd(rect);
148+
149+
expect(setRect).toHaveBeenCalledWith(
150+
expect.objectContaining({
151+
x: 30,
152+
y: 40,
153+
}),
154+
);
155+
});
156+
157+
test("transform end updates rect and calls setValue(rotation)", () => {
158+
const setRect = jest.fn();
159+
const setValue = jest.fn();
160+
161+
render(
162+
<ResizableRotatableRect
163+
rect={baseRect}
164+
imgHeight={400}
165+
imgWidth={600}
166+
setRect={setRect}
167+
setValue={setValue}
168+
drawStatus="DRAW"
169+
/>,
170+
);
171+
172+
const rect = screen.getByTestId("konva-rect");
173+
174+
fireEvent(rect, new MouseEvent("transformend", { bubbles: true }));
175+
fireEvent.click(rect);
176+
});
177+
178+
test("when drawStatus is DELETE, component still renders Stage but rectProps won't be rebuilt", () => {
179+
const setRect = jest.fn();
180+
const setValue = jest.fn();
181+
182+
render(
183+
<ResizableRotatableRect
184+
rect={baseRect}
185+
imgHeight={300}
186+
imgWidth={300}
187+
setRect={setRect}
188+
setValue={setValue}
189+
drawStatus="DELETE"
190+
/>,
191+
);
192+
193+
expect(screen.getByTestId("konva-stage")).toBeInTheDocument();
194+
expect(screen.getByTestId("konva-rect")).toBeInTheDocument();
195+
});
196+
});

0 commit comments

Comments
 (0)