diff --git a/apps/infoalloggi/src/forms/FormChangePassword.tsx b/apps/infoalloggi/src/forms/FormChangePassword.tsx
index 357b233..1bdee1f 100644
--- a/apps/infoalloggi/src/forms/FormChangePassword.tsx
+++ b/apps/infoalloggi/src/forms/FormChangePassword.tsx
@@ -12,7 +12,7 @@ import {
} from "~/components/custom_ui/form";
import { Button } from "~/components/ui/button";
import Input from "~/components/ui/input";
-import { useStrongPassword } from "~/hooks/useStrongPassword";
+import { useMildPassword } from "~/hooks/usePassword";
import { cn } from "~/lib/utils";
import { useZodForm } from "~/lib/zodForm";
import { useTranslation } from "~/providers/I18nProvider";
@@ -25,8 +25,9 @@ export const ChangePasswordForm = () => {
passwordRefine,
getStrengthTxt,
strengthScore,
+ maxStrength,
toggleVisibility,
- } = useStrongPassword();
+ } = useMildPassword();
const router = useRouter();
const ChangePasswordFormSchema = z
@@ -161,7 +162,7 @@ export const ChangePasswordForm = () => {
{
"h-full transition-all duration-500 ease-out",
getStrengthColor(strengthScore),
)}
- style={{ width: `${(strengthScore / 4) * 100}%` }}
+ style={{ width: `${(strengthScore / maxStrength) * 100}%` }}
/>
diff --git a/apps/infoalloggi/src/forms/FormNewUser.tsx b/apps/infoalloggi/src/forms/FormNewUser.tsx
index 688bd2d..6b0e4ad 100644
--- a/apps/infoalloggi/src/forms/FormNewUser.tsx
+++ b/apps/infoalloggi/src/forms/FormNewUser.tsx
@@ -12,7 +12,7 @@ import {
import { Button } from "~/components/ui/button";
import Input from "~/components/ui/input";
import { PhoneInput } from "~/components/ui/phone-input";
-import { useStrongPassword } from "~/hooks/useStrongPassword";
+import { useMildPassword } from "~/hooks/usePassword";
import { generatePassword } from "~/lib/basicPwGenerator";
import { cn } from "~/lib/utils";
import { useZodForm } from "~/lib/zodForm";
@@ -31,7 +31,8 @@ export const FormNewUser = ({
getStrengthTxt,
strengthScore,
toggleVisibility,
- } = useStrongPassword();
+ maxStrength,
+ } = useMildPassword();
const NewUserSchema = z
.object({
@@ -206,7 +207,7 @@ export const FormNewUser = ({
diff --git a/apps/infoalloggi/src/forms/FormOverridePassword.tsx b/apps/infoalloggi/src/forms/FormOverridePassword.tsx
index 8e9fc76..5d119ff 100644
--- a/apps/infoalloggi/src/forms/FormOverridePassword.tsx
+++ b/apps/infoalloggi/src/forms/FormOverridePassword.tsx
@@ -22,7 +22,7 @@ import {
import Input from "~/components/ui/input";
import { Label } from "~/components/ui/label";
import { Separator } from "~/components/ui/separator";
-import { useStrongPassword } from "~/hooks/useStrongPassword";
+import { useMildPassword } from "~/hooks/usePassword";
import { generatePassword } from "~/lib/basicPwGenerator";
import { cn } from "~/lib/utils";
import { useZodForm } from "~/lib/zodForm";
@@ -38,7 +38,8 @@ export const OverridePasswordForm = ({ id }: { id: UsersId }) => {
getStrengthTxt,
strengthScore,
toggleVisibility,
- } = useStrongPassword();
+ maxStrength,
+ } = useMildPassword();
const OverridePasswordFormSchema = z
.object({
@@ -203,7 +204,7 @@ export const OverridePasswordForm = ({ id }: { id: UsersId }) => {
{
"h-full transition-all duration-500 ease-out",
getStrengthColor(strengthScore),
)}
- style={{ width: `${(strengthScore / 4) * 100}%` }}
+ style={{
+ width: `${(strengthScore / maxStrength) * 100}%`,
+ }}
/>
diff --git a/apps/infoalloggi/src/forms/FormRstPwFromToken.tsx b/apps/infoalloggi/src/forms/FormRstPwFromToken.tsx
index 73377f8..598cb77 100644
--- a/apps/infoalloggi/src/forms/FormRstPwFromToken.tsx
+++ b/apps/infoalloggi/src/forms/FormRstPwFromToken.tsx
@@ -1,6 +1,5 @@
import { Eye, EyeOff } from "lucide-react";
import { useRouter } from "next/router";
-import { useState } from "react";
import toast from "react-hot-toast";
import { z } from "zod/v4";
import {
@@ -12,6 +11,7 @@ import {
FormMessage,
} from "~/components/custom_ui/form";
import Input from "~/components/ui/input";
+import { useMildPassword } from "~/hooks/usePassword";
import { cn } from "~/lib/utils";
import { useZodForm } from "~/lib/zodForm";
import { useTranslation } from "~/providers/I18nProvider";
@@ -20,38 +20,16 @@ import { api } from "~/utils/api";
export const FormRstPwFromToken = (props: { token: string }) => {
const { locale, t } = useTranslation();
const router = useRouter();
- const [strengthScore, setStrengthScore] = useState(0);
- const [isVisible, setIsVisible] = useState(false);
- const toggleVisibility = () => setIsVisible((prevState) => !prevState);
- const checkStrength = (pass: string) => {
- const requirements = [
- { regex: /.{8,}/, text: t.auth.signup.pw.lenght },
- { regex: /[0-9]/, text: t.auth.signup.pw.number },
- { regex: /[a-z]/, text: t.auth.signup.pw.lowercase },
- { regex: /[A-Z]/, text: t.auth.signup.pw.uppercase },
- ];
-
- return requirements.map((req) => ({
- met: req.regex.test(pass),
- text: req.text,
- }));
- };
-
- const getStrengthColor = (score: number) => {
- if (score === 0) return "bg-border";
- if (score <= 1) return "bg-red-500";
- if (score <= 2) return "bg-orange-500";
- if (score === 3) return "bg-amber-500";
- return "bg-emerald-500";
- };
- const getStrengthTxt = (score: number) => {
- if (score === 0) return "text-border";
- if (score <= 1) return "text-red-500";
- if (score <= 2) return "text-orange-500";
- if (score === 3) return "text-amber-500";
- return "text-emerald-500";
- };
+ const {
+ isVisible,
+ getStrengthColor,
+ passwordRefine,
+ getStrengthTxt,
+ strengthScore,
+ toggleVisibility,
+ maxStrength,
+ } = useMildPassword();
const ResetFormSchema = z
.object({
@@ -59,21 +37,11 @@ export const FormRstPwFromToken = (props: { token: string }) => {
repeat_password: z.string(),
})
.superRefine(({ password, repeat_password }, refinementContext) => {
- const complexity = checkStrength(password);
-
- if (complexity.filter((req) => req.met).length !== complexity.length) {
- refinementContext.issues.push({
- code: "custom",
- input: "",
- message: complexity
- .filter((req) => !req.met)
- .map((req) => req.text)
- .join("\n"),
- path: ["password"],
- });
- }
- setStrengthScore(complexity.filter((req) => req.met).length);
-
+ passwordRefine({
+ password,
+ path: "password",
+ refinementContext,
+ });
if (password !== repeat_password) {
refinementContext.issues.push({
code: "custom",
@@ -164,7 +132,7 @@ export const FormRstPwFromToken = (props: { token: string }) => {
{
"h-full transition-all duration-500 ease-out",
getStrengthColor(strengthScore),
)}
- style={{ width: `${(strengthScore / 4) * 100}%` }}
+ style={{
+ width: `${(strengthScore / maxStrength) * 100}%`,
+ }}
/>
diff --git a/apps/infoalloggi/src/hooks/usePassword.ts b/apps/infoalloggi/src/hooks/usePassword.ts
new file mode 100644
index 0000000..113415b
--- /dev/null
+++ b/apps/infoalloggi/src/hooks/usePassword.ts
@@ -0,0 +1,190 @@
+import { useState } from "react";
+import { type RefinementCtx, z } from "zod/v4";
+import { useTranslation } from "~/providers/I18nProvider";
+
+export const zStrongPassword = z.string().superRefine((password, ctx) => {
+ const test = [/.{8,}/, /[0-9]/, /[a-z]/, /[A-Z]/].every((regex) =>
+ regex.test(password),
+ );
+ if (!test) {
+ ctx.addIssue({
+ code: "custom",
+ message:
+ "La password deve contenere almeno 8 caratteri, un numero, una lettera minuscola e una maiuscola.",
+ });
+ }
+});
+
+type PasswordManager = {
+ getStrengthColor: (score: number) => string;
+ getStrengthTxt: (score: number) => string;
+ isVisible: boolean;
+ passwordRefine: ({
+ password,
+ refinementContext,
+ path,
+ }: {
+ password: string;
+ refinementContext: RefinementCtx;
+ path: string;
+ }) => void;
+ strengthScore: number;
+ toggleVisibility: () => void;
+ maxStrength: number;
+};
+
+export const useStrongPassword = (): PasswordManager => {
+ const { t } = useTranslation();
+
+ const [isVisible, setIsVisible] = useState(false);
+ const [strengthScore, setStrengthScore] = useState(0);
+
+ const checkStrength = (pass: string) => {
+ const requirements = [
+ { regex: /.{8,}/, text: t.auth.signup.pw.lenght8 },
+ { regex: /[0-9]/, text: t.auth.signup.pw.number },
+ { regex: /[a-z]/, text: t.auth.signup.pw.lowercase },
+ { regex: /[A-Z]/, text: t.auth.signup.pw.uppercase },
+ ];
+
+ return requirements.map((req) => ({
+ met: req.regex.test(pass),
+ text: req.text,
+ }));
+ };
+
+ const getStrengthColor = (score: number) => {
+ if (score === 0) return "bg-border";
+ if (score <= 1) return "bg-red-500";
+ if (score <= 2) return "bg-orange-500";
+ if (score === 3) return "bg-amber-500";
+ return "bg-emerald-500";
+ };
+ const getStrengthTxt = (score: number) => {
+ if (score === 0) return "text-border";
+ if (score <= 1) return "text-red-500";
+ if (score <= 2) return "text-orange-500";
+ if (score === 3) return "text-amber-500";
+ return "text-emerald-500";
+ };
+
+ const toggleVisibility = () => setIsVisible((prevState) => !prevState);
+
+ const passwordRefine = ({
+ password,
+ refinementContext,
+ path,
+ }: {
+ password: string;
+ refinementContext: RefinementCtx;
+ path: string;
+ }) => {
+ const complexity = checkStrength(password);
+
+ if (complexity.filter((req) => req.met).length !== complexity.length) {
+ refinementContext.issues.push({
+ code: "custom",
+ input: "",
+ message: complexity
+ .filter((req) => !req.met)
+ .map((req) => req.text)
+ .join("\n"),
+ path: [path],
+ });
+ }
+ setStrengthScore(complexity.filter((req) => req.met).length);
+ };
+
+ return {
+ getStrengthColor,
+ getStrengthTxt,
+ isVisible,
+ passwordRefine,
+ strengthScore,
+ toggleVisibility,
+ maxStrength: 4,
+ };
+};
+
+export const zMildPassword = z.string().superRefine((password, ctx) => {
+ const test = [/.{6,}/, /[a-z]/, /[A-Z]/].every((regex) =>
+ regex.test(password),
+ );
+ if (!test) {
+ ctx.addIssue({
+ code: "custom",
+ message:
+ "La password deve contenere almeno 6 caratteri, una lettera minuscola e una maiuscola.",
+ });
+ }
+});
+
+export const useMildPassword = (): PasswordManager => {
+ const { t } = useTranslation();
+
+ const [isVisible, setIsVisible] = useState(false);
+ const [strengthScore, setStrengthScore] = useState(0);
+
+ const checkStrength = (pass: string) => {
+ const requirements = [
+ { regex: /.{6,}/, text: t.auth.signup.pw.lenght6 },
+ { regex: /[a-z]/, text: t.auth.signup.pw.lowercase },
+ { regex: /[A-Z]/, text: t.auth.signup.pw.uppercase },
+ ];
+
+ return requirements.map((req) => ({
+ met: req.regex.test(pass),
+ text: req.text,
+ }));
+ };
+
+ const getStrengthColor = (score: number) => {
+ if (score === 0) return "bg-border";
+ if (score <= 1) return "bg-red-500";
+ if (score === 2) return "bg-amber-500";
+ return "bg-emerald-500";
+ };
+ const getStrengthTxt = (score: number) => {
+ if (score === 0) return "text-border";
+ if (score <= 1) return "text-red-500";
+ if (score === 2) return "text-amber-500";
+ return "text-emerald-500";
+ };
+
+ const toggleVisibility = () => setIsVisible((prevState) => !prevState);
+
+ const passwordRefine = ({
+ password,
+ refinementContext,
+ path,
+ }: {
+ password: string;
+ refinementContext: RefinementCtx;
+ path: string;
+ }) => {
+ const complexity = checkStrength(password);
+
+ if (complexity.filter((req) => req.met).length !== complexity.length) {
+ refinementContext.issues.push({
+ code: "custom",
+ input: "",
+ message: complexity
+ .filter((req) => !req.met)
+ .map((req) => req.text)
+ .join("\n"),
+ path: [path],
+ });
+ }
+ setStrengthScore(complexity.filter((req) => req.met).length);
+ };
+
+ return {
+ getStrengthColor,
+ getStrengthTxt,
+ isVisible,
+ passwordRefine,
+ strengthScore,
+ toggleVisibility,
+ maxStrength: 3,
+ };
+};
diff --git a/apps/infoalloggi/src/hooks/useStrongPassword.ts b/apps/infoalloggi/src/hooks/useStrongPassword.ts
deleted file mode 100644
index 2748e73..0000000
--- a/apps/infoalloggi/src/hooks/useStrongPassword.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import { useState } from "react";
-import { type RefinementCtx, z } from "zod/v4";
-import { useTranslation } from "~/providers/I18nProvider";
-
-export const zStrongPassword = z.string().superRefine((password, ctx) => {
- const test = [/.{8,}/, /[0-9]/, /[a-z]/, /[A-Z]/].every((regex) =>
- regex.test(password),
- );
- if (!test) {
- ctx.addIssue({
- code: "custom",
- message:
- "La password deve contenere almeno 8 caratteri, un numero, una lettera minuscola e una maiuscola.",
- });
- }
-});
-
-export const useStrongPassword = () => {
- const { t } = useTranslation();
-
- const [isVisible, setIsVisible] = useState(false);
- const [strengthScore, setStrengthScore] = useState(0);
-
- const checkStrength = (pass: string) => {
- const requirements = [
- { regex: /.{8,}/, text: t.auth.signup.pw.lenght },
- { regex: /[0-9]/, text: t.auth.signup.pw.number },
- { regex: /[a-z]/, text: t.auth.signup.pw.lowercase },
- { regex: /[A-Z]/, text: t.auth.signup.pw.uppercase },
- ];
-
- return requirements.map((req) => ({
- met: req.regex.test(pass),
- text: req.text,
- }));
- };
-
- const getStrengthColor = (score: number) => {
- if (score === 0) return "bg-border";
- if (score <= 1) return "bg-red-500";
- if (score <= 2) return "bg-orange-500";
- if (score === 3) return "bg-amber-500";
- return "bg-emerald-500";
- };
- const getStrengthTxt = (score: number) => {
- if (score === 0) return "text-border";
- if (score <= 1) return "text-red-500";
- if (score <= 2) return "text-orange-500";
- if (score === 3) return "text-amber-500";
- return "text-emerald-500";
- };
-
- const toggleVisibility = () => setIsVisible((prevState) => !prevState);
-
- const passwordRefine = ({
- password,
- refinementContext,
- path,
- }: {
- password: string;
- refinementContext: RefinementCtx;
- path: string;
- }) => {
- const complexity = checkStrength(password);
-
- if (complexity.filter((req) => req.met).length !== complexity.length) {
- refinementContext.issues.push({
- code: "custom",
- input: "",
- message: complexity
- .filter((req) => !req.met)
- .map((req) => req.text)
- .join("\n"),
- path: [path],
- });
- }
- setStrengthScore(complexity.filter((req) => req.met).length);
- };
-
- return {
- getStrengthColor,
- getStrengthTxt,
- isVisible,
- passwordRefine,
- strengthScore,
- toggleVisibility,
- };
-};
diff --git a/apps/infoalloggi/src/i18n/en.ts b/apps/infoalloggi/src/i18n/en.ts
index 7dd980a..3b5f545 100644
--- a/apps/infoalloggi/src/i18n/en.ts
+++ b/apps/infoalloggi/src/i18n/en.ts
@@ -369,7 +369,8 @@ export const en: LangDict = {
nome: "Name",
password: "Password",
pw: {
- lenght: "At least 8 characters",
+ lenght8: "At least 8 characters",
+ lenght6: "At least 6 characters",
lowercase: "At least 1 lowercase letter",
number: "At least 1 number",
uppercase: "At least 1 uppercase letter",
diff --git a/apps/infoalloggi/src/i18n/it.ts b/apps/infoalloggi/src/i18n/it.ts
index 55c1911..c409c5c 100644
--- a/apps/infoalloggi/src/i18n/it.ts
+++ b/apps/infoalloggi/src/i18n/it.ts
@@ -374,7 +374,8 @@ export const it: LangDict = {
nome: "Nome",
password: "Password",
pw: {
- lenght: "Almeno 8 caratteri",
+ lenght8: "Almeno 8 caratteri",
+ lenght6: "Almeno 6 caratteri",
lowercase: "Almeno 1 lettera minuscola",
number: "Almeno 1 numero",
uppercase: "Almeno 1 lettera maiuscola",
diff --git a/apps/infoalloggi/src/i18n/locales.ts b/apps/infoalloggi/src/i18n/locales.ts
index faca6a2..584c308 100644
--- a/apps/infoalloggi/src/i18n/locales.ts
+++ b/apps/infoalloggi/src/i18n/locales.ts
@@ -550,7 +550,8 @@ export type LangDict = {
success: string;
fail: string;
pw: {
- lenght: string;
+ lenght6: string;
+ lenght8: string;
number: string;
lowercase: string;
uppercase: string;
diff --git a/apps/infoalloggi/src/pages/auth/accetta-invito/[token].tsx b/apps/infoalloggi/src/pages/auth/accetta-invito/[token].tsx
index 9c49bdb..41acbbd 100644
--- a/apps/infoalloggi/src/pages/auth/accetta-invito/[token].tsx
+++ b/apps/infoalloggi/src/pages/auth/accetta-invito/[token].tsx
@@ -30,7 +30,7 @@ import {
} from "~/components/ui/alert-dialog";
import { Button } from "~/components/ui/button";
import Input from "~/components/ui/input";
-import { useStrongPassword } from "~/hooks/useStrongPassword";
+import { useMildPassword } from "~/hooks/usePassword";
import { cn } from "~/lib/utils";
import { useZodForm } from "~/lib/zodForm";
import type { NextPageWithLayout } from "~/pages/_app";
@@ -64,7 +64,8 @@ const AcceptInvitePage: NextPageWithLayout = ({
getStrengthTxt,
strengthScore,
toggleVisibility,
- } = useStrongPassword();
+ maxStrength,
+ } = useMildPassword();
const router = useRouter();
const schema = z
@@ -189,7 +190,7 @@ const AcceptInvitePage: NextPageWithLayout = ({
= ({
"h-full transition-all duration-500 ease-out",
getStrengthColor(strengthScore),
)}
- style={{ width: `${(strengthScore / 4) * 100}%` }}
+ style={{
+ width: `${(strengthScore / maxStrength) * 100}%`,
+ }}
/>
diff --git a/apps/infoalloggi/src/server/api/routers/auth.ts b/apps/infoalloggi/src/server/api/routers/auth.ts
index b961874..b29abe1 100644
--- a/apps/infoalloggi/src/server/api/routers/auth.ts
+++ b/apps/infoalloggi/src/server/api/routers/auth.ts
@@ -1,5 +1,5 @@
import { z } from "zod/v4";
-import { zStrongPassword } from "~/hooks/useStrongPassword";
+import { zMildPassword } from "~/hooks/usePassword";
import {
adminProcedure,
createTRPCRouter,
@@ -38,7 +38,7 @@ export const authRouter = createTRPCRouter({
cognome: z.string().nonempty("Inserisci un cognome valido"),
email: z.email(),
nome: z.string().nonempty("Inserisci un nome valido"),
- password: zStrongPassword,
+ password: zMildPassword,
telefono: z.string().nonempty("Inserisci un numero di telefono"),
}),
)