password strength report change, added meter to account page
This commit is contained in:
@@ -540,7 +540,7 @@ export function LeftBar() {
|
|||||||
{/* Navigation Links */}
|
{/* Navigation Links */}
|
||||||
<div class="mt-auto">
|
<div class="mt-auto">
|
||||||
<Typewriter keepAlive={false}>
|
<Typewriter keepAlive={false}>
|
||||||
<ul class="flex flex-col gap-4 py-6">
|
<ul class="flex flex-col gap-4 pt-6">
|
||||||
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
|
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
|
||||||
<a href="/" onClick={handleLinkClick}>
|
<a href="/" onClick={handleLinkClick}>
|
||||||
Home
|
Home
|
||||||
@@ -592,7 +592,7 @@ export function LeftBar() {
|
|||||||
</Typewriter>
|
</Typewriter>
|
||||||
|
|
||||||
{/* Get Lost button - outside Typewriter to allow glitch effect */}
|
{/* Get Lost button - outside Typewriter to allow glitch effect */}
|
||||||
<ul class="flex flex-col gap-4 pb-6">
|
<ul class="pt-4 pb-6">
|
||||||
<li
|
<li
|
||||||
class="hover:text-subtext0 w-fit transition-all duration-500 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold"
|
class="hover:text-subtext0 w-fit transition-all duration-500 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold"
|
||||||
classList={{
|
classList={{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createMemo, For, Show } from "solid-js";
|
import { createMemo, For, Show } from "solid-js";
|
||||||
import { validatePassword, type PasswordStrength } from "~/lib/validation";
|
import { validatePassword } from "~/lib/validation";
|
||||||
import { VALIDATION_CONFIG } from "~/config";
|
import { VALIDATION_CONFIG } from "~/config";
|
||||||
import CheckCircle from "./icons/CheckCircle";
|
import CheckCircle from "./icons/CheckCircle";
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ export default function PasswordStrengthMeter(
|
|||||||
{/* Strength bar */}
|
{/* Strength bar */}
|
||||||
<Show when={props.password.length > 0}>
|
<Show when={props.password.length > 0}>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<div class="bg-surface h-2 w-full overflow-hidden rounded-full">
|
<div class="bg-surface border-yellow h-2 w-full overflow-hidden rounded-full border">
|
||||||
<div
|
<div
|
||||||
class={`${config().color} h-full transition-all duration-300 ease-out`}
|
class={`${config().color} h-full transition-all duration-300 ease-out`}
|
||||||
style={{ width: config().width }}
|
style={{ width: config().width }}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export function validatePassword(password: string): {
|
|||||||
strength: PasswordStrength;
|
strength: PasswordStrength;
|
||||||
} {
|
} {
|
||||||
const errors: string[] = [];
|
const errors: string[] = [];
|
||||||
|
let includesSpecial = false;
|
||||||
|
|
||||||
// Minimum length from config
|
// Minimum length from config
|
||||||
if (password.length < VALIDATION_CONFIG.MIN_PASSWORD_LENGTH) {
|
if (password.length < VALIDATION_CONFIG.MIN_PASSWORD_LENGTH) {
|
||||||
@@ -60,11 +61,11 @@ export function validatePassword(password: string): {
|
|||||||
errors.push("Password must contain at least one number");
|
errors.push("Password must contain at least one number");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (/[^A-Za-z0-9]/.test(password)) {
|
||||||
|
includesSpecial = true;
|
||||||
|
}
|
||||||
// Require special character (if configured)
|
// Require special character (if configured)
|
||||||
if (
|
if (VALIDATION_CONFIG.PASSWORD_REQUIRE_SPECIAL && !includesSpecial) {
|
||||||
VALIDATION_CONFIG.PASSWORD_REQUIRE_SPECIAL &&
|
|
||||||
!/[^A-Za-z0-9]/.test(password)
|
|
||||||
) {
|
|
||||||
errors.push("Password must contain at least one special character");
|
errors.push("Password must contain at least one special character");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +98,13 @@ export function validatePassword(password: string): {
|
|||||||
let strength: PasswordStrength = "weak";
|
let strength: PasswordStrength = "weak";
|
||||||
|
|
||||||
if (errors.length === 0) {
|
if (errors.length === 0) {
|
||||||
|
if (includesSpecial) {
|
||||||
|
if (password.length >= 14) {
|
||||||
|
strength = "strong";
|
||||||
|
} else if (password.length >= VALIDATION_CONFIG.MIN_PASSWORD_LENGTH) {
|
||||||
|
strength = "good";
|
||||||
|
}
|
||||||
|
}
|
||||||
if (password.length >= 16) {
|
if (password.length >= 16) {
|
||||||
strength = "strong";
|
strength = "strong";
|
||||||
} else if (password.length >= 12) {
|
} else if (password.length >= 12) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { VALIDATION_CONFIG } from "~/config";
|
|||||||
import { api } from "~/lib/api";
|
import { api } from "~/lib/api";
|
||||||
|
|
||||||
import type { UserProfile } from "~/types/user";
|
import type { UserProfile } from "~/types/user";
|
||||||
|
import PasswordStrengthMeter from "~/components/PasswordStrengthMeter";
|
||||||
|
|
||||||
const getUserProfile = query(async (): Promise<UserProfile | null> => {
|
const getUserProfile = query(async (): Promise<UserProfile | null> => {
|
||||||
"use server";
|
"use server";
|
||||||
@@ -84,6 +85,7 @@ export default function AccountPage() {
|
|||||||
const [passwordBlurred, setPasswordBlurred] = createSignal(false);
|
const [passwordBlurred, setPasswordBlurred] = createSignal(false);
|
||||||
const [passwordError, setPasswordError] = createSignal(false);
|
const [passwordError, setPasswordError] = createSignal(false);
|
||||||
const [passwordDeletionError, setPasswordDeletionError] = createSignal(false);
|
const [passwordDeletionError, setPasswordDeletionError] = createSignal(false);
|
||||||
|
const [newPassword, setNewPassword] = createSignal("");
|
||||||
|
|
||||||
const [showOldPasswordInput, setShowOldPasswordInput] = createSignal(false);
|
const [showOldPasswordInput, setShowOldPasswordInput] = createSignal(false);
|
||||||
const [showPasswordInput, setShowPasswordInput] = createSignal(false);
|
const [showPasswordInput, setShowPasswordInput] = createSignal(false);
|
||||||
@@ -433,6 +435,7 @@ export default function AccountPage() {
|
|||||||
|
|
||||||
const handleNewPasswordChange = (e: Event) => {
|
const handleNewPasswordChange = (e: Event) => {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
|
setNewPassword(target.value);
|
||||||
checkPasswordLength(target.value);
|
checkPasswordLength(target.value);
|
||||||
if (newPasswordConfRef) {
|
if (newPasswordConfRef) {
|
||||||
checkForMatch(target.value, newPasswordConfRef.value);
|
checkForMatch(target.value, newPasswordConfRef.value);
|
||||||
@@ -838,9 +841,21 @@ export default function AccountPage() {
|
|||||||
>
|
>
|
||||||
<Show
|
<Show
|
||||||
when={showOldPasswordInput()}
|
when={showOldPasswordInput()}
|
||||||
fallback={<Eye />}
|
fallback={
|
||||||
|
<EyeSlash
|
||||||
|
height={24}
|
||||||
|
width={24}
|
||||||
|
strokeWidth={1}
|
||||||
|
class="stroke-text"
|
||||||
|
/>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<EyeSlash />
|
<Eye
|
||||||
|
height={24}
|
||||||
|
width={24}
|
||||||
|
strokeWidth={1}
|
||||||
|
class="stroke-text"
|
||||||
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -861,6 +876,9 @@ export default function AccountPage() {
|
|||||||
/>
|
/>
|
||||||
<span class="bar"></span>
|
<span class="bar"></span>
|
||||||
<label class="underlinedInputLabel">New Password</label>
|
<label class="underlinedInputLabel">New Password</label>
|
||||||
|
<div class="pt-1">
|
||||||
|
<PasswordStrengthMeter password={newPassword()} />
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -868,18 +886,26 @@ export default function AccountPage() {
|
|||||||
}
|
}
|
||||||
class="text-subtext0 absolute top-2 right-0 transition-all hover:brightness-125"
|
class="text-subtext0 absolute top-2 right-0 transition-all hover:brightness-125"
|
||||||
>
|
>
|
||||||
<Show when={showPasswordInput()} fallback={<Eye />}>
|
<Show
|
||||||
<EyeSlash />
|
when={showPasswordInput()}
|
||||||
|
fallback={
|
||||||
|
<EyeSlash
|
||||||
|
height={24}
|
||||||
|
width={24}
|
||||||
|
strokeWidth={1}
|
||||||
|
class="stroke-text"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Eye
|
||||||
|
height={24}
|
||||||
|
width={24}
|
||||||
|
strokeWidth={1}
|
||||||
|
class="stroke-text"
|
||||||
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Show when={showPasswordLengthWarning()}>
|
|
||||||
<div class="text-red mb-4 text-center text-sm">
|
|
||||||
Password too short! Min Length: 8
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<div class="input-group relative mx-4 mb-2">
|
<div class="input-group relative mx-4 mb-2">
|
||||||
<input
|
<input
|
||||||
ref={newPasswordConfRef}
|
ref={newPasswordConfRef}
|
||||||
@@ -894,7 +920,7 @@ export default function AccountPage() {
|
|||||||
/>
|
/>
|
||||||
<span class="bar"></span>
|
<span class="bar"></span>
|
||||||
<label class="underlinedInputLabel">
|
<label class="underlinedInputLabel">
|
||||||
Password Confirmation
|
New Password Confirmation
|
||||||
</label>
|
</label>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -903,8 +929,23 @@ export default function AccountPage() {
|
|||||||
}
|
}
|
||||||
class="text-subtext0 absolute top-2 right-0 transition-all hover:brightness-125"
|
class="text-subtext0 absolute top-2 right-0 transition-all hover:brightness-125"
|
||||||
>
|
>
|
||||||
<Show when={showPasswordConfInput()} fallback={<Eye />}>
|
<Show
|
||||||
<EyeSlash />
|
when={showPasswordConfInput()}
|
||||||
|
fallback={
|
||||||
|
<EyeSlash
|
||||||
|
height={24}
|
||||||
|
width={24}
|
||||||
|
strokeWidth={1}
|
||||||
|
class="stroke-text"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Eye
|
||||||
|
height={24}
|
||||||
|
width={24}
|
||||||
|
strokeWidth={1}
|
||||||
|
class="stroke-text"
|
||||||
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user