Skip to content

Commit

Permalink
dynamic attendee add form complete
Browse files Browse the repository at this point in the history
  • Loading branch information
seesjays committed May 30, 2023
1 parent 10e60d2 commit 358ecfb
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 70 deletions.
25 changes: 14 additions & 11 deletions pages/api/events/[eventID].ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { createServerSupabaseClient } from "@supabase/auth-helpers-nextjs";
import { memberAttendanceType, memberType } from "../../../types/types";
import poster from "../../../utils/poster";

const handler = async (req: NextApiRequest, res: NextApiResponse) =>
{
Expand Down Expand Up @@ -85,6 +86,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) =>

if (req.method === "POST")
{
console.dir(req.body.member);
const { query } = req;
const { member, swag } = req.body;

Expand All @@ -100,15 +102,18 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) =>
// check if they're already in the event, if so, just update swag
const { data: attendanceData, error: eventAttendanceError } = await supabase
.from("event_attendance")
.select(`event_id, timestamp, swag, contacts (*)`)
.eq("contact_id", member.contact_id);
.select(`event_id, timestamp, swag, contact_id`)
.eq("contact_id", member.contact_id)
.eq("event_id", query.eventID);

if (attendanceData)
if (attendanceData && attendanceData.length > 0)
{
const { data: swagUpdated, error: swagUpdateError } = await supabase
.from("event_attendance")
.update({ swag: swag })
.eq("contact_id", member.contact_id);
.eq("contact_id", member.contact_id)
.eq("event_id", query.eventID)
.select();

if (swagUpdateError)
{
Expand All @@ -118,14 +123,14 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) =>
});
}

const resp = swagUpdated;

return res.status(200).json(resp);
return res.status(200).json(swagUpdated);
}

// not already in the event
const { data: attendanceAdded, error: attendanceAddError } = await supabase
.from("event_attendance")
.insert({ event_id: query.eventID, contact_id: member.contact_id, swag: swag });
.insert({ event_id: query.eventID, contact_id: member.contact_id, swag: swag })
.select();

if (attendanceAddError)
{
Expand All @@ -135,9 +140,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) =>
});
}

const resp = attendanceAdded;

return res.status(200).json(resp);
return res.status(200).json(attendanceAdded);
}

if (req.method === "DELETE")
Expand Down
3 changes: 2 additions & 1 deletion pages/api/members.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) =>
});
}

return res.status(200).json({ data: data });
return res.status(200).json({ data: data[0] });
}

if (req.method === "GET")
Expand Down Expand Up @@ -95,6 +95,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) =>

if (deleteResponse.error)
{
console.log(deleteResponse.error.message);
return res.status(500).json({
error: "Internal Server Error",
description: "Something went wrong: We couldn't delete the member.",
Expand Down
2 changes: 1 addition & 1 deletion pages/dashboard/addmember.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const AddMember: NextPage = () =>
shirt_size_id: "M"
};

// ok to use ! here cause guard statement should catch but TS cries anyway
// ok to use ! here cause the guard statement should catch but TS cries anyway
// so ! it is
const contInput: Partial<memberType> & Pick<memberType, "uh_id" | "first_name" | "last_name"> = {
uh_id: parseInt(formData.get("uhid")!.toString()),
Expand Down
177 changes: 120 additions & 57 deletions pages/dashboard/events/[eventID]/addAttendee.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ const AddAttendee: NextPage = () =>
{
const router = useRouter();

const [swag, setSwag] = useState(false);
const [idSearch, setIdSearch] = useState("");
const [contactExists, setContactExists] = useState(false);
const [existingContact, setExistingContact] = useState<memberType | undefined>(undefined);

const { eventID } = router.query;

Expand All @@ -32,58 +31,85 @@ const AddAttendee: NextPage = () =>
const handleExistingSubmit = async (e: React.FormEvent<HTMLFormElement>) =>
{
e.preventDefault();
const formData = new FormData(e.currentTarget);

const fdID = formData.get("uhid");
if (!fdID)
if (!existingContact)
{
toast.error(`Attendee Add Error: Adding requires a UH ID.`);
toast.error(`Attendee Add Error: We couldn't find that contact.`);
return;
}

const id = parseInt(fdID.toString());
const memberDat = data as memberType[];
const toBeAdded = memberDat.find((member) => member.uh_id === id);
const swag = document.getElementsByName("swagcheck")[0] as HTMLInputElement;
const result = await poster(`/api/events/${eventID}`, { member: existingContact, swag: swag.checked });

if (!toBeAdded)
if (result.error)
{
toast.error(`Attendee Add Error: We couldn't find that contact.`);
toast.error("Failed to add attendee! " + result.description);
return;
}

await poster(`/api/events/${eventID}`, { member: toBeAdded, swag: swag });

toast.success("Successfully added attendee!");
mutate(`/api/events/${eventID}`);
setIdSearch("");
};

// basically the code from /addmember.tsx
// with some extra stuff at the end to add it to the event
const handleNewSubmit = async (e: React.FormEvent<HTMLFormElement>) =>
{
e.preventDefault();

const formData = new FormData(e.currentTarget);

const fdID = formData.get("uhid");
if (!fdID)
if (!formData.get("first")?.toString() || !formData.get("uhid")?.toString() || !formData.get("last")?.toString())
{
toast.error(`Attendee Add Error: Adding requires a UH ID.`);
toast.error(`Contact Creation Error: Contact requires at LEAST a first name, last name, and UH ID.`);
return;
}

const id = parseInt(fdID.toString());
const memberDat = data?.attendees as memberType[];

const toBeAdded = memberDat.find((member) => member.uh_id === id);

if (!toBeAdded)
if (!parseInt(formData.get("phone")!.toString()) || formData.get("phone")!.toString().includes("-"))
{
toast.error(`Attendee Add Error: We couldn't find that contact.`);
toast.error(`Contact Creation Error: Rewrite the phone number to use no special characters.`);
return;
}

await poster(`/api/events/${eventID}`, { member: toBeAdded, swag: swag });

toast.success("Successfully added attendee!");
type contactWOTS = Omit<memberType, "timestamp">;

const contactObj: contactWOTS = {
contact_id: crypto.randomUUID(),
uh_id: 1234567,
first_name: "",
last_name: "",
phone_number: 123456789,
email: "",
shirt_size_id: "M"
};

// ok to use ! here cause guard statement should catch but TS cries anyway
// so ! it is
const contInput: Partial<memberType> & Pick<memberType, "uh_id" | "first_name" | "last_name"> = {
uh_id: parseInt(formData.get("uhid")!.toString()),
first_name: formData.get("first")!.toString(),
last_name: formData.get("last")!.toString(),
email: formData.get("email")!.toString(),
phone_number: parseInt(formData.get("phone")!.toString()),
shirt_size_id: formData.get("shirt")!.toString(),
};

Object.assign(contactObj, contInput);

const nuMember = await poster(`/api/members`, contactObj);
const swag = document.getElementsByName("swagcheck")[0] as HTMLInputElement;
const res = await poster(`/api/events/${eventID}`, { member: nuMember.data, swag: swag.checked });

if (res.error)
{
toast.error(`Contact Creation Error: ${res.error.message}`);
}
else
{
toast.success("Successfully created and added attendee!");
mutate(`/api/events/${eventID}`);
setIdSearch("");
}
};

return (
Expand All @@ -96,54 +122,87 @@ const AddAttendee: NextPage = () =>
</Title>

<div className="w-5/12 mx-auto mt-4">
<div className="bg-red-900 bg-opacity-10 px-4 py-2 my-4 rounded-sm border border-red-500">
{/* lil note */}
{idSearch.length < 7 && <div className="bg-neutral-700 bg-opacity-10 px-4 py-2 my-4 rounded-sm border border-neutral-500">
<span className="block font-semibold mx-2">
Notes
Note
</span>
<ul className="list-disc mx-2">
<li className="mt-0.5">
If the attendee's already logged in the event, you can use this page to update
their swag status.
</li>
</ul>
</div>
<label className="w-full">
<input
className="w-full h-9 px-2 bg-selectInputBG placeholder:text-neutral-500 focus:outline-none focus:border-white focus:ring-white border border-neutral-500 rounded-sm"
name="searchBox"
placeholder={"UH ID"}
maxLength={7}
value={idSearch}
onChange={e =>
{
setIdSearch(e.target.value);
const id = parseInt(e.target.value);
const memberDat = data as memberType[];
console.log(memberDat.some((member) => member.uh_id === id));
setContactExists(memberDat.some((member) => member.uh_id === id));
}}
/>
</label>

<form onSubmit={contactExists ? handleExistingSubmit : handleNewSubmit}>
{contactExists ? <ExistingAttendee /> : <NewAttendee />}
<label>
<span className="mr-2 text-md">Did they receive swag?:</span>
<input type="checkbox" className="mt-4 accent-red-500 scale-125" checked={swag} onChange={e => setSwag(e.target.checked)} />
</div>}

{/* contact status */}
{idSearch.length === 7 && <>
{existingContact ? <div className="bg-green-700 bg-opacity-10 px-4 py-2 my-4 rounded-sm border border-green-500">
<span className="block font-semibold mx-2">
Contact Found!
</span>
<ul className="list-disc mx-2">
<li className="mt-0.5">
{existingContact.first_name}'s already logged in our system, so you don't have to enter their info.
</li>
</ul>
</div> : <div className="bg-red-700 bg-opacity-10 px-4 py-2 my-4 rounded-sm border border-red-500">
<span className="block font-semibold mx-2">
Contact Not Found!
</span>
<ul className="list-disc mx-2">
<li className="mt-0.5">
We don't have that contact logged in our system. Please create a new one below:
</li>
</ul>
</div>}
</>}

<form onSubmit={existingContact ? handleExistingSubmit : handleNewSubmit}>
<label className="w-full">
UH ID
<input
className="placeholder:text-neutral-500 focus:outline-none focus:border-blue-500 focus:ring-blue-500 w-full h-9 rounded-sm text-sm px-4 bg-zinc-800 border border-zinc-700"
name="uhid"
placeholder={"UH ID"}
maxLength={7}
value={idSearch}
onChange={e =>
{
setIdSearch(e.target.value);
const id = parseInt(e.target.value);
const memberDat = data as memberType[];

setExistingContact(memberDat.find((member) => member.uh_id === id));
}}
/>
</label>

{idSearch.length === 7 &&
<>
{existingContact ? <ExistingAttendee member={existingContact} /> : <NewAttendee />}
</>
}
</form>
</div>
</Layout >
</Layout>
);
};

export default AddAttendee;


const ExistingAttendee = () =>
type ExistingAttendeeProps = {
member: memberType;
};
const ExistingAttendee = ({ member }: ExistingAttendeeProps) =>
{
return (
<>
<label>
<span className="mr-2 text-md">Did they receive swag?:</span>
<input name="swagcheck" type="checkbox" className="mt-4 accent-red-500 scale-125" />
</label>

<button type="submit" className="mt-6 w-full text-white font-semibold text-sm h-9 rounded-sm bg-red-600 hover:bg-red-700">Add Attendee</button>
</>
);
Expand All @@ -156,7 +215,6 @@ const NewAttendee = () =>

return (
<>
<TextInput className="mt-4" name="uhid" label="UH ID" placeholder="1234567" />
<TextInput className="mt-4" name="first" label="First Name" placeholder="Mihir" />
<TextInput className="mt-4" name="last" label="Last Name" placeholder="Sahu" />
<TextInput className="mt-4" name="phone" label="Phone" placeholder="0123456789" />
Expand All @@ -176,6 +234,11 @@ const NewAttendee = () =>
/>
</div>

<label>
<span className="mr-2 text-md">Did they receive swag?:</span>
<input name="swagcheck" type="checkbox" className="mt-4 accent-red-500 scale-125" />
</label>

<button type="submit" className="mt-6 w-full text-white font-semibold text-sm h-9 rounded-sm bg-red-600 hover:bg-red-700">Add Contact</button>
</>
);
Expand Down

0 comments on commit 358ecfb

Please sign in to comment.