update,
This commit is contained in:
162
_tecky/party-planner/backend/private/comment/comment.css
Normal file
162
_tecky/party-planner/backend/private/comment/comment.css
Normal 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;
|
||||
}
|
158
_tecky/party-planner/backend/private/comment/comment.html
Normal file
158
_tecky/party-planner/backend/private/comment/comment.html
Normal 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>
|
202
_tecky/party-planner/backend/private/comment/comment.js
Normal file
202
_tecky/party-planner/backend/private/comment/comment.js
Normal 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;
|
||||
}
|
@@ -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;
|
||||
}
|
@@ -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>
|
1152
_tecky/party-planner/backend/private/eventSchedule/eventSchedule.js
Normal file
1152
_tecky/party-planner/backend/private/eventSchedule/eventSchedule.js
Normal file
File diff suppressed because it is too large
Load Diff
972
_tecky/party-planner/backend/private/eventSummary/event.css
Normal file
972
_tecky/party-planner/backend/private/eventSummary/event.css
Normal 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;
|
||||
}
|
579
_tecky/party-planner/backend/private/eventSummary/event.html
Normal file
579
_tecky/party-planner/backend/private/eventSummary/event.html
Normal 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>  Option
|
||||
</button>
|
||||
<button id="datetime-remove-option" class="modal-submit-button">
|
||||
<i class="fa-solid fa-minus"></i>  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>  Option
|
||||
</button>
|
||||
<button id="venue-remove-option" class="modal-submit-button">
|
||||
<i class="fa-solid fa-minus"></i>  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>
|
477
_tecky/party-planner/backend/private/eventSummary/event.js
Normal file
477
_tecky/party-planner/backend/private/eventSummary/event.js
Normal 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!');
|
||||
}
|
||||
});
|
@@ -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}`;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
188
_tecky/party-planner/backend/private/index.css
Normal file
188
_tecky/party-planner/backend/private/index.css
Normal 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;
|
||||
}
|
||||
}
|
99
_tecky/party-planner/backend/private/index.html
Normal file
99
_tecky/party-planner/backend/private/index.html
Normal 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>
|
47
_tecky/party-planner/backend/private/index.js
Normal file
47
_tecky/party-planner/backend/private/index.js
Normal 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';
|
||||
});
|
163
_tecky/party-planner/backend/private/itemPostPage/itemPost.css
Normal file
163
_tecky/party-planner/backend/private/itemPostPage/itemPost.css
Normal 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;
|
||||
}
|
259
_tecky/party-planner/backend/private/itemPostPage/itemPost.html
Normal file
259
_tecky/party-planner/backend/private/itemPostPage/itemPost.html
Normal 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>
|
202
_tecky/party-planner/backend/private/itemPostPage/itemPost.js
Normal file
202
_tecky/party-planner/backend/private/itemPostPage/itemPost.js
Normal 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);
|
||||
});
|
||||
});
|
222
_tecky/party-planner/backend/private/listenButtons.js
Normal file
222
_tecky/party-planner/backend/private/listenButtons.js
Normal 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();
|
||||
});
|
||||
}
|
||||
}
|
571
_tecky/party-planner/backend/private/loadEvent.js
Normal file
571
_tecky/party-planner/backend/private/loadEvent.js
Normal 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>
|
||||
|
||||
${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>
|
||||
|
||||
${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>
|
||||
|
||||
${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>
|
||||
|
||||
${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>
|
||||
|
||||
${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}`;
|
||||
}
|
110
_tecky/party-planner/backend/private/newEvent/newEvent.css
Normal file
110
_tecky/party-planner/backend/private/newEvent/newEvent.css
Normal 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%;
|
||||
}
|
95
_tecky/party-planner/backend/private/newEvent/newEvent.html
Normal file
95
_tecky/party-planner/backend/private/newEvent/newEvent.html
Normal 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>
|
69
_tecky/party-planner/backend/private/newEvent/newEvent.js
Normal file
69
_tecky/party-planner/backend/private/newEvent/newEvent.js
Normal 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'; //
|
||||
}
|
||||
}
|
||||
});
|
@@ -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;
|
||||
}
|
@@ -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>
|
@@ -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();
|
||||
}
|
||||
}
|
||||
});
|
149
_tecky/party-planner/backend/private/poll/datetimePoll.css
Normal file
149
_tecky/party-planner/backend/private/poll/datetimePoll.css
Normal 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;
|
||||
}
|
86
_tecky/party-planner/backend/private/poll/datetimePoll.html
Normal file
86
_tecky/party-planner/backend/private/poll/datetimePoll.html
Normal 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>
|
154
_tecky/party-planner/backend/private/poll/datetimePoll.js
Normal file
154
_tecky/party-planner/backend/private/poll/datetimePoll.js
Normal 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';
|
||||
}
|
||||
}
|
149
_tecky/party-planner/backend/private/poll/venuePoll.css
Normal file
149
_tecky/party-planner/backend/private/poll/venuePoll.css
Normal 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;
|
||||
}
|
86
_tecky/party-planner/backend/private/poll/venuePoll.html
Normal file
86
_tecky/party-planner/backend/private/poll/venuePoll.html
Normal 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>
|
134
_tecky/party-planner/backend/private/poll/venuePoll.js
Normal file
134
_tecky/party-planner/backend/private/poll/venuePoll.js
Normal 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';
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user