1
1
import axios from "axios"
2
2
import Head from "next/head"
3
3
import Image from "next/image"
4
- import { useCallback , useEffect , useState } from "react"
4
+ import { useEffect , useState } from "react"
5
5
import { useZuAuth } from "zuauth"
6
+ import { EdDSATicketFieldsToReveal } from "@pcd/zk-eddsa-event-ticket-pcd"
7
+ import Toggle from "@/components/Toggle"
8
+ import DisplayRevealedFields from "@/components/DisplayRevealedFields"
9
+ import DeveloperPanel from "@/components/DeveloperPanel"
10
+
11
+ const defaultSetOfTicketFieldsToReveal : EdDSATicketFieldsToReveal = {
12
+ revealTicketId : false ,
13
+ revealEventId : true ,
14
+ revealProductId : true ,
15
+ revealTimestampConsumed : false ,
16
+ revealTimestampSigned : false ,
17
+ revealAttendeeSemaphoreId : false ,
18
+ revealIsConsumed : false ,
19
+ revealIsRevoked : false ,
20
+ revealTicketCategory : false ,
21
+ revealAttendeeEmail : true ,
22
+ revealAttendeeName : false
23
+ }
6
24
7
25
export default function Home ( ) {
8
26
const { authenticate, pcd } = useZuAuth ( )
9
27
const [ user , setUser ] = useState < any > ( )
28
+ const [ developerMode , setDeveloperMode ] = useState ( false ) ;
29
+ const [ ticketFieldsToReveal , setTicketFieldsToReveal ] = useState < EdDSATicketFieldsToReveal > ( defaultSetOfTicketFieldsToReveal ) ;
10
30
11
31
// Every time the page loads, an API call is made to check if the
12
- // user is logged in and, if they are, to retrieve the current session's user data.
32
+ // user is logged in and, if they are, to retrieve the current session's user data
33
+ // and local storage data (to guarantee consistency across refreshes).
13
34
useEffect ( ( ) => {
14
- ; ( async function ( ) {
35
+ ; ( async function ( ) {
15
36
const { data } = await axios . get ( "/api/user" )
16
-
17
37
setUser ( data . user )
38
+
39
+ const fields = localStorage . getItem ( "ticketFieldsToReveal" ) ;
40
+ const mode = localStorage . getItem ( "developerMode" )
41
+
42
+ if ( fields ) setTicketFieldsToReveal ( JSON . parse ( fields ) ) ;
43
+ if ( mode ) setDeveloperMode ( JSON . parse ( mode ) )
18
44
} ) ( )
19
45
} , [ ] )
20
46
47
+ // When the popup is closed and the user successfully
48
+ // generates the PCD, they can login.
49
+ useEffect ( ( ) => {
50
+ ; ( async function ( ) {
51
+ if ( pcd ) {
52
+ const { data } = await axios . post ( "/api/login" , { pcd } )
53
+ setUser ( data . user )
54
+ }
55
+ } ) ( )
56
+ } , [ pcd ] )
57
+
21
58
// Before logging in, the PCD is generated with the nonce from the
22
59
// session created on the server.
23
60
// Note that the nonce is used as a watermark for the PCD. Therefore,
24
61
// it will be necessary on the server side to verify that the PCD's
25
62
// watermark matches the session nonce.
26
- const login = useCallback ( async ( ) => {
63
+ const login = async ( ) => {
27
64
const { data } = await axios . post ( "/api/nonce" )
28
65
29
66
authenticate (
30
- {
31
- revealAttendeeEmail : true ,
32
- revealEventId : true ,
33
- revealProductId : true
34
- } ,
67
+ developerMode ? { ...ticketFieldsToReveal } : { ...defaultSetOfTicketFieldsToReveal } ,
35
68
data . nonce
36
69
)
37
- } , [ authenticate ] )
70
+ }
38
71
39
- // When the popup is closed and the user successfully
40
- // generates the PCD, they can login.
41
- useEffect ( ( ) => {
42
- ; ( async function ( ) {
43
- if ( pcd ) {
44
- const { data } = await axios . post ( "/api/login" , { pcd } )
72
+ // Logging out simply clears the active session, local storage and state.
73
+ const logout = async ( ) => {
74
+ await axios . post ( "/api/logout" )
75
+ setUser ( false )
45
76
46
- setUser ( data . user )
77
+ localStorage . removeItem ( "ticketFieldsToReveal" )
78
+ localStorage . removeItem ( "developerMode" )
79
+
80
+ setTicketFieldsToReveal ( defaultSetOfTicketFieldsToReveal )
81
+ setDeveloperMode ( false )
82
+ }
83
+
84
+ const handleToggleField = ( fieldToReveal : keyof EdDSATicketFieldsToReveal ) => {
85
+ setTicketFieldsToReveal ( prevState => {
86
+ const fieldsToReveal = {
87
+ ...prevState ,
88
+ [ fieldToReveal ] : ! prevState [ fieldToReveal ]
89
+ } ;
90
+
91
+ localStorage . setItem ( "ticketFieldsToReveal" , JSON . stringify ( fieldsToReveal ) ) ;
92
+ return fieldsToReveal ;
93
+ } ) ;
94
+ } ;
95
+
96
+ const handleSetDeveloperMode = ( ) => {
97
+ setDeveloperMode ( value => {
98
+ const newValue = ! value
99
+
100
+ if ( newValue ) {
101
+ localStorage . setItem ( "ticketFieldsToReveal" , JSON . stringify ( ticketFieldsToReveal ) ) ;
102
+ } else {
103
+ setTicketFieldsToReveal ( defaultSetOfTicketFieldsToReveal )
104
+ localStorage . removeItem ( "ticketFieldsToReveal" )
47
105
}
48
- } ) ( )
49
- } , [ pcd ] )
50
106
51
- // Logging out simply clears the active session.
52
- const logout = useCallback ( async ( ) => {
53
- await axios . post ( "/api/logout" )
107
+ localStorage . setItem ( "developerMode" , JSON . stringify ( newValue ) )
54
108
55
- setUser ( false )
56
- } , [ ] )
109
+ return newValue
110
+ } )
111
+ }
57
112
58
113
return (
59
114
< main className = "flex min-h-screen flex-col items-center justify-center p-12 pb-32" >
60
115
< Head >
61
116
< title > ZuAuth Example</ title >
62
117
< link rel = "icon" type = "image/x-icon" href = "/favicon.ico" />
63
118
</ Head >
64
- < div className = "max-w-xl w-full" >
119
+ < div className = "max-w-4xl w-full mx-auto " >
65
120
< div className = "flex justify-center" >
66
121
< Image width = "150" height = "150" alt = "ZuAuth Icon" src = "/light-icon.png" />
67
122
</ div >
68
123
69
- < h1 className = "my-8 text-2xl font-semibold text-center" > Login</ h1 >
124
+ < h1 className = "my-4 text-2xl font-semibold text-center" >
125
+ ZuAuth Example
126
+ </ h1 >
70
127
71
- < p className = "text-justify" >
128
+ < p className = "my-8 text-justify" >
72
129
This demo illustrates how the{ " " }
73
130
< a
74
131
className = "text-blue-600 visited:text-purple-600"
@@ -89,7 +146,8 @@ export default function Home() {
89
146
>
90
147
IronSession
91
148
</ a >
92
- . Check the{ " " }
149
+ . You can choose which ticket fields to reveal during the authentication process by enabling the Developer Mode.
150
+ We kindly invite you to check the{ " " }
93
151
< a
94
152
className = "text-blue-600 visited:text-purple-600"
95
153
href = "https://github.com/cedoor/zuauth#readme"
@@ -109,14 +167,31 @@ export default function Home() {
109
167
</ button >
110
168
</ div >
111
169
112
- { user && < div className = "text-center" > User: { user . attendeeEmail } </ div > }
170
+ { ! user &&
171
+ < >
172
+ < div className = "my-8 text-center flex flex-col items-center" >
173
+ < p className = "mt-2 text-center" > Developer Mode</ p >
174
+ < Toggle
175
+ checked = { developerMode }
176
+ onToggle = { handleSetDeveloperMode }
177
+ />
178
+ </ div >
113
179
114
- < div className = "mt-10 text-center" >
115
- < a href = "https://github.com/cedoor/zuauth" className = "underline" target = "_blank" >
116
- Github
117
- </ a >
118
- </ div >
180
+ < div style = { { height : "300px" } } >
181
+ { developerMode && (
182
+ < DeveloperPanel
183
+ fieldsToReveal = { ticketFieldsToReveal }
184
+ onToggleField = { handleToggleField }
185
+ disabled = { ! ! user }
186
+ />
187
+ ) }
188
+ </ div >
189
+ </ >
190
+ }
191
+
192
+ { user && < div className = "my-8 text-center" >
193
+ < DisplayRevealedFields user = { user } revealedFields = { ticketFieldsToReveal } /> </ div > }
119
194
</ div >
120
- </ main >
195
+ </ main >
121
196
)
122
- }
197
+ }
0 commit comments