@@ -5,6 +5,7 @@ import { Card } from "@/components/ui/card";
55import { Label } from "@/components/ui/label" ;
66import { Eye , EyeOff , Key , CheckCircle , AlertTriangle , Shield } from "lucide-react" ;
77import { isPasswordStrong } from "@/lib/auth" ;
8+ import { DEMO_MODE } from "@/lib/config" ;
89import { authApi } from "@/lib/api-client" ;
910
1011type MessageType = 'success' | 'error' | 'info' | 'warning' ;
@@ -38,6 +39,7 @@ export const PasswordManager = () => {
3839 const [ resetNewPassword , setResetNewPassword ] = useState ( "" ) ;
3940 const [ tokenResetMessage , setTokenResetMessage ] = useState < Message | null > ( null ) ;
4041 const [ tokenResetLoading , setTokenResetLoading ] = useState ( false ) ;
42+ const demoMode = DEMO_MODE ;
4143
4244 const handleSubmit = async ( e : React . FormEvent ) => {
4345 e . preventDefault ( ) ;
@@ -207,119 +209,126 @@ export const PasswordManager = () => {
207209 </ p >
208210 </ div >
209211
210- < form onSubmit = { handleSubmit } className = "space-y-4" >
211- < div className = "space-y-2" >
212- < Label htmlFor = "current-password" > Current Password</ Label >
213- < div className = "relative" >
214- < Input
215- id = "current-password"
216- type = { showCurrentPassword ? "text" : "password" }
217- value = { currentPassword }
218- onChange = { ( e ) => setCurrentPassword ( e . target . value ) }
219- className = "glass-card border-primary/20 pr-10"
220- placeholder = "Enter current password"
221- required
222- disabled = { isLoading }
223- />
224- < Button
225- type = "button"
226- variant = "ghost"
227- size = "icon"
228- className = "absolute right-0 top-0 h-full px-3 hover:bg-transparent"
229- onClick = { ( ) => setShowCurrentPassword ( ! showCurrentPassword ) }
230- disabled = { isLoading }
231- >
232- { showCurrentPassword ? < EyeOff className = "w-4 h-4" /> : < Eye className = "w-4 h-4" /> }
233- </ Button >
234- </ div >
212+ { demoMode ? (
213+ < div className = "rounded-2xl border border-yellow-300 bg-yellow-50 p-4 text-sm text-yellow-900" >
214+ < p className = "font-semibold" > Demo mode is active</ p >
215+ < p className = "mt-1" > Password change and password reset are disabled in demo mode.</ p >
235216 </ div >
236-
237- < div className = "space-y-2" >
238- < Label htmlFor = "new-password" > New Password</ Label >
239- < div className = "relative" >
240- < Input
241- id = "new-password"
242- type = { showNewPassword ? "text" : "password" }
243- value = { newPassword }
244- onChange = { ( e ) => setNewPassword ( e . target . value ) }
245- className = "glass-card border-primary/20 pr-10"
246- placeholder = "Enter new password"
247- required
248- disabled = { isLoading }
249- />
250- < Button
251- type = "button"
252- variant = "ghost"
253- size = "icon"
254- className = "absolute right-0 top-0 h-full px-3 hover:bg-transparent"
255- onClick = { ( ) => setShowNewPassword ( ! showNewPassword ) }
256- disabled = { isLoading }
257- >
258- { showNewPassword ? < EyeOff className = "w-4 h-4" /> : < Eye className = "w-4 h-4" /> }
259- </ Button >
260- </ div >
261- < div className = "text-xs text-muted-foreground space-y-1" >
262- < p > Requirements:</ p >
263- < ul className = "list-disc list-inside ml-2 space-y-0.5" >
264- < li className = { newPassword . length >= 8 ? 'text-green-400' : '' } > At least 8 characters</ li >
265- < li className = { / [ A - Z ] / . test ( newPassword ) ? 'text-green-400' : '' } > Uppercase letter</ li >
266- < li className = { / [ a - z ] / . test ( newPassword ) ? 'text-green-400' : '' } > Lowercase letter</ li >
267- < li className = { / \d / . test ( newPassword ) ? 'text-green-400' : '' } > Number</ li >
268- < li className = { / [ ! @ # $ % ^ & * ( ) , . ? " : { } | < > ] / . test ( newPassword ) ? 'text-green-400' : '' } > Special character</ li >
269- </ ul >
217+ ) : (
218+ < form onSubmit = { handleSubmit } className = "space-y-4" >
219+ < div className = "space-y-2" >
220+ < Label htmlFor = "current-password" > Current Password</ Label >
221+ < div className = "relative" >
222+ < Input
223+ id = "current-password"
224+ type = { showCurrentPassword ? "text" : "password" }
225+ value = { currentPassword }
226+ onChange = { ( e ) => setCurrentPassword ( e . target . value ) }
227+ className = "glass-card border-primary/20 pr-10"
228+ placeholder = "Enter current password"
229+ required
230+ disabled = { isLoading }
231+ />
232+ < Button
233+ type = "button"
234+ variant = "ghost"
235+ size = "icon"
236+ className = "absolute right-0 top-0 h-full px-3 hover:bg-transparent"
237+ onClick = { ( ) => setShowCurrentPassword ( ! showCurrentPassword ) }
238+ disabled = { isLoading }
239+ >
240+ { showCurrentPassword ? < EyeOff className = "w-4 h-4" /> : < Eye className = "w-4 h-4" /> }
241+ </ Button >
242+ </ div >
270243 </ div >
271- </ div >
272244
273- < div className = "space-y-2" >
274- < Label htmlFor = "confirm-password" > Confirm New Password</ Label >
275- < div className = "relative" >
276- < Input
277- id = "confirm-password"
278- type = { showConfirmPassword ? "text" : "password" }
279- value = { confirmPassword }
280- onChange = { ( e ) => setConfirmPassword ( e . target . value ) }
281- className = "glass-card border-primary/20 pr-10"
282- placeholder = "Confirm new password"
283- required
284- disabled = { isLoading }
285- />
286- < Button
287- type = "button"
288- variant = "ghost"
289- size = "icon"
290- className = "absolute right-0 top-0 h-full px-3 hover:bg-transparent"
291- onClick = { ( ) => setShowConfirmPassword ( ! showConfirmPassword ) }
292- disabled = { isLoading }
293- >
294- { showConfirmPassword ? < EyeOff className = "w-4 h-4" /> : < Eye className = "w-4 h-4" /> }
295- </ Button >
245+ < div className = "space-y-2" >
246+ < Label htmlFor = "new-password" > New Password</ Label >
247+ < div className = "relative" >
248+ < Input
249+ id = "new-password"
250+ type = { showNewPassword ? "text" : "password" }
251+ value = { newPassword }
252+ onChange = { ( e ) => setNewPassword ( e . target . value ) }
253+ className = "glass-card border-primary/20 pr-10"
254+ placeholder = "Enter new password"
255+ required
256+ disabled = { isLoading }
257+ />
258+ < Button
259+ type = "button"
260+ variant = "ghost"
261+ size = "icon"
262+ className = "absolute right-0 top-0 h-full px-3 hover:bg-transparent"
263+ onClick = { ( ) => setShowNewPassword ( ! showNewPassword ) }
264+ disabled = { isLoading }
265+ >
266+ { showNewPassword ? < EyeOff className = "w-4 h-4" /> : < Eye className = "w-4 h-4" /> }
267+ </ Button >
268+ </ div >
269+ < div className = "text-xs text-muted-foreground space-y-1" >
270+ < p > Requirements:</ p >
271+ < ul className = "list-disc list-inside ml-2 space-y-0.5" >
272+ < li className = { newPassword . length >= 8 ? 'text-green-400' : '' } > At least 8 characters</ li >
273+ < li className = { / [ A - Z ] / . test ( newPassword ) ? 'text-green-400' : '' } > Uppercase letter</ li >
274+ < li className = { / [ a - z ] / . test ( newPassword ) ? 'text-green-400' : '' } > Lowercase letter</ li >
275+ < li className = { / \d / . test ( newPassword ) ? 'text-green-400' : '' } > Number</ li >
276+ < li className = { / [ ! @ # $ % ^ & * ( ) , . ? " : { } | < > ] / . test ( newPassword ) ? 'text-green-400' : '' } > Special character</ li >
277+ </ ul >
278+ </ div >
296279 </ div >
297- </ div >
298280
299- { message && (
300- < div className = { `text-sm p-3 rounded-lg flex items-center gap-2 ${
301- message . type === 'success'
302- ? 'bg-green-500/10 text-green-400 border border-green-500/20'
303- : 'bg-destructive/10 text-destructive border border-destructive/20'
304- } `} >
305- { message . type === 'success' ? (
306- < CheckCircle className = "w-4 h-4" />
307- ) : (
308- < AlertTriangle className = "w-4 h-4" />
309- ) }
310- { message . text }
281+ < div className = "space-y-2" >
282+ < Label htmlFor = "confirm-password" > Confirm New Password</ Label >
283+ < div className = "relative" >
284+ < Input
285+ id = "confirm-password"
286+ type = { showConfirmPassword ? "text" : "password" }
287+ value = { confirmPassword }
288+ onChange = { ( e ) => setConfirmPassword ( e . target . value ) }
289+ className = "glass-card border-primary/20 pr-10"
290+ placeholder = "Confirm new password"
291+ required
292+ disabled = { isLoading }
293+ />
294+ < Button
295+ type = "button"
296+ variant = "ghost"
297+ size = "icon"
298+ className = "absolute right-0 top-0 h-full px-3 hover:bg-transparent"
299+ onClick = { ( ) => setShowConfirmPassword ( ! showConfirmPassword ) }
300+ disabled = { isLoading }
301+ >
302+ { showConfirmPassword ? < EyeOff className = "w-4 h-4" /> : < Eye className = "w-4 h-4" /> }
303+ </ Button >
304+ </ div >
311305 </ div >
312- ) }
313306
314- < Button
315- type = "submit"
316- variant = "gradient"
317- className = "w-full"
318- disabled = { isLoading }
319- >
320- { isLoading ? "Changing Password..." : "Change Password" }
321- </ Button >
322- </ form >
307+ { message && (
308+ < div className = { `text-sm p-3 rounded-lg flex items-center gap-2 ${
309+ message . type === 'success'
310+ ? 'bg-green-500/10 text-green-400 border border-green-500/20'
311+ : 'bg-destructive/10 text-destructive border border-destructive/20'
312+ } `} >
313+ { message . type === 'success' ? (
314+ < CheckCircle className = "w-4 h-4" />
315+ ) : (
316+ < AlertTriangle className = "w-4 h-4" />
317+ ) }
318+ { message . text }
319+ </ div >
320+ ) }
321+
322+ < Button
323+ type = "submit"
324+ variant = "gradient"
325+ className = "w-full"
326+ disabled = { isLoading }
327+ >
328+ { isLoading ? "Changing Password..." : "Change Password" }
329+ </ Button >
330+ </ form >
331+ ) }
323332
324333 < div className = "pt-4 border-t border-primary/20" >
325334 < div className = "bg-destructive/10 border border-destructive/20 rounded-lg p-4 space-y-3" >
@@ -343,12 +352,13 @@ export const PasswordManager = () => {
343352 </ div >
344353 </ Card >
345354 { /* Forgot password — token-based reset */ }
346- < Card className = "glass-card p-6 space-y-4" >
347- < button
348- type = "button"
349- className = "w-full text-left flex items-center justify-between"
350- onClick = { ( ) => setShowTokenReset ( v => ! v ) }
351- >
355+ { ! demoMode && (
356+ < Card className = "glass-card p-6 space-y-4" >
357+ < button
358+ type = "button"
359+ className = "w-full text-left flex items-center justify-between"
360+ onClick = { ( ) => setShowTokenReset ( v => ! v ) }
361+ >
352362 < span className = "text-sm font-medium text-muted-foreground" > Forgot your password?</ span >
353363 < span className = "text-xs text-primary" > { showTokenReset ? 'Hide' : 'Show' } </ span >
354364 </ button >
@@ -403,6 +413,7 @@ export const PasswordManager = () => {
403413 </ form >
404414 ) }
405415 </ Card >
416+ ) }
406417 </ div >
407418 ) ;
408419} ;
0 commit comments