style: login page Okay
This commit is contained in:
parent
921007ae13
commit
8c12667693
@ -14,8 +14,11 @@
|
|||||||
"@tanstack/react-query": "^5.69.0",
|
"@tanstack/react-query": "^5.69.0",
|
||||||
"@tanstack/react-table": "^8.21.2",
|
"@tanstack/react-table": "^8.21.2",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.8.4",
|
||||||
|
"bootstrap": "^5.3.3",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"declarations": "link:@/lib/declarations",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
|
"leaflet": "^1.9.4",
|
||||||
"next": "15.2.3",
|
"next": "15.2.3",
|
||||||
"next-auth": "^4.24.11",
|
"next-auth": "^4.24.11",
|
||||||
"nextjs-toploader": "^3.8.15",
|
"nextjs-toploader": "^3.8.15",
|
||||||
@ -32,6 +35,7 @@
|
|||||||
"@eslint/eslintrc": "^3",
|
"@eslint/eslintrc": "^3",
|
||||||
"@svgr/webpack": "^8.1.0",
|
"@svgr/webpack": "^8.1.0",
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"@types/leaflet": "^1.9.17",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
@ -39,7 +43,6 @@
|
|||||||
"eslint-config-next": "15.2.3",
|
"eslint-config-next": "15.2.3",
|
||||||
"install": "^0.13.0",
|
"install": "^0.13.0",
|
||||||
"npm": "^11.2.0",
|
"npm": "^11.2.0",
|
||||||
"tailwindcss": "^4",
|
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
46
pnpm-lock.yaml
generated
46
pnpm-lock.yaml
generated
@ -23,12 +23,21 @@ importers:
|
|||||||
axios:
|
axios:
|
||||||
specifier: ^1.8.4
|
specifier: ^1.8.4
|
||||||
version: 1.8.4
|
version: 1.8.4
|
||||||
|
bootstrap:
|
||||||
|
specifier: ^5.3.3
|
||||||
|
version: 5.3.3(@popperjs/core@2.11.8)
|
||||||
clsx:
|
clsx:
|
||||||
specifier: ^2.1.1
|
specifier: ^2.1.1
|
||||||
version: 2.1.1
|
version: 2.1.1
|
||||||
|
declarations:
|
||||||
|
specifier: link:@/lib/declarations
|
||||||
|
version: link:@/lib/declarations
|
||||||
jwt-decode:
|
jwt-decode:
|
||||||
specifier: ^4.0.0
|
specifier: ^4.0.0
|
||||||
version: 4.0.0
|
version: 4.0.0
|
||||||
|
leaflet:
|
||||||
|
specifier: ^1.9.4
|
||||||
|
version: 1.9.4
|
||||||
next:
|
next:
|
||||||
specifier: 15.2.3
|
specifier: 15.2.3
|
||||||
version: 15.2.3(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.0)
|
version: 15.2.3(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.0)
|
||||||
@ -72,6 +81,9 @@ importers:
|
|||||||
'@tailwindcss/postcss':
|
'@tailwindcss/postcss':
|
||||||
specifier: ^4
|
specifier: ^4
|
||||||
version: 4.0.15
|
version: 4.0.15
|
||||||
|
'@types/leaflet':
|
||||||
|
specifier: ^1.9.17
|
||||||
|
version: 1.9.17
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20
|
specifier: ^20
|
||||||
version: 20.17.27
|
version: 20.17.27
|
||||||
@ -93,9 +105,6 @@ importers:
|
|||||||
npm:
|
npm:
|
||||||
specifier: ^11.2.0
|
specifier: ^11.2.0
|
||||||
version: 11.2.0
|
version: 11.2.0
|
||||||
tailwindcss:
|
|
||||||
specifier: ^4
|
|
||||||
version: 4.0.15
|
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5
|
specifier: ^5
|
||||||
version: 5.8.2
|
version: 5.8.2
|
||||||
@ -1018,6 +1027,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
|
resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
|
|
||||||
|
'@popperjs/core@2.11.8':
|
||||||
|
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||||
|
|
||||||
'@radix-ui/colors@3.0.0':
|
'@radix-ui/colors@3.0.0':
|
||||||
resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==}
|
resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==}
|
||||||
|
|
||||||
@ -1875,12 +1887,18 @@ packages:
|
|||||||
'@types/estree@1.0.7':
|
'@types/estree@1.0.7':
|
||||||
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
|
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
|
||||||
|
|
||||||
|
'@types/geojson@7946.0.16':
|
||||||
|
resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==}
|
||||||
|
|
||||||
'@types/json-schema@7.0.15':
|
'@types/json-schema@7.0.15':
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
|
|
||||||
'@types/json5@0.0.29':
|
'@types/json5@0.0.29':
|
||||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||||
|
|
||||||
|
'@types/leaflet@1.9.17':
|
||||||
|
resolution: {integrity: sha512-IJ4K6t7I3Fh5qXbQ1uwL3CFVbCi6haW9+53oLWgdKlLP7EaS21byWFJxxqOx9y8I0AP0actXSJLVMbyvxhkUTA==}
|
||||||
|
|
||||||
'@types/node@20.17.27':
|
'@types/node@20.17.27':
|
||||||
resolution: {integrity: sha512-U58sbKhDrthHlxHRJw7ZLiLDZGmAUOZUbpw0S6nL27sYUdhvgBLCRu/keSd6qcTsfArd1sRFCCBxzWATGr/0UA==}
|
resolution: {integrity: sha512-U58sbKhDrthHlxHRJw7ZLiLDZGmAUOZUbpw0S6nL27sYUdhvgBLCRu/keSd6qcTsfArd1sRFCCBxzWATGr/0UA==}
|
||||||
|
|
||||||
@ -2100,6 +2118,11 @@ packages:
|
|||||||
boolbase@1.0.0:
|
boolbase@1.0.0:
|
||||||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||||
|
|
||||||
|
bootstrap@5.3.3:
|
||||||
|
resolution: {integrity: sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@popperjs/core': ^2.11.8
|
||||||
|
|
||||||
brace-expansion@1.1.11:
|
brace-expansion@1.1.11:
|
||||||
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||||
|
|
||||||
@ -2845,6 +2868,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==}
|
resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==}
|
||||||
engines: {node: '>=0.10'}
|
engines: {node: '>=0.10'}
|
||||||
|
|
||||||
|
leaflet@1.9.4:
|
||||||
|
resolution: {integrity: sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==}
|
||||||
|
|
||||||
levn@0.4.1:
|
levn@0.4.1:
|
||||||
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@ -4716,6 +4742,8 @@ snapshots:
|
|||||||
'@parcel/watcher-win32-x64': 2.5.1
|
'@parcel/watcher-win32-x64': 2.5.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@popperjs/core@2.11.8': {}
|
||||||
|
|
||||||
'@radix-ui/colors@3.0.0': {}
|
'@radix-ui/colors@3.0.0': {}
|
||||||
|
|
||||||
'@radix-ui/number@1.1.0': {}
|
'@radix-ui/number@1.1.0': {}
|
||||||
@ -5614,10 +5642,16 @@ snapshots:
|
|||||||
|
|
||||||
'@types/estree@1.0.7': {}
|
'@types/estree@1.0.7': {}
|
||||||
|
|
||||||
|
'@types/geojson@7946.0.16': {}
|
||||||
|
|
||||||
'@types/json-schema@7.0.15': {}
|
'@types/json-schema@7.0.15': {}
|
||||||
|
|
||||||
'@types/json5@0.0.29': {}
|
'@types/json5@0.0.29': {}
|
||||||
|
|
||||||
|
'@types/leaflet@1.9.17':
|
||||||
|
dependencies:
|
||||||
|
'@types/geojson': 7946.0.16
|
||||||
|
|
||||||
'@types/node@20.17.27':
|
'@types/node@20.17.27':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.19.8
|
undici-types: 6.19.8
|
||||||
@ -5882,6 +5916,10 @@ snapshots:
|
|||||||
|
|
||||||
boolbase@1.0.0: {}
|
boolbase@1.0.0: {}
|
||||||
|
|
||||||
|
bootstrap@5.3.3(@popperjs/core@2.11.8):
|
||||||
|
dependencies:
|
||||||
|
'@popperjs/core': 2.11.8
|
||||||
|
|
||||||
brace-expansion@1.1.11:
|
brace-expansion@1.1.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
balanced-match: 1.0.2
|
balanced-match: 1.0.2
|
||||||
@ -6765,6 +6803,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
language-subtag-registry: 0.3.23
|
language-subtag-registry: 0.3.23
|
||||||
|
|
||||||
|
leaflet@1.9.4: {}
|
||||||
|
|
||||||
levn@0.4.1:
|
levn@0.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
prelude-ls: 1.2.1
|
prelude-ls: 1.2.1
|
||||||
|
|||||||
@ -7,71 +7,77 @@ import { signIn } from "next-auth/react"
|
|||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const params = useSearchParams().get("redirect_to");
|
const params = useSearchParams().get("redirect_to");
|
||||||
|
|
||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationKey: ['login'],
|
mutationKey: ['login'],
|
||||||
mutationFn: async (data: { email: string; password: string }) => {
|
mutationFn: async (data: { email: string; password: string }) => {
|
||||||
try {
|
try {
|
||||||
const result = await signIn("credentials", {
|
const result = await signIn("credentials", {
|
||||||
email: data.email,
|
email: data.email,
|
||||||
password: data.password,
|
password: data.password,
|
||||||
redirect: false,
|
redirect: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (result?.error) {
|
|
||||||
const errorMessage = result.error.includes("CredentialsSignin")
|
|
||||||
? "Email ou mot de passe incorrect"
|
|
||||||
: result.error;
|
|
||||||
console.error(errorMessage)
|
|
||||||
throw new Error(result.error)
|
|
||||||
} else {
|
|
||||||
if (params) {
|
|
||||||
router.push(params);
|
|
||||||
} else {
|
|
||||||
router.push('/admin/home')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
} catch (error: unknown) {
|
|
||||||
if (error instanceof Error && error.message.includes("Network Error")) {
|
|
||||||
console.error("Problème de connexion au serveur");
|
|
||||||
}
|
|
||||||
console.error("Autre = ", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
},
|
if (result?.error) {
|
||||||
onError: (error: Error) => {
|
const errorMessage = result.error.includes("CredentialsSignin")
|
||||||
console.error(error.message)
|
? "Email ou mot de passe incorrect"
|
||||||
},
|
: result.error;
|
||||||
})
|
console.error(errorMessage)
|
||||||
|
throw new Error(result.error)
|
||||||
|
} else {
|
||||||
|
if (params) {
|
||||||
|
router.push(params);
|
||||||
|
} else {
|
||||||
|
router.push('/admin/home')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof Error && error.message.includes("Network Error")) {
|
||||||
|
console.error("Problème de connexion au serveur");
|
||||||
|
}
|
||||||
|
console.error("Autre = ", error);
|
||||||
|
}
|
||||||
|
|
||||||
return(
|
|
||||||
<div>
|
},
|
||||||
<Form
|
onError: (error: Error) => {
|
||||||
title="Connexion"
|
console.error(error.message)
|
||||||
formClassName="bg-white p-10 shadow-2xl w-3/4 lg:w-lg"
|
},
|
||||||
fields={[
|
})
|
||||||
{
|
|
||||||
label: "Email",
|
return (
|
||||||
name: "email",
|
<div className="d-flex flex-column bg-bluegray h-100 align-items-center">
|
||||||
type: "email",
|
<div className="login-main d-flex justify-content-center align-items-center position-relative">
|
||||||
placeholder: "Entrer votre email"
|
<Form
|
||||||
},
|
title="Connexion"
|
||||||
{
|
formClassName="bg-white p-10 shadow-2xl w-3/4 lg:w-lg"
|
||||||
label: "Password",
|
fields={[
|
||||||
name: "password",
|
{
|
||||||
type: "password",
|
label: "Email",
|
||||||
placeholder: "Enter votre mot de passe",
|
name: "email",
|
||||||
showPasswordToggle: true
|
type: "email",
|
||||||
}
|
placeholder: "Entrer votre email"
|
||||||
]}
|
},
|
||||||
submit={mutation.mutate}
|
{
|
||||||
schema={loginSchema}
|
label: "Password",
|
||||||
child={<button disabled={mutation.isPending} type="submit" className={`${mutation.isPending ? "btn-auth-loading" : "btn-auth"} mt-4`}>{mutation.isPending ? "Chargement..." : "Connexion"}</button>}
|
name: "password",
|
||||||
/>
|
type: "password",
|
||||||
</div>
|
placeholder: "Enter votre mot de passe",
|
||||||
)
|
showPasswordToggle: true
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
submit={mutation.mutate}
|
||||||
|
schema={loginSchema}
|
||||||
|
child={<div className="d-flex justify-content-center w-100"> <button disabled={mutation.isPending} type="submit" className={`${mutation.isPending ? "btn-auth-loading" : "btn-auth"} cta modal-cta`}>{mutation.isPending ? "Chargement..." : "Connexion"}</button></div>}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="version">
|
||||||
|
<p className="fw-bold" >Version 0.0.1</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@ -1,8 +1,6 @@
|
|||||||
@import "tailwindcss";
|
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Urbanist'; /* Nom que vous donnerez à votre police */
|
font-family: 'Urbanist';
|
||||||
src: url('../assets/fonts/Urbanist.ttf') format('truetype'); /* Chemin vers votre fichier */
|
src: url('../assets/fonts/Urbanist.ttf') format('truetype');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
@ -29,15 +27,18 @@
|
|||||||
--background: #ffffff;
|
--background: #ffffff;
|
||||||
--cinder: #999;
|
--cinder: #999;
|
||||||
--bluegray: --primary;
|
--bluegray: --primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
font-family: Urbanist, sans-serif;
|
font-family: Urbanist, sans-serif !important;
|
||||||
|
}
|
||||||
|
*{
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-form {
|
.input-form {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
@ -54,14 +55,22 @@ body {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
left: 12px;
|
left: 12px;
|
||||||
top: -0.45rem;
|
top: -0.45rem;
|
||||||
background-color: white;
|
padding: 1px 5px;
|
||||||
padding-inline: 4px;
|
line-height: normal;
|
||||||
|
color: var(--secondary);
|
||||||
|
background-color: var(--background);
|
||||||
|
border-radius: 400px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-error {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--danger);
|
||||||
|
}
|
||||||
|
|
||||||
.btn-floating-right {
|
.btn-floating-right {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 8px;
|
right: 12px;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
@ -102,7 +111,12 @@ body {
|
|||||||
transition: width 0.2s, height 0.2s;
|
transition: width 0.2s, height 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta{
|
button {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta {
|
||||||
padding: 10px 24px;
|
padding: 10px 24px;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
height: max-content;
|
height: max-content;
|
||||||
@ -116,35 +130,38 @@ body {
|
|||||||
text-wrap: nowrap;
|
text-wrap: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta.modal-cta{
|
.cta.modal-cta {
|
||||||
|
padding: 9px;
|
||||||
|
margin-top: 32px;
|
||||||
width: 240px;
|
width: 240px;
|
||||||
height: 40px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta.cancel{
|
.cta.cancel {
|
||||||
color: var(--secondary);
|
color: var(--secondary);
|
||||||
border: 1px solid var(--gray);
|
border: 1px solid var(--gray);
|
||||||
background-color: var(--gray);
|
background-color: var(--gray);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta.info{
|
.cta.info {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta.danger{
|
.cta.danger {
|
||||||
border: 1px solid var(--danger);
|
border: 1px solid var(--danger);
|
||||||
background-color: var(--danger);
|
background-color: var(--danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.bg-bluegray{
|
.bg-bluegray {
|
||||||
background-color: var(--bluegray);
|
background-color: var(--bluegray);
|
||||||
}
|
}
|
||||||
.bg-gray{
|
|
||||||
|
.bg-gray {
|
||||||
background-color: var(--gray);
|
background-color: var(--gray);
|
||||||
}
|
}
|
||||||
hr{
|
|
||||||
|
hr {
|
||||||
color: var(--gray);
|
color: var(--gray);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,10 +172,10 @@ input[type="checkbox"] {
|
|||||||
|
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
border: 1px solid var(--secondary) !important;
|
border: 1px solid var(--secondary) !important;
|
||||||
border-radius: 6px !important;
|
border-radius: 6px !important;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +187,7 @@ input[type="checkbox"]:checked {
|
|||||||
|
|
||||||
|
|
||||||
input[type="checkbox"]:checked::before {
|
input[type="checkbox"]:checked::before {
|
||||||
content: "✔";
|
content: "✔";
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: white;
|
color: white;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -179,7 +196,7 @@ input[type="checkbox"]:checked::before {
|
|||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-input{
|
.modal-input {
|
||||||
width: 490px;
|
width: 490px;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
@ -189,7 +206,7 @@ input[type="checkbox"]:checked::before {
|
|||||||
/* Scroll Bar */
|
/* Scroll Bar */
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 4px;
|
width: 7px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@ -224,4 +241,95 @@ input[type="checkbox"]:checked::before {
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Login Header */
|
||||||
|
.login-header {
|
||||||
|
padding: 20px 0;
|
||||||
|
box-shadow: 0 0 24px #0000001A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.word {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: black;
|
||||||
|
position: relative;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
/* font-size: 14px; */
|
||||||
|
color: blue;
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
left: 22px;
|
||||||
|
animation: bounce 1s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-main {
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
padding: 48px 64px;
|
||||||
|
margin: auto;
|
||||||
|
width: max-content;
|
||||||
|
max-width: 624px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 0 24px #0000001A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-fields {
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
|
||||||
|
|
||||||
|
.login-main{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.form-container {
|
||||||
|
padding: 24px 32px;
|
||||||
|
margin: 0 4%;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-fields {
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-input {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
.form-title{
|
||||||
|
margin-bottom: 2px!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta.modal-cta{
|
||||||
|
margin: 0!important;
|
||||||
|
}
|
||||||
|
.input-form{
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -21,6 +21,8 @@ export default function RootLayout({
|
|||||||
<head>
|
<head>
|
||||||
<link rel="icon" href="/favicon.svg" />
|
<link rel="icon" href="/favicon.svg" />
|
||||||
<link rel="favicon.svg" href="/favicon.svg" />
|
<link rel="favicon.svg" href="/favicon.svg" />
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossOrigin="anonymous"/>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossOrigin="anonymous"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
|
|||||||
16
src/assets/icons/final-index.tsx
Normal file
16
src/assets/icons/final-index.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
//import { GeneralHtmlAttr } from "@/lib/declarations";
|
||||||
|
//export type GeneralHtmlAttr = React.HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
import L from "leaflet";
|
||||||
|
|
||||||
|
export const HomeIcon = (props) => {
|
||||||
|
return (
|
||||||
|
<div {...props}>
|
||||||
|
<svg width="22" height="21" viewBox="0 0 22 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M1.25 11L10.205 2.045C10.3094 1.94056 10.4333 1.85772 10.5697 1.80119C10.7061 1.74467 10.8523 1.71558 11 1.71558C11.1477 1.71558 11.2939 1.74467 11.4303 1.80119C11.5667 1.85772 11.6906 1.94056 11.795 2.045L20.75 11M3.5 8.75V18.875C3.5 19.496 4.004 20 4.625 20H8.75V15.125C8.75 14.504 9.254 14 9.875 14H12.125C12.746 14 13.25 14.504 13.25 15.125V20H17.375C17.996 20 18.5 19.496 18.5 18.875V8.75M7.25 20H15.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
9
src/assets/icons/full-logo.svg
Normal file
9
src/assets/icons/full-logo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 462 KiB |
@ -30,7 +30,7 @@ export default function FloatingLabelInput({
|
|||||||
switch(type) {
|
switch(type) {
|
||||||
case 'select':
|
case 'select':
|
||||||
return (
|
return (
|
||||||
<div className="relative w-full">
|
<div className="position-relative w-full">
|
||||||
<select
|
<select
|
||||||
className="input-form modal-input focus:ring-2 focus:ring-blue-500 outline-none"
|
className="input-form modal-input focus:ring-2 focus:ring-blue-500 outline-none"
|
||||||
name={name}
|
name={name}
|
||||||
@ -46,7 +46,7 @@ export default function FloatingLabelInput({
|
|||||||
|
|
||||||
case 'password':
|
case 'password':
|
||||||
return (
|
return (
|
||||||
<div className="relative w-full">
|
<div className="position-relative w-full">
|
||||||
<input
|
<input
|
||||||
name={name}
|
name={name}
|
||||||
type={showPassword ? "text" : "password"}
|
type={showPassword ? "text" : "password"}
|
||||||
@ -66,14 +66,14 @@ export default function FloatingLabelInput({
|
|||||||
src={icons.eyeSlashIcon}
|
src={icons.eyeSlashIcon}
|
||||||
width={20}
|
width={20}
|
||||||
height={20}
|
height={20}
|
||||||
alt=''
|
alt='show password'
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Image
|
<Image
|
||||||
src={icons.eyeIcon}
|
src={icons.eyeIcon}
|
||||||
width={20}
|
width={20}
|
||||||
height={20}
|
height={20}
|
||||||
alt=''
|
alt='hide password'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
@ -84,7 +84,7 @@ export default function FloatingLabelInput({
|
|||||||
|
|
||||||
case 'search':
|
case 'search':
|
||||||
return (
|
return (
|
||||||
<div className="relative w-full">
|
<div className="position-relative w-full">
|
||||||
<div className='btn-floating-left'>
|
<div className='btn-floating-left'>
|
||||||
<Image alt='' src={icons.searchIcon} />
|
<Image alt='' src={icons.searchIcon} />
|
||||||
</div>
|
</div>
|
||||||
@ -102,7 +102,7 @@ export default function FloatingLabelInput({
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<div className="relative w-full">
|
<div className="position-relative w-full">
|
||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
@ -118,7 +118,7 @@ export default function FloatingLabelInput({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="position-relative">
|
||||||
<label
|
<label
|
||||||
htmlFor={name}
|
htmlFor={name}
|
||||||
className="input-label text-gray-400 text-sm"
|
className="input-label text-gray-400 text-sm"
|
||||||
|
|||||||
@ -5,72 +5,71 @@ import { FormProps } from "#/types"
|
|||||||
import { FormEvent, useState } from "react"
|
import { FormEvent, useState } from "react"
|
||||||
|
|
||||||
export default function Form({
|
export default function Form({
|
||||||
fields,
|
fields,
|
||||||
submit,
|
submit,
|
||||||
className,
|
className,
|
||||||
child,
|
child,
|
||||||
title,
|
title,
|
||||||
schema,
|
schema,
|
||||||
formClassName
|
formClassName
|
||||||
} : FormProps) {
|
}: FormProps) {
|
||||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||||
|
|
||||||
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
|
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
const formData = new FormData(e.currentTarget)
|
const formData = new FormData(e.currentTarget)
|
||||||
const data = Object.fromEntries(formData)
|
const data = Object.fromEntries(formData)
|
||||||
|
|
||||||
console.log("FORM DATA = ", data)
|
console.log("FORM DATA = ", data)
|
||||||
const result = schema.safeParse(data);
|
const result = schema.safeParse(data);
|
||||||
console.log("ZOD = ", result.error?.format())
|
console.log("ZOD = ", result.error?.format())
|
||||||
|
|
||||||
if(!result.success) {
|
if (!result.success) {
|
||||||
const formatedErrors = result.error.format() as Record<string, { _errors?: string[] }>;
|
const formatedErrors = result.error.format() as Record<string, { _errors?: string[] }>;
|
||||||
|
|
||||||
const newErrors: Record<string, string> = {};
|
const newErrors: Record<string, string> = {};
|
||||||
Object.keys(formatedErrors).forEach((field) => {
|
Object.keys(formatedErrors).forEach((field) => {
|
||||||
if (field !== "_errors" && formatedErrors[field]._errors?.length) {
|
if (field !== "_errors" && formatedErrors[field]._errors?.length) {
|
||||||
newErrors[field] = formatedErrors[field]._errors[0];
|
newErrors[field] = formatedErrors[field]._errors[0];
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setErrors(newErrors)
|
|
||||||
} else {
|
|
||||||
setErrors({})
|
|
||||||
submit(result.data)
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setErrors(newErrors)
|
||||||
|
} else {
|
||||||
|
setErrors({})
|
||||||
|
submit(result.data)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit} className={formClassName}>
|
<form onSubmit={handleSubmit} className={(formClassName) + " form-container"}>
|
||||||
<div className="flex justify-center text-black">
|
<div className="form-title d-flex justify-content-center text-black mb-3 ">
|
||||||
<p className="text-3xl font-bold">{title}</p>
|
<p className="fs-3 fw-bold">{title}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={`d-flex flex-column form-fields ${className}`}>
|
||||||
|
|
||||||
|
{
|
||||||
|
fields.map((item, index) => (
|
||||||
|
<div key={index}>
|
||||||
|
<FloatingLabelInput
|
||||||
|
label={item.label}
|
||||||
|
name={item.name}
|
||||||
|
type={item.type}
|
||||||
|
button={item.button}
|
||||||
|
defaultValue={item.defaultValue}
|
||||||
|
options={item.options}
|
||||||
|
placeholder={item.placeholder}
|
||||||
|
showPasswordToggle={item.showPasswordToggle}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span className="form-error">{errors[item.name]}</span>
|
||||||
</div>
|
</div>
|
||||||
|
))
|
||||||
<div className={`space-y-8 my-2 ${className}`}>
|
}
|
||||||
|
</div>
|
||||||
{
|
{child}
|
||||||
fields.map((item, index) => (
|
</form>
|
||||||
<div key={index}>
|
)
|
||||||
<FloatingLabelInput
|
|
||||||
label={item.label}
|
|
||||||
name={item.name}
|
|
||||||
type={item.type}
|
|
||||||
button={item.button}
|
|
||||||
defaultValue={item.defaultValue}
|
|
||||||
options={item.options}
|
|
||||||
placeholder={item.placeholder}
|
|
||||||
showPasswordToggle={item.showPasswordToggle}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<span className="text-red-500 text-xs mt-1">{errors[item.name]}</span>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
{child}
|
|
||||||
</form>
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
@ -2,16 +2,18 @@ import { icons } from "#/assets/icons";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
return(
|
return (
|
||||||
<div className="w-full bg-white shadow-md py-4">
|
<div className="d-flex justify-content-center login-header ">
|
||||||
<div className="container mx-auto text-center flex items-center justify-center gap-2">
|
<div className="d-flex justify-content-center align-items-center gap-2">
|
||||||
<Image
|
<Image
|
||||||
src={icons.logo}
|
src={icons.logo}
|
||||||
alt="Private Docs"
|
alt="Private Docs"
|
||||||
className="text-red-500 h-auto"
|
className="text-red-500 h-auto"
|
||||||
/>
|
height={30}
|
||||||
<p className="text-2xl font-bold text-black">Private Docs</p>
|
/>
|
||||||
</div>
|
{/* <p className="text-2xl font-bold text-black">Private Docs</p> */}
|
||||||
</div>
|
<p className="r-p-m-0 word">Pr<span className="dot">•</span>ıvate Docs</p>
|
||||||
)
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
9
src/lib/bootstrapLoader.tsx
Normal file
9
src/lib/bootstrapLoader.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||||
|
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||||
|
import 'bootstrap/dist/js/bootstrap.bundle.min.js';
|
||||||
|
|
||||||
|
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
return <>{children}</>;
|
||||||
|
}
|
||||||
@ -23,6 +23,6 @@
|
|||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["svgr.d.ts", "next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": ["svgr.d.ts", "next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "src/assets/icons/final-index.js"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user