diff --git a/aeye/app/(nav)/cams/page.tsx b/aeye/app/(nav)/cams/page.tsx
index 38c6723..f1653ae 100644
--- a/aeye/app/(nav)/cams/page.tsx
+++ b/aeye/app/(nav)/cams/page.tsx
@@ -1,27 +1,16 @@
"use client";
import { useEffect } from "react";
+import fetchWithInterception from "@/app/fetchWrapper";
export default function Cams() {
- const fetchVids = async () => {
- try {
- const res = await fetch("https://api.a-eye.live/video", {
- method: "GET",
- headers: {
- Authorization: `Bearer ${localStorage.getItem("accessToken")}`,
- },
- });
- if (res.ok) {
- const jsonData = await res.json();
- console.log(jsonData.data);
- }
- } catch (err) {
- console.error(err);
- }
- };
-
useEffect(() => {
- fetchVids();
+ fetchWithInterception("https://api.a-eye.live/video", {
+ method: "GET",
+ })
+ .then((response) => response.json())
+ .then((jsonData) => console.log(jsonData.data))
+ .catch((error) => console.error(error));
}, []);
return
;
}
diff --git a/aeye/app/(nav)/home/SearchResult.tsx b/aeye/app/(nav)/home/SearchResult.tsx
index cf8eccd..ce1cc58 100644
--- a/aeye/app/(nav)/home/SearchResult.tsx
+++ b/aeye/app/(nav)/home/SearchResult.tsx
@@ -4,6 +4,9 @@ import { searchQueryState } from "@/app/recoil-states";
import { useEffect, useState } from "react";
import Vidpane from "@/app/components/Vidpane";
import { Grid, Paper, Typography } from "@mui/material";
+import fetchWithInterception from "@/app/fetchWrapper";
+
+const FETCH_TIMEOUT = 200;
function Vidgroup({ videos }: { videos: VideoDocument[] }) {
return (
@@ -22,39 +25,30 @@ function Vidgroup({ videos }: { videos: VideoDocument[] }) {
export default function SearchResult() {
const searchQuery = useRecoilValue(searchQueryState);
const [results, setResults] = useState();
- const [searchTimeout, setSearchTimeout] = useState(
- null
- );
-
- const fetchResults = async () => {
- const res = await fetch(
- `https://api.a-eye.live/video/search?keyword=${searchQuery}`,
- {
- method: "GET",
- headers: {
- Authorization: `Bearer ${localStorage.getItem("accessToken")}`,
- },
- }
- );
- if (res.ok) {
- const jsonData = await res.json();
- console.log(jsonData.data);
- setResults(jsonData.data);
- }
- };
useEffect(() => {
- if (searchTimeout) {
- clearTimeout(searchTimeout);
- }
+ let searchTimeout: NodeJS.Timeout;
- setSearchTimeout(setTimeout(fetchResults, 200));
-
- return () => {
- if (searchTimeout) {
- clearTimeout(searchTimeout);
- }
+ const fetchResults = () => {
+ fetchWithInterception(
+ `https://api.a-eye.live/video/search?keyword=${searchQuery}`,
+ { method: "GET" }
+ )
+ .then((response) => {
+ if (!response.ok) {
+ throw new Error("Network response was not ok");
+ }
+ return response.json();
+ })
+ .then((jsonData) => setResults(jsonData.data))
+ .catch((error) => console.error(error));
};
+
+ if (searchQuery) {
+ searchTimeout = setTimeout(fetchResults, FETCH_TIMEOUT);
+ }
+
+ return () => clearTimeout(searchTimeout);
}, [searchQuery]);
return (
diff --git a/aeye/app/(nav)/my/page.tsx b/aeye/app/(nav)/my/page.tsx
index 718571c..f26310f 100644
--- a/aeye/app/(nav)/my/page.tsx
+++ b/aeye/app/(nav)/my/page.tsx
@@ -2,6 +2,7 @@
import React, { useEffect, useState } from "react";
import { styled } from "@mui/material/styles";
import { Box, Grid, Paper, Avatar, Tooltip, Typography } from "@mui/material";
+import fetchWithInterception from "@/app/fetchWrapper";
const StyledPaper = styled(Paper)(({ theme }) => ({
backgroundColor: theme.palette.mode === "dark" ? "#1A2027" : "#fff",
@@ -26,23 +27,12 @@ function ProfileAvatar() {
const [member, setMember] = useState();
useEffect(() => {
- const fetchMember = async () => {
- try {
- const res = await fetch("https://api.a-eye.live/member/detail", {
- method: "GET",
- headers: {
- Authorization: `Bearer ${localStorage.getItem("accessToken")}`,
- },
- });
- if (res.ok) {
- const jsonData = await res.json();
- setMember(jsonData.data);
- }
- } catch (err) {
- console.log(err);
- }
- };
- fetchMember();
+ fetchWithInterception("https://api.a-eye.live/member/detail", {
+ method: "GET",
+ })
+ .then((response) => response.json())
+ .then((jsonData) => setMember(jsonData.data))
+ .catch((error) => console.error(error));
}, []);
return (
diff --git a/aeye/app/fetchWrapper.ts b/aeye/app/fetchWrapper.ts
new file mode 100644
index 0000000..dd8f1f7
--- /dev/null
+++ b/aeye/app/fetchWrapper.ts
@@ -0,0 +1,33 @@
+// Example usage:
+// fetchWithInterception(apiUrl, { method: 'GET' })
+// .then(response => response.json())
+// .then(data => console.log(data))
+// .catch(error => console.error(error));
+
+const fetchWithInterception = async (
+ url: string,
+ options?: RequestInit
+): Promise => {
+ const modifiedOptions = { ...options };
+ modifiedOptions.headers = {
+ ...modifiedOptions.headers,
+ Authorization: `Bearer ${localStorage.getItem("accessToken")}`,
+ };
+ return fetch(url, modifiedOptions)
+ .then(async (response: Response) => {
+ if (!response.ok) {
+ if (response.status === 401) {
+ alert("토근이 만료되었습니다. 다시 로그인해주세요.");
+ window.location.href = "/";
+ }
+ throw new Error("Request failed");
+ }
+ return response;
+ })
+ .catch((error: Error) => {
+ console.error("Fetch error:", error);
+ throw error;
+ });
+};
+
+export default fetchWithInterception;