This commit is contained in:
louiscklaw
2025-02-01 01:58:47 +08:00
parent b3da7aaef5
commit 04dbefcbaf
1259 changed files with 280657 additions and 0 deletions

View File

@@ -0,0 +1,162 @@
body {
padding-left: 50px;
padding-right: 50px;
font-family: 'Kalam';
}
#my-events-header {
font-size: 2vw;
}
#participated-events-header {
font-size: 2vw;
}
#page-header {
font-size: 40px;
padding-top: 10px;
}
.header {
text-align: center;
}
#comment-page-container {
text-align: center;
}
header {
text-align: center;
}
#my-events {
background-color: #efefd0;
font-size: 1vw;
min-height: 600px;
max-height: 600px;
width: 100%;
border-radius: 30px;
padding: 20px;
overflow: auto;
}
#participated-events {
font-size: 1vw;
max-height: 600px;
min-height: 600px;
width: 100%;
background-color: #efefd0;
border-radius: 30px;
padding: 20px;
overflow: auto;
}
#my-events-list {
min-width: 100%;
min-height: 100%;
background-color: #f29659;
border-radius: 30px;
}
#participated-events-list {
min-width: 100%;
min-height: 100%;
background-color: #f29659;
border-radius: 30px;
}
.background-frame {
min-height: 100%;
}
#input-list-my-events {
max-width: 100%;
text-align: center;
}
#input-list-participated-events {
max-width: 100%;
text-align: center;
}
#btn-container {
display: flex;
justify-content: center;
text-align: center;
}
/* CSS */
.button-53 {
background-color: #f29659;
border: 0 solid #e5e7eb;
box-sizing: border-box;
color: #000000;
display: flex;
font-family: ui-sans-serif, system-ui, -apple-system, system-ui, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
font-size: 1rem;
font-weight: 700;
justify-content: center;
line-height: 1.75rem;
padding: 0.75rem 1.65rem;
position: relative;
text-align: center;
text-decoration: none #000000 solid;
text-decoration-thickness: auto;
width: 100%;
max-width: 460px;
position: relative;
cursor: pointer;
transform: rotate(-2deg);
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
}
.button-53:focus {
outline: 0;
}
.button-53:after {
content: '';
position: absolute;
border: 1px solid #000000;
bottom: 4px;
left: 4px;
width: calc(100% - 1px);
height: calc(100% - 1px);
}
.button-53:hover:after {
bottom: 2px;
left: 2px;
}
@media (min-width: 768px) {
.button-53 {
padding: 0.75rem 3rem;
font-size: 1.25rem;
}
}
/* Scroll bar */
::-webkit-scrollbar {
width: 15px;
}
::-webkit-scrollbar-track {
box-shadow: inset 0 0 5px grey;
border-radius: 5px;
height: 200px;
}
::-webkit-scrollbar-thumb {
background: #f29659;
border-radius: 5px;
min-height: 250px;
}
::-webkit-scrollbar-thumb:hover {
background: white;
}

View File

@@ -0,0 +1,158 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link href="https://fonts.googleapis.com/css?family=Kalam" rel="stylesheet" />
<link rel="stylesheet" href="./comment.css" />
<title>Comment Page</title>
</head>
<body style="display: none">
<div class="navbar-container container">
<!-- NAVBAR: to be loaded with js -->
</div>
<header id="page-header">COMMENT</header>
<div id="btn-container">
<div class="btn button-53" data-bs-toggle="modal" data-bs-target="#comment-modal">Submit Comment</div>
</div>
<div id="comment-page" class="row">
<div class="col-md-6">
<div class="eventname frame line1">
<div class="background-frame">
<div class="header" id="my-events-header">My Events</div>
<div id="my-events">
<div id="my-events-list">
<table class="table" id="input-list-my-events">
<thead>
<tr>
<th scope="col">Sender</th>
<th scope="col">Message</th>
<th scope="col">Event</th>
<th scope="col">Received on</th>
<th scope="col">Mark as read</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="date-time frame line1">
<div class="background-frame">
<div class="header" id="participated-events-header">Participated Events</div>
<div id="participated-events">
<div id="participated-events-list">
<table class="table" id="input-list-participated-events">
<thead>
<tr>
<th scope="col">Sender</th>
<th scope="col">Message</th>
<th scope="col">Event</th>
<th scope="col">Received on</th>
<th scope="col">Read by Creator</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Comment Modal -->
<div
class="modal fade"
id="comment-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">SUBMIT COMMENT</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div class="input-group">
<form id="comment-form" class="register-form">
<div class="input-panel mb-3">
<div class="form-header">RECEIVER</div>
<select name="receiver" id="receiver">
<option value="null">Selector Receiver</option>
<!-- to be input by JS -->
</select>
</div>
<div class="input-panel mb-3">
<div class="form-header">COMMENT</div>
<textarea id="comment" class="form-control" name="comment" rows="5" cols="50">
</textarea>
</div>
<div class="input-panel mb-3">
<div class="form-header">Regarding...</div>
<select name="category" id="category">
<option value="items">Event Items</option>
<option value="venue">Location</option>
<option value="date-time">Event Date/Time</option>
<option value="budget">Budget</option>
<option value="participant">Participant</option>
<option value="activity">Event Activity</option>
<option value="others">others</option>
</select>
</div>
<div class="input-panel mb-3"></div>
<input type="checkbox" id="anonymous" name="anonymous" unchecked />
<label for="anonymous">Send anonymously?</label><br />
<div class="modal-footer">
<button id="submit-comment" type="submit" class="btn btn-primary button-53">
Submit
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="https://thibaultjanbeyer.github.io/DragSelect/ds.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8"
crossorigin="anonymous"
></script>
<script type="module" src="./comment.js"></script>
</body>
</html>

View File

@@ -0,0 +1,202 @@
import { addNavbar } from '/functions/addNavbar.js';
import { loadName } from '/functions/loadName.js';
window.addEventListener('load', async () => {
addNavbar();
await loadName();
await getComment();
await checkedComment();
document.body.style.display = 'block';
});
async function getComment() {
const res = await fetch(`/comment/`);
if (res.status !== 200) {
const data = await res.json();
alert(data.msg);
return;
}
const result = await res.json();
// to Creator List
const creatorCommentArr = result.cComment;
const creatorCommentContainer = document.querySelector('#input-list-my-events');
creatorCommentArr.forEach((comment) => {
let name = comment.first_name + ' ' + comment.last_name;
if (comment.anonymous) {
name = 'Anonymous';
}
let checked = 'unchecked';
const eventId = comment.event_id;
const content = comment.content;
const receivingTime = new Date(comment.created_at).toLocaleDateString('en-US');
const commentId = comment.id;
const eventName = comment.name;
if (comment.read) {
checked = 'checked';
creatorCommentContainer.innerHTML += `
<tr id="comment-box" class="comment-box">
<th class="table-secondary">${name}</th>
<th class="table-secondary">${content}</th>
<th class="table-secondary">${eventName}</th>
<th class="table-secondary">${receivingTime}</th>
<th class="table-secondary"><input type="checkbox" event="${eventId}" value="${commentId}" id="creator-read" name="creator-read" ${checked}></th>
</tr>
`;
} else {
creatorCommentContainer.innerHTML += `
<tr id="comment-box" class="comment-box">
<th class="table-primary">${name}</th>
<th class="table-primary">${content}</th>
<th class="table-primary">${eventName}</th>
<th class="table-primary">${receivingTime}</th>
<th class="table-primary"><input type="checkbox" event="${eventId}" value="${commentId}" id="creator-read" name="creator-read" ${checked}></th>
</tr>
`;
}
});
// to Participant List
const participantsCommentArr = result.pComment;
const participantsCommentContainer = document.querySelector('#input-list-participated-events');
participantsCommentArr.forEach(async (comment) => {
let name = comment.first_name + ' ' + comment.last_name;
if (comment.anonymous) {
name = 'Anonymous';
}
let checked = 'unchecked';
const content = comment.content;
const receivingTime = new Date(comment.created_at).toLocaleDateString('en-US');
const commentId = comment.id;
const eventName = comment.name;
if (comment.read) {
checked = 'checked';
participantsCommentContainer.innerHTML += `
<tr id="comment-box" class="comment-box">
<th class="table-secondary">${name}</th>
<th class="table-secondary">${content}</th>
<th class="table-secondary">${eventName}</th>
<th class="table-secondary">${receivingTime}</th>
<th class="table-secondary"><input type="checkbox" value="${commentId}" id="read" name="read" disabled readonly ${checked}></th>
</tr>
`;
} else {
participantsCommentContainer.innerHTML += `
<tr id="comment-box" class="comment-box">
<th class="table-primary">${name}</th>
<th class="table-primary">${content}</th>
<th class="table-primary">${eventName}</th>
<th class="table-primary">${receivingTime}</th>
<th class="table-primary"><input type="checkbox" value="${commentId}" id="read" name="read" disabled readonly ${checked}></th>
</tr>
`;
}
});
postComment(result);
}
async function postComment(result) {
const eventArr = result.events;
eventArr.forEach((event) => {
document.querySelector('#receiver').innerHTML += `
<option value="${event.event_id}">${event.name}</option>
`;
});
document.querySelector('#comment-form').addEventListener('submit', async (e) => {
e.preventDefault();
const form = e.target;
const receiver = form['receiver'].value;
const comment = form['comment'].value;
const category = form['category'].value;
const anonymous = form['anonymous'].checked;
let dataPass = true;
if (!comment || onlySpaces(comment)) {
dataPass = false;
alert('Comment field seems to be empty or only space');
return;
}
if (receiver === 'null') {
dataPass = false;
alert('Please select a receiving event!');
return;
}
if (dataPass) {
const formObj = {
receiver: receiver,
comment: comment,
category: category,
anonymous: anonymous
};
const res = await fetch(`/comment/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formObj)
});
if (res.status !== 200) {
const data = await res.json();
alert(data.msg);
return;
}
const result = await res.json();
console.log(result);
if (result.status === true) {
alert('Comment successfully sent!');
location.reload();
}
}
});
}
async function checkedComment() {
document.querySelectorAll('#creator-read').forEach((checkbox) => {
checkbox.addEventListener('change', async (e) => {
e.preventDefault;
const commentId = e.target.value;
const check = e.target.checked;
const eventId = e.target.getAttribute('event');
const obj = {
commentId: commentId,
check: check,
eventId: eventId
};
const res = await fetch(`/comment/`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(obj)
});
const result = await res.json();
if (result.status) {
console.log(result.msg);
} else {
alert('something when wrong when marking message as read');
}
});
});
}
function onlySpaces(str) {
return str.trim().length === 0;
}

View File

@@ -0,0 +1,427 @@
body {
position: relative;
margin-left: 2px;
margin-right: 20px;
font-family: 'Kalam';
font-size: 16px;
}
.modal-body {
height: fit-content;
}
.input-group {
display: flex;
justify-content: center;
}
.input-panel {
margin: 0px;
}
.item-list-box {
min-height: 150px;
min-width: 100px;
}
#item-form-text {
text-align: center;
}
header {
display: flex;
justify-content: center;
}
#item-form-header {
text-align: center;
}
.item-list-box {
border-radius: 10px;
background-color: #e8e892;
height: 100%;
padding-top: 10px;
padding-bottom: 10px;
overflow: auto;
}
.modal-content {
align-items: center;
width: fit-content;
}
#date-selector-container {
display: flex;
justify-content: right;
padding-bottom: 10px;
padding-right: 10px;
}
textarea {
border-radius: 5px;
background: none;
border-color: #3f3f3f;
max-height: 100%;
overflow: auto;
}
header {
text-align: center;
}
#time-block-memo-container {
position: relative;
max-height: 100%;
}
#close-memo {
position: absolute;
top: 0px;
font-size: 10px;
right: 10px;
}
#time-block-page-container {
max-height: 800px;
height: 550px;
padding-top: 0px;
padding-bottom: 30px;
}
#event-time-container {
text-align: center;
}
.event-schedule {
background-color: #efefd0 !important;
}
.event-schedule:hover {
background-color: #e8e892 !important;
}
@media (max-width: 1000px) {
#line {
display: none;
}
}
@media (max-width: 576px) {
#line {
display: none;
}
#memo {
font-size: large;
max-height: 100%;
max-width: 100%;
overflow: auto;
}
#time-block-memo-container {
max-height: 300px;
height: 300px;
overflow: auto;
}
#rundown-container {
max-height: 300px;
}
}
#memo {
background-color: #efefd0;
height: 90%;
border-radius: 10px;
overflow: auto;
}
#page {
display: flex;
justify-content: center;
height: 90%;
width: 100%;
}
/* #line {
position: absolute;
} */
textarea {
width: 100%;
}
.create-button {
position: fixed;
left: 30px;
bottom: 30px;
}
#rundown {
max-height: 80%;
max-width: 100%;
}
#rundown-container {
max-height: 100%;
position: relative;
}
.time-stamp-container {
background-color: none;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.individual-time-block {
height: 100%;
padding: 2px;
max-width: 100%;
overflow: visible;
}
.time-block {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-color: rgba(181, 180, 180, 0.625);
padding: 10px;
border-radius: 5px;
padding: 1px;
font-size: 1.5vw;
text-align: center;
transition: background-color 50ms ease-out 50ms;
}
.save-time-block {
height: 100%;
color: white;
opacity: 0.7;
padding: 10px;
border-radius: 5px;
text-align: center;
transition: background-color 50ms ease-out 50ms;
}
.save-time-block:hover {
opacity: 0.8;
transform: scale(1.01);
}
.time-stamp {
position: absolute;
top: -5px;
right: 10px;
font-size: 10px;
}
.last-time-stamp {
position: absolute;
bottom: -5px;
right: 10px;
font-size: 10px;
}
.memo-item-container {
position: relative;
background-color: rgba(255, 255, 255, 0.522);
border-radius: 10px;
width: 100%;
height: 100%;
margin-bottom: 10px;
padding: 10px;
font-size: 15px;
}
#memo-item-cluster {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
padding: 10px;
}
.memo-item-label {
font-weight: 800;
font-size: 15px;
padding: 5px;
}
/* Scroll bar */
::-webkit-scrollbar {
width: 15px;
}
::-webkit-scrollbar-track {
box-shadow: inset 0 0 5px grey;
border-radius: 5px;
height: 200px;
}
::-webkit-scrollbar-thumb {
background: #efefd0;
border-radius: 5px;
min-height: 250px;
}
::-webkit-scrollbar-thumb:hover {
background: white;
}
#memo,
#memo-tag {
animation-duration: 0.5s;
animation-name: animate-fade;
animation-delay: 0.1s;
animation-fill-mode: backwards;
}
@keyframes animate-fade {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#edit-activities {
border-radius: 100px;
background-color: #f2965985;
color: white;
text-align: center;
min-width: 22px !important;
min-height: 22px !important;
padding: 3px;
font-size: 10px;
}
#edit-remarks {
border-radius: 100px;
background-color: #f2965985;
color: white;
text-align: center;
min-width: 22px !important;
min-height: 22px !important;
padding: 3px;
font-size: 10px;
}
#edit-show-item {
border-radius: 100px;
background-color: #f2965985;
color: white;
text-align: center;
min-width: 22px !important;
min-height: 22px !important;
padding: 3px;
font-size: 10px;
}
.edit-button {
position: absolute;
top: 5px;
right: 5px;
}
.modal-dialog {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
#event-name {
font-size: 2vw;
padding-top: 10px;
}
.fa-trash {
z-index: 1000;
right: 20px;
top: 20px;
}
.creator-function {
z-index: 1000;
}
.modal-body {
align-items: center;
text-align: center;
}
/* CSS */
.button-53 {
background-color: #f29659;
border: 0 solid #e5e7eb;
box-sizing: border-box;
color: #000000;
display: flex;
font-family: ui-sans-serif, system-ui, -apple-system, system-ui, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
font-size: 1rem;
font-weight: 700;
justify-content: center;
line-height: 1.75rem;
padding: 0.75rem 1.65rem;
position: relative;
text-align: center;
text-decoration: none #000000 solid;
text-decoration-thickness: auto;
width: 100%;
max-width: 460px;
position: relative;
cursor: pointer;
transform: rotate(-2deg);
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
}
.button-53:focus {
outline: 0;
}
.button-53:after {
content: '';
position: absolute;
border: 1px solid #000000;
bottom: 4px;
left: 4px;
width: calc(100% - 1px);
height: calc(100% - 1px);
}
.button-53:hover:after {
bottom: 2px;
left: 2px;
}
@media (min-width: 768px) {
.button-53 {
padding: 0.75rem 3rem;
font-size: 1.25rem;
}
}
#back-page {
position: absolute;
left: 50px;
top: 110px;
text-decoration: none;
}
.bi-chevron-left {
font-size: 30px;
top: 90px;
left: 40px;
color: #444a58;
cursor: pointer;
}

View File

@@ -0,0 +1,353 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link href="https://fonts.googleapis.com/css?family=Kalam" rel="stylesheet" />
<link rel="stylesheet" href="./eventSchedule.css" />
<title>Event Schedule</title>
</head>
<body>
<div class="navbar-container container">
<!-- NAVBAR: to be loaded with js -->
</div>
<header id="event-name"></header>
<div id="event-time-container">
<!-- time and date input here -->
</div>
<div class="container container-fluid" id="page">
<div id="time-block-page-container" class="container row">
<div id="date-selector-container" class="col-12">
<!-- time selector here -->
</div>
<div id="time-block-memo-container" class="col-sm-5 overflow-auto"></div>
<div id="rundown-container" class="col-sm-7 overflow-auto">
<div id="rundown" class="rundown" data-current="0">
<!-- Add Time Block and Time-stamp on window load -->
</div>
</div>
</div>
<!-- Back Button -->
<a id="back-page">
<i class="bi bi-chevron-left"></i>
</a>
</div>
<!-- create time block modal -->
<div
class="modal fade"
id="create-time-block-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">CREATE ACTIVITY</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div class="input-group">
<form id="activity-form" class="register-form">
<div class="input-panel mb-3">
<div class="form-header">Activity Name *</div>
<input
type="text"
class="form-control"
name="activity-name"
aria-label="first-name"
aria-describedby="basic-addon1"
/>
</div>
<div class="input-panel mb-3">
<div class="form-header">Description</div>
<textarea
id="description"
class="form-control"
name="description"
rows="5"
cols="50"
></textarea>
</div>
<div id="time-container">
<div class="input-panel mb-3">
<div class="form-header">Start Time *</div>
<input
type="time"
name="start"
class="form-control"
id="start-time"
name="start-time"
min="00:00"
max="24:00"
step="900"
required
/>
</div>
<div class="input-panel mb-3">
<div class="form-header">End Time *</div>
<input
type="time"
name="end"
class="form-control"
id="end-time"
name="end-time"
min="00:00"
max="24:00"
step="900"
required
/>
</div>
</div>
<div class="input-panel mb-3">
<div class="form-header">Remarks</div>
<textarea
id="remark"
class="form-control"
name="remark"
rows="5"
cols="50"
></textarea>
</div>
<div class="input-panel mb-3">
<div class="form-header">Display Color</div>
<input value="#f29659" id="color" class="form-control" name="color" type="color" />
</div>
<div class="modal-footer">
<button id="submit-new-activity" type="submit" class="btn btn-primary button-53">
Submit
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- edit Time block modal (name and time only) -->
<div
class="modal fade"
id="edit-time-name-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">EDIT NAME AND TIME</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div class="input-group">
<form id="edit-time-name-form" class="register-form">
<div class="input-panel mb-3">
<div class="form-header">Activity Name *</div>
<input
type="text"
class="form-control"
name="edit-activity-name"
id="edit-activity-name"
aria-describedby="basic-addon1"
/>
</div>
<div id="time-container">
<div class="input-panel mb-3">
<div class="form-header">Start Time *</div>
<input
type="time"
name="start"
class="form-control"
id="edit-start-time"
name="edit-start-time"
min="00:00"
max="24:00"
step="900"
required
/>
</div>
<div class="input-panel mb-3">
<div class="form-header">End Time *</div>
<input
type="time"
name="end"
class="form-control"
id="edit-end-time"
name="edit-end-time"
min="00:00"
max="24:00"
step="900"
required
/>
</div>
</div>
<div class="input-panel mb-3">
<div class="form-header">Display Color</div>
<input
value="#f29659"
id="edit-color"
class="form-control"
name="color"
type="color"
/>
</div>
<div class="modal-footer">
<button id="submit-edit-time-name" type="submit" class="btn btn-primary button-53">
Submit
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- Edit Item Modal -->
<div
class="modal fade"
id="edit-item-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">ITEM LIST</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div id="item-form-text" class="form-text">
Select items you wish to add to this activity. Blanketed indicates total quantity of each
items assigned to the event.
</div>
<div class="input-group">
<form id="edit-item-form" class="edit-item-form row">
<div class="input-panel mb-3 col-6">
<div class="form-header" id="item-form-header">Food</div>
<div class="list-items-container">
<ul
id="food-list"
class="item-list-box"
role="listbox"
tabindex="0"
aria-label="emails list"
>
<!-- to be added by JS -->
</ul>
</div>
</div>
<div class="input-panel mb-3 col-6">
<div class="form-header" id="item-form-header">Drinks</div>
<div class="list-items-container">
<ul
id="drink-list"
class="item-list-box"
role="listbox"
tabindex="0"
aria-label="emails list"
>
<!-- to be added by JS -->
</ul>
</div>
</div>
<div class="input-panel mb-3 col-6">
<div class="form-header" id="item-form-header">Decoration</div>
<div class="list-items-container">
<ul
id="decoration-list"
class="item-list-box"
role="listbox"
tabindex="0"
aria-label="emails list"
>
<!-- to be added by JS -->
</ul>
</div>
</div>
<div class="input-panel mb-3 col-6">
<div class="form-header" id="item-form-header">Others</div>
<div class="list-items-container">
<ul
id="other-list"
class="item-list-box"
role="listbox"
tabindex="0"
aria-label="emails list"
>
<!-- to be added by JS -->
</ul>
</div>
</div>
<div class="modal-footer">
<button id="submit-edit-item" type="submit" class="btn btn-primary button-53">
Submit
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="https://thibaultjanbeyer.github.io/DragSelect/ds.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8"
crossorigin="anonymous"
></script>
<script type="module" src="./eventSchedule.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,972 @@
/* @import */
body {
font-family: 'Calibri';
background-color: #ffffff;
font-size: 16px;
font-family: 'Lato', sans-serif;
}
textarea {
border-radius: 10px;
background: none;
border-color: #3f3f3f;
}
a {
color: inherit;
text-decoration: none;
}
.content {
height: calc(100vh - 115px);
margin-top: 10px;
}
.vertical-flex {
flex-direction: column;
justify-content: flex-start !important;
align-items: flex-start !important;
}
.background-frame:not(.eventname .background-frame) {
background-color: #f9f9da;
border-radius: 10px;
}
.background-frame {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
padding: 10px 20px;
}
.line1 {
height: 15vh;
}
.line2 {
height: 65vh;
display: flex;
flex-direction: column;
}
.participant {
height: 65%;
}
.venue {
height: 35%;
}
.frame {
padding: 10px 0 10px 0;
}
.frame-title {
font-size: 20px;
font-weight: bold;
text-align: left;
}
.frame-title-container {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.frame-content-container {
width: 100%;
display: flex;
padding: 10px 0;
height: 100%;
overflow-y: auto;
}
.eventname {
font-size: 20px;
font-weight: bold;
text-align: center;
line-height: 100%;
}
.eventname .emoji {
font-size: 30px;
}
.date-time .background-frame > div {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.date-time .background-frame > div:first-child {
width: 30%;
}
.date-time .background-frame > div:nth-child(2) {
width: 70%;
}
.date-time .background-frame {
display: flex;
justify-content: space-between;
align-items: center;
text-align: center;
}
.date-time .frame-content,
.date-time .frame-content-label {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.date-time .frame-content-label {
width: 20%;
}
.date-time .frame-content {
width: 80%;
}
.participant .frame-content-container {
width: 100%;
max-height: 70%;
overflow-y: auto;
}
.venue .frame-title-container,
.schedule .frame-title-container {
justify-content: space-between;
align-items: center;
}
#number-of-participants {
margin: 0 10px;
display: flex;
justify-content: center;
align-items: center;
background-color: #f2d492;
color: #ee6c4d;
width: 30px;
height: 30px;
border-radius: 5px;
}
.participant .left {
display: flex;
align-items: center;
}
.datetime-form {
width: 100%;
}
.red_creator {
color: red;
font-weight: bold;
}
.input-group-text {
cursor: pointer;
}
#invitation-link {
display: flex;
justify-content: center;
align-items: center;
}
.copied {
background-color: #059862;
color: white;
font-weight: bold;
border: 4px solid #07c982;
}
.name-block {
display: flex;
margin: 10px 15px 10px 10px;
justify-content: center;
align-items: center;
}
.delete_event-button-container {
position: absolute;
right: 10px;
top: 50%;
transform: translate(0, -50%);
}
.warning-sign {
font-size: 70px;
width: 90px;
height: 90px;
border-radius: 200px;
border: solid 4px black;
display: flex;
justify-content: center;
align-items: center;
}
.warning {
font-size: 30px;
font-weight: bold;
}
#delete-event-modal .modal-body,
#overwrite-venue-poll-modal .modal-body,
#overwrite-datetime-poll-modal .modal-body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.hide {
display: none;
}
div[class^='venue_poll_'] {
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
margin: 5px 0;
}
div[class^='datetime_poll_'] {
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
margin: 5px 0;
}
.datetime_title {
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
margin: 5px 0;
}
div[class^='venue_poll_'] label {
width: 80px;
}
div[class^='datetime_poll_'] label {
width: 80px;
}
.datetime_title > div:first-child {
width: 80px;
}
.datetime_title > div:nth-child(2) {
display: flex;
width: 100%;
}
.datetime_title > div:nth-child(2) div {
width: 50%;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
}
.venue-poll-options-container {
margin: 10px 20px !important;
}
/* ↓↓ Scroll bar ↓↓ */
.frame-content-container::-webkit-scrollbar {
display: none;
}
/* ↑↑ Scroll bar ↑↑ */
/* ↓↓ Buttons ↓↓ */
.venue-buttons-container {
display: flex;
}
.edit-button,
.poll-button {
border-radius: 100px;
background-color: #f29559;
color: white;
width: 22px;
height: 22px;
font-size: 10px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.poll-button {
margin: 0 10px;
}
.invite-button {
border-radius: 100px;
background-color: #f29559;
color: white;
width: 22px;
height: 22px;
font-size: 13px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
margin-right: 10px;
}
.info-button {
border-radius: 100px;
background-color: #f29559;
color: white;
width: 22px;
height: 22px;
font-size: 10px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.delete-button {
border-radius: 100px;
background-color: #c74b38;
color: white;
width: 22px;
height: 22px;
font-size: 10px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
#delete-event-submit,
#overwrite-venue-poll-submit,
#overwrite-datetime-poll-submit {
background-color: #d8684e;
color: white;
font-weight: bold;
border: #c7492c 3px solid;
}
#delete-event-modal .modal-submit-button,
#overwrite-venue-poll-modal .modal-submit-button,
#overwrite-datetime-poll-modal .modal-submit-button {
box-shadow: none;
}
.switch-buttons-container {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 15px;
}
.btn-outline-success,
.btn-outline-danger {
--bs-btn-color: #6c757d;
--bs-btn-border-color: #6c757d;
--bs-btn-active-bg: #6c757d;
--bs-btn-active-border-color: #6c757d;
font-size: 15px;
}
.btn-outline-success {
--bs-btn-border-radius: 0.375rem 0 0 0.375rem;
}
.btn-outline-danger {
--bs-btn-border-radius: 0 0.375rem 0.375rem 0;
}
.option-button-container {
display: flex;
align-items: center;
justify-content: center;
}
#venue-add-option,
#venue-remove-option {
margin: 10px;
box-shadow: none;
}
/* ↑↑ Button ↑↑ */
/* Modal */
.modal-submit-button {
font-size: 14px;
color: #293241;
font-family: 'Lato', sans-serif;
background-color: #f2d492;
padding: 10px 20px 10px 20px;
border-radius: 20px;
margin: 18px;
min-width: 110px;
border: none;
box-shadow: 0px 1px 12px #f2d492;
}
.modal-footer {
display: flex;
justify-content: center;
align-content: center;
}
.modal-login {
font-size: 14px;
color: #293241;
font-family: 'Lato', sans-serif;
background-color: #f2d492;
padding: 10px 20px 10px 20px;
border-radius: 20px;
margin: 18px;
width: 110px;
border: none;
box-shadow: 0px 1px 12px #f2d492;
}
.modal-header {
display: flex;
justify-content: space-between;
}
.modal-title {
font-size: 25px;
font-weight: bold;
color: #293241;
font-family: 'Lato', sans-serif;
transform: translateX(10px);
}
.form-label {
color: #293241;
font-family: 'Lato', sans-serif;
}
.input-group-container {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
margin: 0 0 10px 0;
}
.input-title,
.reminder-text {
text-align: center;
}
.reminder-text {
color: grey;
width: 70%;
}
.form-control {
border-width: 2px;
border-radius: 10px;
}
#datetime-submit,
#venue-submit,
#venue-poll-submit {
width: 50%;
}
.form-header {
margin: 0 0 5px 0;
}
.form,
.input-panel {
margin: 20px 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.invite-button-container {
position: absolute;
bottom: -25px;
left: 50%;
transform: translate(-50%, -50%);
width: 80%;
height: 20%;
display: flex;
justify-content: center;
align-items: center;
}
#participants-list-container {
display: flex;
justify-content: center;
align-items: center;
}
.participants-list {
height: 35vh;
padding: 10px;
margin-top: 18px;
border-radius: 10px;
border: solid grey 2px;
position: relative;
}
.participants-list-title {
position: absolute;
top: -3px;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
font-size: 20px;
font-weight: bold;
}
#current-participants-list .participants-list-title {
color: #2fd0c1;
}
#deleted-participants-list .participants-list-title {
color: #d02f3e;
}
.user-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
}
#participants-modal .frame-content-container > div {
width: 100%;
}
.datetime-buttons-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-end;
}
.date-time .poll-button {
margin: 0 0 5px 0;
}
/* From eventPageSchedule.css */
.item-list-box {
min-height: 150px;
min-width: 100px;
}
#item-form-text {
text-align: center;
}
#item-form-header {
text-align: center;
}
.item-list-box {
border-radius: 10px;
background-color: #e8e892;
height: 100%;
padding-top: 10px;
padding-bottom: 10px;
overflow: auto;
}
#date-selector-container {
display: flex;
justify-content: right;
padding-bottom: 10px;
padding-right: 10px;
}
#time-block-memo-container {
position: relative;
max-height: 100%;
}
#close-memo {
position: absolute;
top: 0px;
font-size: 10px;
right: 10px;
}
#time-block-page-container {
max-height: 800px;
height: 550px;
padding-top: 0px;
padding-bottom: 30px;
}
#event-time-container {
text-align: center;
}
.event-schedule {
background-color: #efefd0 !important;
}
.event-schedule:hover {
background-color: #e8e892 !important;
}
@media (max-width: 1000px) {
#line {
display: none;
}
}
@media (max-width: 576px) {
@media (max-width: 1000px) {
#line {
display: none;
}
#memo {
font-size: large;
max-height: 100%;
max-width: 100%;
overflow: auto;
}
#time-block-memo-container {
max-height: 300px;
height: 300px;
overflow: auto;
}
#rundown-container {
max-height: 300px;
}
}
}
#memo {
background-color: #efefd0;
height: 90%;
border-radius: 10px;
overflow: auto;
}
#page {
display: flex;
justify-content: center;
height: 90%;
width: 100%;
}
/* #line {
position: absolute;
} */
#rundown {
max-height: 80%;
max-width: 100%;
}
#rundown-container {
max-height: 100%;
position: relative;
background-color: white;
padding-top: 30px;
padding-bottom: 20px;
}
.time-stamp-container {
background-color: none;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.individual-time-block {
height: 100%;
padding: 2px;
max-width: 100%;
overflow: visible;
}
.time-block {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-color: rgba(181, 180, 180, 0.625);
padding: 10px;
border-radius: 5px;
padding: 1px;
font-size: 1.5vw;
text-align: center;
transition: background-color 50ms ease-out 50ms;
}
.save-time-block {
height: 100%;
color: white;
opacity: 0.7;
padding: 10px;
border-radius: 5px;
text-align: center;
transition: background-color 50ms ease-out 50ms;
}
.save-time-block:hover {
opacity: 0.8;
transform: scale(1.01);
}
.time-stamp {
position: absolute;
top: -5px;
right: 10px;
font-size: 10px;
}
.last-time-stamp {
position: absolute;
bottom: -5px;
right: 10px;
font-size: 10px;
}
.memo-item-container {
position: relative;
background-color: rgba(255, 255, 255, 0.522);
border-radius: 10px;
width: 100%;
height: 100%;
margin-bottom: 10px;
padding: 10px;
font-size: 15px;
}
#memo-item-cluster {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
padding: 10px;
}
.memo-item-label {
font-weight: 800;
font-size: 15px;
padding: 5px;
}
/* Scroll bar */
::-webkit-scrollbar {
width: 15px;
}
::-webkit-scrollbar-track {
box-shadow: inset 0 0 5px grey;
border-radius: 5px;
height: 200px;
}
::-webkit-scrollbar-thumb {
background: #efefd0;
border-radius: 5px;
min-height: 250px;
}
::-webkit-scrollbar-thumb:hover {
background: white;
}
#memo,
#memo-tag {
animation-duration: 0.5s;
animation-name: animate-fade;
animation-delay: 0.1s;
animation-fill-mode: backwards;
}
@keyframes animate-fade {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#edit-activities {
border-radius: 100px;
background-color: #f2965985;
color: white;
text-align: center;
min-width: 22px !important;
min-height: 22px !important;
padding: 3px;
font-size: 10px;
}
#edit-remarks {
border-radius: 100px;
background-color: #f2965985;
color: white;
text-align: center;
min-width: 22px !important;
min-height: 22px !important;
padding: 3px;
font-size: 10px;
}
#edit-show-item {
border-radius: 100px;
background-color: #f2965985;
color: white;
text-align: center;
min-width: 22px !important;
min-height: 22px !important;
padding: 3px;
font-size: 10px;
}
.modal-dialog {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
#event-name {
font-size: 2vw;
padding-top: 10px;
}
.fa-trash {
z-index: 1000;
right: 20px;
top: 20px;
}
.creator-function {
z-index: 1000;
}
/* CSS */
.button-53 {
background-color: #f29659;
border: 0 solid #e5e7eb;
box-sizing: border-box;
color: #000000;
display: flex;
font-family: ui-sans-serif, system-ui, -apple-system, system-ui, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
font-size: 1rem;
font-weight: 700;
justify-content: center;
line-height: 1.75rem;
padding: 0.75rem 1.65rem;
position: relative;
text-align: center;
text-decoration: none #000000 solid;
text-decoration-thickness: auto;
width: 100%;
max-width: 460px;
position: relative;
cursor: pointer;
transform: rotate(-2deg);
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
}
.button-53:focus {
outline: 0;
}
.button-53:after {
content: '';
position: absolute;
border: 1px solid #000000;
bottom: 4px;
left: 4px;
width: calc(100% - 1px);
height: calc(100% - 1px);
}
.button-53:hover:after {
bottom: 2px;
left: 2px;
}
@media (min-width: 768px) {
.button-53 {
padding: 0.75rem 3rem;
font-size: 1.25rem;
}
}
/* From itemSummary */
.shopping-list {
height: 90%;
border-radius: 20px;
margin: 10px 2px 5px 5px;
width: 100%;
}
.shopping-list .item-list {
position: relative;
height: 100%;
width: 100%;
background-color: #fff;
}
.border {
border: 10px solid #9bafd0;
border-radius: 20px;
padding: 10px;
max-height: 500px;
overflow-y: scroll;
}
.pending-item-header,
.pending-item {
display: flex;
justify-content: space-between;
}
.bi-filter-circle {
color: #495871;
width: 20px;
height: 20px;
}
.shorting-btn {
border: none;
border-radius: 20px;
background-color: #fff;
}
.check-btn {
border: none;
border-radius: 20px;
background-color: #fff;
}
.dropdown-item {
cursor: pointer;
}

View File

@@ -0,0 +1,579 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link rel="stylesheet" href="./event.css" />
<title>Event Summary</title>
</head>
<body style="display: none">
<div class="navbar-container container">
<!-- NAVBAR: to be loaded with js -->
</div>
<div class="content">
<div class="container">
<div class="row">
<div class="col-md-4">
<div class="eventname frame line1">
<div class="background-frame">
<!-- Event Name: to be added by JS -->
</div>
</div>
</div>
<div class="col-md-8">
<div class="date-time frame line1">
<div class="background-frame">
<!-- Event Name: to be added by JS -->
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="participant-venue line2">
<div class="participant frame">
<div class="background-frame vertical-flex">
<!-- Participants: to be added by JS -->
</div>
</div>
<div class="venue frame">
<div class="background-frame vertical-flex">
<!-- Venue: to be added by JS -->
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="schedule frame line2">
<div class="background-frame vertical-flex">
<!-- Schedule: to be added by JS -->
</div>
</div>
</div>
<div class="col-md-4">
<div class="item frame line2">
<div class="background-frame vertical-flex">
<!-- Item: to be added by JS -->
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Modal Parts -->
<!-- Date/Time Modal -->
<div
class="modal fade"
id="datetime-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">Date & Time</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<form>
<div class="switch-buttons-container">
<input
type="radio"
class="btn-check"
name="options-outlined"
id="edit-datetime-switch"
autocomplete="off"
checked
/>
<label class="btn btn-outline-success" for="edit-datetime-switch">Editing</label>
<input
type="radio"
class="btn-check"
name="options-outlined"
id="poll-datetime-switch"
autocomplete="off"
/>
<label class="btn btn-outline-danger" for="poll-datetime-switch">Polling</label>
</div>
</form>
<!-- Edit datetime part -->
<div class="input-group edit-input">
<div class="input-group-container">
<div class="input-title">Please edit your date & time below.</div>
<form id="datetime-form">
<div class="datetime-start input-panel mb-3">
<div class="form-label">Start date and time</div>
<input
class="clock"
type="datetime-local"
id="datetime-start"
name="datetime_start"
min="2021-06-07T00:00"
max="2035-12-30T00:00"
step="900"
/>
</div>
<div class="datetime-end input-panel mb-3">
<div class="form-label">End date and time</div>
<input
class="clock"
type="datetime-local"
id="datetime-end"
name="datetime_end"
min="2021-06-07T00:00"
max="2035-12-30T00:00"
step="900"
/>
</div>
<div class="input-panel mb-3">
<div class="reminder-text">
Please fill in both start and end date/time. <br />
Enter the time in 15 mins interval, e.g. 15:00 or 15:15 or 15:30 or 15:45.
</div>
</div>
<div class="modal-footer">
<button id="datetime-submit" type="submit" class="modal-submit-button">
Edit
</button>
</div>
</form>
</div>
</div>
<!-- Poll Datetime Form -->
<div class="input-group poll-input hide">
<div class="input-group-container">
<div class="input-title">Please enter your polling options below:</div>
<form id="datetime-poll-form">
<div class="datetime-poll-options-container input-panel mb-3">
<div class="datetime_title">
<div></div>
<div>
<div>Start</div>
<div>End</div>
</div>
</div>
<div class="datetime_poll_1">
<label for="datetime_poll">Option 1: </label>
<input
class="clock"
type="datetime-local"
id="datetime_poll_start"
name="datetime_poll_start"
min="2021-06-07T00:00"
max="2035-12-30T00:00"
step="900"
/>
<input
class="clock"
type="datetime-local"
id="datetime_poll_end"
name="datetime_poll_end"
min="2021-06-07T00:00"
max="2035-12-30T00:00"
step="900"
/>
</div>
<div class="datetime_poll_2">
<label for="datetime_poll">Option 2: </label>
<input
class="clock"
type="datetime-local"
id="datetime_poll_start"
name="datetime_poll_start"
min="2021-06-07T00:00"
max="2035-12-30T00:00"
step="900"
/>
<input
class="clock"
type="datetime-local"
id="datetime_poll_end"
name="datetime_poll_end"
min="2021-06-07T00:00"
max="2035-12-30T00:00"
step="900"
/>
</div>
<!-- More options added by JS -->
</div>
<div class="input-panel mb-3">
<div class="reminder-text">
Please fill in both start and end date/time. <br />
Enter the time in 15 mins interval, e.g. 15:00 or 15:15 or 15:30 or 15:45.
</div>
</div>
<div class="option-button-container">
<button id="datetime-add-option" class="modal-submit-button">
<i class="fa-solid fa-plus"></i>&nbsp Option
</button>
<button id="datetime-remove-option" class="modal-submit-button">
<i class="fa-solid fa-minus"></i>&nbsp Option
</button>
</div>
<div class="modal-footer">
<button id="datetime-poll-submit" type="submit" class="modal-submit-button">
Start Polling
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Overwrite datetime Poll Confirmation Modal -->
<div
class="modal fade"
id="overwrite-datetime-poll-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">Overwrite Poll</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div class="warning-sign">
<i class="fa-solid fa-exclamation"></i>
</div>
<div class="warning">Are you sure?</div>
<div class="reminder-text">Overwritten poll cannot be restored!</div>
<div class="modal-footer">
<button id="overwrite-datetime-poll-submit" type="submit" class="modal-submit-button">
OVERWRITE
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Venue Modal -->
<div
class="modal fade"
id="venue-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">Venue</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<form>
<div class="switch-buttons-container">
<input
type="radio"
class="btn-check"
name="options-outlined"
id="edit-venue-switch"
autocomplete="off"
checked
/>
<label class="btn btn-outline-success" for="edit-venue-switch">Editing</label>
<input
type="radio"
class="btn-check"
name="options-outlined"
id="poll-venue-switch"
autocomplete="off"
/>
<label class="btn btn-outline-danger" for="poll-venue-switch">Polling</label>
</div>
</form>
<!-- Edit Venue Form -->
<div class="input-group edit-input">
<div class="input-group-container">
<div class="input-title">Please enter your venue below:</div>
<form id="venue-form">
<div class="venue-start input-panel mb-3">
<input
type="text"
class="form-control"
name="venue"
aria-label="venue"
aria-describedby="basic-addon1"
/>
</div>
<div class="modal-footer">
<button id="venue-submit" type="submit" class="modal-submit-button">
Edit
</button>
</div>
</form>
</div>
</div>
<!-- Poll Venue Form -->
<div class="input-group poll-input hide">
<div class="input-group-container">
<div class="input-title">Please enter your polling options below:</div>
<form id="venue-poll-form">
<div class="venue-poll-options-container input-panel mb-3">
<div class="venue_poll_1">
<label for="venue_poll">Option 1: </label>
<input
type="text"
class="form-control"
name="venue_poll"
aria-label="venue_poll"
aria-describedby="basic-addon1"
/>
</div>
<div class="venue_poll_2">
<label for="venue_poll">Option 2: </label>
<input
type="text"
class="form-control"
name="venue_poll"
aria-label="venue_poll"
aria-describedby="basic-addon1"
/>
</div>
<!-- More options added by JS -->
</div>
<div class="option-button-container">
<button id="venue-add-option" class="modal-submit-button">
<i class="fa-solid fa-plus"></i>&nbsp Option
</button>
<button id="venue-remove-option" class="modal-submit-button">
<i class="fa-solid fa-minus"></i>&nbsp Option
</button>
</div>
<div class="modal-footer">
<button id="venue-poll-submit" type="submit" class="modal-submit-button">
Start Polling
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Overwrite Venue Poll Confirmation Modal -->
<div
class="modal fade"
id="overwrite-venue-poll-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">Overwrite Poll</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div class="warning-sign">
<i class="fa-solid fa-exclamation"></i>
</div>
<div class="warning">Are you sure?</div>
<div class="reminder-text">Overwritten poll cannot be restored!</div>
<div class="modal-footer">
<button id="overwrite-venue-poll-submit" type="submit" class="modal-submit-button">
OVERWRITE
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Delete Participants Modal -->
<div
class="modal fade"
id="participants-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">Participants</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div class="input-group">
<div class="input-group-container">
<div class="input-title">Please edit your participants below:</div>
<div id="participants-list-container">
<div class="container">
<div class="row justify-content-center">
<div class="col-sm-6">
<div class="participants-list" id="current-participants-list">
<div class="participants-list-title">Current</div>
<!-- Current Participants Here -->
</div>
</div>
<div class="col-sm-6">
<div class="participants-list" id="deleted-participants-list">
<div class="participants-list-title">Deleted</div>
<!-- Participants To Be Removed Here -->
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button id="participants-submit" type="submit" class="modal-submit-button">Submit</button>
<button id="participants-reset" type="reset" class="modal-submit-button">Reset</button>
</div>
</div>
</div>
</div>
<!-- Invitation Link Modal -->
<div
class="modal fade"
id="invitation-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">Invitation</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div class="input-title">Please send your friend the invitation link below:</div>
<div class="input-group mb-3">
<input
type="text"
class="form-control"
aria-label="invitation"
name="invitation"
aria-describedby="invitation-link"
readonly
/>
<a class="input-group-text" id="invitation-link">Copy Link</a>
</div>
<form id="invitation-form">
<div class="modal-footer">
<div class="reminder-text">
Note: Previous link will be invalid <br />
when new link is created.
</div>
<button id="invitation-submit" type="submit" class="modal-submit-button">
Create New Link
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Delete Event Confirmation Modal -->
<div
class="modal fade"
id="delete-event-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">Delete Event</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div class="warning-sign">
<i class="fa-solid fa-exclamation"></i>
</div>
<div class="warning">Are you sure?</div>
<div class="reminder-text">You will not be able to revert this action!</div>
<div class="modal-footer">
<button id="delete-event-submit" type="submit" class="modal-submit-button">
DELETE EVENT
</button>
</div>
</div>
</div>
</div>
</div>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8"
crossorigin="anonymous"
></script>
<script type="module" src="./event.js"></script>
</body>
</html>

View File

@@ -0,0 +1,477 @@
import { addNavbar } from '/functions/addNavbar.js';
import { loadName } from '/functions/loadName.js';
import { loadEventDetails, pasteInvitationLink } from '../loadEvent.js';
import { deletedParticipantsList } from '../listenButtons.js';
import { getEventSchedule } from './eventPageSchedule/eventPageSchedule.js';
import { fetchPendingItems } from './itemSummary.js';
window.addEventListener('load', async () => {
addNavbar();
await loadName();
await loadEventDetails();
getEventSchedule();
await fetchPendingItems('food');
document.body.style.display = 'block';
});
// Submit datetime form
document.querySelector('#datetime-form').addEventListener('submit', async function (e) {
e.preventDefault();
const form = e.target;
const startTime = form.datetime_start.value ? new Date(form.datetime_start.value).toISOString() : null;
const endTime = form.datetime_end.value ? new Date(form.datetime_end.value).toISOString() : null;
const nowTimeValue = new Date().getTime();
const startTimeValue = new Date(startTime).getTime();
const endTimeValue = new Date(endTime).getTime();
let dataPass = true;
if (startTimeValue && endTimeValue) {
if (startTimeValue <= nowTimeValue) {
dataPass = false;
alert('Start time must be later than time now!');
} else if (startTimeValue >= endTimeValue) {
dataPass = false;
alert('Start time cannot equals or later than end time!');
}
} else if (!!startTimeValue + !!endTimeValue) {
dataPass = false;
alert('You cannot only leave 1 time blank!');
}
if (dataPass) {
const formObj = {
startTime,
endTime
};
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const res = await fetch(`/events/detail/datetime/${eventId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formObj)
});
const eventsResult = await res.json();
if (eventsResult.status) {
alert('Date & Time successfully updated!');
const myModal = bootstrap.Modal.getInstance(document.getElementById('datetime-modal'));
myModal.hide();
loadEventDetails();
} else {
alert('Unable to update.');
}
}
});
// Datetime edit-poll toggle
document.querySelector('#edit-datetime-switch').addEventListener('change', () => {
document.querySelector('#datetime-modal .edit-input').classList.toggle('hide');
document.querySelector('#datetime-modal .poll-input').classList.toggle('hide');
});
document.querySelector('#poll-datetime-switch').addEventListener('change', () => {
document.querySelector('#datetime-modal .edit-input').classList.toggle('hide');
document.querySelector('#datetime-modal .poll-input').classList.toggle('hide');
});
// Datetime polling add option button
document.querySelector('#datetime-add-option').addEventListener('click', (e) => {
e.preventDefault();
const numberOfOptions = document.querySelectorAll('div[class^="datetime_poll_"]').length;
let newDiv = document.createElement('div');
newDiv.classList = `datetime_poll_${numberOfOptions + 1}`;
newDiv.innerHTML = `
<label for="datetime_poll">Option ${numberOfOptions + 1}: </label>
<input class="clock" type="datetime-local" id="datetime_poll_start" name="datetime_poll_start"
min="2021-06-07T00:00" max="2035-12-30T00:00" step="900">
<input class="clock" type="datetime-local" id="datetime_poll_end" name="datetime_poll_end"
min="2021-06-07T00:00" max="2035-12-30T00:00" step="900">
`;
document.querySelector('.datetime-poll-options-container').appendChild(newDiv);
});
// Datetime polling remove option button
document.querySelector('#datetime-remove-option').addEventListener('click', (e) => {
e.preventDefault();
const venuePollOptionsDivList = document.querySelectorAll('div[class^="datetime_poll_"]');
const numberOfOptions = venuePollOptionsDivList.length;
if (numberOfOptions > 2) {
venuePollOptionsDivList[numberOfOptions - 1].remove();
}
});
// Submit datetime polling
document.querySelector('#datetime-poll-form').addEventListener('submit', async (e) => {
e.preventDefault();
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
let dataPass = true;
let formList = [];
const form = e.target;
const startList = form.datetime_poll_start;
const endList = form.datetime_poll_end;
for (let i = 0; i < startList.length; i++) {
if (!startList[i].value || !endList[i].value) {
dataPass = false;
alert('Please fill in all options!');
break;
} else if (new Date(startList[i].value).getTime() <= new Date().getTime()) {
dataPass = false;
alert('Start time must be later than today!');
break;
} else if (new Date(startList[i].value).getTime() >= new Date(endList[i].value).getTime()) {
dataPass = false;
alert('Start time must be before end time!');
break;
} else {
formList.push({
start: new Date(startList[i].value),
end: new Date(endList[i].value)
});
}
}
if (dataPass) {
const res = await fetch(`/events/poll/datetime/${eventId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formList)
});
const result = await res.json();
if (result.status) {
alert('Successfully created a datetime poll!');
window.location.href = `/poll/datetimePoll.html?${params}&is-creator=1`;
} else {
if (result.created) {
// Modal not yet added
alert('Poll has been created before!');
const datetimePollModal = bootstrap.Modal.getInstance(document.getElementById('datetime-modal'));
datetimePollModal.hide();
const datetimePollOverwriteModal = new bootstrap.Modal(
document.getElementById('overwrite-datetime-poll-modal')
);
datetimePollOverwriteModal.show();
} else {
alert('Unable to create poll.');
}
}
}
});
// Overwrite datetime poll confirmed
document.querySelector('#overwrite-datetime-poll-submit').addEventListener('click', async (e) => {
e.preventDefault();
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
let dataPass = true;
let formList = [];
const form = document.querySelector('#datetime-poll-form');
const startList = form.datetime_poll_start;
const endList = form.datetime_poll_end;
for (let i = 0; i < startList.length; i++) {
if (!startList[i].value || !endList[i].value) {
dataPass = false;
alert('Please fill in all options!');
break;
} else if (new Date(startList[i].value).getTime() <= new Date().getTime()) {
dataPass = false;
alert('Start time must be later than today!');
break;
} else if (new Date(startList[i].value).getTime() >= new Date(endList[i].value).getTime()) {
dataPass = false;
alert('Start time must be before end time!');
break;
} else {
formList.push({
start: new Date(startList[i].value),
end: new Date(endList[i].value)
});
}
}
if (dataPass) {
const res = await fetch(`/events/poll/datetime/replacement/${eventId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formList)
});
const result = await res.json();
if (result.status) {
alert('Successfully created a datetime poll!');
window.location.href = `/poll/datetimePoll.html?${params}&is-creator=1`;
} else {
alert('Unable to create poll.');
}
}
});
// Submit venue form
document.querySelector('#venue-form').addEventListener('submit', async function (e) {
e.preventDefault();
const form = e.target;
const venue = form.venue.value;
let dataPass = true;
if (!venue) {
dataPass = false;
alert('Please enter new venue to update!');
}
if (dataPass) {
const formObj = {
venue
};
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const res = await fetch(`/events/detail/venue/${eventId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formObj)
});
const eventsResult = await res.json();
if (eventsResult.status) {
alert('Venue successfully updated!');
const myModal = bootstrap.Modal.getInstance(document.getElementById('venue-modal'));
myModal.hide();
loadEventDetails();
} else {
alert('Unable to update.');
}
}
});
// Venue edit-poll toggle
document.querySelector('#edit-venue-switch').addEventListener('change', () => {
document.querySelector('#venue-modal .edit-input').classList.toggle('hide');
document.querySelector('#venue-modal .poll-input').classList.toggle('hide');
});
document.querySelector('#poll-venue-switch').addEventListener('change', () => {
document.querySelector('#venue-modal .edit-input').classList.toggle('hide');
document.querySelector('#venue-modal .poll-input').classList.toggle('hide');
});
// Venue polling add option button
document.querySelector('#venue-add-option').addEventListener('click', (e) => {
e.preventDefault();
const numberOfOptions = document.querySelectorAll('div[class^="venue_poll_"]').length;
let newDiv = document.createElement('div');
newDiv.classList = `venue_poll_${numberOfOptions + 1}`;
newDiv.innerHTML = `
<label for="venue_poll">Option ${numberOfOptions + 1}: </label>
<input type="text" class="form-control" name="venue_poll" aria-label="venue_poll"
aria-describedby="basic-addon1" />
`;
document.querySelector('.venue-poll-options-container').appendChild(newDiv);
});
// Venue polling remove option button
document.querySelector('#venue-remove-option').addEventListener('click', (e) => {
e.preventDefault();
const venuePollOptionsDivList = document.querySelectorAll('div[class^="venue_poll_"]');
const numberOfOptions = venuePollOptionsDivList.length;
if (numberOfOptions > 2) {
venuePollOptionsDivList[numberOfOptions - 1].remove();
}
});
// Submit venue polling
document.querySelector('#venue-poll-form').addEventListener('submit', async (e) => {
e.preventDefault();
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
let dataPass = true;
let formList = [];
const form = e.target;
const formInputNodeList = form.venue_poll;
formInputNodeList.forEach((each) => {
if (!!each.value) {
formList.push(each.value);
}
});
if (formList.length < 2) {
dataPass = false;
alert('Please enter at least 2 options!');
}
if (dataPass) {
const res = await fetch(`/events/poll/venue/${eventId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formList)
});
const result = await res.json();
if (result.status) {
alert('Successfully created a venue poll!');
window.location.href = `/poll/venuePoll.html?event-id=${eventId}&is-creator=1`;
} else {
if (result.created) {
alert('Poll has been created before!');
const venuePollModal = bootstrap.Modal.getInstance(document.getElementById('venue-modal'));
venuePollModal.hide();
const venuePollOverwriteModal = new bootstrap.Modal(
document.getElementById('overwrite-venue-poll-modal')
);
venuePollOverwriteModal.show();
} else {
alert('Unable to create poll.');
}
}
}
});
// Overwrite venue poll confirmed
document.querySelector('#overwrite-venue-poll-submit').addEventListener('click', async (e) => {
e.preventDefault();
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
let dataPass = true;
let formList = [];
const form = document.querySelector('#venue-poll-form');
const formInputNodeList = form.venue_poll;
formInputNodeList.forEach((each) => {
if (!!each.value) {
formList.push(each.value);
}
});
if (formList.length < 2) {
formList = false;
alert('Please enter at least 2 options!');
}
if (dataPass) {
const res = await fetch(`/events/poll/venue/replacement/${eventId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formList)
});
const result = await res.json();
if (result.status) {
alert('Successfully created a venue poll!');
window.location.href = `/poll/venuePoll.html?event-id=${eventId}&is-creator=1`;
} else {
alert('Unable to create poll.');
}
}
});
// Submit participants form
document.querySelector('#participants-submit').addEventListener('click', async () => {
const params = new URLSearchParams(window.location.search);
const eventId = parseInt(params.get('event-id'));
const res = await fetch(`/events/participants/${eventId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(deletedParticipantsList)
});
if (res.status !== 200) {
const data = await res.json();
alert(data.msg);
return;
}
const result = await res.json();
if (result.status) {
if (result.notDeletable.length) {
let warnText = 'Unable to remove following participant(s):';
for (let each of result.notDeletable) {
warnText += `
# ${each.deletedParticipant.id} ${each.deletedParticipant.first_name} ${each.deletedParticipant.last_name}
Unsettled Item(s):`;
for (let i = 0; i < each.itemInCharge.length; i++) {
warnText += `
[${each.itemInCharge[i].type_name}] ${each.itemInCharge[i].name}`;
}
warnText += `
`;
}
alert(warnText);
deletedParticipantsList.splice(0, deletedParticipantsList.length);
loadEventDetails();
//Warn
} else {
deletedParticipantsList.splice(0, deletedParticipantsList.length);
loadEventDetails();
alert('Successfully deleted all selected participants!');
}
} else {
alert('Unable to delete selected participants!');
}
});
// Reset participants form
document.querySelector('#participants-reset').addEventListener('click', async () => {
deletedParticipantsList.splice(0, deletedParticipantsList.length);
loadEventDetails();
});
// Submit Invitation Copy Link Button
document.querySelector('#invitation-form').addEventListener('submit', async function (e) {
e.preventDefault();
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const res = await fetch(`/events/detail/invitation/${eventId}`);
const invitationResult = await res.json();
if (invitationResult.status) {
pasteInvitationLink(eventId, invitationResult.invitation_token);
alert('Link renewed!');
} else {
alert('Unable to create link.');
}
});
// Copy Invitation Link Button
document.querySelector('#invitation-link').addEventListener('click', (e) => {
const linkTextDiv = document.querySelector('#invitation-modal .form-control');
// Select the text field
linkTextDiv.select();
linkTextDiv.setSelectionRange(0, 99999); // For mobile devices
// Copy the text inside the text field
navigator.clipboard.writeText(linkTextDiv.value);
// Change button to copied
e.target.classList.add('copied');
const currentWidth = e.target.offsetWidth;
e.target.style.width = `${currentWidth}px`;
e.target.innerHTML = 'Copied!';
// Change back the button to normal
setTimeout(() => {
e.target.classList.remove('copied');
e.target.innerHTML = 'Copy Link';
}, 5000);
});
// Delete Event Button
document.querySelector('#delete-event-submit').addEventListener('click', async () => {
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const res = await fetch(`/events/${eventId}`, {
method: 'DELETE'
});
const result = await res.json();
if (result.status) {
alert('Event deleted!');
window.location.href = '/index.html';
} else {
alert('Unable to delete event!');
}
});

View File

@@ -0,0 +1,307 @@
export async function getEventSchedule() {
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const isCreator = params.get('is-creator');
const res = await fetch(`/events/?event-id=${eventId}&is-creator=${isCreator}`);
if (res.status !== 200) {
const data = await res.json();
alert(data.msg);
return;
}
const result = await res.json();
if (result.status) {
const option = {
hour12: false,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
};
const startDateTime = new Date(result.detail.start_datetime)
.toLocaleString('en-US', option)
.replace(', ', ' ')
.slice(0, -3);
const endDateTime = new Date(result.detail.end_datetime)
.toLocaleString('en-US', option)
.replace(', ', ' ')
.slice(0, -3);
const activitiesArr = result.activities;
const startTime = startDateTime.slice(-5);
const endTime = endDateTime.slice(-5);
const startDate = startDateTime.slice(0, 10);
const endDate = endDateTime.slice(0, 10);
const startYear = startDateTime.slice(6, 10);
const endYear = endDateTime.slice(6, 10);
const startMonth = startDateTime.slice(0, 2);
const endMonth = endDateTime.slice(0, 2);
const startDay = startDateTime.slice(3, 5);
const endDay = endDateTime.slice(3, 5);
const date = `${startYear}${startMonth}${startDay}`;
let startTimeInMin = toMin(startTime);
let endTimeInMin = toMin(endTime);
const dayDifference = (new Date(endDate).getTime() - new Date(startDate).getTime()) / 1000 / 60 / 60 / 24;
if (
dayDifference > 0 &&
date !== `${startYear}${startMonth}${startDay}` &&
date !== `${endYear}${endMonth}${endDay}`
) {
startTimeInMin = 0;
endTimeInMin = 1440;
}
if (dayDifference > 0 && date === `${startYear}${startMonth}${startDay}`) {
endTimeInMin = 1440;
}
if (dayDifference > 0 && date === `${endYear}${endMonth}${endDay}`) {
startTimeInMin = 0;
}
await getPresetTimeBlock(startTimeInMin);
await getSavedTimeBlocks(activitiesArr);
await correctDiv(startTimeInMin, endTimeInMin);
setGlobalHeight(2);
}
}
async function getPresetTimeBlock(startTime) {
let rundown = document.querySelector('#rundown');
//generate time block for 24 hours
for (let i = 0; i < 96; i++) {
let start = i * 15;
let end = (i + 1) * 15;
const timeString = minToTimeString(start);
const height = end - start;
rundown.innerHTML += `
<div id="time-block-container-${start}" start="${start}" end="${end}" class="individual-time-block row">
<span id="time-stamp-box" class="time-stamp-container col-sm-2">
<div id="stamp-${start}" class="time-stamp">${timeString}</div>
</span>
<span id="time-block-${start}" start="${start}" end="${end}" class="time-block col-sm-10"></span>
</div>
`;
document.querySelector(`#time-block-${start}`).style.height = `${height}px`;
}
//set scroll bar top
document.querySelector(`#time-block-${startTime}`).innerHTML = 'Event Start Time';
const scrollBarDiv = document.querySelector('#rundown-container');
scrollBarDiv.scrollTop = document.querySelector(`#time-block-${startTime}`).offsetTop;
}
async function getSavedTimeBlocks(activitiesArr) {
activitiesArr.forEach(async (activity) => {
const start = activity.start_time;
const title = activity.title;
const startTimeInMin = toMin(activity.start_time);
const endTimeInMin = toMin(activity.end_time);
const divHeight = endTimeInMin - startTimeInMin;
const id = activity.id;
const presetColor = '#f29659';
let color = activity.color;
if (activity.color === null || undefined) {
color = presetColor;
}
document.querySelector(`#time-block-container-${startTimeInMin}`).innerHTML = `
<span id="time-stamp-box" class="time-stamp-container col-2">
<div id="stamp-${startTimeInMin}" class="time-stamp">${start}</div>
</span>
<span value="${id}" type="button" id="time-block-${startTimeInMin}" start="${startTimeInMin}" end="${endTimeInMin}" class="time-block save-time-block col-10">
</span>
`;
document.querySelector(`#time-block-${startTimeInMin}`).innerHTML = title;
document.querySelector(`#time-block-${startTimeInMin}`).style.height = `${divHeight}px`;
document.querySelector(`#time-block-${startTimeInMin}`).style.backgroundColor = `${color}`;
});
}
async function fixDivHeight(x) {
if (x > 0) {
const divCluster = document.querySelectorAll('.time-block');
divCluster.forEach((div) => {
let nextDiv;
if (div.parentElement.nextElementSibling?.childNodes) {
nextDiv = div.parentElement.nextElementSibling.childNodes[3];
}
const height = parseInt(div.getAttribute('end')) - parseInt(div.getAttribute('start'));
if (!!div.parentElement.nextElementSibling?.childNodes) {
if (nextDiv) {
if (div.classList === nextDiv.classList && !div.classList.contains('save-time-block')) {
div.style.height = newHeight;
const newHeight = parseInt(nextDiv.getAttribute('end')) - parseInt(div.getAttribute('start'));
div.setAttribute(`start`, `${nextDiv.getAttribute('end')}`);
nextDiv.parentElement.innerHTML = '';
} else if (height > 60 && !div.classList.contains('save-time-block')) {
div.style.height = '60px';
const redundantHeight = height - 60;
nextDiv.setAttribute(`start`, `${parseInt(nextDiv.getAttribute('start')) + redundantHeight}`);
} else {
div.style.height = `${height}px`;
}
}
}
});
fixDivHeight(x - 1);
} else {
return;
}
}
function toMin(timeInput) {
const hourInMin = parseInt(timeInput.slice(0, 2)) * 60;
const min = parseInt(timeInput.slice(3, 5));
return hourInMin + min;
}
async function setGlobalHeight(input) {
const allBlocks = document.querySelectorAll('.time-block');
allBlocks.forEach((block) => {
const originalHeight = parseInt(block.style.height.slice(0, -2));
block.style.height = `${originalHeight * input}px`;
});
}
async function fixTimeStamp() {
const timeStampDiv = document.querySelectorAll('.time-stamp');
timeStampDiv.forEach((stamp) => {
let nextTimeBlock;
let placeholder = stamp.parentElement.nextElementSibling;
while (placeholder) {
if (placeholder.classList.contains('time-block')) {
nextTimeBlock = placeholder;
break;
}
placeholder = placeholder.nextElementSibling;
}
const time = minToTimeString(parseInt(nextTimeBlock.getAttribute('start')));
stamp.innerHTML = time;
});
}
async function deleteRedundantDiv(x) {
const divCluster = document.querySelectorAll(`.time-block`);
if (x > 0) {
for (let i = 0; i < divCluster.length; i++) {
if (!!divCluster[i + 1]) {
const endTime = parseInt(divCluster[i].getAttribute('end'));
const nextStartTime = parseInt(divCluster[i + 1].getAttribute('start'));
if (endTime > nextStartTime) {
divCluster[i + 1].parentElement.remove();
} else if (endTime < nextStartTime) {
divCluster[i + 1].setAttribute(`start`, `${endTime}`);
}
}
}
deleteRedundantDiv(x - 1);
}
return;
}
async function correctDiv(eventStartTimeInMin, eventEndTimeInMin) {
const divCluster = document.querySelectorAll(`.time-block`);
const params = new URLSearchParams(window.location.search);
const isCreator = params.get('is-creator');
for (let i = 0; i < divCluster.length; i++) {
const startTime = parseInt(divCluster[i].getAttribute('start'));
const endTime = parseInt(divCluster[i].getAttribute('end'));
const height = endTime - startTime;
const timeString = minToTimeString(startTime);
if (!!divCluster[i + 1]) {
divCluster[i].style.height = `${height}px`;
const nextStartTime = parseInt(divCluster[i + 1].getAttribute('start'));
const nextEndTime = parseInt(divCluster[i + 1].getAttribute('end'));
const newDivHeight = nextStartTime - endTime;
const nextStartTimeFormat = minToTimeString(nextStartTime);
if (endTime < nextStartTime && startTime >= eventStartTimeInMin && startTime < eventEndTimeInMin) {
divCluster[i].parentNode.insertAdjacentHTML(
'afterend',
`
<div id="time-block-container-${endTime}" class="individual-time-block row">
<span id="time-stamp-box" class="time-stamp-container col-2">
<div id="stamp-${endTime}" class="time-stamp">${nextStartTimeFormat}</div>
</span>
<span type="button" id="time-block-${endTime}" start="${endTime}" end="${nextStartTime}" class="time-block event-schedule col-10" data-bs-toggle="modal" data-bs-target="#create-time-block-modal"></span>
</div>
`
);
document.querySelector(`#time-block-${endTime}`).style.height = `${newDivHeight}px`;
} else if (endTime < nextStartTime) {
divCluster[i].parentNode.insertAdjacentHTML(
'afterend',
`
<div id="time-block-container-${endTime}" class="individual-time-block row">
<span id="time-stamp-box" class="time-stamp-container col-2">
<div id="stamp-${endTime}" class="time-stamp">${nextStartTimeFormat}</div>
</span>
<span id="time-block-${endTime}" start="${endTime}" end="${nextStartTime}" class="time-block col-10"></span>
</div>
`
);
document.querySelector(`#time-block-${endTime}`).style.height = `${newDivHeight}px`;
}
document.querySelector(`#stamp-${startTime}`).innerHTML = timeString;
divCluster[i].style.height = `${height}`;
}
if (
startTime >= eventStartTimeInMin &&
startTime < eventEndTimeInMin &&
!divCluster[i].classList.contains('save-time-block')
) {
divCluster[i].classList.add('event-schedule');
if (isCreator === '1') {
divCluster[i].setAttribute(`data-bs-target`, `#create-time-block-modal`);
divCluster[i].setAttribute(`type`, 'button');
divCluster[i].setAttribute(`data-bs-toggle`, `modal`);
}
}
}
deleteRedundantDiv(100);
fixTimeStamp();
fixDivHeight(10);
}
function minToTimeString(timeInMin) {
if (timeInMin < 10) {
return `00:0${timeInMin}`;
} else if (timeInMin < 60) {
return `00:${timeInMin}`;
} else if (Math.floor(timeInMin / 60) < 10 && timeInMin % 60 < 10) {
const hour = Math.floor(timeInMin / 60);
const min = timeInMin % 60;
return `0${hour}:0${min}`;
} else if (Math.floor(timeInMin / 60) >= 10 && timeInMin % 60 < 10) {
const hour = Math.floor(timeInMin / 60);
const min = timeInMin % 60;
return `${hour}:0${min}`;
} else if (Math.floor(timeInMin / 60) >= 10 && timeInMin % 60 >= 10) {
const hour = Math.floor(timeInMin / 60);
const min = timeInMin % 60;
return `${hour}:${min}`;
} else if (Math.floor(timeInMin / 60) < 10 && timeInMin % 60 >= 10) {
const hour = Math.floor(timeInMin / 60);
const min = timeInMin % 60;
return `0${hour}:${min}`;
}
}

View File

@@ -0,0 +1,410 @@
body {
position: relative;
margin-left: 2px;
margin-right: 20px;
font-family: 'Kalam';
font-size: 16px;
}
.modal-body {
height: fit-content;
}
.input-group {
display: flex;
justify-content: center;
}
.input-panel {
margin: 0px;
}
.item-list-box {
min-height: 150px;
min-width: 100px;
}
#item-form-text {
text-align: center;
}
header {
display: flex;
justify-content: center;
}
#item-form-header {
text-align: center;
}
.item-list-box {
border-radius: 10px;
background-color: #e8e892;
height: 100%;
padding-top: 10px;
padding-bottom: 10px;
overflow: auto;
}
.modal-content {
align-items: center;
width: fit-content;
}
#date-selector-container {
display: flex;
justify-content: right;
padding-bottom: 10px;
padding-right: 10px;
}
textarea {
border-radius: 5px;
background: none;
border-color: #3f3f3f;
max-height: 100%;
overflow: auto;
}
header {
text-align: center;
}
#time-block-memo-container {
position: relative;
max-height: 100%;
}
#close-memo {
position: absolute;
top: 0px;
font-size: 10px;
right: 10px;
}
#time-block-page-container {
max-height: 800px;
height: 550px;
padding-top: 0px;
padding-bottom: 30px;
}
#event-time-container {
text-align: center;
}
.event-schedule {
background-color: #efefd0 !important;
}
.event-schedule:hover {
background-color: #e8e892 !important;
}
@media (max-width: 1000px) {
#line {
display: none;
}
}
@media (max-width: 576px) {
@media (max-width: 1000px) {
#line {
display: none;
}
#memo {
font-size: large;
max-height: 100%;
max-width: 100%;
overflow: auto;
}
#time-block-memo-container {
max-height: 300px;
height: 300px;
overflow: auto;
}
#rundown-container {
max-height: 300px;
}
}
}
#memo {
background-color: #efefd0;
height: 90%;
border-radius: 10px;
overflow: auto;
}
#page {
display: flex;
justify-content: center;
height: 90%;
width: 100%;
}
/* #line {
position: absolute;
} */
textarea {
width: 100%;
}
.create-button {
position: fixed;
left: 30px;
bottom: 30px;
}
#rundown {
max-height: 80%;
max-width: 100%;
}
#rundown-container {
max-height: 100%;
position: relative;
background-color: white;
padding-top: 30px;
padding-bottom: 20px;
}
.time-stamp-container {
background-color: none;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.individual-time-block {
height: 100%;
padding: 2px;
max-width: 100%;
overflow: visible;
}
.time-block {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-color: rgba(181, 180, 180, 0.625);
padding: 10px;
border-radius: 5px;
padding: 1px;
font-size: 1.5vw;
text-align: center;
transition: background-color 50ms ease-out 50ms;
}
.save-time-block {
height: 100%;
color: white;
opacity: 0.7;
padding: 10px;
border-radius: 5px;
text-align: center;
transition: background-color 50ms ease-out 50ms;
}
.save-time-block:hover {
opacity: 0.8;
transform: scale(1.01);
}
.time-stamp {
position: absolute;
top: -5px;
right: 10px;
font-size: 10px;
}
.last-time-stamp {
position: absolute;
bottom: -5px;
right: 10px;
font-size: 10px;
}
.memo-item-container {
position: relative;
background-color: rgba(255, 255, 255, 0.522);
border-radius: 10px;
width: 100%;
height: 100%;
margin-bottom: 10px;
padding: 10px;
font-size: 15px;
}
#memo-item-cluster {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
padding: 10px;
}
.memo-item-label {
font-weight: 800;
font-size: 15px;
padding: 5px;
}
/* Scroll bar */
::-webkit-scrollbar {
width: 15px;
}
::-webkit-scrollbar-track {
box-shadow: inset 0 0 5px grey;
border-radius: 5px;
height: 200px;
}
::-webkit-scrollbar-thumb {
background: #efefd0;
border-radius: 5px;
min-height: 250px;
}
::-webkit-scrollbar-thumb:hover {
background: white;
}
#memo,
#memo-tag {
animation-duration: 0.5s;
animation-name: animate-fade;
animation-delay: 0.1s;
animation-fill-mode: backwards;
}
@keyframes animate-fade {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#edit-activities {
border-radius: 100px;
background-color: #f2965985;
color: white;
text-align: center;
min-width: 22px !important;
min-height: 22px !important;
padding: 3px;
font-size: 10px;
}
#edit-remarks {
border-radius: 100px;
background-color: #f2965985;
color: white;
text-align: center;
min-width: 22px !important;
min-height: 22px !important;
padding: 3px;
font-size: 10px;
}
#edit-show-item {
border-radius: 100px;
background-color: #f2965985;
color: white;
text-align: center;
min-width: 22px !important;
min-height: 22px !important;
padding: 3px;
font-size: 10px;
}
.edit-button {
position: absolute;
top: 5px;
right: 5px;
}
.modal-dialog {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
#event-name {
font-size: 2vw;
padding-top: 10px;
}
.fa-trash {
z-index: 1000;
right: 20px;
top: 20px;
}
.creator-function {
z-index: 1000;
}
/* CSS */
.button-53 {
background-color: #f29659;
border: 0 solid #e5e7eb;
box-sizing: border-box;
color: #000000;
display: flex;
font-family: ui-sans-serif, system-ui, -apple-system, system-ui, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
font-size: 1rem;
font-weight: 700;
justify-content: center;
line-height: 1.75rem;
padding: 0.75rem 1.65rem;
position: relative;
text-align: center;
text-decoration: none #000000 solid;
text-decoration-thickness: auto;
width: 100%;
max-width: 460px;
position: relative;
cursor: pointer;
transform: rotate(-2deg);
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
}
.button-53:focus {
outline: 0;
}
.button-53:after {
content: '';
position: absolute;
border: 1px solid #000000;
bottom: 4px;
left: 4px;
width: calc(100% - 1px);
height: calc(100% - 1px);
}
.button-53:hover:after {
bottom: 2px;
left: 2px;
}
@media (min-width: 768px) {
.button-53 {
padding: 0.75rem 3rem;
font-size: 1.25rem;
}
}

View File

@@ -0,0 +1,47 @@
export async function fetchPendingItems(selectType) {
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const resShopList = await (await fetch(`/items/pendingItems?eventID=${eventId}`)).json();
if (resShopList.status) {
let listItems = '';
for (const items of resShopList.itemObj[selectType]) {
listItems += `
<tr id="list-item-${items.id}">
<td>
<div class="pending-item">
${items.name}
<button id="checking-${items.id}" class="check-btn">
<i class="bi bi-check-circle"></i>
</button>
</div>
</td>
</tr>
`;
}
document.querySelector(`#shopping-list-update`).innerHTML = listItems;
checkShoppingListItem();
document.querySelectorAll(`.dropdown-item`).forEach((dropdown) => {
dropdown.addEventListener('click', function (e) {
const selectType = e.currentTarget.innerHTML.toLowerCase();
fetchPendingItems(selectType);
});
});
}
}
function checkShoppingListItem() {
document.querySelectorAll(`.check-btn`).forEach((button) => {
button.addEventListener('click', async function (e) {
const itemID = e.currentTarget.id.slice(9);
const res = await fetch(`/items/pendingItems/${itemID}`, {
method: 'PUT'
});
if ((await res.json()).status === true) {
const updateOnTheList = document.querySelector('#list-item-' + itemID);
updateOnTheList.remove();
}
});
});
}

View File

@@ -0,0 +1,188 @@
body {
font-family: 'Lato', sans-serif;
background-color: #ffffff;
}
.initial-hide {
display: none;
}
.table-header {
background-color: white;
}
#add-new-party-button {
width: 500px;
background-color: #f2d492;
border-radius: 10px;
font-size: 20px;
font-weight: bold;
border: none;
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 15px;
}
.round {
border-radius: 50%;
background-color: #f1f1f1;
color: grey;
}
#add-new-party-button {
width: 500px;
background-color: #f2d492;
}
#add-new-party-button .text {
color: black;
border-radius: 10px;
text-align: left;
}
#add-new-party-button .plus {
display: flex;
justify-content: center;
align-items: center;
}
#add-new-party-button .plus div {
background-color: #f29559;
border-radius: 100px;
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
font-size: 15px;
font-weight: unset;
}
th {
text-align: center;
height: 30px;
}
th > div {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.container {
padding: 0 0 20px 0;
}
.table-content-row {
font-size: 1vw;
border-bottom: grey 1px solid;
}
.turn-page-button-container {
display: flex;
justify-content: flex-end;
align-items: center;
}
.previous-round,
.next-round {
margin: 0;
padding: 10px 15px;
width: 40px;
height: 25px;
font-size: 10px;
border: rgb(197, 197, 197) 1px solid;
display: flex;
justify-content: center;
align-items: center;
}
.previous-round {
border-radius: 10px 0 0 10px;
}
.next-round {
border-radius: 0 10px 10px 0;
}
.page-number {
margin: 10px;
font-size: 8px;
color: grey;
}
.parties-list-container header {
margin: 10px 0 0 0;
font-size: 20px;
font-weight: bold;
}
.parties-list-container .table-container {
background-color: #fdfdf4;
padding: 20px;
border-radius: 20px;
}
.parties-list-container .table-header {
background-color: white;
border: rgba(191, 191, 191, 0.473) solid 1px;
font-size: 1vw;
}
.deletedStatus {
background-color: #979797;
color: white;
}
.completedStatus {
background-color: #caefe2;
color: #00b69b;
}
.progressStatus {
background-color: #ded2f3;
color: #6226ef;
}
.deletedStatus,
.completedStatus,
.progressStatus {
display: flex;
justify-content: center;
align-items: center;
padding: 0 15px;
height: 25px;
border-radius: 5px;
}
.edit-button {
border-radius: 100px;
background-color: #f29559;
color: white;
width: 22px;
height: 22px;
font-size: 10px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
@media only screen and (max-width: 600px) {
#add-new-party-button {
width: 90%;
}
.hidable-1 {
display: none;
}
}
@media only screen and (max-width: 420px) {
.hidable-2 {
display: none;
}
}

View File

@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link rel="stylesheet" href="./index.css" />
<title>Dashboard</title>
</head>
<body style="display: none">
<div class="navbar-container container">
<!-- NAVBAR: to be loaded with js -->
</div>
<div class="container">
<a href="/newEvent/newEvent.html" class="btn btn-primary" id="add-new-party-button">
<div class="text">Add New Party</div>
<div class="plus"><div>+</div></div>
</a>
<div class="parties-list-container">
<header>Created:</header>
<div class="create table-container">
<table class="table table-body table-hover">
<thead>
<tr class="table-header">
<th scope="col" class="hidable-2">ID</th>
<th scope="col">PARTY NAME</th>
<th scope="col">ADDRESS</th>
<th scope="col">START TIME</th>
<th scope="col" class="hidable-1">END TIME</th>
<th scope="col">STATUS</th>
<th scope="col"></th>
</tr>
</thead>
<tbody class="events-container">
<!-- to be added by loadEvent.js -->
</tbody>
</table>
<span class="turn-page-button-container">
<button type="button" class="previous-round btn btn-light">
<i class="fa-sharp fa-solid fa-less-than"></i>
</button>
<button type="button" class="next-round btn btn-light">
<i class="fa-sharp fa-solid fa-greater-than"></i>
</button>
</span>
</div>
<header>Participated:</header>
<div class="participate table-container">
<table class="table table-body table-hover">
<thead>
<tr class="table-header">
<th scope="col">ID</th>
<th scope="col">PARTY NAME</th>
<th scope="col">ADDRESS</th>
<th scope="col">START TIME</th>
<th scope="col">END TIME</th>
<th scope="col">STATUS</th>
<th scope="col"></th>
</tr>
</thead>
<tbody class="events-container">
<!-- to be added by loadEvent.js -->
</tbody>
</table>
<span class="turn-page-button-container">
<button type="button" class="previous-round btn btn-light">
<i class="fa-sharp fa-solid fa-less-than"></i>
</button>
<button type="button" class="next-round btn btn-light">
<i class="fa-sharp fa-solid fa-greater-than"></i>
</button>
</span>
</div>
</div>
</div>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8"
crossorigin="anonymous"
></script>
<script type="module" src="./index.js"></script>
</body>
</html>

View File

@@ -0,0 +1,47 @@
import { loadCreateEvents, loadParticipateEvents } from './loadEvent.js';
import { addNavbar } from '/functions/addNavbar.js';
import { loadName } from '/functions/loadName.js';
function onlyNumbers(str) {
return /^[0-9]+$/.test(str);
}
window.addEventListener('load', async () => {
addNavbar();
loadName();
const params = new URLSearchParams(window.location.search);
let createPage = '1';
let participatePage = '1';
if (!params.has('create-page')) {
loadCreateEvents(createPage);
} else {
if (onlyNumbers(params.get('create-page'))) {
if (parseInt(params.get('create-page')) >= 1) {
createPage = params.get('create-page');
createPage = await loadCreateEvents(createPage);
} else {
loadCreateEvents(createPage);
}
} else {
loadCreateEvents(createPage);
}
}
if (!params.has('participate-page')) {
loadParticipateEvents(participatePage);
} else {
if (onlyNumbers(params.get('participate-page'))) {
if (parseInt(params.get('participate-page')) >= 1) {
participatePage = params.get('participate-page');
participatePage = await loadParticipateEvents(participatePage);
} else {
loadParticipateEvents(participatePage);
}
} else {
loadParticipateEvents(participatePage);
}
}
document.body.style.display = 'block';
});

View File

@@ -0,0 +1,163 @@
.bi-chevron-left {
font-size: 30px;
position: fixed;
top: 90px;
left: 40px;
color: #444a58;
cursor: pointer;
}
.category-text {
font-size: 20px;
font-family: 'Lato', sans-serif;
margin-bottom: 10px;
}
/* shopping list */
.shopping-list {
background-color: #fefde2;
height: 700px;
border-radius: 20px;
margin: 10px 2px 5px 5px;
width: 100%;
padding: 20px;
}
.shopping-list .item-list {
height: 700px;
width: 100%;
background-color: #fff;
}
.pending-item-header {
display: flex;
justify-content: space-between;
}
.bi-filter-circle {
color: #495871;
width: 20px;
height: 20px;
}
.pending-item {
display: flex;
justify-content: space-between;
}
.check-btn {
border: none;
border-radius: 20px;
background-color: #fff;
}
.bi-check-circle {
color: #495871;
width: 20px;
height: 20px;
}
.shorting-btn {
border: none;
border-radius: 20px;
background-color: #fff;
}
/* item category */
.category-text-items {
font-size: 20px;
font-family: 'Lato', sans-serif;
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
margin-bottom: 10px;
}
.category-edit {
border-radius: 20px;
border: none;
background-color: #f29559;
color: #fff;
}
.bi-pencil-square:hover {
color: #495871;
}
.item-category {
background-color: #fefde2;
height: 338px;
border-radius: 20px;
margin: 15px;
width: 100%;
padding: 20px;
}
.item-category .item-list {
height: 70%;
width: 100%;
background-color: #fff;
}
/* Modal UI */
#editModalTittle {
font-size: 30px;
font-family: 'Lato', sans-serif;
}
.modal-header {
display: flex;
justify-content: space-between;
}
/* modal - table */
.border {
border: 10px solid #9bafd0;
border-radius: 20px;
padding: 10px;
max-height: 500px;
overflow-y: scroll;
}
tr {
font-family: 'Lato', sans-serif;
color: #293241;
}
.bi-trash {
color: #ee6c4d;
}
.delete-btn {
border-radius: 20px;
border: none;
background-color: #fff;
}
/* modal - footer */
.format {
justify-content: space-between;
font-family: 'Lato', sans-serif;
color: #293241;
}
.save-submit {
font-size: 18px;
color: #293241;
font-family: 'Lato', sans-serif;
background-color: #f2d492;
padding: 4px 14px 4px 14px;
border-radius: 20px;
margin: 8px;
width: 100px;
box-sizing: border-box;
border: none;
outline: solid 3px #f2d492;
transition: outline 0.3s linear;
margin: 0.5em;
}
.save-submit:hover {
outline-width: 5px;
}

View File

@@ -0,0 +1,259 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Lato:wght@300;400&family=Pacifico&display=swap"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link rel="stylesheet" href="./itemPost.css" />
<title>Post Event Items</title>
</head>
<body style="display: none">
<div class="navbar-container container">
<!-- NAVBAR: to be loaded with js -->
</div>
<div class="container">
<a id="back-page"><i class="bi bi-chevron-left"></i></a>
<div class="row">
<div class="col-xl-4">
<div class="shopping-list">
<div class="category-text">Shopping list:</div>
<div class="item-list border">
<table class="table">
<thead>
<tr>
<th scope="col" class="pending-item-header">
Pending Items:
<div>
<button
id="shopping-list-shorting"
class="shorting-btn"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i class="bi bi-filter-circle"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item">Food</a></li>
<li><a class="dropdown-item">Drink</a></li>
<li><a class="dropdown-item">Decoration</a></li>
<li><a class="dropdown-item">Other</a></li>
</ul>
</div>
</th>
</tr>
</thead>
<tbody id="shipping-list-update">
<!--loaded with itemPost.js "shopping list JS"-->
</tbody>
</table>
</div>
</div>
</div>
<!-- item category -->
<div class="col-xl-4">
<div class="item-category">
<div class="item-category-title">
<div class="category-text-items">
Food:
<button
type="button"
class="category-edit"
data-bs-toggle="modal"
data-bs-target="#editModal"
itemtype="food"
>
<i class="bi bi-pencil-square"></i>
</button>
</div>
</div>
<div class="item-list border">
<table id="food-table" class="table">
<tbody>
<!-- loaded with itemPost.js "category items JS"-->
</tbody>
</table>
</div>
</div>
<div class="item-category">
<div class="category-text-items">
Decoration:
<button
type="button"
class="category-edit"
data-bs-toggle="modal"
data-bs-target="#editModal"
itemtype="decoration"
>
<i class="bi bi-pencil-square"></i>
</button>
</div>
<div class="item-list border">
<table id="decoration-table" class="table">
<tbody>
<tr>
<!-- loaded with itemPost.js "category items JS" -->
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-xl-4">
<div class="item-category">
<div class="category-text-items">
Drink:
<button
type="button"
class="category-edit"
data-bs-toggle="modal"
data-bs-target="#editModal"
itemtype="drink"
>
<i class="bi bi-pencil-square"></i>
</button>
</div>
<div class="item-list border">
<table id="drink-table" class="table">
<tbody>
<tr>
<!-- loaded with itemPost.js "category items JS"-->
</tr>
</tbody>
</table>
</div>
</div>
<div class="item-category">
<div class="category-text-items">
Others:
<button
type="button"
class="category-edit"
data-bs-toggle="modal"
data-bs-target="#editModal"
itemtype="others"
>
<i class="bi bi-pencil-square"></i>
</button>
</div>
<div class="item-list border">
<table id="other-table" class="table">
<tbody>
<tr>
<!-- loaded with itemPost.js "category items JS"-->
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- modal UI -->
<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h1 class="modal-title fs-5" id="editModalTittle">Edit Item</h1>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div class="border">
<table class="table">
<thead class="table-light">
<tr>
<th scope="col">Item description</th>
<th scope="col">Quantity</th>
<th scope="col">Price $</th>
<th scope="col"><i class="bi bi-person-fill"></i></th>
<th scope="col"></th>
</tr>
</thead>
<tbody id="edit-item-list">
<!-- loaded with itemPost.js "category model list JS" -->
</tbody>
</table>
</div>
</div>
<!-- footer modal -->
<div class="modal-footer">
<div class="container-fluid">
<form id="from-container">
<div class="row format">
<div class="col-md-5">
<label for="add-item" class="form-label">Item name</label>
<input type="text" class="form-control" id="add-item" name="item_name" />
</div>
<div class="col-md-1">
<label for="add-quantity" class="form-label">Quantity</label>
<input
type="number"
class="form-control"
id="add-quantity"
name="item_quantity"
min="1"
/>
</div>
<div class="col-md-1">
<label for="add-price" class="form-label">Price</label>
<input
type="number"
class="form-control"
id="add-price"
name="item_price"
min="0"
/>
</div>
<div class="col-md-2">
<label for="add-user" class="form-label">
<i class="bi bi-person-fill"></i>
PIC
</label>
<select id="select-participant" class="form-select" name="item_user">
<option selected value="">Select</option>
<!-- loaded with itemPost.js "modal participants select"-->
</select>
</div>
<button class="save-submit">Add</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8"
crossorigin="anonymous"
></script>
<script type="module" src="./itemPost.js"></script>
</body>
</html>

View File

@@ -0,0 +1,202 @@
import { addNavbar } from '/functions/addNavbar.js';
import { loadName } from '/functions/loadName.js';
let editingType = null;
let itemData = null;
let eventID = null;
window.addEventListener('load', async () => {
const query = new URLSearchParams(window.location.search);
eventID = query.get('event-id');
itemData = await (await fetch(`/items?eventID=${eventID}`)).json();
addNavbar();
await loadName();
fetchItem();
fetchParticipant(eventID);
fetchPendingItems('food');
document.body.style.display = 'block';
});
document.querySelectorAll('.category-edit').forEach((button) => {
button.addEventListener('click', function (e) {
editingType = button.attributes.itemType.value;
fetchEditItem(itemData);
});
});
document.querySelector('#from-container').addEventListener('submit', async function (e) {
const query = new URLSearchParams(window.location.search);
const eventID = query.get('event-id');
e.preventDefault();
const form = e.target;
const typeName = editingType;
const itemName = form.item_name.value;
const itemQuantity = form.item_quantity.value;
const itemPrice = form.item_price.value || null;
const user_id = form.item_user.value || null;
let formObj = {
typeName,
itemName,
itemQuantity,
itemPrice,
user_id
};
let dataPass = true;
if (!user_id) {
alert('Please select PIC');
return;
}
if (dataPass) {
const res = await fetch(`/items/eventId/${eventID}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formObj)
});
const eventsResult = await res.json();
if (eventsResult.status === true) {
const itemData = await (await fetch(`/items?eventID=${eventID}`)).json();
fetchEditItem(itemData);
}
}
form.reset();
fetchItem();
fetchPendingItems(typeName);
});
// category items JS
async function fetchItem() {
const res = await (await fetch(`/items?eventID=${eventID}`)).json();
if (res.status === true) {
const typeName = ['food', 'drink', 'decoration', 'other'];
for (const tableName of typeName) {
let itemsList = '';
for (const items of res.itemObj[tableName]) {
itemsList += `
<tr>
<td>${items.name}</td>
</tr>
`;
}
document.querySelector(`#${tableName}-table`).innerHTML = itemsList;
}
}
}
// category model list JS
async function fetchEditItem() {
const resEditItem = await (await fetch(`/items?eventID=${eventID}`)).json();
if (resEditItem.status === true) {
let items = '';
for (const itemsData of resEditItem.itemObj[editingType]) {
items += `
<tr id="item-row-${itemsData.id}">
<td>${itemsData.name}</td>
<td>${itemsData.quantity}</td>
<td>${itemsData.price}</td>
<td>${itemsData.first_name} ${itemsData.last_name}</td>
<td>
<button id="item-${itemsData.id}" data-type-name="${itemsData.type_name}"
itemDelete="button" class="delete-btn">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
`;
}
document.querySelector(`#edit-item-list`).innerHTML = items;
addDeleteEventListener();
}
}
function addDeleteEventListener() {
document.querySelectorAll('.delete-btn').forEach((button) => {
button.addEventListener('click', async function (e) {
const itemID = e.currentTarget.id.slice(5);
const typeName = e.currentTarget.getAttribute('data-type-name');
const res = await fetch(`/items/${itemID}`, {
method: 'DELETE'
});
if ((await res.json()).status === true) {
const deleteResult = document.querySelector('#item-row-' + itemID);
deleteResult.remove();
fetchItem();
fetchPendingItems(typeName);
}
});
});
}
// modal participants select
async function fetchParticipant(eventID) {
const resParticipant = await (await fetch(`/items/participated?eventID=${eventID}`)).json();
if (resParticipant.status === true) {
for (const participantData of resParticipant.user) {
document.querySelector(`#select-participant`).innerHTML += `
<option value="${participantData.id}">${participantData.first_name} ${participantData.last_name}
</option>
`;
}
}
}
// shopping list JS
async function fetchPendingItems(selectType) {
const resShopList = await (await fetch(`/items/pendingItems?eventID=${eventID}`)).json();
if (resShopList.status === true) {
let listItems = '';
for (const items of resShopList.itemObj[selectType]) {
listItems += `
<tr id="list-item-${items.id}">
<td>
<div class="pending-item">
${items.name}
<button id="checking-${items.id}" class="check-btn">
<i class="bi bi-check-circle"></i>
</button>
</div>
</td>
</tr>
`;
}
document.querySelector(`#shipping-list-update`).innerHTML = listItems;
checkShoppingListItem();
fetchItem();
}
}
function checkShoppingListItem() {
document.querySelectorAll(`.check-btn`).forEach((button) => {
button.addEventListener('click', async function (e) {
const itemID = e.currentTarget.id.slice(9);
const res = await fetch(`/items/pendingItems/${itemID}`, {
method: 'PUT'
});
if ((await res.json()).status === true) {
const updateOnTheList = document.querySelector('#list-item-' + itemID);
updateOnTheList.remove();
}
});
});
}
document.querySelector(`#back-page`).addEventListener('click', function () {
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const isCreator = params.get('is-creator');
window.location = `/eventSummary/event.html?event-id=${eventId}&is-creator=${isCreator}`;
});
document.querySelectorAll(`.dropdown-item`).forEach((dropdown) => {
dropdown.addEventListener('click', function (e) {
const selectType = e.currentTarget.innerHTML.toLowerCase();
fetchPendingItems(selectType);
});
});

View File

@@ -0,0 +1,222 @@
import {
loadCreateEvents,
loadParticipateEvents,
currentParticipantsList,
loadParticipantsModal
} from './loadEvent.js';
function onlyNumbers(str) {
return /^[0-9]+$/.test(str);
}
export function listenCreateButtons() {
document.querySelector('.create .next-round').addEventListener('click', async (e) => {
e.stopImmediatePropagation();
const params = new URLSearchParams(window.location.search);
let page = '2';
if (!params.has('create-page')) {
page = await loadCreateEvents(page);
} else {
if (onlyNumbers(params.get('create-page'))) {
if (parseInt(params.get('create-page')) >= 1) {
page = (parseInt(params.get('create-page')) + 1).toString();
page = await loadCreateEvents(page);
} else {
page = '1';
page = await loadCreateEvents(page);
}
} else {
page = '1';
page = await loadCreateEvents(page);
}
}
if (!params.has('participate-page')) {
history.pushState({}, 'Dashboard', `http://localhost:8080/index.html?create-page=${page}`);
} else {
const participatePage = params.get('participate-page');
history.pushState(
{},
'Dashboard',
`http://localhost:8080/index.html?create-page=${page}&participate-page=${participatePage}`
);
}
listenCreateButtons();
});
document.querySelector('.create .previous-round').addEventListener('click', async (e) => {
e.stopImmediatePropagation();
const params = new URLSearchParams(window.location.search);
let page = '1';
if (!params.has('create-page')) {
page = await loadCreateEvents(page);
} else {
if (onlyNumbers(params.get('create-page'))) {
if (parseInt(params.get('create-page')) >= 2) {
page = (parseInt(params.get('create-page')) - 1).toString();
page = await loadCreateEvents(page);
} else {
page = '1';
page = await loadCreateEvents(page);
}
} else {
page = '1';
page = await loadCreateEvents(page);
}
}
if (!params.has('participate-page')) {
history.pushState({}, 'Dashboard', `http://localhost:8080/index.html?create-page=${page}`);
} else {
const participatePage = params.get('participate-page');
history.pushState(
{},
'Dashboard',
`http://localhost:8080/index.html?create-page=${page}&participate-page=${participatePage}`
);
}
listenCreateButtons();
});
}
export function listenParticipateButtons() {
document.querySelector('.participate .next-round').addEventListener('click', async (e) => {
e.stopImmediatePropagation();
const params = new URLSearchParams(window.location.search);
let page = '2';
if (!params.has('participate-page')) {
page = await loadParticipateEvents(page);
} else {
if (onlyNumbers(params.get('participate-page'))) {
if (parseInt(params.get('participate-page')) >= 1) {
page = (parseInt(params.get('participate-page')) + 1).toString();
page = await loadParticipateEvents(page);
} else {
page = '1';
page = await loadParticipateEvents(page);
}
} else {
page = '1';
page = await loadParticipateEvents(page);
}
}
if (!params.has('create-page')) {
history.pushState({}, 'Dashboard', `http://localhost:8080/index.html?participate-page=${page}`);
} else {
const createPage = params.get('create-page');
history.pushState(
{},
'Dashboard',
`http://localhost:8080/index.html?create-page=${createPage}&participate-page=${page}`
);
}
listenParticipateButtons();
});
document.querySelector('.participate .previous-round').addEventListener('click', async (e) => {
e.stopImmediatePropagation();
const params = new URLSearchParams(window.location.search);
let page = '1';
if (!params.has('participate-page')) {
page = await loadParticipateEvents(page);
} else {
if (onlyNumbers(params.get('participate-page'))) {
if (parseInt(params.get('participate-page')) >= 2) {
page = (parseInt(params.get('participate-page')) - 1).toString();
page = await loadParticipateEvents(page);
} else {
page = '1';
page = await loadParticipateEvents(page);
}
} else {
page = '1';
page = await loadParticipateEvents(page);
}
}
if (!params.has('create-page')) {
history.pushState({}, 'Dashboard', `http://localhost:8080/index.html?participate-page=${page}`);
} else {
const createPage = params.get('create-page');
history.pushState(
{},
'Dashboard',
`http://localhost:8080/index.html?create-page=${createPage}&participate-page=${page}`
);
}
listenParticipateButtons();
});
}
export function listenEditButtons() {
const editCreatedButtons = document.querySelectorAll("[class^='created_detail_'] a");
for (let editButton of editCreatedButtons) {
editButton.addEventListener('click', async () => {
const className = editButton.parentNode.parentNode.className;
const eventId = className.replace('created_detail_', '');
window.location.href = `/eventSummary/event.html?event-id=${eventId}&is-creator=1`;
});
}
const editParticipatedButtons = document.querySelectorAll("[class^='participated_detail_'] a");
for (let editButton of editParticipatedButtons) {
editButton.addEventListener('click', async () => {
const className = editButton.parentNode.parentNode.className;
const eventId = className.replace('participated_detail_', '');
window.location.href = `/eventSummary/event.html?event-id=${eventId}&is-creator=0`;
});
}
}
export function listenToSchedulePage(datetime) {
const date = datetime ? `${datetime.slice(0, 4)}${datetime.slice(5, 7)}${datetime.slice(8, 10)}` : '';
const toScheduleDiv = document.querySelector('.schedule .info-button');
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const isCreator = params.get('is-creator');
if (toScheduleDiv) {
toScheduleDiv.addEventListener('click', () => {
window.location.href = `/eventSchedule/eventSchedule.html?event-id=${eventId}&is-creator=${isCreator}&date=${date}`;
});
}
}
export function listenToItemPage() {
const toScheduleDiv = document.querySelector('.item .info-button');
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const isCreator = params.get('is-creator');
if (toScheduleDiv) {
toScheduleDiv.addEventListener('click', () => {
window.location.href = `/itemPostPage/itemPost.html?event-id=${eventId}&is-creator=${isCreator}`;
});
}
}
export let deletedParticipantsList = [];
export function listenToDeleteParticipants() {
const deleteButtonDivList = document.querySelectorAll('#participants-modal .delete-button');
for (let deleteButtonDiv of deleteButtonDivList) {
deleteButtonDiv.addEventListener('click', (e) => {
e.stopImmediatePropagation();
const userId = parseInt(e.path[1].id.replace('delete_button_user_', ''));
for (let i = 0; i < currentParticipantsList.length; i++) {
if (currentParticipantsList[i].id === userId) {
const [deletedParticipant] = currentParticipantsList.splice(i, 1);
deletedParticipantsList.push(deletedParticipant);
loadParticipantsModal(currentParticipantsList, deletedParticipantsList);
}
}
listenToDeleteParticipants();
});
}
}

View File

@@ -0,0 +1,571 @@
import {
listenCreateButtons,
listenParticipateButtons,
listenEditButtons,
listenToSchedulePage,
listenToItemPage,
listenToDeleteParticipants
} from './listenButtons.js';
export let currentParticipantsList = [];
let deletedParticipantsList = [];
export async function loadCreateEvents(page) {
const res = await fetch(`/events/created?page=${page}`);
if (res.status !== 200) {
const data = await res.json();
alert(data.msg);
return;
}
const result = await res.json();
const events = result.object;
const currentPage = result.currentPage;
const totalPage = result.page;
const eventsCreateContainer = document.querySelector('.create .events-container');
const pageCreateContainer = document.querySelector('.create .turn-page-button-container');
let eventsCreateHTML = '';
for (let event of events) {
let status = '';
let statusClass = '';
const today = new Date().getTime();
const eventStartDate = new Date(event.start_datetime).getTime();
if (event.deleted) {
status = 'Deleted';
statusClass = 'deletedStatus';
} else {
if (today > eventStartDate && eventStartDate) {
status = 'Completed';
statusClass = 'completedStatus';
} else {
status = 'Processing';
statusClass = 'progressStatus';
}
}
eventsCreateHTML += `
<tr class="table-content-row">
<th scope="col" class="ID_${event.id} hidable-2">
<div>${event.id}</div>
</th>
<th scope="col" class="name_${event.id}">
<div>${event.name}</div>
</th>
<th scope="col" class="address_${event.id}">
<div>${!event.venue ? 'TBD' : event.venue}</div>
</th>
<th scope="col" class="start_datetime_${event.id}">
<div>
${
!event.start_datetime
? 'TBD'
: new Date(event.start_datetime)
.toLocaleString('en-US', { hour12: false })
.replace(', ', ' ')
.slice(0, -3)
}
</div>
</th>
<th scope="col" class="end_datetime_${event.id} hidable-1">
<div>
${
!event.end_datetime
? 'TBD'
: new Date(event.end_datetime)
.toLocaleString('en-US', { hour12: false })
.replace(', ', ' ')
.slice(0, -3)
}
</div>
</th>
<th scope="col" class="event_status_${event.id}">
<div><div class="${statusClass}">${status}</div></div>
</th>
<th scope="col" class="created_detail_${event.id}">
<div>
<a class="edit-button">
<i class="fa-regular fa-pen-to-square"></i>
</a>
</div>
</th>
</tr>
`;
}
const pageHTML = !totalPage ? '' : `Showing ${currentPage} of ${totalPage}`;
eventsCreateContainer.innerHTML = eventsCreateHTML;
pageCreateContainer.innerHTML = `
<div class="page-number">${pageHTML}</div>
<button type="button" class="previous-round btn btn-light">
<i class="fa-sharp fa-solid fa-less-than"></i>
</button>
<button type="button" class="next-round btn btn-light">
<i class="fa-sharp fa-solid fa-greater-than"></i>
</button>
`;
listenCreateButtons();
listenEditButtons();
return currentPage;
}
export async function loadParticipateEvents(page) {
const res = await fetch(`/events/participated?page=${page}`);
if (res.status !== 200) {
const data = await res.json();
alert(data.msg);
return;
}
const result = await res.json();
const events = result.object;
const currentPage = result.currentPage;
const totalPage = result.page;
const eventsParticipateContainer = document.querySelector('.participate .events-container');
const pageParticipateContainer = document.querySelector('.participate .turn-page-button-container');
let eventsParticipateHTML = '';
for (let event of events) {
let status = '';
let statusClass = '';
const today = new Date().getTime();
const eventStartDate = new Date(event.start_datetime).getTime();
if (event.deleted) {
status = 'Deleted';
statusClass = 'deletedStatus';
} else {
if (today > eventStartDate && eventStartDate) {
status = 'Completed';
statusClass = 'completedStatus';
} else {
status = 'Processing';
statusClass = 'progressStatus';
}
}
eventsParticipateHTML += `
<tr class="table-content-row">
<th scope="col" class="ID_${event.id} hidable-2">
<div>${event.id}</div>
</th>
<th scope="col" class="name_${event.id}">
<div>${event.name}</div>
</th>
<th scope="col" class="address_${event.id}">
<div>${!event.venue ? 'TBD' : event.venue}</div>
</th>
<th scope="col" class="start_datetime_${event.id}">
<div>
${
!event.start_datetime
? 'TBD'
: new Date(event.start_datetime)
.toLocaleString('en-US', { hour12: false })
.replace(', ', ' ')
.slice(0, -3)
}
</div>
</th>
<th scope="col" class="end_datetime_${event.id} hidable-1">
<div>
${
!event.end_datetime
? 'TBD'
: new Date(event.end_datetime)
.toLocaleString('en-US', { hour12: false })
.replace(', ', ' ')
.slice(0, -3)
}
</div>
</th>
<th scope="col" class="event_status_${event.id}">
<div><div class="${statusClass}">${status}</div></div>
</th>
<th scope="col" class="participated_detail_${event.id}">
<div>
<a class="edit-button">
<i class="fa-regular fa-pen-to-square"></i>
</a>
</div>
</th>
</tr>
`;
}
const pageHTML = !totalPage ? '' : `Showing ${currentPage} of ${totalPage}`;
eventsParticipateContainer.innerHTML = eventsParticipateHTML;
pageParticipateContainer.innerHTML = `
<div class="page-number">${pageHTML}</div>
<button type="button" class="previous-round btn btn-light">
<i class="fa-sharp fa-solid fa-less-than"></i>
</button>
<button type="button" class="next-round btn btn-light">
<i class="fa-sharp fa-solid fa-greater-than"></i>
</button>
`;
listenParticipateButtons();
listenEditButtons();
return currentPage;
}
export async function loadEventDetails() {
const params = new URLSearchParams(window.location.search);
const isCreator = parseInt(params.get('is-creator'));
const eventId = params.get('event-id');
const res = await fetch(`/events/detail/${isCreator ? 'created' : 'participated'}/${eventId}`);
if (res.status !== 200) {
const data = await res.json();
alert(data.msg);
return;
}
const result = await res.json();
if (result.status) {
// Check if the event is processing
const today = new Date().getTime();
const eventStartDate = new Date(result.detail.start_datetime).getTime();
const processing = today <= eventStartDate || !eventStartDate;
const deleted = result.detail.deleted;
// Load Event Name into Page
let deleteEventButton = '';
if (isCreator && processing && !deleted) {
deleteEventButton = `
<div class="delete_event-button-container">
<a class="delete-button" id="delete_event-button" data-bs-toggle="modal" data-bs-target="#delete-event-modal">
<i class="fa-solid fa-trash-can"></i>
</a>
</div>
`;
}
const eventName = document.querySelector('.eventname .background-frame');
eventName.innerHTML = `
<div class="name-block">
<div class="emoji">
🎉
</div>
<div>
${result.detail.name}
</div>
</div>
${deleteEventButton}
`;
// Load Date Time into Page
let dateTimeLabel = '';
let startDateTimeString = '';
let endDateTimeString = '';
if (result.detail.start_datetime && result.detail.end_datetime) {
startDateTimeString = new Date(result.detail.start_datetime)
.toLocaleString('en-US', { hour12: false })
.replace(', ', ' ')
.slice(0, -3);
endDateTimeString = new Date(result.detail.end_datetime)
.toLocaleString('en-US', { hour12: false })
.replace(', ', ' ')
.slice(0, -3);
dateTimeLabel = `
<div>Start:</div>
<div>End:</div>
`;
} else {
startDateTimeString = 'To Be Determined';
}
let editTimeButton = '';
if (isCreator && processing && !deleted) {
editTimeButton = `
<a class="edit-button" data-bs-toggle="modal" data-bs-target="#datetime-modal">
<i class="fa-regular fa-pen-to-square"></i>
</a>
`;
}
let datetimePollButton = '';
if (result.detail.date_poll_created) {
datetimePollButton = `
<a class="poll-button" href="/poll/datetimePoll.html?${params}">
<i class="fa-solid fa-check"></i>
</a>
`;
}
const dateTime = document.querySelector('.date-time .background-frame');
dateTime.innerHTML = `
<div class="frame-title">
Date & Time
</div>
<div>
<div class="frame-content-label">
${dateTimeLabel}
</div>
<div class="frame-content">
<div>${startDateTimeString}</div>
<div>${endDateTimeString}</div>
</div>
<div class="datetime-buttons-container">
${datetimePollButton}
${editTimeButton}
</div>
</div>
`;
// Load Participants into Page
let participantListHTML = '';
participantListHTML += '<div>';
participantListHTML += `
<div class="red_creator creator_${result.creator.id}">
<i class="fa-solid fa-user"></i>
&nbsp; &nbsp;
${result.creator.first_name} ${result.creator.last_name}
</div>
`;
if (result.participants.length) {
const userList = result.participants;
for (let user of userList) {
participantListHTML += `
<div class="user_${user.id}">
<i class="fa-solid fa-user"></i>
&nbsp; &nbsp;
${user.first_name} ${user.last_name}
</div>
`;
}
}
participantListHTML += '</div>';
let editParticipantsButton = '';
if (isCreator && processing && !deleted) {
editParticipantsButton = `
<a class="edit-button" data-bs-toggle="modal" data-bs-target="#participants-modal">
<i class="fa-regular fa-pen-to-square"></i>
</a>
`;
}
let inviteButton = '';
if (isCreator && processing && !deleted) {
inviteButton = `
<div class="invite-button-container">
<a class="invite-button" data-bs-toggle="modal" data-bs-target="#invitation-modal">
+
</a>
<div>
Invite more friends
</div>
</div>
`;
}
const participant = document.querySelector('.participant .background-frame');
participant.innerHTML = `
<div class="frame-title-container">
<div class="left">
<div class="frame-title">
Participants
</div>
<div id="number-of-participants">
${result.participants.length + 1}
</div>
</div>
${editParticipantsButton}
</div>
<div class="frame-content-container">
${participantListHTML}
</div>
${inviteButton}
`;
// Load Participants Modal
currentParticipantsList = structuredClone(result.participants);
loadParticipantsModal(currentParticipantsList, deletedParticipantsList);
// Load Invitation Link
pasteInvitationLink(result.detail.id, result.detail.invitation_token);
// Load Venue into Page
let venueString = '';
if (result.detail.venue) {
venueString = `
<a href="https://www.google.com/maps/search/${result.detail.venue.replaceAll(' ', '+')}/" target="_blank">
${result.detail.venue || ''}
</a>
`;
} else {
venueString = 'To Be Determined';
}
let editVenueButton = '';
if (isCreator && processing && !deleted) {
editVenueButton = `
<a class="edit-button" data-bs-toggle="modal" data-bs-target="#venue-modal">
<i class="fa-regular fa-pen-to-square"></i>
</a>
`;
}
let venuePollButton = '';
if (result.detail.venue_poll_created) {
venuePollButton = `
<a class="poll-button" href="/poll/venuePoll.html?${params}">
<i class="fa-solid fa-check"></i>
</a>
`;
}
const venue = document.querySelector('.venue .background-frame');
venue.innerHTML = `
<div class="frame-title-container">
<div class="frame-title">
Venue
</div>
<div class="venue-buttons-container">
${venuePollButton}
${editVenueButton}
</div>
</div>
<div class="frame-content-container">
<i class="fa-solid fa-location-dot"></i>
&nbsp; &nbsp;
${venueString}
</div>
`;
// Load schedule into Page
let infoButtonHTML = '';
if (result.detail.start_datetime && result.detail.end_datetime) {
infoButtonHTML = `
<a class="info-button">
<i class="fa-solid fa-info"></i>
</a>
`;
}
const schedule = document.querySelector('.schedule .background-frame');
schedule.innerHTML = `
<div class="frame-title-container">
<div id="frame-content-container" class="frame-title">
Schedule
</div>
${infoButtonHTML}
</div>
<div class="frame-content-container">
<div id="rundown-container" class="overflow-auto" data-current="0">
<div id="rundown" class="row">
</div>
</div>
</div>
`;
// Load item into Page
const item = document.querySelector('.item .background-frame');
item.innerHTML = `
<div class="frame-title-container">
<div class="frame-title">
Item
</div>
<a class="info-button">
<i class="fa-solid fa-info"></i>
</a>
</div>
<div class="frame-content-container">
<div class="shopping-list">
<div class="item-list border">
<table class="table">
<thead>
<tr>
<th scope="col" class="pending-item-header">
Pending Items:
<div>
<button id="shopping-list-shorting" class="shorting-btn" type="button"
data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-filter-circle"></i></button>
<ul class="dropdown-menu">
<li><a class="dropdown-item">Food</a></li>
<li><a class="dropdown-item">Drink</a></li>
<li><a class="dropdown-item">Decoration</a></li>
<li><a class="dropdown-item">Other</a></li>
</ul>
</div>
</th>
</tr>
</thead>
<tbody id="shopping-list-update">
<!--loaded with itemPost.js "shopping list JS"-->
</tbody>
</table>
</div>
</div>
</div>
`;
listenToSchedulePage(result.detail.start_datetime);
listenToItemPage();
listenToDeleteParticipants();
} else {
const roleName = isCreator ? 'creator' : 'participant';
alert(`You are not ${roleName} of the event!`);
}
}
export function loadParticipantsModal(currentList, deletedList) {
let currentParticipantListModalHTML = '';
if (currentList.length) {
currentParticipantListModalHTML += '<div>';
for (let user of currentList) {
currentParticipantListModalHTML += `
<div class="user-wrapper current" id="wrapper_user_${user.id}">
<div class="user_${user.id}">
<i class="fa-solid fa-user"></i>
&nbsp; &nbsp;
${user.first_name} ${user.last_name}
</div>
<a class="delete-button" id="delete_button_user_${user.id}">
<i class="fa-solid fa-trash-can"></i>
</a>
</div>
`;
}
currentParticipantListModalHTML += '</div>';
}
const currentParticipantModal = document.querySelector('#participants-modal #current-participants-list');
currentParticipantModal.innerHTML = `
<div class="participants-list-title">
Current
</div>
<div class="frame-content-container">
${currentParticipantListModalHTML}
</div>
`;
let deletedParticipantListModalHTML = '';
if (deletedList.length) {
deletedParticipantListModalHTML += '<div>';
for (let user of deletedList) {
deletedParticipantListModalHTML += `
<div class="user-wrapper current" id="wrapper_user_${user.id}">
<div class="user_${user.id}">
<i class="fa-solid fa-user"></i>
&nbsp; &nbsp;
${user.first_name} ${user.last_name}
</div>
</div>
`;
}
deletedParticipantListModalHTML += '</div>';
}
const deletedParticipantModal = document.querySelector('#participants-modal #deleted-participants-list');
deletedParticipantModal.innerHTML = `
<div class="participants-list-title">
Deleted
</div>
<div class="frame-content-container">
${deletedParticipantListModalHTML}
</div>
`;
}
export function pasteInvitationLink(eventId, invitation_token) {
document.querySelector(
'#invitation-modal .form-control'
).value = `http://${window.location.host}/invitationPage/invitation.html?event-id=${eventId}&token=${invitation_token}`;
}

View File

@@ -0,0 +1,110 @@
.bi-chevron-left {
font-size: 30px;
position: fixed;
top: 90px;
left: 50px;
color: #444a58;
cursor: pointer;
}
/* event body CSS */
#from-container {
display: flex;
justify-content: center;
margin: 30px 10px;
}
.box {
margin: 10px 10px;
}
.form-header {
font-size: 20px;
font-family: 'Lato', sans-serif;
padding: 3px;
}
.venue-check {
display: flex;
font-size: 16px;
font-family: 'Lato', sans-serif;
}
.form-check {
margin: 10px;
font-size: 16 px;
font-family: 'Lato', sans-serif;
}
/* Date part */
.eventDate-box {
display: flex;
flex-direction: row;
}
.event-time-label {
font-size: 19px;
font-family: 'Lato', sans-serif;
margin: 4px 10px 4px 0px;
}
.event-time-label-box {
display: flex;
flex-direction: column;
}
.event-time-label-box > input {
color: #495871;
}
.clock {
margin: 4px 10px 4px 0px;
}
/* parking */
.parking-box {
display: flex;
margin: 15px 0px 5px 0px;
color: #495871;
}
.parking-number-input {
margin-left: 10px;
width: 70px;
}
/* budget */
.budget-box {
color: #495871;
font-family: 'Lato', sans-serif;
margin: 5px 0px;
}
.budget-box span {
margin-left: 5px;
}
/* submit btn */
.submit-btn {
display: flex;
justify-content: center;
max-height: 50px;
}
#event-submit {
border: none;
margin-top: 10px;
background-color: white;
}
.event-date-reminder {
color: grey;
font-size: 12px;
}
/* Remark Css */
.form-control {
border-width: 2px;
border-radius: 10px;
width: 90%;
}

View File

@@ -0,0 +1,95 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link rel="stylesheet" href="./newEvent.css" />
<title>Add New Party</title>
</head>
<body style="display: none">
<div class="navbar-container container">
<!-- NAVBAR: to be loaded with js -->
</div>
<div class="container">
<a href="/index.html"><i class="bi bi-chevron-left"></i></a>
<div class="row">
<form id="from-container">
<div class="outer-container">
<div class="event-name-box">
<div class="form-header">Name of the Event *</div>
<input id="event-name-input" type="text" class="form-control" name="event_name" />
</div>
<div class="Venue-box">
<div class="form-header">Venue of the party</div>
<input type="text" class="form-control" name="event_venue" />
</div>
<div class="event-date">
<div class="eventDate-box">
<div class="event-time-label-box">
<label for="meeting-time-start" class="event-time-label">Start date & time:</label>
<label for="meeting-time-end" class="event-time-label">End date & time:</label>
</div>
<div class="event-time-label-box">
<input
class="clock"
type="datetime-local"
id="meeting-time-start"
name="event_date_start"
min="2021-06-07T00:00"
max="2035-12-30T00:00"
step="900"
/>
<input
class="clock"
type="datetime-local"
id="meeting-time-end"
name="event_date_end"
min="2021-06-07T00:00"
max="2035-12-30T00:00"
step="900"
/>
</div>
</div>
</div>
<div class="event-date-reminder">
Enter the time in 15 mins interval, e.g. 15:00 or 15:15 or 15:30 or 15:45.
</div>
<!-- submit btn -->
<div class="submit-btn">
<button id="event-submit">
<img src="/asset/submit_button.svg" alt="Submit Button" />
</button>
</div>
</div>
</form>
</div>
</div>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8"
crossorigin="anonymous"
></script>
<script type="module" src="./newEvent.js"></script>
</body>
</html>

View File

@@ -0,0 +1,69 @@
import { addNavbar } from '/functions/addNavbar.js';
import { loadName } from '/functions/loadName.js';
function onlyNumbers(str) {
return /^[0-9]+$/.test(str);
}
window.addEventListener('load', () => {
addNavbar();
loadName();
document.body.style.display = 'block';
});
document.querySelector('#from-container').addEventListener('submit', async function (e) {
e.preventDefault();
const form = e.target;
const eventName = form.event_name.value;
const eventVenue = form.event_venue.value || null;
const startTime = form.event_date_start.value ? new Date(form.event_date_start.value).toISOString() : null;
const endTime = form.event_date_end.value ? new Date(form.event_date_end.value).toISOString() : null;
let dataPass = true;
if (!eventName) {
dataPass = false;
alert('Please fill in the event name!');
}
const nowTimeValue = new Date().getTime();
const startTimeValue = new Date(startTime).getTime();
const endTimeValue = new Date(endTime).getTime();
// check time validity
if (startTimeValue && endTimeValue) {
if (startTimeValue <= nowTimeValue) {
dataPass = false;
alert('Start time must be later than time now!');
} else if (startTimeValue >= endTimeValue) {
dataPass = false;
alert('Start time cannot equals or later than end time!');
}
} else if (!!startTimeValue + !!endTimeValue) {
dataPass = false;
alert('You cannot only leave 1 time blank!');
}
if (dataPass) {
let formObj = {
eventName,
eventVenue,
startTime,
endTime
};
const res = await fetch('/events', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formObj)
});
const eventsResult = await res.json();
if (eventsResult.msg === 'Posted to DB') {
window.location.href = '/index.html'; //
}
}
});

View File

@@ -0,0 +1,61 @@
#account-info {
text-align: center;
}
#personal-page-form {
max-width: 400px;
}
/* @media (min-width: 1200px) {
.form-container {
padding: 0px 400px !important;
}
} */
.form-container {
padding: 0px 50px;
display: flex;
justify-content: center;
}
.name_container {
display: flex;
}
.first_name_container {
padding: 0px 20px 0px 0px;
}
.update {
border-radius: 20px;
color: black;
background-color: #f29559;
border: none;
}
.cancel {
border-radius: 20px;
color: black;
background-color: #9bafd0;
border: none;
}
.btn {
min-width: 120px;
font-size: 15px;
}
.mb-3 {
max-width: 400px;
}
.button-container {
padding: 30px;
display: flex;
justify-content: space-between;
}
#account-info {
padding: 50px 0px;
}

View File

@@ -0,0 +1,109 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css" />
<link rel="stylesheet" href="./personalPage.css" />
<title>Personal Page</title>
</head>
<body style="display: none">
<div class="navbar-container container">
<!-- NAVBAR: to be loaded with js -->
</div>
<header id="account-info">Account Info</header>
<div class="form-container">
<form action="/personalPage" method="PUT" id="personal-page-form">
<div class="mb-3 name_container">
<span class="first_name_container">
<label for="first_name" class="form-label">First Name</label>
<input
type="text"
class="form-control"
name="first_name"
id="first_name"
placeholder="Input Your First Name"
value=""
required
/>
</span>
<span>
<label for="last_name" class="form-label">Last Name</label>
<input
type="text"
class="form-control"
name="last_name"
id="last_name"
placeholder="Input Your Last Name"
required
/>
</span>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" name="email" id="email" readonly />
</div>
<div class="mb-3">
<label for="phone" class="form-label">Phone</label>
<input
type="text"
class="form-control"
name="phone"
id="phone"
placeholder="Input Phone"
pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"
required
/>
<div class="form-text">Phone number must be in the following format: e.g. 647-111-1111</div>
</div>
<div class="mb-3 google-user">
<label for="current_password" class="form-label">Current Password</label>
<input type="password" class="form-control" name="current_password" id="current_password" />
<div class="form-text">Enter your current password if you wish to update a new password</div>
</div>
<div class="mb-3 google-user">
<label for="new_password" class="form-label">New Password</label>
<input
type="password"
class="form-control"
name="new_password"
id="new_password"
placeholder="Input your new password here"
minlength="8"
/>
<div class="form-text">Password must be 8 characters long</div>
</div>
<div class="mb-3 google-user">
<label for="new_confirmed_password" class="form-label">Confirm Password</label>
<input
type="password"
class="form-control"
name="new_confirmed_password"
id="new_confirmed_password"
placeholder="Type the new password again"
minlength="8"
/>
</div>
<div class="button-container mb-3">
<button type="submit" value="submit" class="btn btn-primary update">Update</button>
<button type="reset" value="cancel" class="btn btn-primary cancel">Cancel</button>
</div>
</form>
</div>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8"
crossorigin="anonymous"
></script>
<script type="module" src="./personalPage.js"></script>
</body>
</html>

View File

@@ -0,0 +1,117 @@
import { addNavbar } from '/functions/addNavbar.js';
import { loadName } from '/functions/loadName.js';
window.addEventListener('load', async () => {
await loadInfo();
await hideInfo();
addNavbar();
loadName();
document.body.style.display = 'block';
});
async function isGoogleUser(password) {
if (password.substring(0, 11) === 'google_user') {
return true;
} else {
return false;
}
}
async function hideInfo() {
const res = await fetch(`/personalPage`);
const result = await res.json();
const divCluster = document.querySelectorAll('.google-user');
if (await isGoogleUser(result.password)) {
divCluster.forEach((div) => {
div.style.display = 'none';
});
} else {
divCluster.forEach((div) => {
div.style.display = 'block';
});
}
}
async function loadInfo() {
const res = await fetch(`/personalPage`);
const result = await res.json();
const firstName = document.querySelector('#first_name');
const lastName = document.querySelector('#last_name');
const email = document.querySelector('#email');
const phone = document.querySelector('#phone');
const currentPassword = document.querySelector('#current_password');
const newPassword = document.querySelector('#new_password');
const newConfirmedPassword = document.querySelector('#new_confirmed_password');
firstName.value = result.first_name;
lastName.value = result.last_name;
email.value = result.email;
phone.value = result.phone;
currentPassword.value = '';
newPassword.value = '';
newConfirmedPassword.value = '';
}
document.querySelector('#personal-page-form').addEventListener('submit', async function updateInfo(event) {
event.preventDefault();
const form = event.target;
const lastName = form.last_name.value;
const firstName = form.first_name.value;
const phone = form.phone.value;
const email = form.email.value;
const currentPassword = form.current_password.value;
const newPassword = form.new_password.value;
const newConfirmedPassword = form.new_confirmed_password.value;
let dataPass = true;
if (newPassword || newConfirmedPassword) {
if (!(newPassword === newConfirmedPassword)) {
dataPass = false;
alert('Password and confirm password do not match!');
} else if (newPassword === currentPassword) {
dataPass = false;
alert('Your current password and the new password are the same!');
} else if (!currentPassword) {
dataPass = false;
alert('Please input your current password if you wish to update your password');
}
}
if (dataPass) {
const formObject = {};
formObject['first_name'] = firstName;
formObject['last_name'] = lastName;
formObject['email'] = email;
formObject['phone'] = phone;
formObject['current_password'] = currentPassword;
formObject['new_password'] = newPassword;
if (newPassword) {
formObject['password'] = newPassword;
} else {
formObject['password'] = currentPassword;
}
const res = await fetch(`/personalPage`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formObject)
});
const result = await res.json();
console.log(result);
if (res.status === 400) {
alert('Something wrong, please check if you have the correct password');
} else {
alert('Update successful!');
location.reload();
}
}
});

View File

@@ -0,0 +1,149 @@
body {
font-family: 'Calibri';
position: relative;
}
.poll-container {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.poll-frame {
display: flex;
justify-content: center;
align-items: flex-start;
margin: 20px 0;
flex-wrap: wrap;
}
.option-container {
width: 200px;
height: 200px;
background-color: #f9f9da;
border-radius: 20px;
margin: 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex-wrap: wrap;
cursor: pointer;
}
.option-container:hover {
opacity: 0.7;
}
.title {
font-size: 30px;
font-weight: bold;
}
.address {
font-size: 20px;
}
#poll-submit-button,
#poll-terminate-button,
#poll-terminate-confirm-button {
font-size: 20px;
font-family: 'Lato', sans-serif;
padding: 10px 20px 10px 20px;
border-radius: 20px;
margin: 18px;
min-width: 110px;
}
#poll-submit-button {
box-shadow: 0px 1px 12px #f2d492;
background-color: #f2d492;
border: none;
color: #293241;
}
#poll-terminate-button,
#poll-terminate-confirm-button {
box-shadow: none;
background-color: #d8684e;
border: #c7492c 3px solid;
color: white;
font-weight: bold;
}
.poll-title {
font-size: 20px;
margin-top: 20px;
font-weight: bold;
}
.selected {
border: solid black 5px;
}
.vote {
font-size: 15px;
}
.warning-sign {
font-size: 70px;
width: 90px;
height: 90px;
border-radius: 200px;
border: solid 4px black;
display: flex;
justify-content: center;
align-items: center;
}
.warning {
font-size: 30px;
font-weight: bold;
}
.reminder-text {
text-align: center;
}
.modal-title {
font-size: 25px;
font-weight: bold;
color: #293241;
font-family: 'Lato', sans-serif;
transform: translateX(10px);
}
.modal-header {
display: flex;
justify-content: space-between;
}
.modal-body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.modal-footer {
display: flex;
justify-content: center;
align-content: center;
}
#back-page {
position: absolute;
left: 50px;
top: 15px;
text-decoration: none;
}
.bi-chevron-left {
font-size: 30px;
top: 90px;
left: 40px;
color: #444a58;
cursor: pointer;
}

View File

@@ -0,0 +1,86 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link rel="stylesheet" href="./datetimePoll.css" />
<title>Venue Poll</title>
</head>
<body style="display: none">
<div class="navbar-container container">
<!-- NAVBAR: to be loaded with js -->
</div>
<div class="poll-container">
<div class="poll-title"></div>
<div class="poll-frame"></div>
<div class="button-container"></div>
<!-- Back Button -->
<a id="back-page">
<i class="bi bi-chevron-left"></i>
</a>
</div>
<!-- Modal -->
<!-- Terminate Poll Confirmation Modal -->
<div
class="modal fade"
id="delete-poll-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">Terminate Poll</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div class="warning-sign">
<i class="fa-solid fa-exclamation"></i>
</div>
<div class="warning">Are you sure?</div>
<div class="reminder-text">You will not be able to revert this action!</div>
<div class="modal-footer">
<button id="poll-terminate-confirm-button" type="submit" class="modal-submit-button">
TERMINATE
</button>
</div>
</div>
</div>
</div>
</div>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8"
crossorigin="anonymous"
></script>
<script type="module" src="./datetimePoll.js"></script>
</body>
</html>

View File

@@ -0,0 +1,154 @@
import { addNavbar } from '/functions/addNavbar.js';
import { loadName } from '/functions/loadName.js';
window.addEventListener('load', async () => {
addNavbar();
await loadName();
await loadOptions();
document.body.style.display = 'block';
});
async function loadOptions() {
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const res = await fetch(`/events/poll/datetime/${eventId}`);
const result = await res.json();
if (result.status) {
let pollTitle = '';
let pollFrameHTML = '';
let buttonContainerHTML = '';
// Poll title HTML
if (result.pollTerminated) {
pollTitle = 'Poll Terminated';
} else if (result.eventDeleted) {
pollTitle = 'Deleted Event';
} else if (!result.creator) {
if (result.choice) {
pollTitle = `Your choice was: <br>
start: ${new Date(result.choice.start)
.toLocaleString('en-US', { hour12: false })
.replace(',', '')
.slice(0, -3)}<br>
end: ${new Date(result.choice.end)
.toLocaleString('en-US', { hour12: false })
.replace(',', '')
.slice(0, -3)}
`;
} else {
pollTitle = 'Please click on the venue option to vote:';
}
} else {
pollTitle = 'You may click button below to terminate poll.';
}
// Poll Options HTML
const optionsList = result.pollOptions;
optionsList.forEach((each, index) => {
const voteCount = result.voteCounts[each.id].count;
pollFrameHTML += `
<div class="option-container" id="option_${each.id}">
<div class="title">
Datetime ${index + 1}
</div>
<div class="start">
Start: ${new Date(each.start_datetime)
.toLocaleString('en-US', { hour12: false })
.replace(',', '')
.slice(0, -3)}
</div>
<div class="end">
End: ${new Date(each.end_datetime)
.toLocaleString('en-US', { hour12: false })
.replace(',', '')
.slice(0, -3)}
</div>
<div class="vote">
${voteCount === '1' ? `${voteCount} Vote` : `${voteCount} Votes`}
</div>
</div>
`;
});
// Button HTML
if (!result.pollTerminated && !result.eventDeleted) {
if (result.creator) {
buttonContainerHTML = `<button id="poll-terminate-button">Terminate Poll</button>`;
} else {
if (!result.choice) {
buttonContainerHTML = `<button id="poll-submit-button">Submit Choice</button>`;
}
}
}
// Add HTML to the page
document.querySelector('.poll-title').innerHTML = pollTitle;
document.querySelector('.poll-frame').innerHTML = pollFrameHTML;
document.querySelector('.button-container').innerHTML = buttonContainerHTML;
// Check if participant that has not yet voted
if (!result.pollTerminated && !result.eventDeleted) {
if (!result.creator && !result.choice) {
// Listen option choice
let optionId;
const optionsDiv = document.querySelectorAll('.option-container');
optionsDiv.forEach((each) => {
each.addEventListener('click', (e) => {
if (e.target.classList.contains('option-container')) {
e.target.classList.add('selected');
optionId = e.target.id;
const otherDiv = document.querySelectorAll(`.option-container:not([id*="${optionId}"])`);
otherDiv.forEach((each) => {
each.classList.remove('selected');
});
}
});
});
// Listen submit button for voting
document.querySelector('#poll-submit-button').addEventListener('click', async () => {
const optionId = document.querySelector('.selected').id.replace('option_', '');
const res = await fetch(`/events/poll/datetime/vote/${eventId}/${optionId}`, {
method: 'POST'
});
const result = await res.json();
if (result.status) {
alert('Successfully voted!');
await loadOptions();
} else {
alert('Unable to submit vote!');
}
});
} else if (result.creator) {
// Listen to terminate button
document.querySelector('#poll-terminate-button').addEventListener('click', () => {
const dateTimeTerminatePoll = new bootstrap.Modal(document.getElementById('delete-poll-modal'));
dateTimeTerminatePoll.show();
document.querySelector('#poll-terminate-confirm-button').addEventListener('click', async () => {
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const res = await fetch(`/events/poll/datetime/${eventId}`, {
method: 'DELETE'
});
const result = await res.json();
if (result.status) {
alert('Successfully terminated poll!');
dateTimeTerminatePoll.hide();
loadOptions();
} else {
alert('Unable to terminate poll!');
}
});
});
}
}
// Add backward button
document.querySelector('#back-page').href = `/eventSummary/event.html?${params}`;
} else {
alert('Unable to load datetime poll page!');
window.location.href = '/index.html';
}
}

View File

@@ -0,0 +1,149 @@
body {
font-family: 'Calibri';
position: relative;
}
.poll-container {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.poll-frame {
display: flex;
justify-content: center;
align-items: flex-start;
margin: 20px 0;
flex-wrap: wrap;
}
.option-container {
width: 200px;
height: 200px;
background-color: #f9f9da;
border-radius: 20px;
margin: 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex-wrap: wrap;
cursor: pointer;
}
.option-container:hover {
opacity: 0.7;
}
.title {
font-size: 30px;
font-weight: bold;
}
.address {
font-size: 20px;
}
#poll-submit-button,
#poll-terminate-button,
#poll-terminate-confirm-button {
font-size: 20px;
font-family: 'Lato', sans-serif;
padding: 10px 20px 10px 20px;
border-radius: 20px;
margin: 18px;
min-width: 110px;
}
#poll-submit-button {
box-shadow: 0px 1px 12px #f2d492;
background-color: #f2d492;
border: none;
color: #293241;
}
#poll-terminate-button,
#poll-terminate-confirm-button {
box-shadow: none;
background-color: #d8684e;
border: #c7492c 3px solid;
color: white;
font-weight: bold;
}
.poll-title {
font-size: 20px;
margin-top: 20px;
font-weight: bold;
}
.selected {
border: solid black 5px;
}
.vote {
font-size: 15px;
}
.warning-sign {
font-size: 70px;
width: 90px;
height: 90px;
border-radius: 200px;
border: solid 4px black;
display: flex;
justify-content: center;
align-items: center;
}
.warning {
font-size: 30px;
font-weight: bold;
}
.reminder-text {
text-align: center;
}
.modal-title {
font-size: 25px;
font-weight: bold;
color: #293241;
font-family: 'Lato', sans-serif;
transform: translateX(10px);
}
.modal-header {
display: flex;
justify-content: space-between;
}
.modal-body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.modal-footer {
display: flex;
justify-content: center;
align-content: center;
}
#back-page {
position: absolute;
left: 50px;
top: 15px;
text-decoration: none;
}
.bi-chevron-left {
font-size: 30px;
top: 90px;
left: 40px;
color: #444a58;
cursor: pointer;
}

View File

@@ -0,0 +1,86 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link rel="stylesheet" href="./venuePoll.css" />
<title>Venue Poll</title>
</head>
<body style="display: none">
<div class="navbar-container container">
<!-- NAVBAR: to be loaded with js -->
</div>
<div class="poll-container">
<div class="poll-title"></div>
<div class="poll-frame"></div>
<div class="button-container"></div>
<!-- Back Button -->
<a id="back-page">
<i class="bi bi-chevron-left"></i>
</a>
</div>
<!-- Modal -->
<!-- Terminate Poll Confirmation Modal -->
<div
class="modal fade"
id="delete-poll-modal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div></div>
<h5 class="modal-title">Terminate Poll</h5>
<div class="exit-modal">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<div class="warning-sign">
<i class="fa-solid fa-exclamation"></i>
</div>
<div class="warning">Are you sure?</div>
<div class="reminder-text">You will not be able to revert this action!</div>
<div class="modal-footer">
<button id="poll-terminate-confirm-button" type="submit" class="modal-submit-button">
TERMINATE
</button>
</div>
</div>
</div>
</div>
</div>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8"
crossorigin="anonymous"
></script>
<script type="module" src="./venuePoll.js"></script>
</body>
</html>

View File

@@ -0,0 +1,134 @@
import { addNavbar } from '/functions/addNavbar.js';
import { loadName } from '/functions/loadName.js';
window.addEventListener('load', async () => {
addNavbar();
await loadName();
await loadOptions();
document.body.style.display = 'block';
});
async function loadOptions() {
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const res = await fetch(`/events/poll/venue/${eventId}`);
const result = await res.json();
if (result.status) {
let pollTitle = '';
let pollFrameHTML = '';
let buttonContainerHTML = '';
// Poll title HTML
if (result.pollTerminated) {
pollTitle = 'Poll Terminated';
} else if (result.eventDeleted) {
pollTitle = 'Deleted Event';
} else if (!result.creator) {
if (result.choice) {
pollTitle = `Your choice was: ${result.choice.address}`;
} else {
pollTitle = 'Please click on the venue option to vote:';
}
} else {
pollTitle = 'You may click button below to terminate poll.';
}
// Poll Options HTML
const optionsList = result.pollOptions;
optionsList.forEach((each, index) => {
const voteCount = result.voteCounts[each.id].count;
pollFrameHTML += `
<div class="option-container" id="option_${each.id}">
<div class="title">
Venue ${index + 1}
</div>
<div class="address">
${each.address}
</div>
<div class="vote">
${voteCount === '1' ? `${voteCount} Vote` : `${voteCount} Votes`}
</div>
</div>
`;
});
// Button HTML
if (!result.pollTerminated && !result.eventDeleted) {
if (result.creator) {
buttonContainerHTML = `<button id="poll-terminate-button">Terminate Poll</button>`;
} else {
if (!result.choice) {
buttonContainerHTML = `<button id="poll-submit-button">Submit Choice</button>`;
}
}
}
// Add HTML to the page
document.querySelector('.poll-title').innerHTML = pollTitle;
document.querySelector('.poll-frame').innerHTML = pollFrameHTML;
document.querySelector('.button-container').innerHTML = buttonContainerHTML;
// Check if participant that has not yet voted
if (!result.pollTerminated && !result.eventDeleted) {
if (!result.creator && !result.choice) {
// Listen option choice
let optionId;
const optionsDiv = document.querySelectorAll('.option-container');
optionsDiv.forEach((each) => {
each.addEventListener('click', (e) => {
e.currentTarget.classList.add('selected');
optionId = e.currentTarget.id;
const otherDiv = document.querySelectorAll(`.option-container:not([id*="${optionId}"])`);
otherDiv.forEach((each) => {
each.classList.remove('selected');
});
});
});
// Listen submit button for voting
document.querySelector('#poll-submit-button').addEventListener('click', async () => {
const optionId = document.querySelector('.selected').id.replace('option_', '');
const res = await fetch(`/events/poll/venue/vote/${eventId}/${optionId}`, {
method: 'POST'
});
const result = await res.json();
if (result.status) {
alert('Successfully voted!');
await loadOptions();
} else {
alert('Unable to submit vote!');
}
});
} else if (result.creator) {
// Listen to terminate button
document.querySelector('#poll-terminate-button').addEventListener('click', () => {
const venueTerminatePoll = new bootstrap.Modal(document.getElementById('delete-poll-modal'));
venueTerminatePoll.show();
document.querySelector('#poll-terminate-confirm-button').addEventListener('click', async () => {
const params = new URLSearchParams(window.location.search);
const eventId = params.get('event-id');
const res = await fetch(`/events/poll/venue/${eventId}`, {
method: 'DELETE'
});
const result = await res.json();
if (result.status) {
alert('Successfully terminated poll!');
venueTerminatePoll.hide();
loadOptions();
} else {
alert('Unable to terminate poll!');
}
});
});
}
}
// Add backward button
document.querySelector('#back-page').href = `/eventSummary/event.html?${params}`;
} else {
alert('Unable to load venue poll page!');
window.location.href = '/index.html';
}
}