1
1
import React , { useEffect , useState } from 'react'
2
- import { StyleSheet , Text , View } from 'react-native'
2
+ import { Modal , Pressable , StyleSheet , Text , View } from 'react-native'
3
3
import { useNavigation } from '@react-navigation/native'
4
+ import { Feather } from '@expo/vector-icons'
5
+ import Toast from 'react-native-toast-message'
6
+ import { useMutation , useQueryCache } from 'react-query'
4
7
5
8
import Emojis from './Emojis'
6
9
import relativeTime from 'src/utils/relativeTime'
10
+ import client from 'src/api/client'
11
+ import { useSelector } from 'react-redux'
12
+
13
+ const fireMutation = async ( {
14
+ id,
15
+ type,
16
+ stateKey
17
+ } : {
18
+ id : string
19
+ type : 'mute' | 'block' | 'domain_blocks' | 'reports'
20
+ stateKey ?: 'muting' | 'blocking'
21
+ } ) => {
22
+ let res
23
+ switch ( type ) {
24
+ case 'mute' :
25
+ case 'block' :
26
+ res = await client ( {
27
+ method : 'post' ,
28
+ instance : 'local' ,
29
+ endpoint : `accounts/${ id } /${ type } `
30
+ } )
31
+
32
+ if ( res . body [ stateKey ] === true ) {
33
+ Toast . show ( {
34
+ type : 'success' ,
35
+ position : 'bottom' ,
36
+ text1 : '功能成功' ,
37
+ visibilityTime : 2000 ,
38
+ autoHide : true ,
39
+ bottomOffset : 65
40
+ } )
41
+ return Promise . resolve ( )
42
+ } else {
43
+ Toast . show ( {
44
+ type : 'error' ,
45
+ position : 'bottom' ,
46
+ text1 : '请重试' ,
47
+ autoHide : false ,
48
+ bottomOffset : 65
49
+ } )
50
+ return Promise . reject ( )
51
+ }
52
+ break
53
+ case 'domain_blocks' :
54
+ res = await client ( {
55
+ method : 'post' ,
56
+ instance : 'local' ,
57
+ endpoint : `domain_blocks` ,
58
+ query : {
59
+ domain : id || ''
60
+ }
61
+ } )
62
+
63
+ if ( ! res . body . error ) {
64
+ Toast . show ( {
65
+ type : 'success' ,
66
+ position : 'bottom' ,
67
+ text1 : '隐藏域名成功' ,
68
+ visibilityTime : 2000 ,
69
+ autoHide : true ,
70
+ bottomOffset : 65
71
+ } )
72
+ return Promise . resolve ( )
73
+ } else {
74
+ Toast . show ( {
75
+ type : 'error' ,
76
+ position : 'bottom' ,
77
+ text1 : '隐藏域名失败,请重试' ,
78
+ autoHide : false ,
79
+ bottomOffset : 65
80
+ } )
81
+ return Promise . reject ( )
82
+ }
83
+ break
84
+ // case 'reports':
85
+ // res = await client({
86
+ // method: 'post',
87
+ // instance: 'local',
88
+ // endpoint: `reports`,
89
+ // query: {
90
+ // domain: id || ''
91
+ // }
92
+ // })
93
+
94
+ // if (!res.body.error) {
95
+ // Toast.show({
96
+ // type: 'success',
97
+ // position: 'bottom',
98
+ // text1: '隐藏域名成功',
99
+ // visibilityTime: 2000,
100
+ // autoHide: true,
101
+ // bottomOffset: 65
102
+ // })
103
+ // return Promise.resolve()
104
+ // } else {
105
+ // Toast.show({
106
+ // type: 'error',
107
+ // position: 'bottom',
108
+ // text1: '隐藏域名失败,请重试',
109
+ // autoHide: false,
110
+ // bottomOffset: 65
111
+ // })
112
+ // return Promise.reject()
113
+ // }
114
+ // break
115
+ }
116
+ }
7
117
8
118
export interface Props {
119
+ queryKey : store . QueryKey
120
+ accountId : string
121
+ domain : string
9
122
name : string
10
123
emojis ?: mastodon . Emoji [ ]
11
124
account : string
@@ -14,14 +127,55 @@ export interface Props {
14
127
}
15
128
16
129
const Header : React . FC < Props > = ( {
130
+ queryKey,
131
+ accountId,
132
+ domain,
17
133
name,
18
134
emojis,
19
135
account,
20
136
created_at,
21
137
application
22
138
} ) => {
23
139
const navigation = useNavigation ( )
140
+ const localAccountId = useSelector ( state => state . instanceInfo . localAccountId )
141
+ const localDomain = useSelector ( state => state . instanceInfo . local )
24
142
const [ since , setSince ] = useState ( relativeTime ( created_at ) )
143
+ const [ modalVisible , setModalVisible ] = useState ( false )
144
+
145
+ const queryCache = useQueryCache ( )
146
+ const [ mutateAction ] = useMutation ( fireMutation , {
147
+ onMutate : ( ) => {
148
+ queryCache . cancelQueries ( queryKey )
149
+ const prevData = queryCache . getQueryData ( queryKey )
150
+ return prevData
151
+ } ,
152
+ onSuccess : ( newData , params ) => {
153
+ if ( params . type === 'domain_blocks' ) {
154
+ console . log ( 'clearing cache' )
155
+ queryCache . invalidateQueries ( [ 'Following' , { page : 'Following' } ] )
156
+ }
157
+ // queryCache.setQueryData(queryKey, (oldData: any) => {
158
+ // oldData &&
159
+ // oldData.map((paging: any) => {
160
+ // paging.toots.map(
161
+ // (status: mastodon.Status | mastodon.Notification, i: number) => {
162
+ // if (status.id === newData.id) {
163
+ // paging.toots[i] = newData
164
+ // }
165
+ // }
166
+ // )
167
+ // })
168
+ // return oldData
169
+ // })
170
+ return Promise . resolve ( )
171
+ } ,
172
+ onError : ( err , variables , prevData ) => {
173
+ queryCache . setQueryData ( queryKey , prevData )
174
+ } ,
175
+ onSettled : ( ) => {
176
+ queryCache . invalidateQueries ( queryKey )
177
+ }
178
+ } )
25
179
26
180
// causing full re-render
27
181
useEffect ( ( ) => {
@@ -32,18 +186,26 @@ const Header: React.FC<Props> = ({
32
186
33
187
return (
34
188
< View >
35
- < View style = { styles . names } >
189
+ < View style = { styles . nameAndAction } >
36
190
< View style = { styles . name } >
37
191
{ emojis ? (
38
192
< Emojis content = { name } emojis = { emojis } dimension = { 14 } />
39
193
) : (
40
- < Text > { name } </ Text >
194
+ < Text numberOfLines = { 1 } > { name } </ Text >
41
195
) }
42
196
</ View >
43
- < Text style = { styles . account } numberOfLines = { 1 } >
44
- @{ account }
45
- </ Text >
197
+ { accountId !== localAccountId && domain !== localDomain && (
198
+ < Pressable
199
+ style = { styles . action }
200
+ onPress = { ( ) => setModalVisible ( true ) }
201
+ >
202
+ < Feather name = 'more-horizontal' color = 'gray' />
203
+ </ Pressable >
204
+ ) }
46
205
</ View >
206
+ < Text style = { styles . account } numberOfLines = { 1 } >
207
+ @{ account }
208
+ </ Text >
47
209
< View style = { styles . meta } >
48
210
< View >
49
211
< Text style = { styles . created_at } > { since } </ Text >
@@ -63,21 +225,98 @@ const Header: React.FC<Props> = ({
63
225
</ View >
64
226
) }
65
227
</ View >
228
+
229
+ < Modal
230
+ animationType = 'fade'
231
+ presentationStyle = 'overFullScreen'
232
+ transparent
233
+ visible = { modalVisible }
234
+ >
235
+ < Pressable
236
+ style = { styles . modalBackground }
237
+ onPress = { ( ) => setModalVisible ( false ) }
238
+ >
239
+ < View style = { styles . modalSheet } >
240
+ { accountId !== localAccountId && (
241
+ < Pressable
242
+ onPress = { ( ) => {
243
+ setModalVisible ( false )
244
+ mutateAction ( {
245
+ id : accountId ,
246
+ type : 'mute' ,
247
+ stateKey : 'muting'
248
+ } )
249
+ } }
250
+ >
251
+ < Text > 静音用户</ Text >
252
+ </ Pressable >
253
+ ) }
254
+ { accountId !== localAccountId && (
255
+ < Pressable
256
+ onPress = { ( ) => {
257
+ setModalVisible ( false )
258
+ mutateAction ( {
259
+ id : accountId ,
260
+ type : 'block' ,
261
+ stateKey : 'blocking'
262
+ } )
263
+ } }
264
+ >
265
+ < Text > 屏蔽用户</ Text >
266
+ </ Pressable >
267
+ ) }
268
+ { domain !== localDomain && (
269
+ < Pressable
270
+ onPress = { ( ) => {
271
+ setModalVisible ( false )
272
+ mutateAction ( {
273
+ id : domain ,
274
+ type : 'domain_blocks'
275
+ } )
276
+ } }
277
+ >
278
+ < Text > 屏蔽域名</ Text >
279
+ </ Pressable >
280
+ ) }
281
+ { accountId !== localAccountId && (
282
+ < Pressable
283
+ onPress = { ( ) => {
284
+ setModalVisible ( false )
285
+ mutateAction ( {
286
+ id : accountId ,
287
+ type : 'reports'
288
+ } )
289
+ } }
290
+ >
291
+ < Text > 举报用户</ Text >
292
+ </ Pressable >
293
+ ) }
294
+ </ View >
295
+ </ Pressable >
296
+ </ Modal >
66
297
</ View >
67
298
)
68
299
}
69
300
70
301
const styles = StyleSheet . create ( {
71
- names : {
72
- flexDirection : 'row'
302
+ nameAndAction : {
303
+ width : '100%' ,
304
+ flexDirection : 'row' ,
305
+ justifyContent : 'space-between'
73
306
} ,
74
307
name : {
75
308
flexDirection : 'row' ,
76
- marginRight : 8
309
+ marginRight : 8 ,
310
+ fontWeight : '900'
311
+ } ,
312
+ action : {
313
+ width : 14 ,
314
+ height : 14 ,
315
+ marginLeft : 8
77
316
} ,
78
317
account : {
79
- fontSize : 12 ,
80
- lineHeight : 14
318
+ lineHeight : 14 ,
319
+ flexShrink : 1
81
320
} ,
82
321
meta : {
83
322
flexDirection : 'row'
@@ -92,6 +331,21 @@ const styles = StyleSheet.create({
92
331
application : {
93
332
fontSize : 12 ,
94
333
lineHeight : 11
334
+ } ,
335
+ modalBackground : {
336
+ width : '100%' ,
337
+ height : '100%' ,
338
+ backgroundColor : 'rgba(0, 0, 0, 0.75)' ,
339
+ flex : 1 ,
340
+ flexDirection : 'row' ,
341
+ justifyContent : 'center' ,
342
+ alignItems : 'flex-end'
343
+ } ,
344
+ modalSheet : {
345
+ width : '100%' ,
346
+ height : '50%' ,
347
+ backgroundColor : 'white' ,
348
+ flex : 1
95
349
}
96
350
} )
97
351
0 commit comments