@@ -38,6 +38,7 @@ import { isNoin } from '@/app/lib/lib'
3838import { addWordQueryType } from '@/app/types/type'
3939import Link from 'next/link'
4040import { ArrowLeft } from 'lucide-react'
41+ import ThemeSelectModal from './ThemeSelectModal'
4142
4243// 타입 정의
4344type Theme = {
@@ -65,10 +66,24 @@ export default function AdminHome({ requestDatas, refreshFn }: { requestDatas: W
6566 const [ currentPage , setCurrentPage ] = useState < number > ( 1 ) ;
6667 const [ allSelected , setAllSelected ] = useState < boolean > ( false ) ;
6768 const [ errorModalView , setErrorModalView ] = useState < ErrorMessage | null > ( null ) ;
69+ const [ themeModalOpen , setThemeModalOpen ] = useState < boolean > ( false ) ;
70+ const [ selectedRequestForModal , setSelectedRequestForModal ] = useState < WordRequest | null > ( null ) ;
71+ const [ allThemes , setAllThemes ] = useState < { id : number ; name : string ; code : string } [ ] > ( [ ] ) ;
6872 const user = useSelector ( ( state : RootState ) => state . user ) ;
6973
7074 const PAGE_SIZE = 30 ;
7175
76+ // 전체 주제 목록 불러오기
77+ useEffect ( ( ) => {
78+ const loadAllThemes = async ( ) => {
79+ const { data, error } = await SCM . get ( ) . allThemes ( ) ;
80+ if ( ! error && data ) {
81+ setAllThemes ( data ) ;
82+ }
83+ } ;
84+ loadAllThemes ( ) ;
85+ } , [ ] ) ;
86+
7287 // 요청 타입별 필터링
7388 const filteredRequests = requestDatas . filter ( request => {
7489 if ( selectedTab === "all" ) return true ;
@@ -108,30 +123,32 @@ export default function AdminHome({ requestDatas, refreshFn }: { requestDatas: W
108123 setSelectedRequests ( newSelected ) ;
109124 } ;
110125
111- // 주제 선택 토글
112- const toggleTheme = ( requestId : number , themeId : number ) => {
113- const currentThemes = selectedThemes [ requestId ] || new Set < number > ( ) ;
126+ // 주제 선택 버튼 클릭 핸들러
127+ const handleThemeSelectClick = ( request : WordRequest ) => {
128+ setSelectedRequestForModal ( request ) ;
129+ setThemeModalOpen ( true ) ;
130+ } ;
131+
132+ // 모달에서 주제 선택 확인 핸들러
133+ const handleThemeModalConfirm = ( selectedThemesList : Theme [ ] ) => {
134+ if ( ! selectedRequestForModal ) return ;
135+
114136 const newSelectedThemes = { ...selectedThemes } ;
137+ const themeIds = new Set ( selectedThemesList . map ( t => t . theme_id ) ) ;
138+ newSelectedThemes [ selectedRequestForModal . id ] = themeIds ;
139+ setSelectedThemes ( newSelectedThemes ) ;
115140
116- if ( currentThemes . has ( themeId ) ) {
117- currentThemes . delete ( themeId ) ;
118- if ( currentThemes . size === 0 ) {
119- toggleRequest ( requestId )
120- }
121- } else {
122- currentThemes . add ( themeId ) ;
141+ // 주제가 선택되면 해당 요청도 자동으로 선택
142+ if ( themeIds . size > 0 ) {
123143 const newSelected = new Set ( selectedRequests ) ;
124- if ( ! newSelected . has ( requestId ) ) {
125- newSelected . add ( requestId ) ;
144+ if ( ! newSelected . has ( selectedRequestForModal . id ) ) {
145+ newSelected . add ( selectedRequestForModal . id ) ;
126146 if ( newSelected . size === currentRequests . length ) {
127147 setAllSelected ( true ) ;
128148 }
129149 setSelectedRequests ( newSelected ) ;
130150 }
131151 }
132-
133- newSelectedThemes [ requestId ] = currentThemes ;
134- setSelectedThemes ( newSelectedThemes ) ;
135152 } ;
136153
137154 const makeError = ( error : PostgrestError ) => {
@@ -155,11 +172,18 @@ export default function AdminHome({ requestDatas, refreshFn }: { requestDatas: W
155172 const request = requestDatas . find ( r => r . id === reqId ) ;
156173 const selectedThemeIds = selectedThemes [ reqId ] || new Set < number > ( ) ;
157174
175+ // allThemes에서 선택된 주제 정보 가져오기
176+ const selectedThemeObjects = allThemes
177+ . filter ( theme => selectedThemeIds . has ( theme . id ) )
178+ . map ( theme => ( {
179+ theme_id : theme . id ,
180+ theme_name : theme . name ,
181+ theme_code : theme . code
182+ } ) ) ;
183+
158184 return {
159185 ...request ,
160- selectedThemes : request ?. wait_themes ?. filter ( theme =>
161- selectedThemeIds . has ( theme . theme_id )
162- )
186+ selectedThemes : selectedThemeObjects
163187 } ;
164188 } ) ;
165189
@@ -173,6 +197,8 @@ export default function AdminHome({ requestDatas, refreshFn }: { requestDatas: W
173197
174198 // 승인할 목록에서 쿼리에 맞게 배분
175199 for ( const req of requestsToApprove ) {
200+ const selectedThemeIds = selectedThemes [ req . id ! ] || new Set < number > ( ) ;
201+
176202 switch ( req . request_type ) {
177203 case "add" :
178204 if ( ! req . word || ! req . selectedThemes || req . selectedThemes . length === 0 ) continue ;
@@ -188,10 +214,16 @@ export default function AdminHome({ requestDatas, refreshFn }: { requestDatas: W
188214 continue
189215
190216 case "theme_change" :
191- if ( ! req . word_id || ! req . selectedThemes ) continue ;
217+ if ( ! req . word_id ) continue ;
192218 const addT : { word_id : number , theme_id : number } [ ] = [ ] ;
193219 const delT : { word_id : number , theme_id : number } [ ] = [ ] ;
194- req . selectedThemes . forEach ( ( theme ) => {
220+
221+ // theme_change는 wait_themes를 직접 사용
222+ const themesToProcess = req . wait_themes ?. filter ( theme =>
223+ selectedThemeIds . has ( theme . theme_id )
224+ ) || [ ] ;
225+
226+ themesToProcess . forEach ( ( theme ) => {
195227 if ( theme . typez === "add" ) {
196228 addT . push ( { word_id : req . word_id as number , theme_id : theme . theme_id } )
197229 }
@@ -619,14 +651,57 @@ export default function AdminHome({ requestDatas, refreshFn }: { requestDatas: W
619651 { renderRequestTypeBadge ( request . request_type ) }
620652 </ TableCell >
621653 < TableCell >
622- { request . wait_themes ? (
654+ { request . request_type === 'add' ? (
655+ < div className = "space-y-2" >
656+ < Button
657+ variant = "outline"
658+ size = "sm"
659+ onClick = { ( ) => handleThemeSelectClick ( request ) }
660+ className = "w-full"
661+ >
662+ 주제 선택 ({ selectedThemes [ request . id ] ?. size || 0 } )
663+ </ Button >
664+ { selectedThemes [ request . id ] && selectedThemes [ request . id ] . size > 0 && (
665+ < div className = "flex flex-wrap gap-1" >
666+ { allThemes
667+ . filter ( theme => selectedThemes [ request . id ] ?. has ( theme . id ) )
668+ . map ( ( theme , index ) => (
669+ < Badge key = { `badge-${ theme . id } -${ index } ` } variant = "secondary" className = "text-xs" >
670+ { theme . name }
671+ </ Badge >
672+ ) ) }
673+ </ div >
674+ ) }
675+ </ div >
676+ ) : request . wait_themes ? (
623677 < div className = "flex flex-col gap-2" >
624678 { request . wait_themes . map ( ( theme , index ) => (
625679 < div key = { `t-${ theme . theme_id } -${ request . id } -${ index ^ 10110 } ` } className = "flex items-center gap-2" >
626680 < Checkbox
627681 id = { `theme-${ request . id } -${ theme . theme_id } ` }
628682 checked = { selectedThemes [ request . id ] ?. has ( theme . theme_id ) || false }
629- onCheckedChange = { ( ) => toggleTheme ( request . id , theme . theme_id ) }
683+ onCheckedChange = { ( ) => {
684+ const currentThemes = selectedThemes [ request . id ] || new Set < number > ( ) ;
685+ const newSelectedThemes = { ...selectedThemes } ;
686+ if ( currentThemes . has ( theme . theme_id ) ) {
687+ currentThemes . delete ( theme . theme_id ) ;
688+ if ( currentThemes . size === 0 ) {
689+ toggleRequest ( request . id ) ;
690+ }
691+ } else {
692+ currentThemes . add ( theme . theme_id ) ;
693+ const newSelected = new Set ( selectedRequests ) ;
694+ if ( ! newSelected . has ( request . id ) ) {
695+ newSelected . add ( request . id ) ;
696+ if ( newSelected . size === currentRequests . length ) {
697+ setAllSelected ( true ) ;
698+ }
699+ setSelectedRequests ( newSelected ) ;
700+ }
701+ }
702+ newSelectedThemes [ request . id ] = currentThemes ;
703+ setSelectedThemes ( newSelectedThemes ) ;
704+ } }
630705 />
631706 < label htmlFor = { `theme-${ request . id } -${ theme . theme_id } ` } className = "text-sm flex items-center text-gray-700 dark:text-gray-200" >
632707 { theme . theme_name }
@@ -709,6 +784,19 @@ export default function AdminHome({ requestDatas, refreshFn }: { requestDatas: W
709784 </ CardFooter >
710785 </ Card >
711786 { errorModalView && < ErrorModal error = { errorModalView } onClose = { ( ) => setErrorModalView ( null ) } /> }
787+ { selectedRequestForModal && (
788+ < ThemeSelectModal
789+ isOpen = { themeModalOpen }
790+ onClose = { ( ) => {
791+ setThemeModalOpen ( false ) ;
792+ setSelectedRequestForModal ( null ) ;
793+ } }
794+ word = { selectedRequestForModal . word }
795+ initialSelectedThemes = { selectedRequestForModal . wait_themes || [ ] }
796+ initialSelectedThemeIds = { selectedThemes [ selectedRequestForModal . id ] }
797+ onConfirm = { handleThemeModalConfirm }
798+ />
799+ ) }
712800 </ div >
713801 </ div >
714802 )
0 commit comments