feat: complete day 17
This commit is contained in:
@@ -1,56 +1,97 @@
|
||||
<%- include('partials/header') %>
|
||||
<div style="padding: 32px; max-width: 700px; margin: 0 auto">
|
||||
<h3>Pick a date and time</h3>
|
||||
<p><b>Duration:</b> 1 hour</p>
|
||||
<p>Your timezone: <%= selectedTimezone %></p>
|
||||
<form action="/book" method="POST" style="margin-top: 32px">
|
||||
<h4>Additional Information</h4>
|
||||
<label>*Full Name</label>
|
||||
<input
|
||||
type="text"
|
||||
name="fullName"
|
||||
required
|
||||
style="width: 100%; margin-bottom: 12px"
|
||||
/>
|
||||
<label>*Email</label>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
required
|
||||
style="width: 100%; margin-bottom: 12px"
|
||||
/>
|
||||
<label>*Company</label>
|
||||
<input
|
||||
type="text"
|
||||
name="company"
|
||||
required
|
||||
style="width: 100%; margin-bottom: 12px"
|
||||
/>
|
||||
<label>*Phone</label>
|
||||
<input
|
||||
type="tel"
|
||||
name="phone"
|
||||
required
|
||||
style="width: 100%; margin-bottom: 12px"
|
||||
/>
|
||||
<label>*Your Notes</label>
|
||||
<textarea
|
||||
name="notes"
|
||||
required
|
||||
style="width: 100%; margin-bottom: 16px"
|
||||
></textarea>
|
||||
<button
|
||||
type="submit"
|
||||
style="
|
||||
background: #063970;
|
||||
color: #fff;
|
||||
padding: 8px 24px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
"
|
||||
>
|
||||
Done
|
||||
</button>
|
||||
</form>
|
||||
<div class="calendar-container">
|
||||
<div class="calendar-header">Calendar</div>
|
||||
<div class="calendar-content">
|
||||
<div class="calendar-labels">
|
||||
<div class="calendar-label-main">Pick a date and time</div>
|
||||
<div class="calendar-label-duration">Duration: <span>1 hour</span></div>
|
||||
<div class="calendar-label-timezone">
|
||||
Your timezone: <%= selectedTimezone %>
|
||||
</div>
|
||||
<% if (selectedDate && selectedTime) { %>
|
||||
<div class="calendar-label-selected">
|
||||
<strong>Selected:</strong> <%= selectedDate %> at <%= selectedTime %>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
<form class="booking-form" id="bookingForm">
|
||||
<input type="hidden" name="date" value="<%= selectedDate %>" />
|
||||
<input type="hidden" name="time" value="<%= selectedTime %>" />
|
||||
<input type="hidden" name="tz" value="<%= selectedTimezone %>" />
|
||||
<div class="form-group">
|
||||
<label for="fullName">Full Name</label>
|
||||
<input type="text" id="fullName" name="name" required />
|
||||
<div class="form-error" id="error-name"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" id="email" name="email" required />
|
||||
<div class="form-error" id="error-email"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="company">Company</label>
|
||||
<input type="text" id="company" name="company" required />
|
||||
<div class="form-error" id="error-company"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="phone">Phone</label>
|
||||
<input type="tel" id="phone" name="phone" required />
|
||||
<div class="form-error" id="error-phone"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="notes">Your Notes</label>
|
||||
<textarea id="notes" name="notes" required></textarea>
|
||||
<div class="form-error" id="error-notes"></div>
|
||||
</div>
|
||||
<button type="submit" class="form-submit-btn">Done</button>
|
||||
<div class="form-error" id="error-date"></div>
|
||||
<div class="form-error" id="error-time"></div>
|
||||
<div class="form-error" id="error-timezone"></div>
|
||||
<div class="form-error" id="error-general"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('partials/footer') %>
|
||||
<script>
|
||||
document.getElementById("bookingForm").onsubmit = async function (e) {
|
||||
e.preventDefault();
|
||||
// Clear previous errors
|
||||
document
|
||||
.querySelectorAll(".form-error")
|
||||
.forEach((el) => (el.textContent = ""));
|
||||
const form = e.target;
|
||||
const data = {
|
||||
name: form.fullName.value,
|
||||
email: form.email.value,
|
||||
company: form.company.value,
|
||||
phone: form.phone.value,
|
||||
notes: form.notes.value,
|
||||
date: form.date.value,
|
||||
time: form.time.value,
|
||||
timezone: form.tz.value,
|
||||
};
|
||||
try {
|
||||
const res = await fetch("/api/bookings", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
const result = await res.json();
|
||||
if (result.success) {
|
||||
window.location.href = "/success";
|
||||
} else if (result.error) {
|
||||
if (typeof result.error === "object") {
|
||||
for (const key in result.error) {
|
||||
const el = document.getElementById("error-" + key);
|
||||
if (el) el.textContent = result.error[key];
|
||||
}
|
||||
} else {
|
||||
document.getElementById("error-general").textContent = result.error;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
document.getElementById("error-general").textContent =
|
||||
"An error occurred. Please try again.";
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
+56
-54
@@ -1,58 +1,60 @@
|
||||
<%- include('partials/header') %>
|
||||
<div style="padding: 32px; max-width: 1100px; margin: 0 auto">
|
||||
<h3>Pick a date and time</h3>
|
||||
<p><b>Duration:</b> 1 hour</p>
|
||||
<p>Your timezone: <%= selectedTimezone %> <a href="/timezone">(Change)</a></p>
|
||||
<div style="overflow-x: auto; margin-top: 32px">
|
||||
<table style="width: 100%; border-collapse: collapse">
|
||||
<thead>
|
||||
<tr>
|
||||
<% weekDays.forEach(function(day) { %>
|
||||
<th style="padding: 8px 12px; border-bottom: 2px solid #eee">
|
||||
<div style="font-weight: bold; font-size: 1.1em">
|
||||
<%= day.label %>
|
||||
</div>
|
||||
<div style="font-size: 0.95em; color: #888"><%= day.date %></div>
|
||||
</th>
|
||||
<% }) %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% for (let i = 0; i < maxSlots; i++) { %>
|
||||
<tr>
|
||||
<% weekDays.forEach(function(day) { %>
|
||||
<td style="padding: 8px 12px; text-align: center">
|
||||
<% if (day.slots[i]) { %>
|
||||
<form action="/book" method="GET" style="display: inline">
|
||||
<input type="hidden" name="date" value="<%= day.dateISO %>" />
|
||||
<input type="hidden" name="time" value="<%= day.slots[i] %>" />
|
||||
<button
|
||||
type="submit"
|
||||
style="
|
||||
background: #fff;
|
||||
border: 1px solid #063970;
|
||||
color: #063970;
|
||||
border-radius: 4px;
|
||||
padding: 4px 12px;
|
||||
cursor: pointer;
|
||||
"
|
||||
>
|
||||
<%= day.slots[i] %>
|
||||
</button>
|
||||
</form>
|
||||
<% } %>
|
||||
</td>
|
||||
<% }) %>
|
||||
</tr>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="margin-top: 16px">
|
||||
<% if (showPrevWeek) { %>
|
||||
<a href="/calendar?week=prev">Previous Week</a>
|
||||
<% } %>
|
||||
<a href="/calendar?week=next" style="margin-left: 24px">Next Week</a>
|
||||
<div class="calendar-container">
|
||||
<div class="calendar-header">Calendar</div>
|
||||
<div class="calendar-content">
|
||||
<div class="calendar-labels">
|
||||
<div class="calendar-label-main">Pick a date and time</div>
|
||||
<div class="calendar-label-duration">Duration: <span>1 hour</span></div>
|
||||
<div class="calendar-label-timezone">
|
||||
Your timezone: <%= selectedTimezone %> <a href="/timezone">(Change)</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="calendar-table-wrapper">
|
||||
<table class="calendar-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<% weekDays.forEach(function(day) { %>
|
||||
<th>
|
||||
<div class="calendar-day-label"><%= day.label %></div>
|
||||
<div class="calendar-date-label"><%= day.date %></div>
|
||||
</th>
|
||||
<% }) %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% for (let i = 0; i < maxSlots; i++) { %>
|
||||
<tr>
|
||||
<% weekDays.forEach(function(day) { %>
|
||||
<td>
|
||||
<% if (day.slots[i]) { %>
|
||||
<form action="/book" method="get">
|
||||
<input type="hidden" name="date" value="<%= day.dateISO %>" />
|
||||
<input type="hidden" name="time" value="<%= day.slots[i] %>" />
|
||||
<input
|
||||
type="hidden"
|
||||
name="tz"
|
||||
value="<%= selectedTimezone %>"
|
||||
/>
|
||||
<button class="calendar-slot-btn"><%= day.slots[i] %></button>
|
||||
</form>
|
||||
<% } %>
|
||||
</td>
|
||||
<% }) %>
|
||||
</tr>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="calendar-week-nav">
|
||||
<% if (showPrevWeek) { %>
|
||||
<a href="/calendar?tz=<%= selectedTimezone %>&week=<%= prevWeek %>"
|
||||
>Previous Week</a
|
||||
>
|
||||
<% } %>
|
||||
<a href="/calendar?tz=<%= selectedTimezone %>&week=<%= nextWeek %>"
|
||||
>Next Week</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('partials/footer') %>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<%- include('partials/header') %>
|
||||
<div class="calendar-container">
|
||||
<div class="calendar-header">Error</div>
|
||||
<div class="calendar-content">
|
||||
<h1><%= message %></h1>
|
||||
<h2><%= error.status %></h2>
|
||||
<pre><%= error.stack %></pre>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('partials/footer') %>
|
||||
@@ -1,6 +0,0 @@
|
||||
extends layout
|
||||
|
||||
block content
|
||||
h1= message
|
||||
h2= error.status
|
||||
pre #{error.stack}
|
||||
@@ -0,0 +1,8 @@
|
||||
<%- include('partials/header') %>
|
||||
<div class="calendar-container">
|
||||
<div class="calendar-header"><%= title %></div>
|
||||
<div class="calendar-content">
|
||||
<p>Welcome to <%= title %></p>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('partials/footer') %>
|
||||
@@ -1,5 +0,0 @@
|
||||
extends layout
|
||||
|
||||
block content
|
||||
h1= title
|
||||
p Welcome to #{title}
|
||||
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><%= title %></title>
|
||||
<link rel="stylesheet" href="/stylesheets/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,7 +0,0 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title= title
|
||||
link(rel='stylesheet', href='/stylesheets/style.css')
|
||||
body
|
||||
block content
|
||||
@@ -1 +1,2 @@
|
||||
<div style="height: 40px"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,11 +1,9 @@
|
||||
<div
|
||||
style="
|
||||
background: #063970;
|
||||
color: white;
|
||||
padding: 24px 24px 12px 24px;
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
"
|
||||
>
|
||||
Calendar
|
||||
</div>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Calendar</title>
|
||||
<link rel="stylesheet" href="/stylesheets/style.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<%- include('partials/header') %>
|
||||
<div style="padding: 32px; max-width: 700px; margin: 0 auto">
|
||||
<p style="margin-top: 32px; font-size: 1.2em">
|
||||
<div class="calendar-container">
|
||||
<div class="calendar-header">Calendar</div>
|
||||
<div class="calendar-content success-message">
|
||||
Thanks for filling in the form. You will be emailed next steps.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('partials/footer') %>
|
||||
|
||||
+71
-41
@@ -1,48 +1,78 @@
|
||||
<%- include('partials/header') %>
|
||||
<div style="padding: 32px; max-width: 900px; margin: 0 auto">
|
||||
<h3>Pick a date and time</h3>
|
||||
<p><b>Duration:</b> 1 hour</p>
|
||||
<label>Your timezone:</label>
|
||||
<select name="timezone" id="timezone-select">
|
||||
<% timezones.forEach(function(tz) { %>
|
||||
<option value="<%= tz.value %>"><%= tz.label %></option>
|
||||
<% }) %>
|
||||
</select>
|
||||
<hr />
|
||||
<div style="display: flex; justify-content: center; margin-top: 40px">
|
||||
<div
|
||||
style="
|
||||
background: #fff;
|
||||
padding: 32px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px #0001;
|
||||
min-width: 400px;
|
||||
"
|
||||
>
|
||||
<h4>TIME ZONE</h4>
|
||||
<div style="display: flex; gap: 32px">
|
||||
<% Object.keys(timezoneGroups).forEach(function(region) { %>
|
||||
<div>
|
||||
<b><%= region %></b>
|
||||
<% timezoneGroups[region].forEach(function(tz) { %>
|
||||
<div>
|
||||
<input type="radio" name="timezoneRadio" value="<%= tz.value %>" />
|
||||
<%= tz.label %>
|
||||
</div>
|
||||
<% }) %>
|
||||
</div>
|
||||
<% }) %>
|
||||
<div class="calendar-container">
|
||||
<div class="calendar-header">Calendar</div>
|
||||
<div class="calendar-content">
|
||||
<div class="calendar-labels">
|
||||
<div class="calendar-label-main">Pick a date and time</div>
|
||||
<div class="calendar-label-duration">Duration: <span>1 hour</span></div>
|
||||
<div class="calendar-label-timezone">
|
||||
Your timezone:
|
||||
<button id="select-timezone-btn" class="timezone-btn">
|
||||
Please Select
|
||||
</button>
|
||||
</div>
|
||||
<div style="margin-top: 16px">
|
||||
<label
|
||||
><input type="radio" name="format" value="ampm" checked />
|
||||
am/pm</label
|
||||
>
|
||||
<label style="margin-left: 16px"
|
||||
><input type="radio" name="format" value="24hr" /> 24hr</label
|
||||
>
|
||||
</div>
|
||||
<!-- Modal Overlay -->
|
||||
<div id="timezone-modal" class="modal-overlay" style="display: none">
|
||||
<div class="modal-content">
|
||||
<div class="modal-title">TIME ZONE</div>
|
||||
<div class="modal-format-switch">
|
||||
<label
|
||||
><input type="radio" name="format" value="ampm" checked />
|
||||
am/pm</label
|
||||
>
|
||||
<label><input type="radio" name="format" value="24hr" /> 24hr</label>
|
||||
</div>
|
||||
<div class="timezone-groups">
|
||||
<% for (const group in timezoneGroups) { %>
|
||||
<div class="timezone-group">
|
||||
<div class="timezone-group-title"><%= group %></div>
|
||||
<% timezoneGroups[group].forEach(function(tz) { %>
|
||||
<label class="timezone-option">
|
||||
<input type="radio" name="timezone" value="<%= tz.name %>" />
|
||||
<span
|
||||
class="tz-time"
|
||||
data-am="<%= tz.time_am %>"
|
||||
data-24="<%= tz.time_24 %>"
|
||||
>
|
||||
<%= tz.label %>
|
||||
<span class="tz-time-value"><%= tz.time_am %></span>
|
||||
</span>
|
||||
</label>
|
||||
<% }) %>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('partials/footer') %>
|
||||
<script>
|
||||
// Modal logic
|
||||
const btn = document.getElementById("select-timezone-btn");
|
||||
const modal = document.getElementById("timezone-modal");
|
||||
btn.onclick = () => {
|
||||
modal.style.display = "flex";
|
||||
};
|
||||
modal.onclick = (e) => {
|
||||
if (e.target === modal) modal.style.display = "none";
|
||||
};
|
||||
document.querySelectorAll('input[name="timezone"]').forEach((el) => {
|
||||
el.onclick = () => {
|
||||
window.location.href = "/calendar?tz=" + encodeURIComponent(el.value);
|
||||
};
|
||||
});
|
||||
|
||||
// Time format toggle logic
|
||||
document.querySelectorAll('input[name="format"]').forEach((el) => {
|
||||
el.onchange = function () {
|
||||
const is24 = this.value === "24hr";
|
||||
document.querySelectorAll(".tz-time").forEach((span) => {
|
||||
const am = span.getAttribute("data-am");
|
||||
const t24 = span.getAttribute("data-24");
|
||||
span.querySelector(".tz-time-value").textContent = is24 ? t24 : am;
|
||||
});
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user