Browse Source

added participant page

Liontix 11 months ago
parent
commit
bc84c1e45a

+ 30 - 30
public/html/appointmentscreator.html

@@ -20,38 +20,38 @@
     </ul>
 </nav>
 <div class="content">
-<div class="container">
-    <h2>Create Appointment</h2>
-    <div id="appointment-form">
-        <div class="input-group">
-            <label for="title">Title</label>
-            <input type="text" id="title" placeholder="Enter title" required>
+    <div class="container">
+        <h2>Create Appointment</h2>
+        <div id="appointment-form">
+            <div class="input-group">
+                <label for="title">Title</label>
+                <input type="text" id="title" placeholder="Enter title" required>
+            </div>
+            <div class="input-group">
+                <label for="description">Description</label>
+                <textarea id="description" placeholder="Enter description" rows="4" required></textarea>
+            </div>
+            <div class="input-group">
+                <label for="dueDate">Due Date</label>
+                <input type="date" id="dueDate" required>
+            </div>
+            <div class="input-group">
+                <label for="startDate">Start Date</label>
+                <input type="datetime-local" id="startDate" required>
+            </div>
+            <div class="input-group">
+                <label for="endDate">End Date</label>
+                <input type="datetime-local" id="endDate" required>
+            </div>
+            <div class="input-group">
+                <label for="place">Place</label>
+                <input type="text" id="place" placeholder="Enter location" required>
+            </div>
+            <button type="submit" class="btn-submit" id="appointment-btn">Create Appointment</button>
+            <p id="appointment-error"></p>
+            <p id="appointment-success"></p>
         </div>
-        <div class="input-group">
-            <label for="description">Description</label>
-            <textarea id="description" placeholder="Enter description" rows="4" required></textarea>
-        </div>
-        <div class="input-group">
-            <label for="dueDate">Due Date</label>
-            <input type="date" id="dueDate" required>
-        </div>
-        <div class="input-group">
-            <label for="startDate">Start Date</label>
-            <input type="datetime-local" id="startDate" required>
-        </div>
-        <div class="input-group">
-            <label for="endDate">End Date</label>
-            <input type="datetime-local" id="endDate" required>
-        </div>
-        <div class="input-group">
-            <label for="place">Place</label>
-            <input type="text" id="place" placeholder="Enter location" required>
-        </div>
-        <button type="submit" class="btn-submit" id="appointment-btn">Create Appointment</button>
-        <p id="appointment-error"></p>
-        <p id="appointment-success"></p>
     </div>
 </div>
-</div>
 </body>
 </html>

+ 49 - 2
public/html/bookings.html

@@ -2,9 +2,56 @@
 <html lang="en">
 <head>
     <meta charset="UTF-8">
-    <title>Title</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Appointment Details</title>
+    <script src="../javascripts/navbar.js" async></script>
+    <script src="../javascripts/bookings.js" async></script>
+    <link rel="stylesheet" href="../stylesheets/navbar.css">
+    <link rel="stylesheet" href="../stylesheets/bookings.css">
 </head>
 <body>
+<nav class="navbar">
+    <div class="navbar-brand">Scheduler</div>
+    <ul class="navbar-links">
+        <li><a href="/html/appointments.html">Appointments</a></li>
+        <li><a href="/html/appointmentscreator.html">Create</a></li>
+        <li><a href="#" id="logout-button">Logout</a></li>
+    </ul>
+</nav>
+<div class="content">
+<div class="container">
+    <h1>Appointment Details</h1>
 
+    <!-- Appointment Information -->
+    <div class="appointment-info">
+    </div>
+
+    <!-- Participants Table -->
+    <h2>Participants</h2>
+    <div class="table-wrapper">
+        <table>
+            <thead>
+            <tr>
+                <th>First Name</th>
+                <th>Last Name</th>
+                <th>Email</th>
+            </tr>
+            </thead>
+            <tbody id="participants-table-body">
+            <tr>
+                <td>John</td>
+                <td>Doe</td>
+                <td>johndoe@example.com</td>
+            </tr>
+            <tr>
+                <td>Jane</td>
+                <td>Smith</td>
+                <td>janesmith@example.com</td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+</div>
+</div>
 </body>
-</html>
+</html>

+ 132 - 0
public/javascripts/bookings.js

@@ -0,0 +1,132 @@
+"use strict";
+
+window.addEventListener("load", async function () {
+    const urlParams = new URLSearchParams(window.location.search);
+    const appointment = urlParams.get('appointment');
+    if (!appointment) {
+        window.location.replace("/html/404.html");
+    }
+    await getAppointment(appointment);
+    await fetchBookings(appointment);
+});
+
+async function fetchWithToken(url, options) {
+    const authToken = localStorage.getItem('token');
+    return await fetch(url, {...options, headers: {
+            'Authorization': `Bearer ${authToken}`,
+            'Content-Type': 'application/json',
+        }});
+}
+
+function displayAppointmentDetails(appointmentData) {
+    // Retrieve the container
+    const appointmentInfo = document.querySelector('.appointment-info');
+
+    // Clear existing content
+    while (appointmentInfo.firstChild) {
+        appointmentInfo.removeChild(appointmentInfo.firstChild);
+    }
+
+    // Create and append the updated appointment content
+    const title = document.createElement('p');
+    const titleLabel = document.createElement('strong');
+    titleLabel.textContent = 'Title: ';
+    title.appendChild(titleLabel);
+    title.appendChild(document.createTextNode(appointmentData.title));
+
+    const description = document.createElement('p');
+    const descriptionLabel = document.createElement('strong');
+    descriptionLabel.textContent = 'Description: ';
+    description.appendChild(descriptionLabel);
+    description.appendChild(document.createTextNode(appointmentData.description));
+
+    const place = document.createElement('p');
+    const placeLabel = document.createElement('strong');
+    placeLabel.textContent = 'Place: ';
+    place.appendChild(placeLabel);
+    place.appendChild(document.createTextNode(appointmentData.place));
+
+    const dueDate = document.createElement('p');
+    const dueDateLabel = document.createElement('strong');
+    dueDateLabel.textContent = 'Due Date: ';
+    dueDate.appendChild(dueDateLabel);
+    dueDate.appendChild(document.createTextNode(new Date(appointmentData.dueDate).toLocaleDateString()));
+
+    const timeSpan = document.createElement('p');
+    const timeSpanLabel = document.createElement('strong');
+    timeSpanLabel.textContent = 'Time Span: ';
+    timeSpan.appendChild(timeSpanLabel);
+    timeSpan.appendChild(document.createTextNode(getTimeSpan(appointmentData.startDate, appointmentData.endDate)));
+
+    // Append all the updated elements
+    appointmentInfo.appendChild(title);
+    appointmentInfo.appendChild(description);
+    appointmentInfo.appendChild(place);
+    appointmentInfo.appendChild(dueDate);
+    appointmentInfo.appendChild(timeSpan);
+}
+
+// Helper function to format the time span
+function getTimeSpan(startDate, endDate) {
+    const start = new Date(startDate).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
+    const end = new Date(endDate).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
+    return `${start} to ${end}`;
+}
+
+async function getAppointment(appointment) {
+    const options = {method: 'GET', headers: {'User-Agent': 'insomnia/10.0.0'}};
+
+    const response = await fetch(`/api/schedule?isUser=true&appointmentId=${appointment}`, options)
+        .catch(err => console.error('error:' + err));
+
+    if (response.status === 404) {
+        window.location.replace("/html/404.html");
+    }
+
+    const js = await response.json();
+    displayAppointmentDetails(js);
+}
+
+
+function renderBookings(data) {
+    const tableBody = document.getElementById('participants-table-body');
+    tableBody.innerHTML = ''; // Clear existing rows
+
+    data.forEach(participant => {
+        // Create a new table row
+        const row = document.createElement('tr');
+
+        // Create table cells for first name, last name, and email
+        const firstNameCell = document.createElement('td');
+        const lastNameCell = document.createElement('td');
+        const emailCell = document.createElement('td');
+
+        // Populate cell content with participant data
+        firstNameCell.textContent = participant.firstname;
+        lastNameCell.textContent = participant.lastname;
+        emailCell.textContent = participant.email;
+
+        // Append cells to the row
+        row.appendChild(firstNameCell);
+        row.appendChild(lastNameCell);
+        row.appendChild(emailCell);
+
+        // Append the row to the table body
+        tableBody.appendChild(row);
+    });
+}
+
+
+async function fetchBookings(appointmentId) {
+    const response = await fetchWithToken(`/api/users/bookings?appointmentId=${appointmentId}`);
+    if (response.status === 401) {
+        window.location.replace("/html/auth.html");
+        return;
+    }
+
+    const js = await response.json();
+    if (!response.ok) {
+        window.location.replace("/html/404.html");
+    }
+    renderBookings(js);
+}

+ 8 - 1
public/javascripts/creator-appointments.js

@@ -11,8 +11,15 @@ const placeInput = document.getElementById('place');
 
 
 window.addEventListener("load", async function() {
+    const urlParams = new URLSearchParams(window.location.search);
+    appointment = urlParams.get('appointment');
+
     document.getElementById("appointment-btn").addEventListener('click', async () => {
-        await createAppointment();
+        if (!appointment) {
+            await createAppointment();
+        } else {
+            // modify appointment
+        }
     })
     console.log(titleInput.value);
 });

+ 1 - 0
public/javascripts/index.js

@@ -2,4 +2,5 @@
 
 window.addEventListener("load", function() {
     window.location.replace("/html/appointments.html");
+
 });

+ 15 - 10
public/stylesheets/appointments.css

@@ -3,9 +3,8 @@
     background-color: #f4f4f9;
     margin: 0;
     padding: 0;
-    display: flex;
-    justify-content: center;
-    align-items: center;
+    display: grid;
+    place-items: center;
     box-sizing: border-box;
 }
 
@@ -25,24 +24,30 @@ h2 {
     margin-bottom: 20px;
 }
 
+/* Table Styling */
+.table-wrapper {
+    overflow-x: auto;
+}
+
 table {
     width: 100%;
     border-collapse: collapse;
-    margin: 20px 0;
-    font-size: 16px;
-    color: #333333;
+    text-align: left;
 }
 
 th, td {
-    text-align: left;
     padding: 12px;
-    border-bottom: 1px solid #dddddd;
-    word-wrap: break-word; /* Prevent text from overflowing */
+    border: 1px solid #ddd;
 }
 
 th {
-    background-color: #0078d7;
+    background-color: #6c63ff;
     color: white;
+    font-weight: normal;
+}
+
+tr:nth-child(even) {
+    background-color: #f9f9f9;
 }
 
 tr:hover {

+ 108 - 0
public/stylesheets/bookings.css

@@ -0,0 +1,108 @@
+/* General Reset */
+.content {
+    margin: 0;
+    padding: 0;
+    box-sizing: border-box;
+    font-family: Arial, sans-serif;
+    display: grid;
+    place-items: center;
+    background-color: #f4f4f9;
+}
+
+body {
+    background-color: #f4f4f9;
+}
+
+/* Container */
+.container {
+    background: white;
+    padding: 20px 30px;
+    border-radius: 8px;
+    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+    width: 100%;
+    max-width: 800px;
+    display: grid;
+    gap: 10px;
+}
+
+h1, h2 {
+    text-align: center;
+    color: #333;
+}
+
+/* Appointment Info */
+.appointment-info {
+    display: grid;
+    gap: 5px;
+    font-size: 16px;
+    color: #555;
+}
+
+.appointment-info p {
+    line-height: 1.6;
+}
+
+/* Table Styling */
+.table-wrapper {
+    overflow-x: auto;
+}
+
+table {
+    width: 100%;
+    border-collapse: collapse;
+    text-align: left;
+}
+
+th, td {
+    padding: 12px;
+    border: 1px solid #ddd;
+}
+
+th {
+    background-color: #6c63ff;
+    color: white;
+    font-weight: normal;
+}
+
+tr:nth-child(even) {
+    background-color: #f9f9f9;
+}
+
+tr:hover {
+    background-color: #f1f1f1;
+}
+
+
+/* Responsive adjustments */
+@media (max-width: 768px) {
+    body {
+        height: auto;
+        padding: 20px;
+    }
+
+    h2 {
+        font-size: 1.5rem;
+    }
+
+    table {
+        font-size: 14px;
+    }
+
+    th, td {
+        padding: 10px;
+    }
+}
+
+@media (max-width: 480px) {
+    table {
+        font-size: 10px;
+    }
+
+    th, td {
+        padding: 8px;
+    }
+
+    th {
+        font-size: 0.9rem;
+    }
+}

+ 3 - 0
public/stylesheets/navbar.css

@@ -1,6 +1,9 @@
 
 /* Navbar Styling */
 .navbar {
+    position: sticky;
+    top: 0; /* Stick to the top */
+    z-index: 1000; /* Ensures the navbar stays above other elements */
     display: grid;
     grid-template-columns: auto 1fr auto;
     align-items: center;

+ 3 - 2
routes/appointments.js

@@ -54,13 +54,14 @@ router.post('/create', async function(req, res, next) {
 });
 
 router.get('/', function (req, res, next) {
-    const {appointmentId} = req.query;
+    const {appointmentId, isUser} = req.query;
     Appointment.findOne({ _id: appointmentId })
         .then(appointment => {
             if (appointment === null) {
                 res.status(404).json({'message': "Appointment not found"});
             } else {
-                if (isDueDatePassed(appointment["dueDate"])) {
+                // TODO check if a registered user accesses this / move the endpoint
+                if (isDueDatePassed(appointment["dueDate"]) && !isUser) {
                     return res.status(410).json({ message: 'appointment registration is closed' });
                 } else {
                     res.json(appointment);