| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- //static/js/frontend.js
- function setLoggedIn(loggedInBoolean) {
- let body = document.body;
- body.dataset.loggedIn = !!loggedInBoolean;
- }
- function createExistingVote(voter, vote) {
- let voteDiv = document.createElement('div');
- voteDiv.innerHTML = "";
- if (vote === "yes") {
- voteDiv.classList.add('vote-yes');
- } else if (vote === "no") {
- voteDiv.classList.add('vote-no');
- }
- voteDiv.innerText = voter;
- return voteDiv;
- }
- function createOneDayCard(dayData, currentSession, weather) {
- let date = new Date(dayData.date + 'T00:00:00');
- let card = document.createElement('div');
- card.innerHTML = `
- <div class="cardtop">
- <div class="date">
- <div class="dow">${date.toLocaleString("en-CA", { weekday: 'long' })}</div>
- <div class="dom">${date.toLocaleString("en-CA", { month: 'short', day: 'numeric' })}</div>
- </div>
- <div class="weather">
- <div class="temp">
- ?
- </div>
- <div class="weath">
- <img>
- </div>
- </div>
- </div>
- <div class="make-vote">
- <div class="satis-tier forloggedin">
- Can you attend?
- <div class="">
- <button class="vote yes" data-vote="yes">
- Yes ✔️
- </button>
- <button class="vote maybe" data-vote="">
- ??
- </button>
- <button class="vote no" data-vote="no">
- No ❌
- </button>
- </div>
- </div>
- </div>
- <div class="existing-votes">
- </div>
- `
- card.classList.add("card")
- card.dataset.date = dayData.date;
- if (weather) {
- // you need to figure this part out yourself
- }
- let existingVotesDiv = card.querySelector('.existing-votes');
- for (let [voter, vote] of Object.entries(dayData.votes)) {
- existingVotesDiv.append(createExistingVote(voter, vote))
- }
- return card;
- }
- function updateVotableDays(daysWithVotes, currentSession, weatherForecasts) {
- let daysView = document.querySelector(".days-view");
- if (!daysView) {
- console.error("could not find element to put days into")
- return;
- }
- daysView.innerHTML = '';
- for (let date in daysWithVotes) {
- let votes = daysWithVotes[date];
- let weather = weatherForecasts?.[date];
- daysView.append(createOneDayCard({
- date,
- votes
- }, currentSession, weather))
- }
- }
- class FrontendState {
- constructor() {
- this.currentSession = undefined;
- this.daysWithVotes = [];
- this.weatherForecasts = {};
- }
- async refreshAllState(updateView = true) {
- await Promise.all([
- this.refreshVotesState(false),
- // this.refreshWeatherState(false),
- this.refreshSessionState(false),
- ])
- if (updateView) {
- this.updateView();
- }
- }
- async refreshVotesState(updateView = true) {
- let {
- success,
- data,
- error
- } = await getVotesFromBackend()
- if (success) {
- this.daysWithVotes = data;
- } else {
- // ha ha I'm being lazy. can you do better?
- alert(error)
- }
- if (updateView) {
- this.updateView();
- }
- }
- async refreshWeatherState(updateView = true) {
- let {
- success,
- data,
- error
- } = await getWeather()
- if (success) {
- this.weatherForecasts = data;
- } else {
- // ha ha I'm being lazy. can you do better?
- alert(error)
- }
- if (updateView) {
- this.updateView();
- }
- }
- async refreshSessionState(updateView = true) {
- let {
- success,
- data,
- error
- } = await getSessionFromBackend()
- console.log(data)
- if (success) {
- if (data) { // 檢查 data 是否存在
- this.currentSession = data;
- setLoggedIn(true);
- updateUsernameDisplay(data.username); // 確保在 data 存在時才讀取 username
- } else {
- this.currentSession = undefined;
- setLoggedIn(false);
- updateUsernameDisplay(''); // 如果沒有用戶登入,清空用戶名顯示
- }
- } else {
- // 處理錯誤情況
- alert('Unable to refresh session state. Please try again later.');
- }
- if (updateView) {
- this.updateView();
- }
- }
- async updateView() {
- // 1. update the whole frontend so that it shows relevant logged-in vs logged-out features
- setLoggedIn(!!this.currentSession)
- // 2. optionally update the header so that it shows the username of the person logged in
- // updateHeader(this.currentSession)
- // 3. render the days
- updateVotableDays(this.daysWithVotes, this.currentSession, this.weatherForecasts)
- }
- }
- const fes = new FrontendState();
- fes.refreshAllState()
- async function handleAuthEvent(event) {
- event.preventDefault();
- // console.log(event.currentTarget, event.target)
- let usernameInput = event.currentTarget.querySelector('#headerusername');
- let usernameValue = usernameInput.value;
- let passwordInput = event.currentTarget.querySelector('#headerpassword');
- let passwordValue = passwordInput.value;
- let button = event.target.closest('button');
- if (button) {
- let authActionName = button?.dataset?.authAction;
- let authActionFunction = {
- signup: ajaxSignup,
- login: ajaxLogin,
- logout: ajaxLogout,
- } [authActionName];
- if (authActionFunction) {
- let authResult = await authActionFunction(usernameValue, passwordValue);
- if (authResult && authResult.success) {
- if (authActionName === 'logout') {
- // 登出成功,清除用戶名顯示
- updateUsernameDisplay('');
- } else {
- // 登入或註冊成功,更新用戶名顯示
- updateUsernameDisplay(authResult.data.username);
- }
- await fes.refreshSessionState();
- usernameInput.value = passwordInput.value = '';
- } else if (authResult) {
- // 處理登入、註冊或登出失敗的情況
- alert(authResult.error);
- } else {
- // 處理未知網絡錯誤
- alert("unknown network error");
- }
- }
- }
- }
- function updateUsernameDisplay(username) {
- const usernameSpan = document.querySelector('.username');
- const loggedOutDivs = document.querySelectorAll('.forloggedout');
- const loggedInDivs = document.querySelectorAll('.forloggedin');
- if (username) {
- usernameSpan.textContent = username;
- loggedOutDivs.forEach(div => div.style.display = 'none');
- loggedInDivs.forEach(div => div.style.display = 'block');
- } else {
- usernameSpan.textContent = 'nobody';
- loggedOutDivs.forEach(div => div.style.display = 'block');
- loggedInDivs.forEach(div => div.style.display = 'none');
- }
- }
- const authform = document.querySelector('form.authform')
- authform.addEventListener("click", handleAuthEvent);
- async function handleVoteEvent(event) {
- event.preventDefault();
- let button = event.target.closest('button.vote');
- // console.log(button)
- if (button) {
- let voteVal;
- if (button.classList.contains('yes')) {
- voteVal = 'yes';
- }
- if (button.classList.contains('no')) {
- voteVal = 'no';
- }
- if (button.classList.contains('maybe')) {
- voteVal = 'maybe';
- }
- let cardDiv = button.closest("div.card");
- if (!voteVal || !cardDiv) {
- // console.log({ voteVal, cardDiv })
- return;
- }
- let cardDate = cardDiv.dataset.date
- let voteActionResult = await setMyVote(cardDate, voteVal)
- if (voteActionResult) {
- await fes.refreshVotesState();
- }
- }
- }
- const daysViewDiv = document.querySelector('section.days-view');
- daysViewDiv.addEventListener("click", handleVoteEvent);
|