1
- import React , { useState } from 'react' ;
1
+ import React from 'react' ;
2
2
import { useLocation } from 'react-router-dom' ;
3
3
4
- import { useLatestComment } from '@apis/comment/useComment' ;
4
+ import { usePreviewComment } from '@apis/comment/useComment' ;
5
+ import useReportTopic from '@apis/topic/useReportTopic' ;
5
6
import useVoteTopic from '@apis/topic/useVoteTopic' ;
7
+ import { Col , Row } from '@components/commons/Flex/Flex' ;
6
8
import BackButton from '@components/commons/Header/BackButton/BackButton' ;
7
9
import Layout from '@components/commons/Layout/Layout' ;
10
+ import ActionModalButton from '@components/commons/Modal/ActionModalButton' ;
8
11
import ProfileImg from '@components/commons/ProfileImg/ProfileImg' ;
9
12
import Text from '@components/commons/Text/Text' ;
13
+ import { Toast } from '@components/commons/Toast/Toast' ;
10
14
import ChoiceSlider from '@components/Home/ChoiceSlider/ChoiceSlider' ;
11
15
import CommentBox from '@components/Home/CommentBox/CommentBox' ;
12
16
import Timer from '@components/Home/Timer/Timer' ;
13
17
import {
14
18
TopicCardContainer ,
15
- BestTopicCotainer ,
16
19
TopicContainer ,
17
20
Topic ,
18
- UserInfoContainer ,
19
21
SelectTextContainer ,
22
+ TopicFooter ,
20
23
} from '@components/Home/TopicCard/TopicCard.styles' ;
21
24
import TopicComments from '@components/Home/TopicComments/TopicComments' ;
22
25
import VoteCompletion from '@components/Home/VoteCompletion/VoteCompletion' ;
23
26
import useBottomSheet from '@hooks/useBottomSheet/useBottomSheet' ;
24
- import { LatestComment } from '@interfaces/api/comment ' ;
27
+ import useModal from '@hooks/useModal/useModal ' ;
25
28
import { Choice , TopicResponse } from '@interfaces/api/topic' ;
26
29
30
+ import { useAuthStore } from '@store/auth' ;
31
+
27
32
import { colors } from '@styles/theme' ;
28
33
29
- import { LeftDoubleArrowIcon , RightDoubleArrowIcon } from '@icons/index' ;
34
+ import {
35
+ HideIcon ,
36
+ LeftDoubleArrowIcon ,
37
+ MeatballIcon ,
38
+ RefreshIcon ,
39
+ ReportIcon ,
40
+ RightDoubleArrowIcon ,
41
+ } from '@icons/index' ;
42
+
43
+ import { ResponseError } from '@apis/fetch' ;
30
44
31
45
interface BTopicProps {
32
46
topic : TopicResponse ;
33
47
}
34
48
35
49
const BTopic = ( ) => {
36
50
const location = useLocation ( ) ;
37
- const { topic } = location . state as BTopicProps ;
38
51
const { BottomSheet : CommentSheet , toggleSheet } = useBottomSheet ( { } ) ;
39
- const voteMutation = useVoteTopic ( ) ;
40
- const { data : latestCommentData , isSuccess } = useLatestComment (
52
+ const { Modal, toggleModal } = useModal ( 'action' ) ;
53
+ const memberId = useAuthStore ( ( store ) => store . memberId ) ;
54
+ const { topic } = location . state as BTopicProps ;
55
+ const isMyTopic = topic . author . id === memberId ;
56
+
57
+ const { data : previewComment } = usePreviewComment (
41
58
topic . topicId ,
42
- topic . selectedOption !== null
59
+ topic . selectedOption !== null || isMyTopic
43
60
) ;
44
- const [ latestComment , setLatestComment ] = useState < LatestComment | undefined > ( ) ;
61
+ const voteMutation = useVoteTopic ( ) ;
62
+ const reportMutation = useReportTopic ( topic . topicId ) ;
45
63
46
64
const handleVote = async ( choiceOption : Choice [ 'choiceOption' ] ) => {
47
- const data = await voteMutation . mutateAsync ( {
48
- topicId : topic . topicId ,
49
- choiceOption : choiceOption ,
50
- votedAt : new Date ( ) . getTime ( ) / 1000 ,
51
- } ) ;
52
- setLatestComment ( data . latestComment ) ;
53
- return true ;
65
+ try {
66
+ await voteMutation . mutateAsync ( {
67
+ topicId : topic . topicId ,
68
+ choiceOption : choiceOption ,
69
+ votedAt : new Date ( ) . getTime ( ) / 1000 ,
70
+ } ) ;
71
+ return true ;
72
+ } catch ( error ) {
73
+ if ( error instanceof ResponseError ) {
74
+ if ( error . errorData . abCode === 'VOTED_BY_AUTHOR' ) {
75
+ Toast . error ( '토픽을 작성한 사람은 투표할 수 없어요' ) ;
76
+ }
77
+ }
78
+ return false ;
79
+ }
54
80
} ;
55
81
56
82
const handleCommentBoxClick = ( ) => {
57
- if ( topic . selectedOption !== null ) {
83
+ if ( isMyTopic || topic . selectedOption !== null ) {
58
84
toggleSheet ( ) ;
59
85
}
60
86
} ;
61
87
88
+ const handleTopicOptionClick = ( ) => {
89
+ toggleModal ( ) ;
90
+ } ;
91
+
92
+ const handleHideTopic = ( ) => { } ;
93
+
94
+ const handleReportTopic = ( ) => {
95
+ reportMutation . mutate ( ) ;
96
+ toggleModal ( ) ;
97
+ } ;
98
+
99
+ const handleRevoteTopic = ( ) => {
100
+ throw new Error ( '투표 다시하기 기능을 사용할 수 없습니다.' ) ;
101
+ } ;
102
+
62
103
return (
63
104
< React . Fragment >
64
105
< Layout hasBottomNavigation = { false } HeaderLeft = { < BackButton /> } >
65
106
< TopicCardContainer >
107
+ < Text size = { 18 } color = { colors . purple } >
108
+ { topic . keyword ?. keywordName }
109
+ </ Text >
66
110
< TopicContainer >
67
111
< Topic style = { { width : 170 , wordBreak : 'keep-all' , overflowWrap : 'break-word' } } >
68
112
{ topic . topicTitle }
69
113
</ Topic >
70
114
</ TopicContainer >
71
- < UserInfoContainer >
72
- < ProfileImg url = { topic . author . profileImageUrl } size = { 20 } />
73
- < Text size = { 14 } weight = { 'regular' } color = { colors . white_60 } >
74
- { topic . author . nickname }
75
- </ Text >
76
- </ UserInfoContainer >
77
115
{ topic . selectedOption !== null ? (
78
116
< VoteCompletion
79
117
side = { topic . selectedOption === 'CHOICE_A' ? 'A' : 'B' }
@@ -94,21 +132,51 @@ const BTopic = () => {
94
132
</ Text >
95
133
< RightDoubleArrowIcon />
96
134
</ SelectTextContainer >
97
- < CommentBox
98
- side = { topic . topicSide }
99
- hasVoted = { topic . selectedOption !== null }
100
- topicId = { topic . topicId }
101
- commentCount = { 0 }
102
- voteCount = { 0 }
103
- keyword = { topic . keyword }
104
- latestComment = { latestComment }
105
- onClick = { handleCommentBoxClick }
106
- />
135
+ < TopicFooter >
136
+ < Row >
137
+ < Row gap = { 8 } alignItems = "center" >
138
+ < ProfileImg url = { topic . author . profileImageUrl } size = { '22px' } />
139
+ < Text size = { 13 } color = { colors . white_60 } >
140
+ { topic . author . nickname }
141
+ </ Text >
142
+ </ Row >
143
+ < button onClick = { handleTopicOptionClick } >
144
+ < MeatballIcon fill = { colors . white_60 } />
145
+ </ button >
146
+ </ Row >
147
+ < CommentBox
148
+ hasVoted = { topic . selectedOption !== null || isMyTopic }
149
+ commentCount = { topic . commentCount }
150
+ voteCount = { topic . voteCount }
151
+ previewComment = { previewComment }
152
+ onClick = { handleCommentBoxClick }
153
+ isBig = { true }
154
+ />
155
+ </ TopicFooter >
107
156
</ TopicCardContainer >
108
157
</ Layout >
109
158
< CommentSheet >
110
159
< TopicComments topic = { topic } />
111
160
</ CommentSheet >
161
+ < Modal >
162
+ < Col padding = { '36px 24px' } gap = { 20 } >
163
+ < ActionModalButton
164
+ handleClick = { handleHideTopic }
165
+ Icon = { ( ) => < HideIcon /> }
166
+ label = { '이런 토픽은 안볼래요' }
167
+ />
168
+ < ActionModalButton
169
+ handleClick = { handleReportTopic }
170
+ Icon = { ( ) => < ReportIcon /> }
171
+ label = { '신고하기' }
172
+ />
173
+ < ActionModalButton
174
+ handleClick = { handleRevoteTopic }
175
+ Icon = { ( ) => < RefreshIcon /> }
176
+ label = { '투표 다시 하기' }
177
+ />
178
+ </ Col >
179
+ </ Modal >
112
180
</ React . Fragment >
113
181
) ;
114
182
} ;
0 commit comments