@@ -132,20 +132,6 @@ const updateQuestionGroupsByCheckedEvent = (groups, eventData) => {
132132 return hasUpdatedQuestion ? regroupQuestions ( updatedQuestions ) : groups ;
133133} ;
134134
135- const addQuestionToGroups = ( groups , question ) => {
136- if ( ! question ?. questionId ) return groups ;
137-
138- const existingQuestions = [
139- ...groups . popularQuestions ,
140- ...groups . unresolvedQuestions ,
141- ...groups . resolvedQuestions ,
142- ] ;
143- const alreadyExists = existingQuestions . some ( item => item . questionId === question . questionId ) ;
144-
145- if ( alreadyExists ) return groups ;
146- return regroupQuestions ( [ question , ...existingQuestions ] ) ;
147- } ;
148-
149135const buildUnderstandingCheckFromEvent = ( eventData ) => ( {
150136 checkId : eventData . checkId ,
151137 content : eventData . content ,
@@ -199,6 +185,7 @@ function QnAListPage() {
199185 } ) ;
200186
201187 // ── 필터 / 정렬 상태 ─────────────────────────────
188+ const [ questionScope , setQuestionScope ] = useState ( 'all' ) ;
202189 const [ filterCurious , setFilterCurious ] = useState ( false ) ;
203190 const [ filterUnsolved , setFilterUnsolved ] = useState ( false ) ;
204191 const [ sortOrder , setSortOrder ] = useState ( '정렬' ) ;
@@ -311,47 +298,13 @@ function QnAListPage() {
311298 applyQuestionGroups ( nextGroups ) ;
312299 } , [ applyQuestionGroups ] ) ;
313300
314- const buildQuestionFromCreatedEvent = useCallback ( async ( eventData ) => {
315- if ( ! eventData ?. questionId ) return null ;
316-
317- // SSE 이벤트의 imageUrls 배열을 blob URL로 변환
318- const rawUrls = eventData . imageUrls ?? [ ] ;
319- const blobUrls = await Promise . all (
320- rawUrls . map ( async ( url ) => {
321- try {
322- const imgRes = await authFetch ( url ) ;
323- const blob = await imgRes . blob ( ) ;
324- return URL . createObjectURL ( blob ) ;
325- } catch {
326- return null ;
327- }
328- } )
329- ) ;
301+ const handleQuestionCreatedEvent = useCallback ( ( eventData ) => {
302+ if ( ! eventData ?. questionId ) return ;
330303
331- return {
332- questionId : eventData . questionId ,
333- content : eventData . content ,
334- imageUrls : blobUrls . filter ( Boolean ) ,
335- isResolved : false ,
336- isPopular : false ,
337- isLiked : false ,
338- isMine : false ,
339- isNew : eventData . isNew ?? true ,
340- iLiked : false ,
341- likeCount : eventData . likeCount ?? 0 ,
342- commentCount : eventData . commentCount ?? 0 ,
343- previewComments : [ ] ,
344- createdAt : eventData . createdAt ,
345- } ;
346- } , [ ] ) ;
347-
348- const handleQuestionCreatedEvent = useCallback ( async ( eventData ) => {
349- const createdQuestion = await buildQuestionFromCreatedEvent ( eventData ) ;
350- if ( ! createdQuestion ) return ;
351-
352- const nextGroups = addQuestionToGroups ( questionGroupsRef . current , createdQuestion ) ;
353- applyQuestionGroups ( nextGroups ) ;
354- } , [ applyQuestionGroups , buildQuestionFromCreatedEvent ] ) ;
304+ // 생성 이벤트에는 로그인 사용자 기준 isMine 값이 없으므로,
305+ // 목록을 다시 조회해 "내 질문" 필터에서도 정확히 분류되도록 한다.
306+ void fetchQuestions ( understandingIndex ) ;
307+ } , [ fetchQuestions , understandingIndex ] ) ;
355308
356309 const handleQuestionUpdatedEvent = useCallback ( ( eventData ) => {
357310 const nextGroups = updateQuestionGroupsByQuestionEvent ( questionGroupsRef . current , eventData ) ;
@@ -706,8 +659,9 @@ function QnAListPage() {
706659
707660 const displayedQuestions = ( ( ) => {
708661 let list = allQuestions ;
709- if ( isStaff && filterUnsolved ) list = unresolvedQuestions ;
710- if ( ! isStaff && filterCurious ) list = allQuestions . filter ( q => q . iLiked ) ;
662+ if ( questionScope === 'mine' ) list = list . filter ( q => q . isMine ) ;
663+ if ( isStaff && filterUnsolved ) list = list . filter ( q => ! q . isResolved ) ;
664+ if ( ! isStaff && filterCurious ) list = list . filter ( q => q . iLiked ) ;
711665
712666 if ( sortOrder === '최신순' ) {
713667 list = [ ...list ] . sort ( ( a , b ) => new Date ( b . createdAt ) - new Date ( a . createdAt ) ) ;
@@ -730,35 +684,56 @@ function QnAListPage() {
730684
731685 { /* ── 필터 / 정렬 행 ── */ }
732686 < div className = { styles . filterRow } >
733- { isStaff ? (
734- < label className = { styles . curiousLabel } >
735- < input type = "checkbox" checked = { filterUnsolved }
736- onChange = { e => setFilterUnsolved ( e . target . checked ) }
737- className = { styles . curiousCheckbox } />
738- 미해결 질문
739- </ label >
740- ) : (
741- < label className = { styles . curiousLabel } >
742- < input type = "checkbox" checked = { filterCurious }
743- onChange = { e => setFilterCurious ( e . target . checked ) }
744- className = { styles . curiousCheckbox } />
745- 저도 궁금해요
746- </ label >
747- ) }
748- < div className = { styles . sortWrapper } >
749- < button className = { styles . sortBtn } onClick = { ( ) => setShowSortMenu ( prev => ! prev ) } >
750- { sortOrder } < SortBtn />
687+ < div className = { styles . scopeTabs } role = "group" aria-label = "질문 조회 범위" >
688+ < button
689+ type = "button"
690+ className = { `${ styles . scopeTab } ${ questionScope === 'all' ? styles . scopeTabActive : '' } ` }
691+ aria-pressed = { questionScope === 'all' }
692+ onClick = { ( ) => setQuestionScope ( 'all' ) }
693+ >
694+ 전체 질문
751695 </ button >
752- { showSortMenu && (
753- < ul className = { styles . sortMenu } >
754- { [ '기본' , '최신순' , '저도궁금해요순' ] . map ( option => (
755- < li key = { option } className = { styles . sortOption }
756- onClick = { ( ) => { setSortOrder ( option ) ; setShowSortMenu ( false ) ; } } >
757- { option }
758- </ li >
759- ) ) }
760- </ ul >
696+ < button
697+ type = "button"
698+ className = { `${ styles . scopeTab } ${ questionScope === 'mine' ? styles . scopeTabActive : '' } ` }
699+ aria-pressed = { questionScope === 'mine' }
700+ onClick = { ( ) => setQuestionScope ( 'mine' ) }
701+ >
702+ 내 질문
703+ </ button >
704+ </ div >
705+
706+ < div className = { styles . filterControls } >
707+ { isStaff ? (
708+ < label className = { styles . curiousLabel } >
709+ < input type = "checkbox" checked = { filterUnsolved }
710+ onChange = { e => setFilterUnsolved ( e . target . checked ) }
711+ className = { styles . curiousCheckbox } />
712+ 미해결 질문
713+ </ label >
714+ ) : (
715+ < label className = { styles . curiousLabel } >
716+ < input type = "checkbox" checked = { filterCurious }
717+ onChange = { e => setFilterCurious ( e . target . checked ) }
718+ className = { styles . curiousCheckbox } />
719+ 저도 궁금해요
720+ </ label >
761721 ) }
722+ < div className = { styles . sortWrapper } >
723+ < button className = { styles . sortBtn } onClick = { ( ) => setShowSortMenu ( prev => ! prev ) } >
724+ { sortOrder } < SortBtn />
725+ </ button >
726+ { showSortMenu && (
727+ < ul className = { styles . sortMenu } >
728+ { [ '기본' , '최신순' , '저도궁금해요순' ] . map ( option => (
729+ < li key = { option } className = { styles . sortOption }
730+ onClick = { ( ) => { setSortOrder ( option ) ; setShowSortMenu ( false ) ; } } >
731+ { option }
732+ </ li >
733+ ) ) }
734+ </ ul >
735+ ) }
736+ </ div >
762737 </ div >
763738 </ div >
764739 < hr className = { styles . divider } />
@@ -802,6 +777,15 @@ function QnAListPage() {
802777
803778 { /* ── 질문 목록 ── */ }
804779 < div className = { styles . questionList } >
780+ { displayedQuestions . length === 0 && (
781+ < div className = { styles . emptyState } >
782+ { questionScope === 'mine'
783+ ? '작성한 질문이 없습니다.'
784+ : ( filterCurious || filterUnsolved )
785+ ? '조건에 맞는 질문이 없습니다.'
786+ : '등록된 질문이 없습니다.' }
787+ </ div >
788+ ) }
805789 { displayedQuestions . map ( question => (
806790 < div key = { question . questionId }
807791 className = { `${ styles . questionCard } ${ question . isResolved ? styles . questionCardResolved : '' } ` }
0 commit comments