Skip to content

Commit

Permalink
fix(user): user info form data flow bug
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnsonMao committed Nov 17, 2024
1 parent 9d10f4a commit effe685
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 43 deletions.
18 changes: 6 additions & 12 deletions components/shared/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { useEffect, useState } from "react";
import { useState } from "react";
import Icon, { IconName } from "@/components/shared/Icon";
import Badge from "@/components/shared/Badge";
import { cn } from "@/lib/utils";
import { UserInfoForm } from "@/features/user";
import useUser from "@/hooks/useUser";
import { UserInfo } from "@/requests/users";
import useAuth from "@/hooks/context/useAuth";
import Modal from "./Modal";
import Cover from "./Cover";

Expand Down Expand Up @@ -33,13 +32,7 @@ export default function Header({
onClickChatButton,
}: Readonly<HeaderProps>) {
const [isUserInfoVisible, setIsUserInfoVisible] = useState(false);
// TODO: 待優化登入就應可以取使用者資料
const [currentUserInfo, setCurrentUserInfo] = useState<UserInfo>();
const { getCurrentUser } = useUser();

useEffect(() => {
getCurrentUser().then((result) => setCurrentUserInfo(result));
}, []);
const { currentUser } = useAuth();

const buttons: ButtonProps[] = [
{
Expand Down Expand Up @@ -92,16 +85,17 @@ export default function Header({
</Badge>
))}
</div>
{isUserInfoVisible && currentUserInfo && (
{isUserInfoVisible && currentUser && (
<Modal
title="修改暱稱"
isOpen={isUserInfoVisible}
onClose={() => setIsUserInfoVisible(false)}
size="medium"
>
<UserInfoForm
{...currentUserInfo}
userInfo={currentUser}
onCancel={() => setIsUserInfoVisible(false)}
onSuccess={() => setIsUserInfoVisible(false)}
/>
</Modal>
)}
Expand Down
2 changes: 1 addition & 1 deletion components/shared/Toast/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { UseToastOptions } from "./useToast";
export const MAX_TOAST_QUEUE_SIZE = 100;
export const MAX_TOAST_MOUNT_SIZE = 6;
export const DEFAULT_TOAST_DURATION = 3500;
export const DEFAULT_TOAST_POSITION = "bottom";
export const DEFAULT_TOAST_POSITION = "top";
export const DEFAULT_TOAST_MANUAL_CLOSE_PLAN = "fullBody";
export const INITIAL_TOAST_POSITION: Record<
Required<UseToastOptions>["position"],
Expand Down
2 changes: 1 addition & 1 deletion features/user/components/UserCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function UserCard({ id, nickname, isSelf, isHost }: Readonly<UserCardProps>) {
)}
>
<div className="relative">
<h3 className="truncate text-secondary-300">非凡之人</h3>
{/* <h3 className="truncate text-secondary-300">非凡之人</h3> */}
<h4 className="truncate">{nickname}</h4>
</div>
</div>
Expand Down
26 changes: 17 additions & 9 deletions features/user/components/UserInfoForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,46 @@ import Input from "@/components/shared/Input";
import useRequest from "@/hooks/useRequest";
import { UserInfo, putUserinfoEndpoint } from "@/requests/users";
import { useToast } from "@/components/shared/Toast";
import useAuth from "@/hooks/context/useAuth";

interface UserInfoFormProps extends UserInfo {
interface UserInfoFormProps {
userInfo: UserInfo;
onSuccess: () => void;
onCancel: () => void;
}

type UserInfoFormErrors = Partial<Record<keyof UserInfo, string>>;

function UserInfoForm({
userInfo,
onSuccess,
onCancel,
...userInfoProps
}: Readonly<UserInfoFormProps>) {
const { fetch } = useRequest();
const toast = useToast();
const [userInfo, setUserInfo] = useState<UserInfo>(userInfoProps);
const { setCurrentUser } = useAuth();
const [data, setData] = useState<UserInfo>(userInfo);
const [errors, setErrors] = useState<UserInfoFormErrors>({});
const nicknameInputRef = useRef<HTMLInputElement>(null);

const handleSubmit = async (event: FormEvent) => {
event.preventDefault();
if (Object.keys(errors).length) {
if (Object.values(errors).some(Boolean)) {
nicknameInputRef.current?.focus();
return;
}

try {
await fetch(
const result = await fetch(
putUserinfoEndpoint({
...userInfo,
nickname: userInfo.nickname.trim(),
...data,
nickname: data.nickname.trim(),
}),
{ toast: { show: false } }
);
toast({ state: "success", children: "修改成功" });
setCurrentUser(result);
onSuccess();
} catch (error) {
if (error instanceof AxiosError) {
toast(
Expand All @@ -61,7 +69,7 @@ function UserInfoForm({
// Regex pattern for special characters. Allow only alphanumeric and spaces
const validNameRegex = /^[a-zA-Z0-9\u4E00-\u9FFF ]+$/;

setUserInfo((prev) => ({ ...prev, nickname }));
setData((prev) => ({ ...prev, nickname }));

if (nickname.trim().length === 0) {
setErrors((pre) => ({ ...pre, nickname: "不可空白" }));
Expand Down Expand Up @@ -91,7 +99,7 @@ function UserInfoForm({
onChange={handleNicknameChange}
hintText={errors.nickname}
error={!!errors.nickname}
value={userInfo.nickname}
value={data.nickname}
autoFocus
/>
</div>
Expand Down
34 changes: 14 additions & 20 deletions pages/rooms/[roomId]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { GetStaticProps, GetStaticPaths } from "next";
import { useRouter } from "next/router";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
Expand All @@ -20,7 +20,6 @@ import {
RoomInfo,
leaveRoom,
playerReady,
playerCancelReady,
startGame,
} from "@/requests/rooms";
import { GameType, getAllGamesEndpoint } from "@/requests/games";
Expand All @@ -41,13 +40,14 @@ export default function Room() {
updateUserReadyStatus,
cleanUpRoom,
} = useRoom();
const isFirstReady = useRef(true);
const { socket } = useSocketCore();
const { currentUser, token } = useAuth();
const { updateRoomId } = useUser();
const { updateRoomId, updateGameUrl, getGameUrl } = useUser();
const { Popup, firePopup } = usePopup();
const { fetch } = useRequest();
const { query, replace } = useRouter();
const [gameUrl, setGameUrl] = useState("");
const [gameUrl, setGameUrl] = useState(getGameUrl);
const [gameList, setGameList] = useState<GameType[]>([]);
const roomId = query.roomId as string;
const player = roomInfo.players.find(
Expand Down Expand Up @@ -111,11 +111,13 @@ export default function Room() {
socket.on(SOCKET_EVENT.GAME_STARTED, ({ gameUrl }: { gameUrl: string }) => {
updateRoomStatus("PLAYING");
setGameUrl(`${gameUrl}?token=${token}`);
updateGameUrl(`${gameUrl}?token=${token}`);
});

socket.on(SOCKET_EVENT.GAME_ENDED, () => {
updateRoomStatus("WAITING");
setGameUrl("");
updateGameUrl();
firePopup({
title: `遊戲已結束!`,
});
Expand Down Expand Up @@ -170,6 +172,7 @@ export default function Room() {
await fetch(closeRoom(roomId));
replace("/rooms");
updateRoomId();
updateGameUrl();
} catch (err) {
firePopup({ title: "error!" });
}
Expand All @@ -189,6 +192,7 @@ export default function Room() {
await fetch(leaveRoom(roomId));
replace("/rooms");
updateRoomId();
updateGameUrl();
} catch (err) {
firePopup({ title: "error!" });
}
Expand All @@ -203,35 +207,25 @@ export default function Room() {
});
};

// Event: toggle ready
const handleToggleReady = async () => {
try {
player?.isReady
? await fetch(playerCancelReady(roomId))
: await fetch(playerReady(roomId));
} catch (err) {
firePopup({ title: `error!` });
}
};

// Event: start game
const handleStart = async () => {
try {
// Check all players are ready
const allReady = roomInfo.players.every((player) => player.isReady);
if (!allReady) return firePopup({ title: "尚有玩家未準備就緒" });
const result = await fetch(startGame(roomId));
setGameUrl(`${result.url}?token=${token}`);
const newGameUrl = `${result.url}?token=${token}`;
setGameUrl(newGameUrl);
updateGameUrl(newGameUrl);
} catch (err) {
firePopup({ title: `error!` });
}
};

useEffect(() => {
if (!player?.isReady && roomId) {
if (!player?.isReady && roomId && isFirstReady.current) {
fetch(playerReady(roomId));
isFirstReady.current = false;
}
}, [player?.isReady, roomId, fetch]);
}, [player?.isReady, roomId, fetch, isFirstReady]);

return (
<section className="px-4">
Expand Down

0 comments on commit effe685

Please sign in to comment.