瀏覽代碼

完成weather

steve07s 1 年之前
父節點
當前提交
aedb2b9542
共有 3 個文件被更改,包括 85 次插入23 次删除
  1. 19 0
      routers/api.js
  2. 46 1
      static/js/api_calls.js
  3. 20 22
      static/js/frontend.js

+ 19 - 0
routers/api.js

@@ -70,6 +70,25 @@ router.post('/votes/set', (req, res) => {
   }
 });
 
+router.get("/weather", async (req, res) => {
+  const { lat, lon } = req.query;
+  try {
+    const weatherResponse = await fetch(
+      `${WEATHER_API_URL}?lat=${lat}&lon=${lon}&appid=${WEATHER_API_KEY}&units=metric`
+    );
+    const weatherData = await weatherResponse.json();
+
+    if (!weatherResponse.ok) throw new Error("Weather API request failed.");
+
+    res.json({ success: true, data: weatherData });
+  } catch (error) {
+    console.error(error);
+    res
+      .status(500)
+      .json({ success: false, error: "Failed to fetch weather data" });
+  }
+});
+
 module.exports = router;
 
 

+ 46 - 1
static/js/api_calls.js

@@ -37,7 +37,6 @@ let fake_local_votesdata = [
 async function getSessionFromBackend() {
   try {
     const response = await axios.get('/api/v1/getSession');
-    console.log(response.data)
     return response.data;
   } catch (error) {
     console.error('Error fetching session from backend:', error);
@@ -110,5 +109,51 @@ async function ajaxLogout() {
   }
 }
 
+async function getWeather(lat, lon) {
+  try {
+    const response = await axios.get("/api/v1/weather", {
+      params: {
+        lat: lat,
+        lon: lon,
+      },
+    });
+    return response.data;
+  } catch (error) {
+    console.error("Failed to fetch weather data:", error);
+    return { success: false, error: "Failed to fetch weather data" };
+  }
+}
+
+function fetchWeatherForCurrentLocation() {
+  return new Promise((resolve, reject) => {
+    if ("geolocation" in navigator) {
+      navigator.geolocation.getCurrentPosition(
+        async (position) => {
+          const lat = position.coords.latitude;
+          const lon = position.coords.longitude;
+          try {
+            const weatherData = await getWeather(lat, lon);
+            if (weatherData.success) {
+              console.log("Weather data:", weatherData.data);
+              resolve(weatherData);
+            } else {
+              reject("Failed to fetch weather data");
+            }
+          } catch (error) {
+            reject(error);
+          }
+        },
+        (error) => {
+          console.error("Error getting location:", error);
+          reject("Error getting location");
+        }
+      );
+    } else {
+      console.error("Geolocation is not supported by this browser.");
+      reject("Geolocation is not supported by this browser.");
+    }
+  });
+}
+
 
 

+ 20 - 22
static/js/frontend.js

@@ -22,6 +22,10 @@ function createExistingVote(voter, vote) {
 function createOneDayCard(dayData, currentSession, weather) {
   let date = new Date(dayData.date + 'T00:00:00');
   let card = document.createElement('div');
+
+  let temp = weather.main.temp;
+  let icon = weather.weather[0].icon;
+
   card.innerHTML = `
       <div class="cardtop">
         <div class="date">
@@ -30,10 +34,12 @@ function createOneDayCard(dayData, currentSession, weather) {
         </div>
         <div class="weather">
           <div class="temp">
-            ?
+            ${temp}°C
           </div>
           <div class="weath">
-            <img>
+          <img src="https://openweathermap.org/img/wn/${icon}@2x.png" alt="${
+            weather.weather[0].description
+          }">
           </div>
         </div>
       </div>
@@ -83,7 +89,7 @@ function updateVotableDays(daysWithVotes, currentSession, weatherForecasts) {
   daysView.innerHTML = '';
   for (let date in daysWithVotes) {
     let votes = daysWithVotes[date];
-    let weather = weatherForecasts?.[date];
+    let weather = weatherForecasts.list.find((w) => w.dt_txt.startsWith(date));
     daysView.append(createOneDayCard({
       date,
       votes
@@ -113,7 +119,7 @@ class FrontendState {
   async refreshAllState(updateView = true) {
     await Promise.all([
       this.refreshVotesState(false),
-      // this.refreshWeatherState(false),
+      this.refreshWeatherState(false),
       this.refreshSessionState(false),
     ])
     if (updateView) {
@@ -143,7 +149,7 @@ class FrontendState {
       success,
       data,
       error
-    } = await getWeather()
+    } = await fetchWeatherForCurrentLocation()
     if (success) {
       this.weatherForecasts = data;
     } else {
@@ -161,17 +167,8 @@ class FrontendState {
       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(''); // 如果沒有用戶登入,清空用戶名顯示
-      }
+      this.currentSession = data;
     } else {
       // 處理錯誤情況
       alert('Unable to refresh session state. Please try again later.');
@@ -186,7 +183,10 @@ class FrontendState {
     setLoggedIn(!!this.currentSession)
 
     // 2. optionally update the header so that it shows the username of the person logged in
-    // updateHeader(this.currentSession)
+    if(this.currentSession)
+      updateHeader(this.currentSession.username)
+    else
+      updateHeader('')
 
     // 3. render the days
     updateVotableDays(this.daysWithVotes, this.currentSession, this.weatherForecasts)
@@ -225,10 +225,10 @@ async function handleAuthEvent(event) {
       if (authResult && authResult.success) {
         if (authActionName === 'logout') {
           // 登出成功,清除用戶名顯示
-          updateUsernameDisplay('');
+          updateHeader('');
         } else {
           // 登入或註冊成功,更新用戶名顯示
-          updateUsernameDisplay(authResult.data.username);
+          updateHeader(authResult.data.username);
         }
         await fes.refreshSessionState();
         usernameInput.value = passwordInput.value = '';
@@ -243,12 +243,10 @@ async function handleAuthEvent(event) {
     }
   }
 }
-
-function updateUsernameDisplay(username) {
-  const usernameSpan = document.querySelector('.username');
+function updateHeader(username) {
   const loggedOutDivs = document.querySelectorAll('.forloggedout');
   const loggedInDivs = document.querySelectorAll('.forloggedin');
-
+  const usernameSpan = document.querySelector('.username');
   if (username) {
     usernameSpan.textContent = username;
     loggedOutDivs.forEach(div => div.style.display = 'none');