<html>

<head>
  <title>OBS Ticketing Form</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    /* global styles */
    body {
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      margin: 0;
      padding: 0;
      background-color: #fff;
    }

    h1 {
      font-size: 36px;
      text-align: center;
      margin-top: 20px;
      margin-bottom: 30px;
    }

    form {
      max-width: 50vw;
      margin: 0 auto;
      padding: 20px;
      background-color: #f5f5f5;
      border-radius: 10px;
    }

    label {
      font-weight: bold;
      display: block;
      margin-bottom: 10px;
    }

    select,
    input[type="text"] {
      width: 97%;
      padding: 10px;
      font-size: 16px;
      border-radius: 5px;
      border: none;
      background-color: var(--input-bg-color, #e0e0e0);
      margin-bottom: 20px;
      transition: background-color 0.3s ease;
    }

    select:focus,
    input[type="text"]:focus {
      outline: none;
      box-shadow: 0 0 5px #999;
      background-color: var(--input-focus-bg-color, #f0f0f0);
    }

    .form-fields {
      margin-top: 20px;
      margin-bottom: 20px;
    }

    #error {
      color: red;
      font-weight: bold;
      margin-bottom: 20px;
    }

    #total {
      font-size: 24px;
      font-weight: bold;
      margin-left: 10px;
    }

    button[type="button"] {
      padding: 10px 20px;
      background-color: var(--button-bg-color, #4CAF50);
      border: none;
      color: white;
      font-size: 16px;
      border-radius: 5px;
      cursor: pointer;
      transition: background-color 0.3s ease;
    }

    button[type="button"]:hover {
      background-color: var(--button-hover-bg-color, #3e8e41);
    }

    /* media queries */
    @media screen and (max-width: 600px) {
      form {
        max-width: 100%;
        margin: 0;
        padding: 10px;
      }
    }
  </style>
</head>

<body>
  <h1>Ticketing Form</h1>
  <form id="ticket-form">
    <label for="ticket-type">Ticket Type:</label>
    <select id="ticket-type">
      <option value="Early Bird">Early Bird</option>
      <option value="Late Bird">Late Bird</option>
    </select>
    <br><br>

    <label for="form-of-ticket">Form of Ticket:</label>
    <select id="form-of-ticket">
      <option value="Full Ticket">Full Ticket</option>
      <option value="Partial Ticket">Partial Ticket</option>
    </select>
    <br><br>

    <label for="participant-type">Participant Type:</label>
    <select id="participant-type">
      <option value="ICBAS Student">ICBAS Student</option>
      <option value="Non-ICBAS Student">Non-ICBAS Student</option>
      <option value="Non-Student">Non-Student</option>
    </select>
    <br><br>

    <div id="form-fields">
      <!-- Form fields will be generated dynamically -->
    </div>

    <div>
      <label for="coupon-code">
        Coupon Code:
      </label>
      <input type="text" id="coupon-code" aria-label="Coupon Code" />
      <div id="coupon-error"></div>
    </div>
    <br><br>

    <label for="total">Total:</label>
    <span id="total"></span>

    <br><br>

    <button type="button" id="submit-button">Payment</button>
  </form>
  <button id="checkout-button">Checkout</button>

  <script>
    // Your JavaScript code goes here
    const commonRequiredInfo = ["Full Name", "Email", "Phone Number"];
    const commonCoupons = ["100OFF"];
    const tickets = {
      "Early Bird": {
        "Full Ticket": {
          "ICBAS Student": {
            price: 35.5,
            coupons: [...commonCoupons, "ICBASPROMOFULL"],
            requiredInfo: [...commonRequiredInfo, "Student Number", "Academic Year"]
          },
          "Non-ICBAS Student": {
            price: 38.5,
            coupons: commonCoupons,
            requiredInfo: [
              ...commonRequiredInfo,
              "University",
              "Faculty",
              "Academic Year"
            ]
          }
        },
        "Partial Ticket": {
          "ICBAS Student": {
            price: 15.5,
            coupons: [...commonCoupons, "ICBASPROMOPARTIAL"],
            requiredInfo: [...commonRequiredInfo, "Student Number", "Academic Year"]
          },
          "Non-ICBAS Student": {
            price: 18.5,
            coupons: commonCoupons,
            requiredInfo: [
              ...commonRequiredInfo,
              "University",
              "Faculty",
              "Academic Year"
            ]
          },
          "Non-Student": {
            price: 39.5,
            coupons: commonCoupons,
            requiredInfo: commonRequiredInfo
          }
        }
      },
      "Late Bird": {
        "Full Ticket": {
          "ICBAS Student": {
            price: 38.5,
            coupons: [...commonCoupons, "ICBASPROMOFULL"],
            requiredInfo: [...commonRequiredInfo, "Student Number", "Academic Year"]
          },
          "Non-ICBAS Student": {
            price: 41.5,
            coupons: commonCoupons,
            requiredInfo: [
              ...commonRequiredInfo,
              "University",
              "Faculty",
              "Academic Year"
            ]
          }
        },
        "Partial Ticket": {
          "ICBAS Student": {
            price: 18.5,
            coupons: [...commonCoupons, "ICBASPROMOPARTIAL"],
            requiredInfo: [...commonRequiredInfo, "Student Number", "Academic Year"]
          },
          "Non-ICBAS Student": {
            price: 21.5,
            coupons: commonCoupons,
            requiredInfo: [
              ...commonRequiredInfo,
              "University",
              "Faculty",
              "Academic Year"
            ]
          },
          "Non-Student": {
            price: 42.5,
            coupons: commonCoupons,
            requiredInfo: commonRequiredInfo
          }
        }
      }
    };
    const updateTotal = (price) => {
      const couponCode = document.getElementById("coupon-code").value;
      const couponResult = applyCoupon(couponCode, price);
      if (price === -1) {
        // document.getElementById("coupon-error").textContent = "Invalid";
        // document.getElementById("total").textContent = "invalid";
      } else {
        document.getElementById("coupon-error").textContent = "";
        if (couponResult.isValid) {
          const discountedPrice = couponResult.discount;
          document.getElementById("total").textContent = discountedPrice.toFixed(2);
        } else {
          document.getElementById("coupon-error").textContent = "Invalid coupon code";
          return -1;
        }
      }
      return couponResult.discount;
    };
    const applyCoupon = (couponCode, price) => {
      const couponMapping = {
        "100OFF": 0,
        "ICBASPROMOFULL": 200,
        "ICBASPROMOPARTIAL": 300
      };
      if (couponCode) {
        if (couponMapping.hasOwnProperty(couponCode)) {
          const discount = couponMapping[couponCode];
          return {
            isValid: true,
            discount
          };
        } else {
          return {
            isValid: false
          };
        }
      } else {
        return {
          isValid: true,
          discount: price
        };
      }
    };
    const generateFormFields = (requiredInfo) => {
      let formFields = "";
      requiredInfo.forEach((info) => {
        formFields += `
      <div>
        <label for="${info}">
          ${info}:
        </label>
        <input type="text" id="${info}" required aria-label="${info}" />
      </div>
    `;
      });
      return formFields;
    };
    const updateFormFields = () => {
      const ticketType = document.getElementById("ticket-type");
      const formOfTicket = document.getElementById("form-of-ticket");
      const participantType = document.getElementById("participant-type");
      // Check that required form elements exist
      if (!ticketType || !formOfTicket || !participantType) {
        console.error("Error: Required form elements not found");
        return;
      }
      const ticketTypeValue = ticketType.value;
      const formOfTicketValue = formOfTicket.value;
      const participantTypeValue = participantType.value;
      // Check that entered values are valid
      if (!tickets[ticketTypeValue] || !tickets[ticketTypeValue][formOfTicketValue] || !tickets[ticketTypeValue][formOfTicketValue][participantTypeValue]) {
        console.error("Error: Invalid form values entered");
        return;
      }
      const requiredInfo =
        tickets[ticketTypeValue][formOfTicketValue][participantTypeValue].requiredInfo;
      const formFields = generateFormFields(requiredInfo);
      document.getElementById("form-fields").innerHTML = formFields;
    };
    const checkFormFields = () => {
      const requiredFields = document.querySelectorAll("#form-fields input[required]");
      let isFormValid = true;
      requiredFields.forEach((field) => {
        if (field.value.trim() === "") {
          isFormValid = false;
          updateTotal(-1);
        }
      });
      return isFormValid;
    };
    const calculateTotal = () => {
      try {
        const ticketPrice =
          tickets[document.getElementById("ticket-type").value][
            document.getElementById("form-of-ticket").value
          ][document.getElementById("participant-type").value].price;
        updateTotal(ticketPrice);
        if (!checkFormFields()) {
          throw new Error("Please fill in all required form fields");
        }
      } catch (error) {
        console.error(error);
      }
    };
    const submitForm = (event) => {
      event.preventDefault(); // prevent the default form submission
      const ticketType = document.getElementById("ticket-type").value;
      const formOfTicket = document.getElementById("form-of-ticket").value;
      const participantType = document.getElementById("participant-type").value;
      if (!tickets[ticketType] || !tickets[ticketType][formOfTicket] || !tickets[ticketType][formOfTicket][participantType] || !checkFormFields()) {
        console.error("Error: Invalid form values entered");
        alert("Invalid form values entered. Please select valid options.");
        return;
      }
      const endpoint = 'http://localhost:3000/api/checkout';
      const params = new URLSearchParams({
        ticket_type: ticketType,
        form_of_ticket: formOfTicket,
        participant_type: participantType,
        price: tickets[ticketType][formOfTicket][participantType],
        // add any additional query parameters here
      });
      fetch(`${endpoint}?${params}`, {
          method: 'POST'
        })
        .then(response => {
          if (!response.ok) {
            throw new Error('Network response was not ok');
          }
          return response.json();
        })
        .then(data => {
          // handle the response data
          alert('Order submitted successfully!');
          console.log(data);
        })
        .catch(error => {
          // handle any errors that occur
          alert('Error submitting order. Please try again.');
          console.error(error);
        });
    };
    document.getElementById("ticket-type").addEventListener("change", () => {
      updateFormFields();
      calculateTotal();
    });
    document.getElementById("form-of-ticket").addEventListener("change", () => {
      updateFormFields();
      calculateTotal();
    });
    document.getElementById("participant-type").addEventListener("change", () => {
      updateFormFields();
      calculateTotal();
    });
    document.getElementById("coupon-code").addEventListener("input", () => {
      calculateTotal();
    });
    document.getElementById("submit-button").addEventListener("click", submitForm);
    // initial form setup
    updateFormFields();
    calculateTotal();
  </script>
</body>

</html>
// const button = document.getElementById('checkout-button');

// button.addEventListener('click', () => {
//   const endpoint = 'http://localhost:3000/api/checkout';
//   const params = new URLSearchParams({
//     ticket_type: 'General Admission',
//     promo_code: 'SPRINGSALE',
//     name: 'John Doe',
//     email: 'john.doe@example.com',
//     price: 0
//   });

//   fetch(`${endpoint}?${params}`, { method: 'POST' })
//     .then(response => {
//       // handle the response
//     })
//     .catch(error => {
//       // handle the error
//     });
// });
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js