Forráskód Böngészése

appointment date error handling for edge cases

Liontix 11 hónapja
szülő
commit
e508088991

+ 37 - 3
public/html/appointmentscreator.html

@@ -2,9 +2,43 @@
 <html lang="en">
 <head>
     <meta charset="UTF-8">
-    <title>Title</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Create Appointment</title>
+    <link rel="stylesheet" href="../stylesheets/create-appointment.css">
+    <script src="../javascripts/creator-appointments.js" async></script>
 </head>
 <body>
-
+<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>
 </body>
-</html>
+</html>

+ 64 - 0
public/javascripts/creator-appointments.js

@@ -0,0 +1,64 @@
+"use strict";
+
+const appointmentErrorParagraph = document.getElementById("appointment-error");
+const appointmentSuccessParagraph = document.getElementById("appointment-success");
+const titleInput = document.getElementById('title');
+const descriptionInput = document.getElementById('description');
+const dueDateInput = document.getElementById('dueDate');
+const startDateInput = document.getElementById('startDate');
+const endDateInput = document.getElementById('endDate');
+const placeInput = document.getElementById('place');
+
+
+window.onload = async function() {
+    document.getElementById("appointment-btn").addEventListener('click', async () => {
+        await createAppointment();
+    })
+
+}
+
+async function fetchWithToken(url, options) {
+    const authToken = localStorage.getItem('token');
+    return await fetch(url, {...options, headers: {
+            'Authorization': `Bearer ${authToken}`,
+            'Content-Type': 'application/json',
+        }});
+}
+
+async function createAppointment() {
+    const title = titleInput.value;
+    const description = descriptionInput.value;
+    const dueDate = dueDateInput.value;
+    const startDate = startDateInput.value;
+    const endDate = endDateInput.value;
+    const place = placeInput.value;
+
+    if (!title || !description || !dueDate || !startDate || !endDate) {
+        appointmentSuccessParagraph.innerText = "";
+        appointmentErrorParagraph.innerText = "Not fields filled";
+        return;
+    }
+
+    const response = await fetchWithToken('/api/users/create', {
+        method: 'POST',
+        body: JSON.stringify({
+            title: title,
+            description: description,
+            dueDate: dueDate,
+            startDate: startDate,
+            endDate: endDate,
+            place: place
+        })
+    });
+    const js = await response.json();
+
+    if (!response.ok) {
+        appointmentSuccessParagraph.innerText = "";
+        appointmentErrorParagraph.innerText = js["message"];
+    } else {
+        appointmentErrorParagraph.innerText = "";
+        appointmentSuccessParagraph.innerText = "Appointment created successfully.";
+    }
+}
+
+

+ 87 - 0
public/stylesheets/create-appointment.css

@@ -0,0 +1,87 @@
+/* General Reset */
+* {
+    margin: 0;
+    padding: 0;
+    box-sizing: border-box;
+    font-family: Arial, sans-serif;
+}
+
+body {
+    display: grid;
+    place-items: center;
+    min-height: 100vh;
+    background-color: #f4f4f9;
+    margin: 0;
+}
+
+.container {
+    background: white;
+    padding: 20px 30px;
+    border-radius: 8px;
+    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+    width: 100%;
+    max-width: 500px;
+    display: grid;
+    gap: 20px;
+}
+
+h1 {
+    text-align: center;
+    color: #333;
+}
+
+form {
+    display: grid;
+    gap: 15px;
+}
+
+.input-group {
+    display: grid;
+    gap: 5px;
+}
+
+.input-group label {
+    font-size: 14px;
+    color: #555;
+}
+
+.input-group input {
+    width: 100%;
+    padding: 10px;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+    font-size: 14px;
+    transition: border-color 0.3s;
+}
+
+.input-group input:focus {
+    border-color: #6c63ff;
+    outline: none;
+}
+
+.btn-submit {
+    margin-top: 10px;
+    padding: 12px;
+    padding-inline: 30px;
+    border: none;
+    background: #6c63ff;
+    color: white;
+    font-size: 16px;
+    cursor: pointer;
+    border-radius: 4px;
+    transition: background 0.3s;
+}
+
+.btn-submit:hover {
+    background: #5750d9;
+}
+
+#appointment-error {
+    color: red;
+    margin-top: 10px;
+}
+
+#appointment-success {
+    color: green;
+    margin-top: 10px;
+}

+ 25 - 8
routes/members.js

@@ -4,6 +4,7 @@ import {mongoose} from "mongoose";
 import Appointment from "../schemas/appointmentSchema.js";
 import Booking from "../schemas/bookingSchema.js";
 import AppointmentSchema from "../schemas/appointmentSchema.js";
+import {isDatePassed, isDueDatePassed} from "../utils.js";
 const router = express.Router();
 
 
@@ -23,7 +24,23 @@ router.post('/create', function(req, res, next) {
     const { title, description, dueDate, place, startDate, endDate } = req.body;
 
     if (!title || title.length === 0 || !dueDate || !dueDate || !description || !startDate || !endDate || !place) {
-        res.status(400).json({ 'error': 'Empty parameter' });
+        res.status(400).json({ 'message': 'Empty parameter' });
+        return;
+    }
+
+    if (isDatePassed(startDate, dueDate)) {
+        res.status(400).json({ 'message': 'Due date is after start date' });
+        return;
+    }
+
+    if (isDueDatePassed(dueDate)) {
+        res.status(400).json({ 'message': 'Due date is in the past' });
+        return;
+    }
+
+    // TODO check if end date is before start date
+    if (isDatePassed(endDate, startDate)) {
+        res.status(400).json({ 'message': 'End date is before start date' });
         return;
     }
 
@@ -31,7 +48,7 @@ router.post('/create', function(req, res, next) {
 
     newTask.save()
         .then(doc => res.json({ "success": true }))
-        .catch(err => res.status(500).json({ 'error': err }));
+        .catch(err => res.status(500).json({ 'message': err }));
 
 });
 
@@ -57,17 +74,17 @@ router.put('/modify', function (req, res, next) {
                 res.json({ "success": true });
             } else {
                 console.log("Document not updated");
-                res.status(500).json({ 'error': 'Document has not changed' });
+                res.status(500).json({ 'message': 'Document has not changed' });
             }
         })
-        .catch(err => res.status(404).json({ 'error': 'Not found' }));
+        .catch(err => res.status(404).json({ 'message': 'Not found' }));
 });
 
 router.delete('/delete', function (req, res, next) {
     const user = req.userId;
     const {appointmentId} = req.body;
     if (!appointmentId) {
-        res.status(400).json({ 'error': 'Invalid parameter' });
+        res.status(400).json({ 'message': 'Invalid parameter' });
         return;
     }
 
@@ -76,10 +93,10 @@ router.delete('/delete', function (req, res, next) {
             if (result.deletedCount === 1) {
                 res.json({ 'success': true });
             } else {
-                res.status(404).json({ 'error': 'Not found' });
+                res.status(404).json({ 'message': 'Not found' });
             }
         })
-        .catch(err => res.status(500).json({ 'error': err }));
+        .catch(err => res.status(500).json({ 'message': err }));
 });
 
 
@@ -98,7 +115,7 @@ router.get('/bookings', function (req, res, next) {
     const { appointmentId } = req.query;
 
     if (!appointmentId) {
-        res.status(400).json({ 'error': 'Empty parameter' });
+        res.status(400).json({ 'message': 'Empty parameter' });
         return;
     }
 

+ 6 - 1
utils.js

@@ -10,5 +10,10 @@ function isDueDatePassed(dueDate) {
     return dueDateTime < now;
 }
 
+function isDatePassed(dateA, dateB) {
+    const dueDateA = new Date(dateA);
+    const dueDateB = new Date(dateB);
+    return dueDateA < dueDateB;
+}
 
-export {isValidEmail, isDueDatePassed};
+export {isValidEmail, isDueDatePassed, isDatePassed};