Skip to content

Conversation

@elijahzhao24
Copy link
Member

@elijahzhao24 elijahzhao24 commented Oct 23, 2025

decoupled applicationStatus (review decisions) from registrationStatus (payment/completion lifecycle) to fix UI bugs and provide clearer state management.

DONT MERGE YET AS I STILL WANT TO DO SOME LOCAL TESTING

New Fields

ApplicationStatus (Review Decisions)

REGISTERED - User has applied
INCOMPLETE - User needs to complete registration
ACCEPTED - Admin has accepted the application
WAITLISTED - User is on waitlist
REJECTED - Application was rejected
CHECKED-IN - User has checked in to the event
CANCELLED - Registration was cancelled

RegistrationStatus (Payment/Event Confirmation)

REVIEWING - Waiting for admin review
PENDING - Accepted, waiting for user confirmation
PAYMENTPENDING - Accepted, waiting for payment
COMPLETE - Fully registered and confirmed

Updated Endpoints

POST /registrations

used for registering for an event
Logic Flow
Non-application free: ACCEPTED + COMPLETE
Non-application paid: INCOMPLETE + PAYMENTPENDING
Application-based: REGISTERED + REVIEWING (or WAITLISTED + REVIEWING if full

PUT /registrations/{email}/{fname}

Update registration with admin actions

Admin Actions:
When accepting someone for application-based events:
applicationStatus: "ACCEPTED" auto-sets registrationStatus to "PENDING" (free) or "PAYMENTPENDING" (paid)

Setting applicationStatus: "WAITLISTED", applicationStatus: "REJECTED" will only change those fields. registrationStatus will stay "REVIEWING".

When execs are checking people for an event, just set applicationStatus: "CHECKED-IN". It shouldn't change registrationStatus.

A status change email is sent for all of these.

User Confirmation:
When a user signs up for an application-based free event, they will confirm by pressing a confirmation button. This button calls the PUT endpoint. Clicking this button will set applicationStatus to "ACCEPTED", and registrationStatus to "COMPLETE"
A status change and calendar invite email.

Payments eventRegistration endpoint

This is very similar to the original flow before the refactor.

When a member pays to confirm attendance for an application-based paid event.
When a member pays for a non-application-based paid event.

It will set applicationStatus to "ACCEPTED", and registrationStatus to "COMPLETE"

Sample workflows

Non-Application Free Event

User registers → POST /registrations
Status: ACCEPTED + COMPLETE

User attends → Admin checks in via PUT /registrations
Status: CHECKED-IN + COMPLETE

Non-Application Paid Event

User registers → POST /registrations
Status: INCOMPLETE + PAYMENTPENDING

User pays → Stripe webhook (automatic)
Status: ACCEPTED + COMPLETE

User attends → Admin checks in via PUT /registrations
Status: CHECKED-IN + COMPLETE

Application-Based Free Event

User applies → POST /registrations
Status: REGISTERED + REVIEWING

Admin accepts → PUT /registrations
Status: ACCEPTED + PENDING

User confirms with confirm button → PUT /registrations
Status: ACCEPTED + COMPLETE

User attends → Admin checks in via PUT /registrations
Status: CHECKED-IN + COMPLETE

Application-Based Paid Event

User applies → POST /registrations
Status: REGISTERED + REVIEWING

Admin accepts → PUT /registrations or PUT /registrations/massUpdate
Status: ACCEPTED + PAYMENTPENDING

User pays → Stripe webhook (automatic)
Status: ACCEPTED + COMPLETE

User attends → Admin checks in via PUT /registrations
Status: CHECKED-IN + COMPLETE

@@ -0,0 +1,58 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this file for

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debugging i will remove

let updatedApplicationStatus;
let updatedRegistrationStatus;

if (currentReg.registrationStatus === "PAYMENTPENDING") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should only set PAYMENTPENDING to COMPLETE if application status is already ACCEPTED. I don't think we need the INCOMPLETE state anymore, if it's non-application, we can just say they are ACCEPTED by default. It's just a matter of whether they paid already or not.

thoughts @kevinxiao27

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess i could add more guards, but I think it's unnecessary. This is the webhook that triggers when someone pays through stripe. I have it handled in my front end code that you are only allowed to pay after you have the state applicationStatus === "ACCEPTED" registrationStatus === "PAYMENTPENDING"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good


if (pricing > 0) {
// Paid event
data.applicationStatus = "INCOMPLETE";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can just set this to "COMPLETE" regardless for non-application based events, and just registrationStatus.

It will be better to manage 1 state only instead of 2 for payments, and it will be easier to debug down the line.

thoughts again @kevinxiao27

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nooooooooooooo just leave it how it is i'm too lazy to change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I already explicitly handled this case on the front end

 if (applicationStatus === ApplicationStatus.INCOMPLETE && registrationStatus === RegistrationStatus.PAYMENTPENDING) {
        const PaymentButton = () => {
          const [isLoading, setIsLoading] = useState(false);
          const [error, setError] = useState<string | null>(null); `

          const handlePaymentClick = async () => {
            if (!event || isLoading) return;

            setIsLoading(true);
            setError(null);

            try {
              const paymentUrl = await generatePaymentLink(
                event,
                registrationStatus,
              );
              if (paymentUrl) {
                window.open(paymentUrl, "_blank");
              } else {
                setError("Failed to generate payment link");
              }
            } catch (err) {
              console.error("Payment error:", err);
              setError("An error occurred. Please try again.");
            } finally {
              setIsLoading(false);
            }
          }; 

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good

@elijahzhao24 elijahzhao24 changed the title Refactor registration status Refactor registration status Backend Oct 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants