@@ -102,7 +102,6 @@ public function backToSetup(): void
102
102
103
103
public function confirmTwoFactor (ConfirmTwoFactorAuthentication $confirmTwoFactorAuthentication ): void
104
104
{
105
- dd ($this );
106
105
$this -> validate ();
107
106
$confirmTwoFactorAuthentication (auth ()-> user (), $this -> authCode );
108
107
$this -> twoFactorEnabled = true ;
@@ -152,6 +151,13 @@ public function toggleRecoveryCodes(): void
152
151
$this -> showRecoveryCodes = ! $this -> showRecoveryCodes ;
153
152
}
154
153
154
+ public function fetchRecoveryCodes (): void
155
+ {
156
+ if (! $this -> recoveryCodes ) {
157
+ $this -> loadRecoveryCodes ();
158
+ }
159
+ }
160
+
155
161
private function loadRecoveryCodes (): void
156
162
{
157
163
$this -> recoveryCodes = json_decode (decrypt (auth ()-> user ()-> two_factor_recovery_codes ), true );
@@ -162,14 +168,15 @@ private function loadRecoveryCodes(): void
162
168
@include (' partials.settings-heading' )
163
169
<x-settings .layout :heading =" __('Two Factor Authentication')"
164
170
:subheading =" __('Manage your two-factor authentication settings')" >
165
- <div class =" flex flex-col w-full mx-auto text-sm space-y-6" >
171
+ <div class =" flex flex-col w-full mx-auto text-sm space-y-6" wire:cloak >
166
172
@if (! $twoFactorEnabled )
167
173
<div class =" relative flex flex-col items-start rounded-xl justify-start space-y-4" >
168
174
<flux:badge color =" red" >Disabled</flux:badge >
169
- <p class = " text-stone-500 dark:text-stone-400 " >
175
+ <flux:text variant = " subtle " >
170
176
When you enable two-factor authentication, you will be prompted for a secure pin during login.
171
177
This pin can be retrieved from a TOTP-supported application on your phone.
172
- </p >
178
+ </flux:text >
179
+
173
180
<div class =" w-auto" >
174
181
<flux:button
175
182
variant =" primary"
@@ -188,78 +195,93 @@ private function loadRecoveryCodes(): void
188
195
<div >
189
196
<flux:badge color =" green" >Enabled</flux:badge >
190
197
</div >
191
- <p class = " text-stone-500 dark :text-stone-400 " >
198
+ <flux :text >
192
199
With two-factor authentication enabled, you will be prompted for a secure, random pin during
193
200
login,
194
201
which you can retrieve from the TOTP-supported application on your phone.
195
- </p >
196
-
197
- <div >
198
- <flux:callout icon =" lock-keyhole-open" color =" gray" class =" rounded-b-none" >
199
- <flux:callout .heading >2FA Recovery Codes</flux:callout .heading >
200
- <flux:callout .text >
202
+ </flux:text >
203
+
204
+ <div
205
+ class =" flex flex-col gap-6 rounded-xl border border-zinc-200 dark:border-white/10 py-6 shadow-sm"
206
+ x-data =" { showRecoveryCodes: {{ $showRecoveryCodes ? ' true' : ' false' } } }" >
207
+ <div class =" flex flex-col gap-1.5 px-6" >
208
+ <div class =" flex gap-2" >
209
+ <flux:icon name =" lock-keyhole" class =" size-4" />
210
+ <flux:heading >
211
+ 2FA Recovery Codes
212
+ </flux:heading >
213
+ </div >
214
+ <flux:text variant =" subtle" >
201
215
Recovery codes let you regain access if you lose your 2FA device. Store them in a
202
- secure
203
- password manager.
204
- </flux:callout .text >
205
- </flux:callout >
206
- <div
207
- class =" bg-stone-100 dark:bg-stone-800 rounded-b-xl border-t-0 border border-stone-200 dark:border-stone-700 text-sm" >
216
+ secure password manager.
217
+ </flux:text >
218
+ </div >
219
+ <div class =" px-6" >
220
+ <div class =" flex flex-col gap-3 select-none sm:flex-row sm:items-center sm:justify-between" >
221
+ <flux:button
222
+ x-show =" !showRecoveryCodes"
223
+ icon =" eye"
224
+ variant =" primary"
225
+ @click =" showRecoveryCodes = true"
226
+ aria-expanded =" false"
227
+ aria-controls =" recovery-codes-section"
228
+ >
229
+ View Recovery Codes
230
+ </flux:button >
231
+ <flux:button
232
+ x-show =" showRecoveryCodes"
233
+ icon =" eye-off"
234
+ variant =" primary"
235
+ @click =" showRecoveryCodes = false"
236
+ aria-expanded =" true"
237
+ aria-controls =" recovery-codes-section"
238
+ >
239
+ Hide Recovery Codes
240
+ </flux:button >
241
+ <flux:button
242
+ x-show =" showRecoveryCodes"
243
+ icon =" arrow-path"
244
+ variant =" filled"
245
+ wire:click =" regenerateRecoveryCodes"
246
+ aria-describedby =" regenerate-warning"
247
+ >
248
+ <span wire:loading.remove
249
+ wire:target =" regenerateRecoveryCodes" >{{ __ (' Regenerate Codes' ) } } </span >
250
+ <span wire:loading
251
+ wire:target =" regenerateRecoveryCodes" >{{ __ (' Regenerating...' ) } } </span >
252
+ </flux:button >
253
+ </div >
208
254
<div
209
- wire:click =" toggleRecoveryCodes"
210
- class =" h-10 group cursor-pointer flex items-center select-none justify-between px-5 text-xs"
255
+ x-show =" showRecoveryCodes"
256
+ x-transition
257
+ id =" recovery-codes-section"
258
+ class =" relative overflow-hidden"
259
+ x-bind:aria-hidden =" !showRecoveryCodes"
211
260
>
212
- <div class =" relative transition-opacity duration-200"
213
- @class ([
214
- ' opacity-40 group-hover:opacity-60' => ! $showRecoveryCodes ,
215
- ' opacity-60' => $showRecoveryCodes
216
- ] )>
217
- @if (! $showRecoveryCodes )
218
- <span class =" flex items-center space-x-1" >
219
- <flux:icon .eye class =" size-4" />
220
- <span >View My Recovery Codes</span >
221
- </span >
222
- @else
223
- <span class =" flex items-center space-x-1" >
224
- <flux:icon .eye-off class =" size-4" />
225
- <span >Hide Recovery Codes</span >
226
- </span >
227
- @endif
228
- </div >
229
- @if ($showRecoveryCodes )
230
- <flux:button
231
- size =" xs"
232
- variant =" filled"
233
- class =" text-stone-600"
234
- wire:click.stop =" regenerateRecoveryCodes"
235
- wire:loading.attr =" disabled"
236
- wire:target =" regenerateRecoveryCodes"
237
- >
238
- <span wire:loading.remove
239
- wire:target =" regenerateRecoveryCodes" >{{ __ (' Regenerate Codes' ) } } </span >
240
- <span wire:loading
241
- wire:target =" regenerateRecoveryCodes" >{{ __ (' Regenerating...' ) } } </span >
242
- </flux:button >
243
- @endif
244
- </div >
245
- @if ($showRecoveryCodes )
246
- <div class =" relative" >
261
+ <div class =" mt-3 space-y-3" >
247
262
<div
248
- class =" grid max-w-xl gap-1 px-4 py-4 font-mono text-sm bg-stone-200 dark:bg-stone-900 dark:text-stone-100" >
249
- @forelse ($recoveryCodes as $code )
250
- <div >{{ $code } } </div >
251
- @empty
252
- <div class =" text-stone-500" >No recovery codes available</div >
253
- @endforelse
263
+ class =" grid gap-1 rounded-lg p-4 bg-zinc-200 dark:bg-white/10 font-mono text-sm selection:bg-accent selection:text-accent-foreground"
264
+ role =" list" aria-label =" Recovery codes" >
265
+
266
+ @foreach ($recoveryCodes as $index => $code )
267
+ <div role =" listitem"
268
+ wire:loading
269
+ class =" animate-pulse h-4 opacity-20 rounded bg-zinc-200/80 dark:bg-white/30"
270
+ ></div >
271
+ <div role =" listitem" wire:loading.class =" hidden"
272
+ class =" select-text" >{{ $code } } </div >
273
+ @endforeach
274
+
254
275
</div >
255
- <p class = " px-4 py-3 text-xs select-none text-stone-500 dark:text-stone-400 " >
256
- You have {{ count ( $recoveryCodes ) } } recovery codes left.
257
- Each can be used once to access your account and will be removed after use.
276
+ <flux:text variant = " subtle " class = " text-xs" >
277
+ Each recovery code can be used once to access your account and will be
278
+ removed after use.
258
279
If you need more, click <span class =" font-bold" >Regenerate Codes</span >
259
280
above.
260
- </p >
281
+ </flux:text >
282
+
261
283
</div >
262
- @endif
284
+ </ div >
263
285
</div >
264
286
</div >
265
287
0 commit comments