feat: Enhance task filtering, smart scheduling, audit logs and translations
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -143,44 +143,6 @@ export default function AuthPage() {
|
||||
// Error handling is done in the form submission handler to set field errors
|
||||
});
|
||||
|
||||
if (is2FARequired) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center p-4 bg-background">
|
||||
<Card className="w-full max-w-md shadow-xl border-border/50">
|
||||
<CardHeader className="text-center space-y-2">
|
||||
<div className="mx-auto mb-4">
|
||||
<img src="/favicon.png" alt="Logo" className="w-12 h-12 mx-auto" />
|
||||
</div>
|
||||
<CardTitle className="text-2xl font-bold">{t('auth.2faVerification')}</CardTitle>
|
||||
<CardDescription>
|
||||
{t('auth.enterCodeSentTo')} <span className="font-medium text-foreground">{twoFAUserId && twoFAEmail ? twoFAEmail : 'your email'}</span>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form onSubmit={handleVerify2FA} className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<Input
|
||||
placeholder="123456"
|
||||
className="text-center text-2xl tracking-widest"
|
||||
maxLength={6}
|
||||
value={otpCode}
|
||||
onChange={(e) => setOtpCode(e.target.value.replace(/\D/g, ''))}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground text-center">{t('auth.codeExpiresIn10')}</p>
|
||||
</div>
|
||||
<Button className="w-full" type="submit" disabled={verify2FAMutation.isPending || otpCode.length !== 6}>
|
||||
{verify2FAMutation.isPending ? t('common.verifying') : t('auth.verify')}
|
||||
</Button>
|
||||
<Button variant="ghost" className="w-full" type="button" onClick={() => setIs2FARequired(false)}>
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen grid lg:grid-cols-2 dark">
|
||||
<div className="hidden lg:flex flex-col justify-center items-center bg-zinc-900 p-12 text-white">
|
||||
@@ -196,68 +158,102 @@ export default function AuthPage() {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center p-4 bg-background">
|
||||
<Card className="w-full max-w-md shadow-xl border-border/50">
|
||||
<CardHeader className="text-center space-y-2">
|
||||
<div className="lg:hidden mx-auto mb-4">
|
||||
<img src="/favicon.png" alt="Logo" className="w-12 h-12 mx-auto" />
|
||||
</div>
|
||||
<CardTitle className="text-2xl font-bold">{t('auth.welcomeBack')}</CardTitle>
|
||||
<CardDescription>
|
||||
{settings?.registration_enabled
|
||||
? t('auth.signInDesc')
|
||||
: t('auth.signInDescNoReg')}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex w-full mb-6 bg-zinc-100 dark:bg-zinc-800 p-1 rounded-lg">
|
||||
<button
|
||||
onClick={() => setActiveTab("login")}
|
||||
className={`flex-1 py-2 text-sm font-medium rounded-md transition-all ${activeTab === "login"
|
||||
? "bg-white dark:bg-zinc-950 shadow-sm text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
}`}
|
||||
>
|
||||
{t('auth.login')}
|
||||
</button>
|
||||
{settings?.registration_enabled && (
|
||||
{is2FARequired ? (
|
||||
<Card className="w-full max-w-md shadow-xl border-border/50">
|
||||
<CardHeader className="text-center space-y-2">
|
||||
<div className="lg:hidden mx-auto mb-4">
|
||||
<img src="/favicon.png" alt="Logo" className="w-12 h-12 mx-auto" />
|
||||
</div>
|
||||
<CardTitle className="text-2xl font-bold">{t('auth.2faVerification')}</CardTitle>
|
||||
<CardDescription>
|
||||
{t('auth.enterCodeSentTo')} <span className="font-medium text-foreground">{twoFAUserId && twoFAEmail ? twoFAEmail : 'your email'}</span>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form onSubmit={handleVerify2FA} className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<Input
|
||||
placeholder="123456"
|
||||
className="text-center text-2xl tracking-widest"
|
||||
maxLength={6}
|
||||
value={otpCode}
|
||||
onChange={(e) => setOtpCode(e.target.value.replace(/\D/g, ''))}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground text-center">{t('auth.codeExpiresIn10')}</p>
|
||||
</div>
|
||||
<Button className="w-full" type="submit" disabled={verify2FAMutation.isPending || otpCode.length !== 6}>
|
||||
{verify2FAMutation.isPending ? t('common.verifying') : t('auth.verify')}
|
||||
</Button>
|
||||
<Button variant="ghost" className="w-full" type="button" onClick={() => setIs2FARequired(false)}>
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<Card className="w-full max-w-md shadow-xl border-border/50">
|
||||
<CardHeader className="text-center space-y-2">
|
||||
<div className="lg:hidden mx-auto mb-4">
|
||||
<img src="/favicon.png" alt="Logo" className="w-12 h-12 mx-auto" />
|
||||
</div>
|
||||
<CardTitle className="text-2xl font-bold">{t('auth.welcomeBack')}</CardTitle>
|
||||
<CardDescription>
|
||||
{settings?.registration_enabled
|
||||
? t('auth.signInDesc')
|
||||
: t('auth.signInDescNoReg')}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex w-full mb-6 bg-zinc-100 dark:bg-zinc-800 p-1 rounded-lg">
|
||||
<button
|
||||
onClick={() => setActiveTab("register")}
|
||||
className={`flex-1 py-2 text-sm font-medium rounded-md transition-all ${activeTab === "register"
|
||||
onClick={() => setActiveTab("login")}
|
||||
className={`flex-1 py-2 text-sm font-medium rounded-md transition-all ${activeTab === "login"
|
||||
? "bg-white dark:bg-zinc-950 shadow-sm text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
}`}
|
||||
>
|
||||
{t('auth.register')}
|
||||
{t('auth.login')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{settings?.registration_enabled && (
|
||||
<button
|
||||
onClick={() => setActiveTab("register")}
|
||||
className={`flex-1 py-2 text-sm font-medium rounded-md transition-all ${activeTab === "register"
|
||||
? "bg-white dark:bg-zinc-950 shadow-sm text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
}`}
|
||||
>
|
||||
{t('auth.register')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{activeTab === "login" ? (
|
||||
<AuthForm
|
||||
mode="login"
|
||||
onSubmit={(data) => loginMutation.mutate(data)}
|
||||
isLoading={loginMutation.isPending}
|
||||
/>
|
||||
) : (
|
||||
settings?.registration_enabled ? (
|
||||
{activeTab === "login" ? (
|
||||
<AuthForm
|
||||
mode="register"
|
||||
onSubmit={(data) => {
|
||||
registerMutation.mutate(data as InsertUser, {
|
||||
onError: (error) => {
|
||||
// Handled in form
|
||||
}
|
||||
})
|
||||
}}
|
||||
isLoading={registerMutation.isPending}
|
||||
registerMutation={registerMutation}
|
||||
mode="login"
|
||||
onSubmit={(data) => loginMutation.mutate(data)}
|
||||
isLoading={loginMutation.isPending}
|
||||
/>
|
||||
) : (
|
||||
<div className="p-4 text-center text-muted-foreground">{t('auth.registrationDisabled')}</div>
|
||||
)
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
settings?.registration_enabled ? (
|
||||
<AuthForm
|
||||
mode="register"
|
||||
onSubmit={(data) => {
|
||||
registerMutation.mutate(data as InsertUser, {
|
||||
onError: (error) => {
|
||||
// Handled in form
|
||||
}
|
||||
})
|
||||
}}
|
||||
isLoading={registerMutation.isPending}
|
||||
registerMutation={registerMutation}
|
||||
/>
|
||||
) : (
|
||||
<div className="p-4 text-center text-muted-foreground">{t('auth.registrationDisabled')}</div>
|
||||
)
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user