Skip to content

Commit c2493ca

Browse files
authored
Merge branch 'main' into feature/edit-pages
2 parents 99226f8 + 3329ae4 commit c2493ca

File tree

4 files changed

+221
-1
lines changed

4 files changed

+221
-1
lines changed

src/App.css

+47
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,50 @@ button:hover {
4040
gap: 10px;
4141
margin-top: 10px;
4242
}
43+
44+
.modal-overlay {
45+
position: fixed;
46+
top: 0;
47+
left: 0;
48+
width: 100%;
49+
height: 100%;
50+
background-color: rgba(0, 0, 0, 0.5);
51+
display: flex;
52+
justify-content: center;
53+
align-items: center;
54+
z-index: 1;
55+
}
56+
57+
.modal {
58+
position: relative;
59+
background-color: white;
60+
padding: 20px;
61+
border-radius: 5px;
62+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
63+
width: 400px;
64+
height: 300px;
65+
}
66+
67+
.close-button {
68+
position: absolute;
69+
top: 10px;
70+
right: 10px;
71+
background: none;
72+
border: none;
73+
font-size: 20px;
74+
cursor: pointer;
75+
}
76+
77+
.form {
78+
display: flex;
79+
flex-direction: column;
80+
gap: 10px;
81+
height: 100%;
82+
justify-content: center;
83+
}
84+
85+
.form input {
86+
padding: 10px;
87+
border-radius: 5px;
88+
border: 1px solid #ccc;
89+
}

src/App.js

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import SkillEditPage from "./components/skills/SkillEditPage";
66
import EducationForm from "./components/education/EducationForm";
77
import EducationView from "./components/education/EducationView";
88
import EducationEditPage from "./components/education/EducationEditPage";
9+
import User from "./components/User/page";
910

1011
function App() {
1112
const [showAddSkillForm, setShowAddSkillForm] = useState(false);
@@ -55,6 +56,12 @@ function App() {
5556
return (
5657
<div className="App">
5758
<h1>Resume Builder</h1>
59+
<div className="resumeSection">
60+
<h2>User</h2>
61+
<p>Add User Information</p>
62+
<User />
63+
<br></br>
64+
</div>
5865
<div className="resumeSection">
5966
<h2>Experience</h2>
6067
<p>Experience Placeholder</p>

src/App.test.js

+86-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import React from "react";
2-
import { render, screen } from "@testing-library/react";
2+
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
33
import App from "./App";
4+
import User from "./components/User/page.jsx";
45

6+
// App component test
57
test("renders main components of Resume Builder", () => {
68
render(<App />);
79

@@ -30,3 +32,86 @@ test("renders main components of Resume Builder", () => {
3032
).toBeInTheDocument();
3133
expect(screen.getByRole("button", { name: /Export/i })).toBeInTheDocument();
3234
});
35+
36+
// User component test
37+
describe("User Component", () => {
38+
test("renders Add User button", () => {
39+
render(<User />);
40+
const addButton = screen.getByRole("button", { name: /Add User/i });
41+
expect(addButton).toBeInTheDocument();
42+
});
43+
44+
test("opens modal when Add User button is clicked", async () => {
45+
render(<User />);
46+
const addButton = screen.getByRole("button", { name: /Add User/i });
47+
48+
fireEvent.click(addButton);
49+
50+
await waitFor(() => {
51+
expect(screen.getByRole("dialog")).toBeInTheDocument();
52+
});
53+
});
54+
55+
test("closes modal when close button is clicked", async () => {
56+
render(<User />);
57+
const addButton = screen.getByRole("button", { name: /Add User/i });
58+
59+
fireEvent.click(addButton);
60+
61+
await waitFor(() => {
62+
const closeButton = screen.getByRole("button", { name: /×/i });
63+
fireEvent.click(closeButton);
64+
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
65+
});
66+
});
67+
68+
test("closes modal when clicking outside", async () => {
69+
render(<User />);
70+
const addButton = screen.getByRole("button", { name: /Add User/i });
71+
72+
fireEvent.click(addButton);
73+
74+
await waitFor(() => {
75+
const modal = screen.getByRole("dialog");
76+
fireEvent.mouseDown(document.body);
77+
expect(modal).not.toBeInTheDocument();
78+
});
79+
});
80+
81+
test("handles form input and submission", async () => {
82+
render(<User />);
83+
const addButton = screen.getByRole("button", { name: /Add User/i });
84+
85+
fireEvent.click(addButton);
86+
87+
await waitFor(() => {
88+
const nameInput = screen.getByPlaceholderText(/name/i);
89+
const phoneInput = screen.getByPlaceholderText(/phone/i);
90+
const emailInput = screen.getByPlaceholderText(/email/i);
91+
const submitButton = screen.getByRole("button", { name: /save/i });
92+
93+
fireEvent.change(nameInput, { target: { value: "John Doe" } });
94+
fireEvent.change(phoneInput, { target: { value: "+2343456890" } });
95+
fireEvent.change(emailInput, {
96+
target: { value: "[email protected]" },
97+
});
98+
99+
expect(nameInput).toHaveValue("John Doe");
100+
expect(phoneInput).toHaveValue("+2343456890");
101+
expect(emailInput).toHaveValue("[email protected]");
102+
103+
const consoleSpy = jest.spyOn(console, "log");
104+
fireEvent.click(submitButton);
105+
106+
expect(consoleSpy).toHaveBeenCalledWith({
107+
name: "John Doe",
108+
phone_number: "+2343456890",
109+
110+
});
111+
consoleSpy.mockRestore();
112+
113+
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
114+
});
115+
});
116+
});
117+

src/components/User/page.jsx

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import React, { useState, useRef, useEffect } from "react";
2+
3+
const User = () => {
4+
const [isOpen, setIsOpen] = useState(false);
5+
const [userInfo, setUserInfo] = useState({
6+
name: "",
7+
phone_number: "",
8+
email: "",
9+
});
10+
11+
const handleChange = (e) => {
12+
setUserInfo({ ...userInfo, [e.target.name]: e.target.value });
13+
};
14+
15+
const handleSubmit = (e) => {
16+
e.preventDefault();
17+
// handle form submission here
18+
console.log(userInfo);
19+
setIsOpen(false);
20+
};
21+
22+
// clicking outside modal should close the form
23+
const modalRef = useRef();
24+
25+
const handleClickOutside = (e) => {
26+
if (modalRef.current && !modalRef.current.contains(e.target)) {
27+
setIsOpen(false);
28+
}
29+
};
30+
31+
useEffect(() => {
32+
document.addEventListener("mousedown", handleClickOutside);
33+
return () => {
34+
document.removeEventListener("mousedown", handleClickOutside);
35+
};
36+
}, []);
37+
38+
// modal form
39+
return (
40+
<>
41+
<button onClick={() => setIsOpen(true)}>Add User</button>
42+
43+
{isOpen && (
44+
<div className="modal-overlay">
45+
<div className="modal" ref={modalRef} role="dialog">
46+
<button className="close-button" onClick={() => setIsOpen(false)}>
47+
&times;
48+
</button>
49+
<p>Add User information</p>
50+
<form className="form" onSubmit={handleSubmit} role="form">
51+
<input
52+
type="text"
53+
name="name"
54+
placeholder="Name"
55+
value={userInfo.name}
56+
onChange={handleChange}
57+
/>
58+
<input
59+
type="tel"
60+
name="phone_number"
61+
placeholder="Phone"
62+
value={userInfo.phone_number}
63+
onChange={handleChange}
64+
/>
65+
<input
66+
type="email"
67+
name="email"
68+
placeholder="Email"
69+
value={userInfo.email}
70+
onChange={handleChange}
71+
/>
72+
<button type="submit">Save</button>
73+
</form>
74+
</div>
75+
</div>
76+
)}
77+
</>
78+
);
79+
};
80+
81+
export default User;

0 commit comments

Comments
 (0)