33import Avatar from 'boring-avatars' ;
44import Cookies from 'js-cookie' ;
55import React , { useState , useEffect , useRef , useCallback } from 'react' ;
6- import Link from 'next/link' ;
7- import { useRouter } from 'next/navigation' ;
86import { Button } from '@/components/ui/button' ;
97import { Input } from '@/components/ui/input' ;
108import { Label } from '@/components/ui/label' ;
119import Modal from '@/components/Modal' ;
1210import { authenticatedFetch } from '../../lib/api' ;
1311import { useFormStore } from '../../store/formStore' ;
12+ import { useNavigationStore } from '../../store/navigationStore' ;
1413
1514type View = 'loading' | 'create' | 'waiting' ;
1615type TeamMember = {
@@ -24,6 +23,7 @@ const TEAM_SIZE = process.env.NEXT_PUBLIC_TEAM_SIZE
2423 : 5 ;
2524
2625const WaitingView = ( { teamMembers, myId, teamId, setView } : { teamMembers : TeamMember [ ] , myId : number , teamId : number , setView : ( view : View ) => void } ) => {
26+ const { setCurrentPage } = useNavigationStore ( ) ;
2727 const handleLeaveTeam = async ( ) => {
2828 try {
2929 await authenticatedFetch ( `/api/v1/teams/${ String ( teamId ) } /cancel` , {
@@ -89,6 +89,7 @@ const CreateTeamView = ({
8989} ) => {
9090 const [ showModal , setShowModal ] = useState ( false ) ;
9191 const timeoutRef = useRef < NodeJS . Timeout | null > ( null ) ;
92+ const { setCurrentPage } = useNavigationStore ( ) ;
9293
9394 useEffect ( ( ) => {
9495 const hasSeenModal = Cookies . get ( 'doNotShowModalPage2' ) ;
@@ -107,7 +108,7 @@ const CreateTeamView = ({
107108 < div className = "container mx-auto p-4" >
108109 < Modal
109110 title = "미션 소개"
110- content = { ( '1. 참가자들의 코드를 모으세요!<br /> 코드는 위에 개인별 다른 코드가 있습니다.<br />2 . 5명이 함께 문제 풀기에 도전하세요!<br /> (팁! 문제는 팀원들과 관련된 문제가 나옵니다.)<br />3 . 성공 시 부스 방문해주세요.<br /> 성공 선물을 드립니다.' ) }
111+ content = { ( '1. 참가자들의 코드를 모으세요!\n 코드는 위에 개인별 다른 코드가 있습니다.\n2 . 5명이 함께 문제 풀기에 도전하세요!\n (팁! 문제는 팀원들과 관련된 문제가 나옵니다.)\n3 . 성공 시 부스 방문해주세요.\n 성공 선물을 드립니다.' ) }
111112 onConfirm = { handleConfirm }
112113 onDoNotShowAgain = { handleDoNotShowAgain }
113114 isOpen = { showModal }
@@ -133,23 +134,17 @@ const CreateTeamView = ({
133134 < Button onClick = { handleCreateTeam } className = "w-full" > 문제 풀기</ Button >
134135 </ div >
135136 < nav className = "flex justify-between mt-8" >
136- < Button asChild className = "rounded-full" variant = { 'outline' } >
137- < Link href = "/page1" > <</ Link >
137+ < Button onClick = { ( ) => setCurrentPage ( 'page1' ) } className = "rounded-full" variant = { 'outline' } >
138+ <
138139 </ Button >
139140 </ nav >
140141 </ div >
141142 ) ;
142143} ;
143144
144145export default function Page2 ( ) {
145- const { id : myId , teamId, setTeamId, setMemberIds } = useFormStore ( ) ;
146- const router = useRouter ( ) ;
147-
148- useEffect ( ( ) => {
149- if ( ! myId ) {
150- router . push ( '/page1' ) ;
151- }
152- } , [ myId , router ] ) ;
146+ const { id : myId , teamId, setTeamId, setMemberIds, reset } = useFormStore ( ) ;
147+ const { setCurrentPage } = useNavigationStore ( ) ;
153148
154149 const [ view , setView ] = useState < View > ( 'loading' ) ;
155150 const [ teamMembers , setTeamMembers ] = useState < TeamMember [ ] > ( [ ] ) ;
@@ -189,6 +184,70 @@ export default function Page2() {
189184 setInputs ( newInputs ) ;
190185 } , [ myId , inputs , fetchUserDisplayName ] ) ;
191186
187+ useEffect ( ( ) => {
188+ const hydrateTeam = async ( ) => {
189+ if ( myId && teamId && view === 'loading' ) {
190+ console . log ( 'Hydrating team members from persisted teamId...' ) ;
191+ try {
192+ const response = await authenticatedFetch ( '/api/v1/teams/me' ) ;
193+ if ( ! response . ok ) {
194+ const errorData = await response . json ( ) ;
195+ throw new Error ( `HTTP error! status: ${ response . status } , message: ${ errorData . detail || response . statusText } ` ) ;
196+ }
197+ const teamData = await response . json ( ) ;
198+ if ( teamData && teamData . members && teamData . members . length > 0 ) {
199+ const newInputs : InputState [ ] = Array ( TEAM_SIZE ) . fill ( null ) . map ( ( _ , index ) => {
200+ if ( index === 0 ) {
201+ // My ID should be the first input
202+ const me = teamData . members . find ( ( member : { id : number ; } ) => Number ( member . id ) === Number ( myId ) ) ;
203+ return me ? { id : String ( me . id ) , displayName : me . name } : { id : String ( myId ) , displayName : '' } ;
204+ } else {
205+ // Other members
206+ const member = teamData . members [ index ] ;
207+ return member ? { id : String ( member . id ) , displayName : member . name } : { id : '' , displayName : '' } ;
208+ }
209+ } ) ;
210+
211+ const initialTeamMembers : TeamMember [ ] = teamData . members . map ( ( member : { id : number ; name : string ; } ) => ( {
212+ user_id : Number ( member . id ) ,
213+ displayName : member . name ,
214+ is_ready : false , // will be updated by polling later
215+ } ) ) ;
216+
217+ setInputs ( newInputs ) ;
218+ setTeamMembers ( initialTeamMembers ) ;
219+ setView ( 'waiting' ) ;
220+ } else {
221+ console . warn ( 'No team members found in /teams/me response, falling back to create view.' ) ;
222+ setView ( 'create' ) ;
223+ }
224+ } catch ( error ) {
225+ console . error ( 'Error hydrating team data:' , error ) ;
226+ if ( teamId && teamId > 0 ) {
227+ try {
228+ console . log ( `Attempting to leave team ${ teamId } due to hydration error...` ) ;
229+ await authenticatedFetch ( `/api/v1/teams/${ teamId } /cancel` , {
230+ method : 'POST' ,
231+ } ) ;
232+ console . log ( `Successfully left team ${ teamId } .` ) ;
233+ } catch ( cancelError ) {
234+ console . error ( `Failed to leave team ${ teamId } after hydration error:` , cancelError ) ;
235+ }
236+ }
237+ reset ( ) ;
238+ localStorage . removeItem ( 'lastPage' ) ;
239+ setCurrentPage ( 'page1' ) ;
240+ }
241+ } else if ( ! myId ) {
242+ setCurrentPage ( 'page1' ) ; // Redirect to page1 if myId is missing
243+ } else if ( view === 'loading' ) {
244+ setView ( 'create' ) ; // Fallback if no teamId but not redirected
245+ }
246+ } ;
247+
248+ hydrateTeam ( ) ;
249+ } , [ myId , teamId , view , setCurrentPage , reset ] ) ;
250+
192251 useEffect ( ( ) => {
193252 if ( myId && inputs [ 0 ] . id === '' ) {
194253 fetchUserById ( 0 , String ( myId ) ) ;
@@ -246,9 +305,9 @@ export default function Page2() {
246305 useEffect ( ( ) => {
247306 if ( view === 'waiting' && teamMembers . length > 0 && teamMembers . every ( m => m . is_ready ) ) {
248307 setMemberIds ( teamMembers . map ( m => m . user_id ) ) ;
249- router . push ( '/ page3') ;
308+ setCurrentPage ( ' page3') ;
250309 }
251- } , [ view , teamMembers , router , setMemberIds ] ) ;
310+ } , [ view , teamMembers , setCurrentPage , setMemberIds ] ) ;
252311
253312 const handleInputChange = ( index : number , value : string ) => {
254313 const newInputs = [ ...inputs ] ;
0 commit comments