Initial event load
This commit is contained in:
parent
567ba5da75
commit
2ead3f79c3
|
|
@ -2,7 +2,7 @@ use askama::Template;
|
||||||
use askama_axum::{IntoResponse, Response};
|
use askama_axum::{IntoResponse, Response};
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::State,
|
extract::State,
|
||||||
response::{Html, Redirect},
|
response::{Html, Json, Redirect},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
|
|
@ -69,12 +69,13 @@ pub async fn cottagecalendar(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_next_event(db_pool: &SqlitePool) -> Option<String> {
|
pub async fn get_events(
|
||||||
let next_event = sqlx::query_as::<_, (String, String)>(
|
Extension(user_data): Extension<Option<UserData>>,
|
||||||
"SELECT date, title FROM events ORDER BY date ASC LIMIT 1",
|
State(db_pool): State<SqlitePool>,
|
||||||
)
|
) -> String {
|
||||||
.fetch_one(db_pool)
|
let events = "[{\"title\": \"Chris and Terri\", \"start\": \"2024-12-23T14:00:00\", \"end\": \"2024-12-27T10:00:00\", \"allDay\": false}, {\"title\": \"Stephen\", \"start\": \"2024-12-27T14:00:00\", \"end\": \"2024-12-31T10:00:00\", \"allDay\": false}]";
|
||||||
.await;
|
|
||||||
|
|
||||||
next_event.map(|(date, title)| format!("{} - {}", date, title)).ok()
|
println!("{}", events);
|
||||||
}
|
|
||||||
|
events.to_string()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ async fn main() {
|
||||||
|
|
||||||
// Calendar
|
// Calendar
|
||||||
.route("/cottagecalendar", get(cottagecalendar))
|
.route("/cottagecalendar", get(cottagecalendar))
|
||||||
|
.route("/getevents", get(calendar::get_events))
|
||||||
|
|
||||||
// Wishlist
|
// Wishlist
|
||||||
.route("/wishlists", get(wishlists))
|
.route("/wishlists", get(wishlists))
|
||||||
|
|
|
||||||
|
|
@ -2,451 +2,50 @@
|
||||||
{% block links %}
|
{% block links %}
|
||||||
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/@fullcalendar/core@4.2.0/main.min.css'>
|
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/@fullcalendar/core@4.2.0/main.min.css'>
|
||||||
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/@fullcalendar/daygrid@4.3.0/main.min.css'>
|
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/@fullcalendar/daygrid@4.3.0/main.min.css'>
|
||||||
|
|
||||||
<style>
|
|
||||||
#calendar {
|
|
||||||
max-width: 800px;
|
|
||||||
margin: 40px auto;
|
|
||||||
background: #fff;
|
|
||||||
padding: 15px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-event {
|
|
||||||
border: 1px solid #eee !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-content {
|
|
||||||
padding: 3px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-content .fc-title {
|
|
||||||
display: block !important;
|
|
||||||
overflow: hidden;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-customButton-button {
|
|
||||||
font-size: 13px !important;
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.form-group {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-group>label {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#delete-modal .modal-footer>.btn {
|
|
||||||
|
|
||||||
border-radius: 3px !important;
|
|
||||||
padding: 0px 8px !important;
|
|
||||||
font-size: 15px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.fc-scroller {
|
|
||||||
overflow-y: hidden !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1000;
|
|
||||||
background-color: #fff;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.3);
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* .context-menu.show {
|
|
||||||
display: block;
|
|
||||||
} */
|
|
||||||
|
|
||||||
.context-menu ul {
|
|
||||||
list-style-type: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu ul>li {
|
|
||||||
display: block;
|
|
||||||
;
|
|
||||||
padding: 5px 15px;
|
|
||||||
list-style-type: none;
|
|
||||||
color: #333;
|
|
||||||
display: block;
|
|
||||||
cursor: pointer;
|
|
||||||
margin: 0 auto;
|
|
||||||
transition: 0.10s;
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu ul>li:hover {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #007bff;
|
|
||||||
border-radius: 2px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.fa,
|
|
||||||
.fas {
|
|
||||||
font-size: 13px;
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock links %}
|
{% endblock links %}
|
||||||
{% block center %}
|
{% block center %}
|
||||||
<h1>Cottage Calendar</h1>
|
<h1>Cottage Calendar</h1>
|
||||||
<div id='calendar'></div>
|
<div class="mh-100">
|
||||||
|
<div id="calendar" class="fc"></div>
|
||||||
<!-- Add modal -->
|
|
||||||
|
|
||||||
<div class="modal fade edit-form" id="form" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog" role="document">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header border-bottom-0">
|
|
||||||
<h5 class="modal-title" id="modal-title">Add Event</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<form id="myForm">
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="alert alert-danger " role="alert" id="danger-alert" style="display: none;">
|
|
||||||
End date should be greater than start date.
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="event-title">Event name <span class="text-danger">*</span></label>
|
|
||||||
<input type="text" class="form-control" id="event-title" placeholder="Enter event name"
|
|
||||||
required>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="start-date">Start date <span class="text-danger">*</span></label>
|
|
||||||
<input type="date" class="form-control" id="start-date" placeholder="start-date" required>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="end-date">End date - <small class="text-muted">Optional</small></label>
|
|
||||||
<input type="date" class="form-control" id="end-date" placeholder="end-date">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="event-color">Color</label>
|
|
||||||
<input type="color" class="form-control" id="event-color" value="#3788d8">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer border-top-0 d-flex justify-content-center">
|
|
||||||
<button type="submit" class="btn btn-success" id="submit-button">Submit</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Delete Modal -->
|
|
||||||
<div class="modal fade" id="delete-modal" tabindex="-1" role="dialog" aria-labelledby="delete-modal-title"
|
|
||||||
aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog" role="document">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="delete-modal-title">Confirm Deletion</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body text-center" id="delete-modal-body">
|
|
||||||
Are you sure you want to delete the event?
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer border-0">
|
|
||||||
<button type="button" class="btn btn-secondary rounded-sm" data-dismiss="modal"
|
|
||||||
id="cancel-button">Cancel</button>
|
|
||||||
<button type="button" class="btn btn-danger rounded-lg" id="delete-button">Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock center %}
|
{% endblock center %}
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src='https://cdn.jsdelivr.net/npm/@fullcalendar/core@4.2.0/main.min.js'></script>
|
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/index.global.min.js'></script>
|
||||||
<script src='https://cdn.jsdelivr.net/npm/@fullcalendar/daygrid@4.2.0/main.js'></script>
|
|
||||||
<script src='https://cdn.jsdelivr.net/npm/@fullcalendar/interaction@4.2.0/main.js'></script>
|
|
||||||
<script src='https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js'></script>
|
<script src='https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js'></script>
|
||||||
<script src='https://cdn.jsdelivr.net/npm/uuid@8.3.2/dist/umd/uuidv4.min.js'></script>
|
<script src='https://cdn.jsdelivr.net/npm/uuid@8.3.2/dist/umd/uuidv4.min.js'></script>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
const calendarEl = document.getElementById('calendar');
|
var calendarEl = document.getElementById('calendar');
|
||||||
const myModal = new bootstrap.Modal(document.getElementById('form'));
|
var calendar = new FullCalendar.Calendar(calendarEl, {
|
||||||
const dangerAlert = document.getElementById('danger-alert');
|
initialView: 'dayGridMonth',
|
||||||
const close = document.querySelector('.btn-close');
|
themeSystem: 'bootstrap5',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const myEvents = JSON.parse(localStorage.getItem('events')) || [
|
|
||||||
{
|
|
||||||
id: uuidv4(),
|
|
||||||
title: `Edit Me`,
|
|
||||||
start: '2023-04-11',
|
|
||||||
backgroundColor: 'red',
|
|
||||||
allDay: false,
|
|
||||||
editable: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: uuidv4(),
|
|
||||||
title: `Delete me`,
|
|
||||||
start: '2023-04-17',
|
|
||||||
end: '2023-04-21',
|
|
||||||
|
|
||||||
allDay: false,
|
|
||||||
editable: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
const calendar = new FullCalendar.Calendar(calendarEl, {
|
|
||||||
customButtons: {
|
|
||||||
customButton: {
|
|
||||||
text: 'Add Event',
|
|
||||||
click: function () {
|
|
||||||
myModal.show();
|
|
||||||
const modalTitle = document.getElementById('modal-title');
|
|
||||||
const submitButton = document.getElementById('submit-button');
|
|
||||||
modalTitle.innerHTML = 'Add Event'
|
|
||||||
submitButton.innerHTML = 'Add Event'
|
|
||||||
submitButton.classList.remove('btn-primary');
|
|
||||||
submitButton.classList.add('btn-success');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
close.addEventListener('click', () => {
|
|
||||||
myModal.hide()
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
center: 'customButton', // add your custom button here
|
|
||||||
right: 'today, prev,next '
|
|
||||||
},
|
|
||||||
plugins: ['dayGrid', 'interaction'],
|
|
||||||
allDay: false,
|
|
||||||
editable: true,
|
|
||||||
selectable: true,
|
selectable: true,
|
||||||
unselectAuto: false,
|
displayEventTime: true,
|
||||||
displayEventTime: false,
|
displayEventEnd: true,
|
||||||
events: myEvents,
|
slotDuration: {hours: 12},
|
||||||
eventRender: function (info) {
|
slotLabelInterval: {hours: 24},
|
||||||
info.el.addEventListener('contextmenu', function (e) {
|
headerToolbar: {
|
||||||
e.preventDefault();
|
left: 'prev,next today',
|
||||||
let existingMenu = document.querySelector('.context-menu');
|
center: 'title',
|
||||||
existingMenu && existingMenu.remove();
|
right: 'dayGridMonth,timeGridWeek,timeGridDay,multiMonthYear'
|
||||||
let menu = document.createElement('div');
|
|
||||||
menu.className = 'context-menu';
|
|
||||||
menu.innerHTML = `<ul>
|
|
||||||
<li><i class="fas fa-edit"></i>Edit</li>
|
|
||||||
<li><i class="fas fa-trash-alt"></i>Delete</li>
|
|
||||||
</ul>`;
|
|
||||||
|
|
||||||
const eventIndex = myEvents.findIndex(event => event.id === info.event.id);
|
|
||||||
|
|
||||||
|
|
||||||
document.body.appendChild(menu);
|
|
||||||
menu.style.top = e.pageY + 'px';
|
|
||||||
menu.style.left = e.pageX + 'px';
|
|
||||||
|
|
||||||
// Edit context menu
|
|
||||||
|
|
||||||
menu.querySelector('li:first-child').addEventListener('click', function () {
|
|
||||||
menu.remove();
|
|
||||||
|
|
||||||
const editModal = new bootstrap.Modal(document.getElementById('form'));
|
|
||||||
const modalTitle = document.getElementById('modal-title');
|
|
||||||
const titleInput = document.getElementById('event-title');
|
|
||||||
const startDateInput = document.getElementById('start-date');
|
|
||||||
const endDateInput = document.getElementById('end-date');
|
|
||||||
const colorInput = document.getElementById('event-color');
|
|
||||||
const submitButton = document.getElementById('submit-button');
|
|
||||||
const cancelButton = document.getElementById('cancel-button');
|
|
||||||
modalTitle.innerHTML = 'Edit Event';
|
|
||||||
titleInput.value = info.event.title;
|
|
||||||
startDateInput.value = moment(info.event.start).format('YYYY-MM-DD');
|
|
||||||
endDateInput.value = moment(info.event.end, 'YYYY-MM-DD').subtract(1, 'day').format('YYYY-MM-DD');
|
|
||||||
colorInput.value = info.event.backgroundColor;
|
|
||||||
submitButton.innerHTML = 'Save Changes';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
editModal.show();
|
|
||||||
|
|
||||||
submitButton.classList.remove('btn-success')
|
|
||||||
submitButton.classList.add('btn-primary')
|
|
||||||
|
|
||||||
// Edit button
|
|
||||||
|
|
||||||
submitButton.addEventListener('click', function () {
|
|
||||||
const updatedEvents = {
|
|
||||||
id: info.event.id,
|
|
||||||
title: titleInput.value,
|
|
||||||
start: startDateInput.value,
|
|
||||||
end: moment(endDateInput.value, 'YYYY-MM-DD').add(1, 'day').format('YYYY-MM-DD'),
|
|
||||||
backgroundColor: colorInput.value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updatedEvents.end <= updatedEvents.start) { // add if statement to check end date
|
|
||||||
dangerAlert.style.display = 'block';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const eventIndex = myEvents.findIndex(event => event.id === updatedEvents.id);
|
|
||||||
myEvents.splice(eventIndex, 1, updatedEvents);
|
|
||||||
|
|
||||||
localStorage.setItem('events', JSON.stringify(myEvents));
|
|
||||||
|
|
||||||
// Update the event in the calendar
|
|
||||||
const calendarEvent = calendar.getEventById(info.event.id);
|
|
||||||
calendarEvent.setProp('title', updatedEvents.title);
|
|
||||||
calendarEvent.setStart(updatedEvents.start);
|
|
||||||
calendarEvent.setEnd(updatedEvents.end);
|
|
||||||
calendarEvent.setProp('backgroundColor', updatedEvents.backgroundColor);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
editModal.hide();
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete menu
|
|
||||||
menu.querySelector('li:last-child').addEventListener('click', function () {
|
|
||||||
const deleteModal = new bootstrap.Modal(document.getElementById('delete-modal'));
|
|
||||||
const modalBody = document.getElementById('delete-modal-body');
|
|
||||||
const cancelModal = document.getElementById('cancel-button');
|
|
||||||
modalBody.innerHTML = `Are you sure you want to delete <b>"${info.event.title}"</b>`
|
|
||||||
deleteModal.show();
|
|
||||||
|
|
||||||
const deleteButton = document.getElementById('delete-button');
|
|
||||||
deleteButton.addEventListener('click', function () {
|
|
||||||
myEvents.splice(eventIndex, 1);
|
|
||||||
localStorage.setItem('events', JSON.stringify(myEvents));
|
|
||||||
calendar.getEventById(info.event.id).remove();
|
|
||||||
deleteModal.hide();
|
|
||||||
menu.remove();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
cancelModal.addEventListener('click', function () {
|
|
||||||
deleteModal.hide();
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
document.addEventListener('click', function () {
|
|
||||||
menu.remove();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
events: '/getevents',
|
||||||
|
|
||||||
eventDrop: function (info) {
|
select: function (info) {
|
||||||
let myEvents = JSON.parse(localStorage.getItem('events')) || [];
|
alert('selected ' + info.startStr + ' to ' + info.endStr);
|
||||||
const eventIndex = myEvents.findIndex(event => event.id === info.event.id);
|
let enddate = new Date(info.endStr);
|
||||||
const updatedEvent = {
|
enddate.setDate(enddate.getDate() - 1);
|
||||||
...myEvents[eventIndex],
|
info.view.calendar.addEvent({
|
||||||
id: info.event.id,
|
id: uuidv4(),
|
||||||
title: info.event.title,
|
title: 'New Event',
|
||||||
start: moment(info.event.start).format('YYYY-MM-DD'),
|
start: info.startStr+'T14:00:00',
|
||||||
end: moment(info.event.end).format('YYYY-MM-DD'),
|
end: info.endStr+'T10:00:00',
|
||||||
backgroundColor: info.event.backgroundColor
|
allDay: false
|
||||||
};
|
});
|
||||||
myEvents.splice(eventIndex, 1, updatedEvent); // Replace old event data with updated event data
|
|
||||||
localStorage.setItem('events', JSON.stringify(myEvents));
|
|
||||||
console.log(updatedEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
calendar.on('select', function (info) {
|
|
||||||
|
|
||||||
const startDateInput = document.getElementById('start-date');
|
|
||||||
const endDateInput = document.getElementById('end-date');
|
|
||||||
startDateInput.value = info.startStr;
|
|
||||||
const endDate = moment(info.endStr, 'YYYY-MM-DD').subtract(1, 'day').format('YYYY-MM-DD');
|
|
||||||
endDateInput.value = endDate;
|
|
||||||
if (startDateInput.value === endDate) {
|
|
||||||
endDateInput.value = '';
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
calendar.render();
|
calendar.render();
|
||||||
|
|
||||||
const form = document.querySelector('form');
|
|
||||||
|
|
||||||
form.addEventListener('submit', function (event) {
|
|
||||||
event.preventDefault(); // prevent default form submission
|
|
||||||
|
|
||||||
// retrieve the form input values
|
|
||||||
const title = document.querySelector('#event-title').value;
|
|
||||||
const startDate = document.querySelector('#start-date').value;
|
|
||||||
const endDate = document.querySelector('#end-date').value;
|
|
||||||
const color = document.querySelector('#event-color').value;
|
|
||||||
const endDateFormatted = moment(endDate, 'YYYY-MM-DD').add(1, 'day').format('YYYY-MM-DD');
|
|
||||||
const eventId = uuidv4();
|
|
||||||
|
|
||||||
console.log(eventId);
|
|
||||||
|
|
||||||
if (endDateFormatted <= startDate) { // add if statement to check end date
|
|
||||||
dangerAlert.style.display = 'block';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newEvent = {
|
|
||||||
id: eventId,
|
|
||||||
title: title,
|
|
||||||
start: startDate,
|
|
||||||
end: endDateFormatted,
|
|
||||||
allDay: false,
|
|
||||||
backgroundColor: color
|
|
||||||
};
|
|
||||||
|
|
||||||
// add the new event to the myEvents array
|
|
||||||
myEvents.push(newEvent);
|
|
||||||
|
|
||||||
// render the new event on the calendar
|
|
||||||
calendar.addEvent(newEvent);
|
|
||||||
|
|
||||||
// save events to local storage
|
|
||||||
localStorage.setItem('events', JSON.stringify(myEvents));
|
|
||||||
|
|
||||||
myModal.hide();
|
|
||||||
form.reset();
|
|
||||||
});
|
|
||||||
|
|
||||||
myModal._element.addEventListener('hide.bs.modal', function () {
|
|
||||||
dangerAlert.style.display = 'none';
|
|
||||||
form.reset();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock scripts %}
|
{% endblock scripts %}
|
||||||
Loading…
Reference in New Issue