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
/**
* This enhanced DNDoodle app now includes a feature for the poll creator to set the end date of the poll,
* and a checkbox for users to indicate if they are the DM. The DM's availability is treated as special
* and is displayed differently in the results view.
* The app uses React for the frontend and SQLite for data persistence.
* It features improved styling, interactive elements, and email functionality.
*/
/** @jsxImportSource https://esm.sh/react */
import { addDays, format, parse } from "https://esm.sh/date-fns";
import React, { useEffect, useState } from "https://esm.sh/react";
import { createRoot } from "https://esm.sh/react-dom/client";
function App() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [creatorEmail, setCreatorEmail] = useState("");
const [groupCode, setGroupCode] = useState("");
const [groupName, setGroupName] = useState("");
const [availability, setAvailability] = useState({});
const [groupAvailability, setGroupAvailability] = useState({});
const [bestDate, setBestDate] = useState("");
const [isCreatingGroup, setIsCreatingGroup] = useState(false);
const [createdGroupCode, setCreatedGroupCode] = useState("");
const [createdGroupName, setCreatedGroupName] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [message, setMessage] = useState("");
const [editToken, setEditToken] = useState("");
const [editLink, setEditLink] = useState("");
const [groupShareLink, setGroupShareLink] = useState("");
const [confirmNoEmail, setConfirmNoEmail] = useState(false);
const [allRespondents, setAllRespondents] = useState([]);
const [totalResponses, setTotalResponses] = useState(0);
const [sessionJoined, setSessionJoined] = useState(false);
const [pollDuration, setPollDuration] = useState(2); // Default to 2 weeks
const [pollEndDate, setPollEndDate] = useState("");
const [isDM, setIsDM] = useState(false);
const [showDatesWithoutDM, setShowDatesWithoutDM] = useState(false);
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const code = params.get("code");
const token = params.get("token");
if (code) {
setGroupCode(code);
fetchGroupAvailability(code);
}
if (token) {
setEditToken(token);
fetchUserAvailability(token);
}
}, []);
const fetchGroupAvailability = async (code) => {
setIsLoading(true);
try {
const response = await fetch(`/availability?code=${code}`);
if (!response.ok) {
throw new Error("Session Poll not found");
}
const data = await response.json();
setGroupAvailability(data.availability);
setBestDate(data.bestDate);
setGroupName(data.groupName);
setAllRespondents(data.allRespondents);
setTotalResponses(data.totalResponses);
setPollEndDate(data.pollEndDate);
setSessionJoined(true);
} catch (error) {
setMessage(
error.message === "Session Poll not found"
? "This session poll doesn't exist. Please check the code and try again."
: "Failed to load session poll data. Please try again.",
);
setGroupCode("");
setSessionJoined(false);
} finally {
setIsLoading(false);
}
};
const fetchUserAvailability = async (token) => {
setIsLoading(true);
try {
const response = await fetch(`/user-availability?token=${token}`);
const data = await response.json();
setName(data.name);
setEmail(data.email);
setAvailability(data.availability);
setGroupCode(data.groupCode);
setIsDM(data.isDM);
fetchGroupAvailability(data.groupCode);
setMessage("Your availability data loaded successfully!");
setTimeout(() => setMessage(""), 3000);
} catch (error) {
setMessage("Failed to load your availability data. Please try again.");
} finally {
setIsLoading(false);
}
};