From ed6e1ec9e4f61d322c49de5afa693b8b50c86075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8A=89=E5=A5=87?= Date: Thu, 12 Oct 2023 17:07:56 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=AD=89=E5=BE=85?= =?UTF-8?q?=E7=8E=A9=E5=AE=B6=E5=8A=A0=E5=85=A5=E9=A0=81=E9=9D=A2,=20(webs?= =?UTF-8?q?ocket=E6=9C=83=E6=96=B7=E7=B7=9A,=20=E5=9B=A0=E6=AD=A4=E4=BA=BA?= =?UTF-8?q?=E6=95=B8=E9=82=84=E6=B2=92=E5=81=9A=E5=A5=BD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/app/layout.tsx | 6 ++-- frontend/app/page.tsx | 3 +- frontend/app/waittingJoin/page.tsx | 52 ++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 frontend/app/waittingJoin/page.tsx diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index 04c1f6f..4a274d3 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -1,11 +1,11 @@ -import './globals.css'; import { Inter } from 'next/font/google'; +import './globals.css'; const inter = Inter({ subsets: ['latin'] }); export const metadata = { - title: 'Create Next App', - description: 'Generated by create next app', + title: 'UNO Flip', + description: '正反面都能玩,比傳統 UNO 更刺激有趣。', }; export default function RootLayout({ children }: { children: React.ReactNode }) { diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index c37eb4a..6684520 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -1,6 +1,5 @@ 'use client'; import Image from 'next/image'; -import React from 'react'; export default function Home() { return ( @@ -8,7 +7,7 @@ export default function Home() {

UNO Flip - app/page.tsx + {/* app/page.tsx */}

(null).current?.value || '未命名的玩家'; + const number = 1; + useEffect(() => { + // 創建 WebSocket 連接 + const ws = new WebSocket("ws://localhost:9090/sse/02"); + + ws.onopen = () => { + console.log('register'); + }; + + // 監聽事件 + ws.onmessage = (event) => { + console.log('test2'); + const data = JSON.parse(event.data); + console.log(data); + }; + ws.onclose = () => { + if (ws.readyState === WebSocket.CLOSED) { + // 連接已關閉,執行其他操作 + console.log('連接已關閉'); + } + }; + return () => { + // 在組件卸載時關閉 WebSocket 連接 + ws.close(); + }; + + }, []); + return ( +
+

說明: 因為尚未決定玩家順序,不能表現其他玩家的相對位置

+
+
+
目前玩家人數: {number}
+
+
等待其他玩家加入...
+
+ +
+ {name} +
+
+ +
+ ); +}; From 82b471b88174570b6d26cc8298d7a6f25d33990b Mon Sep 17 00:00:00 2001 From: "chiliteng007@gmail.com" Date: Sat, 14 Oct 2023 01:15:05 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=B7=B2=E5=AE=8C=E6=88=90=E7=AD=89?= =?UTF-8?q?=E5=BE=85=E7=8E=A9=E5=AE=B6=E9=A0=81=E9=9D=A2,=20=E4=BD=86?= =?UTF-8?q?=E5=96=AE=E5=85=83=E6=B8=AC=E8=A9=A6=E6=9C=AA=E5=AE=8C=E6=88=90?= =?UTF-8?q?=20(=E6=89=BE=E4=B8=8D=E5=88=B0=E6=A8=A1=E6=93=ACEventSource?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E6=B3=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unoflip/controller/SSEController.java | 6 +-- frontend/__tests__/WaittingJoin.test.tsx | 24 +++++++++++ frontend/app/waittingJoin/page.tsx | 42 +++++++++---------- 3 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 frontend/__tests__/WaittingJoin.test.tsx diff --git a/backend/src/main/java/tw/waterballsa/gaas/unoflip/controller/SSEController.java b/backend/src/main/java/tw/waterballsa/gaas/unoflip/controller/SSEController.java index 3037538..9465ed3 100644 --- a/backend/src/main/java/tw/waterballsa/gaas/unoflip/controller/SSEController.java +++ b/backend/src/main/java/tw/waterballsa/gaas/unoflip/controller/SSEController.java @@ -4,10 +4,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import tw.waterballsa.gaas.unoflip.service.SseService; @@ -21,6 +18,7 @@ public SSEController(SseService sseService) { } @GetMapping(value = "{playerId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + @CrossOrigin(origins = "http://localhost:3000") public ResponseEntity broadcast(@PathVariable String playerId) { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.set("X-Accel-Buffering", "no"); diff --git a/frontend/__tests__/WaittingJoin.test.tsx b/frontend/__tests__/WaittingJoin.test.tsx new file mode 100644 index 0000000..fa354b5 --- /dev/null +++ b/frontend/__tests__/WaittingJoin.test.tsx @@ -0,0 +1,24 @@ +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import WaittingJoinHomepage from '@/app/waittingJoin/page'; +import fetchMock from 'jest-fetch-mock'; + + + +beforeEach(() => { + fetchMock.resetMocks(); +}); + +describe('WaittingJoinHomepage', () => { + it('should update player count when a message is received', async () => { + const mockData = { position: 3 }; + + fetchMock.mockResponse(JSON.stringify(mockData)); + + render(); + + // 模拟 EventSource 的事件回调 + const playerCount = await screen.findByText('目前玩家人數: 3'); + expect(playerCount).toBeInTheDocument(); + }); +}); \ No newline at end of file diff --git a/frontend/app/waittingJoin/page.tsx b/frontend/app/waittingJoin/page.tsx index 5125a92..87a406b 100644 --- a/frontend/app/waittingJoin/page.tsx +++ b/frontend/app/waittingJoin/page.tsx @@ -1,36 +1,36 @@ 'use client'; -import { useEffect, useRef } from 'react'; +import { useEffect, useRef, useState } from 'react'; export default function WaittingJoinHomepage() { const name = useRef(null).current?.value || '未命名的玩家'; - const number = 1; + const playerId = useRef(null).current?.value || '01'; + const [number, setNumber] = useState(0); + useEffect(() => { - // 創建 WebSocket 連接 - const ws = new WebSocket("ws://localhost:9090/sse/02"); - - ws.onopen = () => { - console.log('register'); + // 創建 EventSource 連接 + const eventSource = new EventSource("http://localhost:9090/sse/"+playerId); + + eventSource.onopen = () => { + console.log('EventSource 連接已打開'); }; - - // 監聽事件 - ws.onmessage = (event) => { - console.log('test2'); - const data = JSON.parse(event.data); - console.log(data); + + eventSource.onmessage = (event) => { + console.log('收到事件:', event.data); + const eventData = JSON.parse(event.data); + if(eventData.position){ + setNumber(eventData.position);} }; - ws.onclose = () => { - if (ws.readyState === WebSocket.CLOSED) { - // 連接已關閉,執行其他操作 - console.log('連接已關閉'); - } + + eventSource.onerror = (error) => { + console.error('EventSource 錯誤:', error); }; + return () => { - // 在組件卸載時關閉 WebSocket 連接 - ws.close(); + eventSource.close(); }; - + }, []); return (