diff --git a/api/handler/timeline.go b/api/handler/timeline.go index da77c34..c18ba82 100644 --- a/api/handler/timeline.go +++ b/api/handler/timeline.go @@ -101,6 +101,7 @@ func (cfg *Handler) Timeline(w http.ResponseWriter, r *http.Request) { Comments: int(k.Comments), }, }) + } respondWithJson(w, http.StatusOK, timeline) diff --git a/web2/app/api/[...path]/route.ts b/web2/app/api/[...path]/route.ts index 4c1684d..9e1680e 100644 --- a/web2/app/api/[...path]/route.ts +++ b/web2/app/api/[...path]/route.ts @@ -93,13 +93,14 @@ export async function GET(request: NextRequest, { params }: { params: { path: st }, }); - const text = await response.text(); // Read response as text - - if (!text.trim()) { - return NextResponse.json({ error: "Empty response from API" }, { status: 502 }); + const responseText = await response.text(); // Read response as text + // console.log("problematic text") + // console.log(responseText) + if (responseText.trim() !== "") { + // return NextResponse.json({ error: "Empty response from API" }, { status: 502 }); + return NextResponse.json(JSON.parse(responseText), { status: response.status }); } - return NextResponse.json(JSON.parse(text), { status: response.status }); } catch (error) { console.error("API error:", error); return NextResponse.json({ error: "Failed to fetch data" }, { status: 500 }); diff --git a/web2/app/api/sse/[...path]/route.ts b/web2/app/api/sse/[...path]/route.ts index 8e61a83..a64dcb0 100644 --- a/web2/app/api/sse/[...path]/route.ts +++ b/web2/app/api/sse/[...path]/route.ts @@ -21,7 +21,13 @@ export async function GET(request: NextRequest) { ); // Proxy the backend SSE stream directly to the client - return new Response(backendResponse.body, { + console.log(backendResponse.body) + let passedValue = await new Response(backendResponse.body).text(); + if (passedValue){ + let valueToJson = JSON.parse(passedValue); + console.log("jsonval:", valueToJson) + } + return new Response("", { status: 200, headers: { "Content-Type": "text/event-stream", @@ -32,7 +38,7 @@ export async function GET(request: NextRequest) { }, }); } catch (error) { - console.error("SSE proxy error:", error); + console.log("SSE proxy error:", error); return new Response("Failed to connect to SSE", { status: 502 }); } } diff --git a/web2/app/layout.tsx b/web2/app/layout.tsx index 2c0fb30..8ef4778 100644 --- a/web2/app/layout.tsx +++ b/web2/app/layout.tsx @@ -29,14 +29,16 @@ export default function RootLayout({ children: React.ReactNode }>) { return ( - - + + + {children} + ) @@ -44,4 +46,5 @@ export default function RootLayout({ -import './globals.css' \ No newline at end of file +import './globals.css' +import { ToastProvider } from "@radix-ui/react-toast" diff --git a/web2/app/login/page.tsx b/web2/app/login/page.tsx index a66716c..b864a96 100644 --- a/web2/app/login/page.tsx +++ b/web2/app/login/page.tsx @@ -10,7 +10,7 @@ import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" import { Label } from "@/components/ui/label" -import { useToast } from "@/components/ui/use-toast" +import { useToast } from "@/hooks/use-toast" import { Loader2, BookOpen } from "lucide-react" export default function LoginPage() { @@ -30,6 +30,7 @@ export default function LoginPage() { router.push("/") } catch (error) { toast({ + open: true, title: "Login failed", description: "Please check your credentials and try again.", variant: "destructive", diff --git a/web2/app/signup/page.tsx b/web2/app/signup/page.tsx index bb2dcba..052fc28 100644 --- a/web2/app/signup/page.tsx +++ b/web2/app/signup/page.tsx @@ -10,7 +10,7 @@ import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" import { Label } from "@/components/ui/label" -import { useToast } from "@/components/ui/use-toast" +import { useToast } from "@/hooks/use-toast" import { Loader2, BookOpen } from "lucide-react" export default function SignupPage() { diff --git a/web2/components/comment-form.tsx b/web2/components/comment-form.tsx index 254b4bd..ff437f0 100644 --- a/web2/components/comment-form.tsx +++ b/web2/components/comment-form.tsx @@ -6,7 +6,7 @@ import { useState } from "react" import { useAuth } from "@/lib/auth-hooks" import { Button } from "@/components/ui/button" import { Textarea } from "@/components/ui/textarea" -import { useToast } from "@/components/ui/use-toast" +import { useToast } from "@/hooks/use-toast" import { Loader2 } from "lucide-react" export function CommentForm({ proseId }: { proseId: string }) { diff --git a/web2/components/comments-list.tsx b/web2/components/comments-list.tsx index 4db12a9..eab5a60 100644 --- a/web2/components/comments-list.tsx +++ b/web2/components/comments-list.tsx @@ -8,7 +8,7 @@ import { Button } from "@/components/ui/button" import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card" import { Skeleton } from "@/components/ui/skeleton" import { Heart } from "lucide-react" -import { useToast } from "@/components/ui/use-toast" +import { useToast } from "@/hooks/use-toast" import { useSSE } from "@/lib/use-sse" import Link from "next/link" diff --git a/web2/components/compose-prose-dialog.tsx b/web2/components/compose-prose-dialog.tsx index ba75105..fd61aa3 100644 --- a/web2/components/compose-prose-dialog.tsx +++ b/web2/components/compose-prose-dialog.tsx @@ -15,7 +15,7 @@ import { DialogTitle, } from "@/components/ui/dialog" import { Textarea } from "@/components/ui/textarea" -import { useToast } from "@/components/ui/use-toast" +import { useToast } from "@/hooks/use-toast" import { Loader2 } from "lucide-react" type ComposeProseDialogProps = { diff --git a/web2/components/notifications-list.tsx b/web2/components/notifications-list.tsx index eb3dd06..5cb6036 100644 --- a/web2/components/notifications-list.tsx +++ b/web2/components/notifications-list.tsx @@ -7,7 +7,7 @@ import { useAuth } from "@/lib/auth-hooks" import { Button } from "@/components/ui/button" import { Card, CardHeader } from "@/components/ui/card" import { Skeleton } from "@/components/ui/skeleton" -import { useToast } from "@/components/ui/use-toast" +import { useToast } from "@/hooks/use-toast" import { useSSE } from "@/lib/use-sse" import { Heart, MessageCircle, UserPlus, RefreshCw } from "lucide-react" diff --git a/web2/components/prose-card.tsx b/web2/components/prose-card.tsx index ff91165..79e5b94 100644 --- a/web2/components/prose-card.tsx +++ b/web2/components/prose-card.tsx @@ -9,7 +9,7 @@ import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card" import { Heart, MessageCircle, Share2, MoreHorizontal } from "lucide-react" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" import { useAuth } from "@/lib/auth-hooks" -import { useToast } from "@/components/ui/use-toast" +import { useToast } from "@/hooks/use-toast" type ProseCardProps = { prose: { diff --git a/web2/components/prose-detail.tsx b/web2/components/prose-detail.tsx index f53b178..ba2fad8 100644 --- a/web2/components/prose-detail.tsx +++ b/web2/components/prose-detail.tsx @@ -8,7 +8,7 @@ import { CommentsList } from "@/components/comments-list" import { CommentForm } from "@/components/comment-form" import { Button } from "@/components/ui/button" import { ArrowLeft } from "lucide-react" -import { useToast } from "@/components/ui/use-toast" +import { useToast } from "@/hooks/use-toast" type ProseDetailProps = { prose: { diff --git a/web2/components/timeline.tsx b/web2/components/timeline.tsx index 3396f14..5c79d82 100644 --- a/web2/components/timeline.tsx +++ b/web2/components/timeline.tsx @@ -4,7 +4,7 @@ import { useState, useEffect } from "react"; import { useAuth } from "@/lib/auth-hooks"; import { ProseCard } from "@/components/prose-card"; import { Skeleton } from "@/components/ui/skeleton"; -import { useToast } from "@/components/ui/use-toast"; +import { useToast } from "@/hooks/use-toast"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { AlertCircle, RefreshCw } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -35,47 +35,50 @@ export function Timeline() { // Use SSE to get timeline updates const { data, error: sseError } = useSSE("/api/sse/timeline", token, "timeline",{ - // onMessage: (data) => { - // if (data) { - // console.log("SSE CHECK FOR TL") - // console.log(data) - // if (data!=null){ - // setTimelineItems(data); - // setIsLoading(false); - // } - // } - // console.log("SSE NO DATA FOR TL") - // }, - // fallbackToFetch: true, - // }); - onMessage: (newItem) => { - if (newItem) { - console.log("SSE received new timeline item:", newItem); - - // Add new item to the timeline without duplicates - setTimelineItems(prevItems => { - // Check if this item already exists in our timeline - const exists = prevItems.some(item => item.id === newItem.id); - if (exists) { - return prevItems; + onMessage: (ndata) => { + if (ndata) { + // console.log("SSE CHECK FOR TL") + // console.log(data) + // if (data!=null){ + // setTimelineItems(data); + // setIsLoading(false); + if (ndata) { + console.log("SSE received new timeline item:", ndata); + + // Add new item to the timeline without duplicates + setTimelineItems(prevItems => { + // Check if this item already exists in our timeline + const exists = prevItems.some(item => item.id === ndata.id); + if (exists) { + return prevItems; + } + + // Add new item to the beginning of the timeline + return [ndata, ...prevItems]; + }); + + setIsLoading(false); } - - // Add new item to the beginning of the timeline - return [newItem, ...prevItems]; - }); - - setIsLoading(false); + } + console.log("sse data maybe") + console.log(data) + // console.log("SSE NO DATA FOR TL") + }, + fallbackToFetch: true, + onError: (err) => { + console.error("SSE error:", err); + // Let the useEffect handle errors } - }, - fallbackToFetch: true, - onError: (err) => { - console.error("SSE error:", err); - // Let the useEffect handle errors - } -}); + }); // Fetch timeline if SSE fails useEffect(() => { + fetchTimelineItems(); + + // Handle SSE errors by falling back to regular fetch + if (sseError) { + console.log("SSE error detected, falling back to regular fetch:", sseError); + fetchTimelineItems();} // if (data) { // if (data!=null){ // setTimelineItems(data)} else { @@ -83,17 +86,12 @@ export function Timeline() { // } // setIsLoading(false) // } - fetchTimelineItems() - if (sseError) { - console.log("SSE error detected, falling back to regular fetch:", sseError); - fetchTimelineItems(); - } + + // if (sseError) { + // fetchTimelineItems() + // } }, [sseError]); - // if (sseError) { - // fetchTimelineItems() - // } - // }, [data, sseError]); // Fetch timeline function const fetchTimelineItems = async () => { @@ -113,7 +111,7 @@ export function Timeline() { } const responseData = await response.json(); - console.log("DATA:", responseData); + // console.log("DATA:", responseData); if (responseData!=null){ setTimelineItems(responseData); diff --git a/web2/components/ui/toaster.tsx b/web2/components/ui/toaster.tsx index 171beb4..5529576 100644 --- a/web2/components/ui/toaster.tsx +++ b/web2/components/ui/toaster.tsx @@ -1,3 +1,40 @@ +// "use client" + +// import { useToast } from "@/hooks/use-toast" +// import { +// Toast, +// ToastClose, +// ToastDescription, +// ToastProvider, +// ToastTitle, +// ToastViewport, +// } from "@/components/ui/toast" + +// export function Toaster() { +// const { toasts } = useToast() +// console.log("TOASTER RECEIVED TOASTS:", toasts); + +// return ( +// +// {toasts.map(function ({ id, title, description, action, ...props }) { +// return ( +// +//
+// {title && {title}} +// {description && ( +// {description} +// )} +//
+// {action} +// +//
+// ) +// })} +// +//
+// ) +// } + "use client" import { useToast } from "@/hooks/use-toast" @@ -5,31 +42,26 @@ import { Toast, ToastClose, ToastDescription, - ToastProvider, ToastTitle, ToastViewport, } from "@/components/ui/toast" export function Toaster() { const { toasts } = useToast() - + return ( - - {toasts.map(function ({ id, title, description, action, ...props }) { - return ( - -
- {title && {title}} - {description && ( - {description} - )} -
- {action} - -
- ) - })} + <> + {toasts.map(({ id, title, description, action, ...props }) => ( + +
+ {title && {title}} + {description && {description}} +
+ {action} + +
+ ))} -
+ ) } diff --git a/web2/components/ui/use-toast.ts b/web2/components/ui/use-toast.ts index 02e111d..06031f1 100644 --- a/web2/components/ui/use-toast.ts +++ b/web2/components/ui/use-toast.ts @@ -1,194 +1,195 @@ -"use client" - -// Inspired by react-hot-toast library -import * as React from "react" - -import type { - ToastActionElement, - ToastProps, -} from "@/components/ui/toast" - -const TOAST_LIMIT = 1 -const TOAST_REMOVE_DELAY = 1000000 - -type ToasterToast = ToastProps & { - id: string - title?: React.ReactNode - description?: React.ReactNode - action?: ToastActionElement -} - -const actionTypes = { - ADD_TOAST: "ADD_TOAST", - UPDATE_TOAST: "UPDATE_TOAST", - DISMISS_TOAST: "DISMISS_TOAST", - REMOVE_TOAST: "REMOVE_TOAST", -} as const - -let count = 0 - -function genId() { - count = (count + 1) % Number.MAX_SAFE_INTEGER - return count.toString() -} - -type ActionType = typeof actionTypes - -type Action = - | { - type: ActionType["ADD_TOAST"] - toast: ToasterToast - } - | { - type: ActionType["UPDATE_TOAST"] - toast: Partial - } - | { - type: ActionType["DISMISS_TOAST"] - toastId?: ToasterToast["id"] - } - | { - type: ActionType["REMOVE_TOAST"] - toastId?: ToasterToast["id"] - } - -interface State { - toasts: ToasterToast[] -} - -const toastTimeouts = new Map>() - -const addToRemoveQueue = (toastId: string) => { - if (toastTimeouts.has(toastId)) { - return - } - - const timeout = setTimeout(() => { - toastTimeouts.delete(toastId) - dispatch({ - type: "REMOVE_TOAST", - toastId: toastId, - }) - }, TOAST_REMOVE_DELAY) - - toastTimeouts.set(toastId, timeout) -} - -export const reducer = (state: State, action: Action): State => { - switch (action.type) { - case "ADD_TOAST": - return { - ...state, - toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), - } - - case "UPDATE_TOAST": - return { - ...state, - toasts: state.toasts.map((t) => - t.id === action.toast.id ? { ...t, ...action.toast } : t - ), - } - - case "DISMISS_TOAST": { - const { toastId } = action - - // ! Side effects ! - This could be extracted into a dismissToast() action, - // but I'll keep it here for simplicity - if (toastId) { - addToRemoveQueue(toastId) - } else { - state.toasts.forEach((toast) => { - addToRemoveQueue(toast.id) - }) - } - - return { - ...state, - toasts: state.toasts.map((t) => - t.id === toastId || toastId === undefined - ? { - ...t, - open: false, - } - : t - ), - } - } - case "REMOVE_TOAST": - if (action.toastId === undefined) { - return { - ...state, - toasts: [], - } - } - return { - ...state, - toasts: state.toasts.filter((t) => t.id !== action.toastId), - } - } -} - -const listeners: Array<(state: State) => void> = [] - -let memoryState: State = { toasts: [] } - -function dispatch(action: Action) { - memoryState = reducer(memoryState, action) - listeners.forEach((listener) => { - listener(memoryState) - }) -} - -type Toast = Omit - -function toast({ ...props }: Toast) { - const id = genId() - - const update = (props: ToasterToast) => - dispatch({ - type: "UPDATE_TOAST", - toast: { ...props, id }, - }) - const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) - - dispatch({ - type: "ADD_TOAST", - toast: { - ...props, - id, - open: true, - onOpenChange: (open) => { - if (!open) dismiss() - }, - }, - }) - - return { - id: id, - dismiss, - update, - } -} - -function useToast() { - const [state, setState] = React.useState(memoryState) - - React.useEffect(() => { - listeners.push(setState) - return () => { - const index = listeners.indexOf(setState) - if (index > -1) { - listeners.splice(index, 1) - } - } - }, [state]) - - return { - ...state, - toast, - dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), - } -} - -export { useToast, toast } +// "use client" + +// // Inspired by react-hot-toast library +// import * as React from "react" + +// import type { +// ToastActionElement, +// ToastProps, +// } from "@/components/ui/toast" + +// const TOAST_LIMIT = 1 +// const TOAST_REMOVE_DELAY = 1000000 + +// type ToasterToast = ToastProps & { +// id: string +// title?: React.ReactNode +// description?: React.ReactNode +// action?: ToastActionElement +// } + +// const actionTypes = { +// ADD_TOAST: "ADD_TOAST", +// UPDATE_TOAST: "UPDATE_TOAST", +// DISMISS_TOAST: "DISMISS_TOAST", +// REMOVE_TOAST: "REMOVE_TOAST", +// } as const + +// let count = 0 + +// function genId() { +// count = (count + 1) % Number.MAX_SAFE_INTEGER +// return count.toString() +// } + +// type ActionType = typeof actionTypes + +// type Action = +// | { +// type: ActionType["ADD_TOAST"] +// toast: ToasterToast +// } +// | { +// type: ActionType["UPDATE_TOAST"] +// toast: Partial +// } +// | { +// type: ActionType["DISMISS_TOAST"] +// toastId?: ToasterToast["id"] +// } +// | { +// type: ActionType["REMOVE_TOAST"] +// toastId?: ToasterToast["id"] +// } + +// interface State { +// toasts: ToasterToast[] +// } + +// const toastTimeouts = new Map>() + +// const addToRemoveQueue = (toastId: string) => { +// if (toastTimeouts.has(toastId)) { +// return +// } + +// const timeout = setTimeout(() => { +// toastTimeouts.delete(toastId) +// dispatch({ +// type: "REMOVE_TOAST", +// toastId: toastId, +// }) +// }, TOAST_REMOVE_DELAY) + +// toastTimeouts.set(toastId, timeout) +// } + +// export const reducer = (state: State, action: Action): State => { +// switch (action.type) { +// case "ADD_TOAST": +// return { +// ...state, +// toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), +// } + +// case "UPDATE_TOAST": +// return { +// ...state, +// toasts: state.toasts.map((t) => +// t.id === action.toast.id ? { ...t, ...action.toast } : t +// ), +// } + +// case "DISMISS_TOAST": { +// const { toastId } = action + +// // ! Side effects ! - This could be extracted into a dismissToast() action, +// // but I'll keep it here for simplicity +// if (toastId) { +// addToRemoveQueue(toastId) +// } else { +// state.toasts.forEach((toast) => { +// addToRemoveQueue(toast.id) +// }) +// } + +// return { +// ...state, +// toasts: state.toasts.map((t) => +// t.id === toastId || toastId === undefined +// ? { +// ...t, +// open: false, +// } +// : t +// ), +// } +// } +// case "REMOVE_TOAST": +// if (action.toastId === undefined) { +// return { +// ...state, +// toasts: [], +// } +// } +// return { +// ...state, +// toasts: state.toasts.filter((t) => t.id !== action.toastId), +// } +// } +// } + +// const listeners: Array<(state: State) => void> = [] + +// let memoryState: State = { toasts: [] } + +// function dispatch(action: Action) { +// memoryState = reducer(memoryState, action) +// listeners.forEach((listener) => { +// listener(memoryState) +// }) +// } + +// type Toast = Omit + +// function toast({ ...props }: Toast) { +// const id = genId() +// console.log("TOAST TRIGGERED:", props); + +// const update = (props: ToasterToast) => +// dispatch({ +// type: "UPDATE_TOAST", +// toast: { ...props, id }, +// }) +// const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) + +// dispatch({ +// type: "ADD_TOAST", +// toast: { +// ...props, +// id, +// open: true, +// onOpenChange: (open) => { +// if (!open) dismiss() +// }, +// }, +// }) + +// return { +// id: id, +// dismiss, +// update, +// } +// } + +// function useToast() { +// const [state, setState] = React.useState(memoryState) + +// React.useEffect(() => { +// listeners.push(setState) +// return () => { +// const index = listeners.indexOf(setState) +// if (index > -1) { +// listeners.splice(index, 1) +// } +// } +// }, [state]) + +// return { +// ...state, +// toast, +// dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), +// } +// } + +// export { useToast, toast } diff --git a/web2/components/user-profile.tsx b/web2/components/user-profile.tsx index f6affff..2304cf8 100644 --- a/web2/components/user-profile.tsx +++ b/web2/components/user-profile.tsx @@ -8,7 +8,7 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ProseCard } from "@/components/prose-card"; -import { useToast } from "@/components/ui/use-toast"; +import { useToast } from "@/hooks/use-toast"; import { Loader2 } from "lucide-react"; type Prose = { diff --git a/web2/components/users-list.tsx b/web2/components/users-list.tsx index 2242ef7..216985b 100644 --- a/web2/components/users-list.tsx +++ b/web2/components/users-list.tsx @@ -5,7 +5,7 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; -import { useToast } from "@/components/ui/use-toast"; +import { useToast } from "@/hooks/use-toast"; import Link from "next/link"; type User = { diff --git a/web2/lib/auth-provider.tsx b/web2/lib/auth-provider.tsx index 52607ea..c77fad2 100644 --- a/web2/lib/auth-provider.tsx +++ b/web2/lib/auth-provider.tsx @@ -4,7 +4,7 @@ import type React from "react" import { createContext, useState, useEffect } from "react" import { useRouter } from "next/navigation" -import { useToast } from "@/components/ui/use-toast" +import { useToast } from "@/hooks/use-toast" type User = { id: string diff --git a/web2/lib/use-sse.tsx b/web2/lib/use-sse.tsx index a4203fb..ea86610 100644 --- a/web2/lib/use-sse.tsx +++ b/web2/lib/use-sse.tsx @@ -1,6 +1,6 @@ // "use client" -// import { useState, useEffect} from "react" +// import { useState, useEffect } from "react" // type SSEOptions = { // onMessage?: (data: any) => void @@ -9,13 +9,12 @@ // fallbackToFetch?: boolean // } +// export function useSSE(url: string, token: string | null, eventListener: string, options: SSEOptions = {}) { -// export function useSSE(url: string, token: string | null, eventListener: string, options: SSEOptions= {}) { // const [data, setData] = useState(null) // const [error, setError] = useState(null) // const [isConnected, setIsConnected] = useState(false) - // useEffect(() => { // if (!token) return @@ -182,8 +181,7 @@ export function useSSE( fullUrl.searchParams.append('token', token); // Create EventSource connection - const eventSource = new EventSource(fullUrl.toString()); - eventSourceRef.current = eventSource; + const eventSource = new EventSource(fullUrl.toString(),{ withCredentials: true }); // Listen for open events eventSource.onopen = () => { @@ -196,6 +194,8 @@ export function useSSE( console.log(`Received ${eventName} event:`, event); if (event.data) { + console.log(event.data) + const parsedData = JSON.parse(event.data) as T; setData(parsedData); options.onMessage?.(parsedData); @@ -260,9 +260,14 @@ export function useSSE( throw new Error(`Fallback fetch failed with status: ${response.status}`); } - const responseData = await response.json(); - setData(responseData as T); - options.onMessage?.(responseData as T); + const responseText = await response.text(); + + if (responseText){ + const responseData = JSON.parse(responseText) + setData(responseData as T); + options.onMessage?.(responseData as T); + } + } catch (err) { console.error('Fallback fetch error:', err); const error = err instanceof Error ? err : new Error(String(err)); @@ -273,4 +278,3 @@ export function useSSE( }, [url, token, eventName]); return { data, error }; -} \ No newline at end of file diff --git a/web2/next.config.mjs b/web2/next.config.mjs index 060b74a..0878f65 100644 --- a/web2/next.config.mjs +++ b/web2/next.config.mjs @@ -7,6 +7,7 @@ try { /** @type {import('next').NextConfig} */ const nextConfig = { + reactStrictMode: true, eslint: { ignoreDuringBuilds: true, },