1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@6.1.18/index.global.min.js'></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const now = new Date();
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: ''
},
selectable: true,
select: (info) => {
console.log(info);
const days = Math.floor(Math.abs(info.end - info.start) / (1000 * 60 * 60 * 24));
if (days == 1) {
toast('add transaction', 'info');
Swal.fire(input());
return;
}
toast('show mini stats for range', 'info');
const events = calendar.getEvents().filter((event) => {
const start = event.start;
const end = event.end || event.start;
return start < info.end && end >= info.start
});
console.log(events);
const sum = events.reduce((acc, event) => acc + event.extendedProps.amount, 0);
toast(`\$${sum}`, 'success')
},
eventClick: (info) => {
const event = info.event;
const props = event.extendedProps;
Swal.fire(input(event.id, props.title, props.amount, props.recurring));
},
eventClassNames: 'cursor-pointer',
events: [{id: '1', title: 'A bill! ($200)', start: now, allDay: true, extendedProps: {title: 'A bill!', amount: 200, recurring: true}}, {id: '2', title: 'Another bill! ($150)', start: new Date(now.getTime() + (1000 * 60 * 60 * 24 * 2)), allDay: true, extendedProps: {title: 'Another bill!', amount: 150, recurring: false}}],
});
calendar.render();
});
function toast(message, level = "error", duration = 5) {
const Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: duration * 1000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('click', () => Swal.close());
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
Toast.fire({
icon: level,
title: message
});
}
function input(id = '', title = 'New Transaction', amount = 0, recurring = true) {
return {
title: `<input type="text" class="font-semibold" value="${title}"/>`,
html: `
<div class="grid grid-cols-1 gap-x-4 gap-y-3 items-center text-left">
<input type="hidden" name="id" value="${id}"/>
<label class="font-semibold">Amount: $<input class="border rounded w-30 mx-px p-1" type="number" name="amount" value="${amount}"/></label>
<label class="font-semibold">Recurring? <input class="border rounded w-4 h-4" type="checkbox" name="recurring" ${recurring ? "checked" : ""}/></label>
<div id="recurringOptions" class="${recurring ? "" : "hidden"}">
<label><input type="radio" name="recurrance"/> Monthly on the 1st</label>
<br/>
<label><input type="radio" name="recurrance"/> Every <input class="border rounded w-15 p-1" type="number" min="1" max="4" value="1"/> weeks on Monday</label>
</div>
</div>
`,
allowOutsideClick: false,
showCloseButton: true,
confirmButtonText: 'Save',
didRender: (swal) => {
const $recurring = document.querySelector("[name='recurring']");
const $opts = document.getElementById("recurringOptions");
$recurring.addEventListener('change', () => {
$recurring.checked ? $opts.classList.remove('hidden') : $opts.classList.add('hidden');
});
}
}
return
}
</script>
</head>
<body>
<div id='calendar' class='max-w-[90vw] max-h-[90vh] m-[40px_auto]'></div>
</body>
</html>
|