1
- import { type SubscriptionStatus } from '../../../payment/plans' ;
2
- import { updateIsUserAdminById , useQuery , getPaginatedUsers } from 'wasp/client/operations' ;
1
+ import { SubscriptionStatus } from '../../../payment/plans' ;
2
+ import { useQuery , getPaginatedUsers } from 'wasp/client/operations' ;
3
3
import { useState , useEffect } from 'react' ;
4
- import SwitcherOne from './SwitcherOne' ;
4
+ import SwitcherOne from '../../elements/forms /SwitcherOne' ;
5
5
import LoadingSpinner from '../../layout/LoadingSpinner' ;
6
6
import DropdownEditDelete from './DropdownEditDelete' ;
7
+ import { updateIsUserAdminById } from 'wasp/client/operations' ;
8
+ import { type User } from 'wasp/entities' ;
9
+
10
+ function AdminSwitch ( { id, isAdmin } : Pick < User , 'id' | 'isAdmin' > ) {
11
+ return (
12
+ < SwitcherOne isOn = { isAdmin } onChange = { ( value ) => updateIsUserAdminById ( { id : id , isAdmin : value } ) } />
13
+ ) ;
14
+ }
7
15
8
16
const UsersTable = ( ) => {
9
- const [ skip , setskip ] = useState ( 0 ) ;
10
- const [ page , setPage ] = useState ( 1 ) ;
11
- const [ email , setEmail ] = useState < string | undefined > ( undefined ) ;
17
+ const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
18
+ const [ emailFilter , setEmailFilter ] = useState < string | undefined > ( undefined ) ;
12
19
const [ isAdminFilter , setIsAdminFilter ] = useState < boolean | undefined > ( undefined ) ;
13
- const [ statusOptions , setStatusOptions ] = useState < SubscriptionStatus [ ] > ( [ ] ) ;
14
- const { data, isLoading, error } = useQuery ( getPaginatedUsers , {
15
- skip,
16
- emailContains : email ,
17
- isAdmin : isAdminFilter ,
18
- subscriptionStatus : statusOptions ?. length > 0 ? statusOptions : undefined ,
19
- } ) ;
20
+ const [ subscriptionStatusFilter , setSubcriptionStatusFilter ] = useState < Array < SubscriptionStatus | null > > (
21
+ [ ]
22
+ ) ;
20
23
21
- useEffect ( ( ) => {
22
- setPage ( 1 ) ;
23
- } , [ email , statusOptions ] ) ;
24
+ const skipPages = currentPage - 1 ;
24
25
25
- useEffect ( ( ) => {
26
- setskip ( ( page - 1 ) * 10 ) ;
27
- } , [ page ] ) ;
26
+ const { data, isLoading } = useQuery ( getPaginatedUsers , {
27
+ skipPages,
28
+ filter : {
29
+ ...( emailFilter && { emailContains : emailFilter } ) ,
30
+ ...( isAdminFilter !== undefined && { isAdmin : isAdminFilter } ) ,
31
+ ...( subscriptionStatusFilter . length > 0 && { subscriptionStatusIn : subscriptionStatusFilter } ) ,
32
+ } ,
33
+ } ) ;
34
+
35
+ useEffect (
36
+ function backToPageOne ( ) {
37
+ setCurrentPage ( 1 ) ;
38
+ } ,
39
+ [ emailFilter , subscriptionStatusFilter , isAdminFilter ]
40
+ ) ;
28
41
29
42
return (
30
43
< div className = 'flex flex-col gap-4' >
@@ -41,7 +54,8 @@ const UsersTable = () => {
41
54
id = 'email-filter'
42
55
43
56
onChange = { ( e ) => {
44
- setEmail ( e . currentTarget . value ) ;
57
+ const value = e . currentTarget . value ;
58
+ setEmailFilter ( value === '' ? undefined : value ) ;
45
59
} }
46
60
className = 'rounded border border-stroke py-2 px-5 bg-white outline-none transition focus:border-primary active:border-primary disabled:cursor-default disabled:bg-whiter dark:border-form-strokedark dark:bg-form-input dark:focus:border-primary'
47
61
/>
@@ -50,8 +64,8 @@ const UsersTable = () => {
50
64
</ label >
51
65
< div className = 'flex-grow relative z-20 rounded border border-stroke pr-8 outline-none bg-white transition focus:border-primary active:border-primary dark:border-form-strokedark dark:bg-form-input' >
52
66
< div className = 'flex items-center' >
53
- { ! ! statusOptions && statusOptions . length > 0 ? (
54
- statusOptions . map ( ( opt , idx ) => (
67
+ { subscriptionStatusFilter . length > 0 ? (
68
+ subscriptionStatusFilter . map ( ( opt ) => (
55
69
< span
56
70
key = { opt }
57
71
className = 'z-30 flex items-center my-1 mx-2 py-1 px-2 outline-none transition focus:border-primary active:border-primary disabled:cursor-default disabled:bg-whiter dark:border-form-strokedark dark:bg-form-input dark:focus:border-primary'
@@ -60,26 +74,13 @@ const UsersTable = () => {
60
74
< span
61
75
onClick = { ( e ) => {
62
76
e . stopPropagation ( ) ;
63
- setStatusOptions ( ( prevValue ) => {
77
+ setSubcriptionStatusFilter ( ( prevValue ) => {
64
78
return prevValue ?. filter ( ( val ) => val !== opt ) ;
65
79
} ) ;
66
80
} }
67
81
className = 'z-30 cursor-pointer pl-2 hover:text-danger'
68
82
>
69
- < svg
70
- width = '14'
71
- height = '14'
72
- viewBox = '0 0 12 12'
73
- fill = 'none'
74
- xmlns = 'http://www.w3.org/2000/svg'
75
- >
76
- < path
77
- fillRule = 'evenodd'
78
- clipRule = 'evenodd'
79
- d = 'M9.35355 3.35355C9.54882 3.15829 9.54882 2.84171 9.35355 2.64645C9.15829 2.45118 8.84171 2.45118 8.64645 2.64645L6 5.29289L3.35355 2.64645C3.15829 2.45118 2.84171 2.45118 2.64645 2.64645C2.45118 2.84171 2.45118 3.15829 2.64645 3.35355L5.29289 6L2.64645 8.64645C2.45118 8.84171 2.45118 9.15829 2.64645 9.35355C2.84171 9.54882 3.15829 9.54882 3.35355 9.35355L6 6.70711L8.64645 9.35355C8.84171 9.54882 9.15829 9.54882 9.35355 9.35355C9.54882 9.15829 9.54882 8.84171 9.35355 8.64645L6.70711 6L9.35355 3.35355Z'
80
- fill = 'currentColor'
81
- > </ path >
82
- </ svg >
83
+ < XIcon />
83
84
</ span >
84
85
</ span >
85
86
) )
@@ -91,45 +92,37 @@ const UsersTable = () => {
91
92
</ div >
92
93
< select
93
94
onChange = { ( e ) => {
94
- const targetValue = e . target . value === '' ? null : e . target . value ;
95
- setStatusOptions ( ( prevValue ) => {
96
- if ( prevValue ?. includes ( targetValue as SubscriptionStatus ) ) {
97
- return prevValue ?. filter ( ( val ) => val !== targetValue ) ;
98
- } else if ( ! ! prevValue ) {
99
- return [ ...prevValue , targetValue as SubscriptionStatus ] ;
100
- } else {
101
- return prevValue ;
102
- }
103
- } ) ;
95
+ const selectedValue = e . target . value == 'has_not_subscribed' ? null : e . target . value ;
96
+
97
+ console . log ( selectedValue ) ;
98
+ if ( selectedValue === 'clear-all' ) {
99
+ setSubcriptionStatusFilter ( [ ] ) ;
100
+ } else {
101
+ setSubcriptionStatusFilter ( ( prevValue ) => {
102
+ if ( prevValue . includes ( selectedValue as SubscriptionStatus ) ) {
103
+ return prevValue . filter ( ( val ) => val !== selectedValue ) ;
104
+ } else {
105
+ return [ ...prevValue , selectedValue as SubscriptionStatus ] ;
106
+ }
107
+ } ) ;
108
+ }
104
109
} }
105
110
name = 'status-filter'
106
111
id = 'status-filter'
107
112
className = 'absolute top-0 left-0 z-20 h-full w-full bg-white opacity-0'
108
113
>
109
- < option value = '' > Select filters</ option >
110
- { [ 'past_due' , 'canceled' , 'active' , 'deleted' , null ] . map ( ( status ) => {
111
- if ( ! statusOptions . includes ( status as SubscriptionStatus ) ) {
112
- return < option value = { status || '' } > { status ? status : 'has not subscribed' } </ option > ;
113
- }
114
- } ) }
114
+ < option value = 'select-filters' > Select filters</ option >
115
+ { [ ...Object . values ( SubscriptionStatus ) , null ]
116
+ . filter ( ( status ) => ! subscriptionStatusFilter . includes ( status ) )
117
+ . map ( ( status ) => {
118
+ const extendedStatus = status ?? 'has_not_subscribed'
119
+ return < option key = { extendedStatus } value = { extendedStatus } >
120
+ { extendedStatus }
121
+ </ option >
122
+ } ) }
115
123
</ select >
116
124
< span className = 'absolute top-1/2 right-4 z-10 -translate-y-1/2' >
117
- < svg
118
- width = '24'
119
- height = '24'
120
- viewBox = '0 0 24 24'
121
- fill = 'none'
122
- xmlns = 'http://www.w3.org/2000/svg'
123
- >
124
- < g opacity = '0.8' >
125
- < path
126
- fillRule = 'evenodd'
127
- clipRule = 'evenodd'
128
- d = 'M5.29289 8.29289C5.68342 7.90237 6.31658 7.90237 6.70711 8.29289L12 13.5858L17.2929 8.29289C17.6834 7.90237 18.3166 7.90237 18.7071 8.29289C19.0976 8.68342 19.0976 9.31658 18.7071 9.70711L12.7071 15.7071C12.3166 16.0976 11.6834 16.0976 11.2929 15.7071L5.29289 9.70711C4.90237 9.31658 4.90237 8.68342 5.29289 8.29289Z'
129
- fill = '#637381'
130
- > </ path >
131
- </ g >
132
- </ svg >
125
+ < ChevronDownIcon />
133
126
</ span >
134
127
</ div >
135
128
< div className = 'flex items-center gap-2' >
@@ -158,11 +151,14 @@ const UsersTable = () => {
158
151
< span className = 'text-md mr-2 text-black dark:text-white' > page</ span >
159
152
< input
160
153
type = 'number'
161
- value = { page }
162
154
min = { 1 }
155
+ defaultValue = { currentPage }
163
156
max = { data ?. totalPages }
164
157
onChange = { ( e ) => {
165
- setPage ( parseInt ( e . currentTarget . value ) ) ;
158
+ const value = parseInt ( e . currentTarget . value ) ;
159
+ if ( data ?. totalPages && value <= data ?. totalPages && value > 0 ) {
160
+ setCurrentPage ( value ) ;
161
+ }
166
162
} }
167
163
className = 'rounded-md border-1 border-stroke bg-transparent px-4 font-medium outline-none transition focus:border-primary active:border-primary dark:border-form-strokedark dark:bg-form-input dark:focus:border-primary'
168
164
/>
@@ -215,7 +211,7 @@ const UsersTable = () => {
215
211
</ div >
216
212
< div className = 'col-span-1 flex items-center' >
217
213
< div className = 'text-sm text-black dark:text-white' >
218
- < SwitcherOne user = { user } updateIsUserAdminById = { updateIsUserAdminById } />
214
+ < AdminSwitch { ... user } />
219
215
</ div >
220
216
</ div >
221
217
< div className = 'col-span-1 flex items-center' >
@@ -228,4 +224,32 @@ const UsersTable = () => {
228
224
) ;
229
225
} ;
230
226
227
+ function ChevronDownIcon ( ) {
228
+ return (
229
+ < svg width = '24' height = '24' viewBox = '0 0 24 24' fill = 'none' xmlns = 'http://www.w3.org/2000/svg' >
230
+ < g opacity = '0.8' >
231
+ < path
232
+ fillRule = 'evenodd'
233
+ clipRule = 'evenodd'
234
+ d = 'M5.29289 8.29289C5.68342 7.90237 6.31658 7.90237 6.70711 8.29289L12 13.5858L17.2929 8.29289C17.6834 7.90237 18.3166 7.90237 18.7071 8.29289C19.0976 8.68342 19.0976 9.31658 18.7071 9.70711L12.7071 15.7071C12.3166 16.0976 11.6834 16.0976 11.2929 15.7071L5.29289 9.70711C4.90237 9.31658 4.90237 8.68342 5.29289 8.29289Z'
235
+ fill = '#637381'
236
+ > </ path >
237
+ </ g >
238
+ </ svg >
239
+ ) ;
240
+ }
241
+
242
+ function XIcon ( ) {
243
+ return (
244
+ < svg width = '14' height = '14' viewBox = '0 0 12 12' fill = 'none' xmlns = 'http://www.w3.org/2000/svg' >
245
+ < path
246
+ fillRule = 'evenodd'
247
+ clipRule = 'evenodd'
248
+ d = 'M9.35355 3.35355C9.54882 3.15829 9.54882 2.84171 9.35355 2.64645C9.15829 2.45118 8.84171 2.45118 8.64645 2.64645L6 5.29289L3.35355 2.64645C3.15829 2.45118 2.84171 2.45118 2.64645 2.64645C2.45118 2.84171 2.45118 3.15829 2.64645 3.35355L5.29289 6L2.64645 8.64645C2.45118 8.84171 2.45118 9.15829 2.64645 9.35355C2.84171 9.54882 3.15829 9.54882 3.35355 9.35355L6 6.70711L8.64645 9.35355C8.84171 9.54882 9.15829 9.54882 9.35355 9.35355C9.54882 9.15829 9.54882 8.84171 9.35355 8.64645L6.70711 6L9.35355 3.35355Z'
249
+ fill = 'currentColor'
250
+ > </ path >
251
+ </ svg >
252
+ ) ;
253
+ }
254
+
231
255
export default UsersTable ;
0 commit comments