From 0563a09aa8b58f51c9eb9978f3efa297cfa72a3c Mon Sep 17 00:00:00 2001 From: kyochan <66947667+kyochn@users.noreply.github.com> Date: Sat, 22 Oct 2022 10:45:03 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix=20cross-env=E5=85=A5=E3=82=8C=E3=81=A6W?= =?UTF-8?q?indows=E3=81=AB=E5=AF=BE=E5=BF=9C=20(#147)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- desktop/package.json | 3 ++- desktop/yarn.lock | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/desktop/package.json b/desktop/package.json index a792b5a6..952f2bb2 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -3,7 +3,7 @@ "version": "1.0.0-SNAPSHOT", "main": "dist-electron/electron/main/app.js", "scripts": { - "dev": "NODE_ENV=development vite", + "dev": "cross-env NODE_ENV=development vite", "build": "tsc && vite build", "codegen": "openapi-generator-cli generate -g typescript-axios -i http://localhost:8080/v3/api-docs/Public%20API -o ./electron/main/generated/http-client", "lint": "eslint src electron", @@ -37,6 +37,7 @@ "@typescript-eslint/parser": "5.40.1", "@vitejs/plugin-react": "2.1.0", "axios": "^1.1.3", + "cross-env": "^7.0.3", "electron": "^21.1.1", "electron-builder": "^23.3.3", "electron-reload": "^2.0.0-alpha.1", diff --git a/desktop/yarn.lock b/desktop/yarn.lock index 185b3368..5bc27161 100644 --- a/desktop/yarn.lock +++ b/desktop/yarn.lock @@ -2998,6 +2998,13 @@ crc@^3.8.0: dependencies: buffer "^5.1.0" +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" From 3893b2f08df0a3805e238a50b46e1c78e40f9a1d Mon Sep 17 00:00:00 2001 From: ygkn <2000ygkn0713@gmail.com> Date: Sat, 22 Oct 2022 10:56:33 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=9E=E3=83=BC?= =?UTF-8?q?=E3=81=86=E3=81=94=E3=81=8F=E3=82=88=E3=81=86=E3=81=AB=E3=81=97?= =?UTF-8?q?=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/pointer/src/components/Timer.tsx | 206 +++++++++++++----- 1 file changed, 157 insertions(+), 49 deletions(-) diff --git a/app/src/main/pointer/src/components/Timer.tsx b/app/src/main/pointer/src/components/Timer.tsx index 789e0ae1..504aca14 100644 --- a/app/src/main/pointer/src/components/Timer.tsx +++ b/app/src/main/pointer/src/components/Timer.tsx @@ -20,21 +20,32 @@ import { InputLeftAddon, InputRightAddon, Heading, + useToast, } from "@chakra-ui/react"; import { Cog6ToothIcon } from "@heroicons/react/24/solid"; -import { FC, useState } from "react"; +import { FC, useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { stompClient } from "@/stomp"; import { AuthData } from "@/types/AuthData"; type Props = { authData: AuthData; }; +type FormValues = { + minutes: string; + seconds: string; +}; + export const Timer: FC = ({ authData }) => { const { isOpen, onOpen, onClose } = useDisclosure(); const [state, setState] = useState<"READY" | "RUNNING">("READY"); + const [finishTimestamp, setFinishedTimestamp] = useState(null); const [noticeTime, setNoticeTime] = useState("1"); + const toast = useToast(); + const completeNoticeTime = () => { if (noticeTime === "") { setNoticeTime("0"); @@ -42,13 +53,117 @@ export const Timer: FC = ({ authData }) => { onClose(); }; + const { register, handleSubmit, setValue } = useForm(); + + const onStartStop = (values: FormValues) => { + console.log(values); + switch (state) { + case "READY": { + stompClient.publish({ + destination: `/app/rooms/${authData.roomId}/timer/start`, + body: JSON.stringify({ + value: Number(values.minutes) * 60 + Number(values.seconds), + }), + }); + return; + } + case "RUNNING": { + stompClient.publish({ + destination: `/app/rooms/${authData.roomId}/timer/stop`, + }); + return; + } + } + }; + + useEffect(() => { + stompClient.subscribe( + `/topic/rooms/${authData.roomId}/timer`, + (message) => { + console.log(message); + const { status, value, finishAt } = JSON.parse(message.body) as { + status: 0 | 1; + value: number; + finishAt: string; + }; + switch (status) { + case 0: { + const minutes = Math.floor(value / 60); + const seconds = value % 60; + setValue("minutes", minutes.toString()); + setValue("seconds", seconds.toString()); + setState("READY"); + return; + } + case 1: { + setFinishedTimestamp( + performance.now() + new Date(finishAt).valueOf() - Date.now() + ); + setState("RUNNING"); + return; + } + } + } + ); + }, [authData.roomId, setValue]); + + useEffect(() => { + if (finishTimestamp === null) { + return; + } + + let requestId: number | null; + + const tick = (now: number) => { + const timeStamp = finishTimestamp - now; + + if (timeStamp <= 0) { + setValue("minutes", "0"); + setValue("seconds", "0"); + setState("READY"); + toast({ + title: "タイマーが終了しました", + description: "お疲れ様でした", + status: "success", + duration: 9000, + isClosable: true, + }); + return; + } + + const seconds = Math.floor((timeStamp / 1000) % 60); + const minutes = Math.floor((timeStamp / 1000 / 60) % 60); + setValue("minutes", minutes.toString()); + setValue("seconds", seconds.toString()); + + requestId = requestAnimationFrame(tick); + }; + + if (state === "RUNNING") { + requestId = requestAnimationFrame(tick); + } + + return () => { + if (requestId) { + cancelAnimationFrame(requestId); + } + }; + }, [finishTimestamp, setValue, state]); + return ( タイマー - + - + @@ -68,7 +183,14 @@ export const Timer: FC = ({ authData }) => { /> - + @@ -76,58 +198,44 @@ export const Timer: FC = ({ authData }) => { - - - - - - 残り時間通知 - - - - 残り - setNoticeTime(value)} - > - - - - - - - - - - - - - - - + + + + 残り時間通知 + + + + 残り + setNoticeTime(value)} + > + + + + + + + + + + + + + + + ); }; From a346e72098f3e52f037f6333557ce40eba9662d5 Mon Sep 17 00:00:00 2001 From: ygkn <2000ygkn0713@gmail.com> Date: Sat, 22 Oct 2022 11:22:22 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=E5=85=A5=E5=AE=A4=E3=83=95=E3=82=A9?= =?UTF-8?q?=E3=83=BC=E3=83=A0=E3=82=92=E3=81=8A=E3=81=97=E3=82=83=E3=82=8C?= =?UTF-8?q?=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pointer/src/components/JoinRoomForm.tsx | 72 ++++++++++++++----- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/app/src/main/pointer/src/components/JoinRoomForm.tsx b/app/src/main/pointer/src/components/JoinRoomForm.tsx index 4c446046..13de8cab 100644 --- a/app/src/main/pointer/src/components/JoinRoomForm.tsx +++ b/app/src/main/pointer/src/components/JoinRoomForm.tsx @@ -6,9 +6,14 @@ import { FormHelperText, Button, FormErrorMessage, + useToast, + PinInput, + PinInputField, + Flex, } from "@chakra-ui/react"; +import { AxiosError } from "axios"; import { FC } from "react"; -import { useForm } from "react-hook-form"; +import { Controller, useForm } from "react-hook-form"; import { roomApi } from "@/api"; import { AuthData } from "@/types/AuthData"; @@ -28,10 +33,13 @@ type FormValues = { export const JoinRoomForm: FC = ({ onSubmit: onSubmitProps }) => { const url = new URL(location.href); + const toast = useToast(); + const { handleSubmit, register, formState: { errors, isSubmitting }, + control, } = useForm({ defaultValues: { userName: localStorage.getItem(localStorageKey) ?? "", @@ -41,17 +49,35 @@ export const JoinRoomForm: FC = ({ onSubmit: onSubmitProps }) => { }); const onSubmit = async (values: FormValues) => { - console.log(values); - const { data } = await roomApi.joinRoom(values.roomId, { - passcode: values.passcode, - name: values.userName, - }); - localStorage.setItem(localStorageKey, values.userName); - onSubmitProps({ - ...data, - userName: values.userName, - roomId: values.roomId, - }); + try { + const { data } = await roomApi.joinRoom(values.roomId, { + passcode: values.passcode, + name: values.userName, + }); + localStorage.setItem(localStorageKey, values.userName); + onSubmitProps({ + ...data, + userName: values.userName, + roomId: values.roomId, + }); + + toast({ + title: "ログインに成功しました。", + status: "success", + duration: 3000, + isClosable: true, + }); + } catch (error) { + if (error instanceof AxiosError) { + toast({ + title: "ログインに失敗しました。", + description: error.response?.data.message, + status: "error", + duration: 3000, + isClosable: true, + }); + } + } }; return ( @@ -83,12 +109,22 @@ export const JoinRoomForm: FC = ({ onSubmit: onSubmitProps }) => { パスコード - + + ( + + + + + + + + + )} + /> + {errors.passcode?.message}