Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Karm/user #132

Merged
merged 17 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions web/__test__/components/FormInput.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { describe, expect, it } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import FormInput from "../../src/components/FormInput";
import React from "react";

describe("FormInput Component", () => {
it("renders input field", () => {
render(<FormInput placeholder="e.g Clark" name="firstName" />);
expect(screen.getByPlaceholderText(/e.g Clark/i)).toBeInTheDocument();
});

it("shows error message", () => {
render(
<FormInput
placeholder="e.g Clark"
name="firstName"
errorMessage="First Name is Required"
/>
);
expect(screen.getByText(/First Name is Required/i)).toBeInTheDocument();
});

it("handles input change", () => {
const handleChange = vi.fn();
render(
<FormInput
placeholder="e.g Clark"
name="firstName"
onChange={handleChange}
/>
);
const input = screen.getByPlaceholderText(/e.g Clark/i);
fireEvent.change(input, { target: { value: "John" } });

expect(handleChange).toHaveBeenCalledTimes(1);
});

it("renders radio options", () => {
const options = ["International", "Domestic"];
render(<FormInput type="radio" name="residency" options={options} />);

expect(screen.getByLabelText(/International/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Domestic/i)).toBeInTheDocument();
});
});
30 changes: 30 additions & 0 deletions web/__test__/components/UserInformationForm.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, expect, it } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import UserInformationForm from "../../src/components/UserInformationForm";
import React from "react";

describe("UserInformationForm Component", () => {
it("renders the form", () => {
render(<UserInformationForm />);
expect(screen.getByText(/Thanks for Joining/i)).toBeInTheDocument();
});

it("validates form fields", () => {
render(<UserInformationForm />);

const submitButton = screen.getByText(/Purchase membership/i);
fireEvent.click(submitButton);

expect(screen.getByText(/First Name is Required/i)).toBeInTheDocument();
expect(screen.getByText(/Last Name is Required/i)).toBeInTheDocument();
expect(
screen.getByText(/Your University is Required/i)
).toBeInTheDocument();
expect(
screen.getByText(/Your Graduation Year is Required/i)
).toBeInTheDocument();
expect(
screen.getByText(/Membership Type is Required/i)
).toBeInTheDocument();
});
});
19 changes: 15 additions & 4 deletions web/src/components/FormInput.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import React from "react";

interface FormInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string;
placeholder?: string;
Expand All @@ -7,6 +9,7 @@ interface FormInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
name?: string;
options?: string[];
errorMessage?: string;
onChange?: React.ChangeEventHandler<HTMLInputElement>;
}

const FormInput: React.FC<FormInputProps> = ({
Expand All @@ -21,17 +24,25 @@ const FormInput: React.FC<FormInputProps> = ({
if (type === "radio" && options.length > 0) {
return (
<div className="mb-4 mt-4">
<div className="mt-2">
{options.map((option, index) => (
<div className="mt-2 flex flex-col md:flex-row md:items-center">
{options.map((option: string, index: number) => (
<label
key={option}
className={`inline-flex items-center ${index !== 0 ? "ml-6" : ""}`}
className={`inline-flex items-center ${index !== 0 ? "ml-0 md:ml-6" : ""}`}
>
<input type="radio" name={props.name} value={option} />
<input
type="radio"
name={props.name}
value={option}
onChange={props.onChange}
/>
<span className="ml-2">{option}</span>
</label>
))}
</div>
{props.errorMessage && (
<span className="text-red-500">{props.errorMessage}</span>
)}
</div>
);
} else {
Expand Down
247 changes: 192 additions & 55 deletions web/src/components/UserInformationForm.tsx
Original file line number Diff line number Diff line change
@@ -1,82 +1,219 @@
import FormInput from "@components/FormInput.tsx";
import FormInput from "../components/FormInput";
import { useState } from "react";
import axios from "axios";

function UserInformationForm() {
const [values, setValues] = useState({
firstName: "",
lastName: "",
university: "",
graudationYear: "",
graduationYear: "",
UPI: "",
studentID: "",
studyOption: "",
residency: "",
duration: "",
});

const [errors, setErrors] = useState({
firstName: "",
lastName: "",
university: "",
graduationYear: "",
duration: "",
});

const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// Need to do validation here
setValues({ ...values, [e.target.name]: e.target.value });
console.log(values);
setErrors({ ...errors, [e.target.name]: "" });
};

const residencyOptions = ["International", "Domestic"];
const paymentOptions = ["One Semester ($8)", "Two Semesters ($15)"];

function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
const validate = () => {
const newErrors = {
firstName: values.firstName ? "" : "First Name is Required",
lastName: values.lastName ? "" : "Last Name is Required",
university: values.university ? "" : "Your University is Required",
graduationYear: values.graduationYear
? ""
: "Your Graduation Year is Required",
duration: values.duration ? "" : "Membership Type is Required",
};
setErrors(newErrors);

return !Object.values(newErrors).some((error) => error);
};

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("submitted");
}
if (validate()) {
const payload = { ...values };

try {
const response = await axios.post("/api/submitForm", payload, {
headers: {
"Content-Type": "application/json",
},
});

if (response.status === 200) {
console.log("Form submitted successfully");
} else {
console.error("Form submission failed");
}
} catch (error) {
console.error("Error submitting form:", error);
}
} else {
console.log("Form has errors");
}
};

return (
<div className="flex items-center justify-center">
<div className="w-full max-w-lg rounded-lg bg-white p-8 shadow-lg">
<div className="min-w-screen flex items-center justify-center">
<div className="w-full max-w-3xl rounded-lg p-8 shadow-lg">
<h2 className="mb-6 text-center text-2xl font-semibold">
We need some more information for your membership
Thanks for joining!{" "}
<span role="img" aria-label="emoji">
😊
</span>{" "}
We just need a bit more info about your membership—it'll be quick!
</h2>

<form onSubmit={handleSubmit}>
<FormInput
placeholder={"First Name"}
id="firstName"
errorMessage="First Name is Required"
onChange={onChange}
/>
<FormInput
placeholder={"Last Name"}
id="lastName"
errorMessage="Last Name is Required"
onChange={onChange}
/>
<FormInput
placeholder={"University (or alumni)"}
id="university"
errorMessage="Your Univeristiy is Required"
onChange={onChange}
/>
<FormInput
placeholder={"What year are you in (or alumni)"}
id="year"
errorMessage="Your Graduation Year is Required"
onChange={onChange}
/>
<FormInput
placeholder={"UPI (if you have one)"}
id="upi"
onChange={onChange}
/>
<FormInput
placeholder={"Student ID (if you have one)"}
id="studentId"
onChange={onChange}
/>
<FormInput
placeholder={"What are you studying)"}
id="study"
onChange={onChange}
/>

<FormInput type="radio" name="residency" options={residencyOptions} />
<FormInput type="radio" name="duration" options={paymentOptions} />

<button className="w-full rounded-lg bg-black py-2 text-white hover:bg-gray-800">
<form onSubmit={handleSubmit} className="flex flex-col space-y-4">
<div className="flex flex-col space-y-4 md:flex-row md:space-x-7 md:space-y-0">
<div className="flex flex-1 flex-col">
<label className="text-gray-700">First Name</label>
<FormInput
placeholder="e.g Clark"
name="firstName"
errorMessage={errors.firstName}
onChange={onChange}
/>
</div>
<div className="flex flex-1 flex-col">
<label className="text-gray-700">Last Name</label>
<FormInput
placeholder="e.g Kent"
name="lastName"
errorMessage={errors.lastName}
onChange={onChange}
/>
</div>
</div>

<div className="flex flex-col space-y-4 md:flex-row md:space-x-7 md:space-y-0">
<div className="flex flex-1 flex-col">
<label className="text-gray-700">
University (or alumni){" "}
<span role="img" aria-label="emoji">
🎓
</span>
</label>
<FormInput
placeholder="e.g University of Auckland"
name="university"
errorMessage={errors.university}
onChange={onChange}
/>
</div>
<div className="flex flex-1 flex-col">
<label className="text-gray-700">
What year are you in (or alumni){" "}
<span role="img" aria-label="emoji">
📅
</span>
</label>
<FormInput
placeholder="e.g Year 3"
name="graduationYear"
errorMessage={errors.graduationYear}
onChange={onChange}
/>
</div>
</div>

<div className="flex flex-col space-y-4 md:flex-row md:space-x-7 md:space-y-0">
<div className="flex flex-1 flex-col">
<label className="text-gray-700">
Student ID (if you have one){" "}
<span role="img" aria-label="emoji">
🆔
</span>
</label>
<FormInput
placeholder="e.g 1234566789.."
name="studentID"
onChange={onChange}
/>
</div>
<div className="flex flex-1 flex-col">
<label className="text-gray-700">
UPI (if you have one){" "}
<span role="img" aria-label="emoji">
🆔
</span>
</label>
<FormInput
placeholder="e.g abcd123.."
name="UPI"
onChange={onChange}
/>
</div>
</div>

<div className="flex flex-col space-y-4 md:flex-row md:space-x-7 md:space-y-0">
<div className="flex flex-1 flex-col">
<label className="text-gray-700">
What are you studying?{" "}
<span role="img" aria-label="emoji">
📚
</span>
</label>
<FormInput
placeholder="e.g Software Engineering"
name="studyOption"
onChange={onChange}
/>
</div>
<div className="flex flex-1 flex-col">
<label className="text-gray-700">
Domestic or International?{" "}
<span role="img" aria-label="emoji">
🌏
</span>
</label>
<FormInput
type="radio"
name="residency"
options={residencyOptions}
onChange={onChange}
/>
</div>
</div>

<div className="mt-4 flex flex-col items-start md:items-center md:space-x-7">
<label className="text-gray-700">
Membership Types{" "}
<span role="img" aria-label="emoji">
💳
</span>
</label>
<FormInput
type="radio"
name="duration"
options={paymentOptions}
errorMessage={errors.duration}
onChange={onChange}
/>
</div>

<button
type="submit"
className="mt-6 w-full rounded-lg bg-black py-2 text-white hover:bg-gray-800"
>
Purchase membership
</button>
</form>
Expand Down
Loading