diff --git a/back/tsconfig.json b/back/tsconfig.json index 2954c5b..2fc79b1 100644 --- a/back/tsconfig.json +++ b/back/tsconfig.json @@ -8,10 +8,6 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, - "include": [ - "src/**/*.ts" - ], - "exclude": [ - "node_modules" - ] + "include": ["src/**/*.ts"], + "exclude": ["node_modules"] } diff --git a/front/README.md b/front/README.md index c403366..5ce4a7c 100644 --- a/front/README.md +++ b/front/README.md @@ -24,8 +24,8 @@ This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-opti To learn more about Next.js, take a look at the following resources: -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! diff --git a/front/next.config.mjs b/front/next.config.mjs index 068574e..36ea146 100644 --- a/front/next.config.mjs +++ b/front/next.config.mjs @@ -2,23 +2,23 @@ import path from "path"; /** @type {import('next').NextConfig} */ const nextConfig = { - /** - * https://nextjs.org/docs/app/building-your-application/styling/sass - */ - sassOptions: { - // optional: prependData: `@import "@/styles/variables";`, - includePaths: [path.join("@", "styles")], - }, - images: { - remotePatterns: [ - { - protocol: "https", - hostname: "picsum.photos", - port: "", - pathname: "/**", - }, - ], - }, + /** + * https://nextjs.org/docs/app/building-your-application/styling/sass + */ + sassOptions: { + // optional: prependData: `@import "@/styles/variables";`, + includePaths: [path.join("@", "styles")], + }, + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "picsum.photos", + port: "", + pathname: "/**", + }, + ], + }, }; export default nextConfig; diff --git a/front/src/app/(home)/page.tsx b/front/src/app/(home)/page.tsx index 0f918c7..55b3e81 100644 --- a/front/src/app/(home)/page.tsx +++ b/front/src/app/(home)/page.tsx @@ -1,15 +1,15 @@ export default function Home() { - return ( - - Main page - - ); + return ( + + Main page + + ); } diff --git a/front/src/middleware.ts b/front/src/middleware.ts index 59365a2..61dff88 100644 --- a/front/src/middleware.ts +++ b/front/src/middleware.ts @@ -2,38 +2,38 @@ import { withAuth } from "next-auth/middleware"; import { authOptions } from "./modules/auth/configs/auth.options"; export default withAuth({ - pages: authOptions.pages, - callbacks: { - authorized({ req, token }) { - if (token && token.apiSession.exp * 1000 > Date.now()) { - return true; - } - const pathname = req.nextUrl.pathname; - return ( - pathname.startsWith("/_next/") || - pathname.startsWith("/favicon.ico") || - pathname.startsWith("/assets/") - ); + pages: authOptions.pages, + callbacks: { + authorized({ req, token }) { + if (token && token.apiSession.exp * 1000 > Date.now()) { + return true; + } + const pathname = req.nextUrl.pathname; + return ( + pathname.startsWith("/_next/") || + pathname.startsWith("/favicon.ico") || + pathname.startsWith("/assets/") + ); + }, }, - }, }); const value = { - token: { - name: "dqnid", - picture: "https://picsum.photos/200/300", - sub: "dqnid", - user: { - id: "dqnid", - roles: ["user", "manager", "admin"], - image: "https://picsum.photos/200/300", - name: "dqnid", + token: { + name: "dqnid", + picture: "https://picsum.photos/200/300", + sub: "dqnid", + user: { + id: "dqnid", + roles: ["user", "manager", "admin"], + image: "https://picsum.photos/200/300", + name: "dqnid", + }, + apiSession: { + exp: 1725398177, + }, + iat: 1725394577, + exp: 1727986577, + jti: "3203d3c7-dc27-4599-b37e-16737b3a6674", }, - apiSession: { - exp: 1725398177, - }, - iat: 1725394577, - exp: 1727986577, - jti: "3203d3c7-dc27-4599-b37e-16737b3a6674", - }, }; diff --git a/front/src/modules/auth/components/log-in/log-in.module.scss b/front/src/modules/auth/components/log-in/log-in.module.scss index 818e25c..f8c788b 100644 --- a/front/src/modules/auth/components/log-in/log-in.module.scss +++ b/front/src/modules/auth/components/log-in/log-in.module.scss @@ -1,179 +1,179 @@ .container { - max-width: 50em; - height: fit-content; + max-width: 50em; + height: fit-content; - display: flex; - flex-direction: row; - - font-size: 1.4rem; - overflow: hidden; - - border-radius: 0.4rem; - border: 2px solid rgba(var(--color-grey-90-rgb), 0.4); - background-color: var(--color-white); - - .side__illustration { display: flex; - flex-direction: column; - justify-content: space-between; - max-width: 16em; - box-sizing: content-box; - opacity: 0.8; + flex-direction: row; - text-shadow: rgba(var(--color-grey-10), 0.3); - padding: 2rem 2rem; + font-size: 1.4rem; + overflow: hidden; - --s: 100px; - --c1: rgba(var(--color-grey-70-rgb), 0.4); - --c2: var(--color-white); + border-radius: 0.4rem; + border: 2px solid rgba(var(--color-grey-90-rgb), 0.4); + background-color: var(--color-white); - --_g: #0000 90deg, var(--c1) 0; - background: conic-gradient(from 90deg at 2px 2px, var(--_g)), - conic-gradient(from 90deg at 1px 1px, var(--_g)), var(--c2); - background-size: - var(--s) var(--s), - calc(var(--s) / 5) calc(var(--s) / 5); - background-position: -2px -2px; + .side__illustration { + display: flex; + flex-direction: column; + justify-content: space-between; + max-width: 16em; + box-sizing: content-box; + opacity: 0.8; - & > h1 { - font-size: 3.4rem; - font-weight: bold; - text-align: left; + text-shadow: rgba(var(--color-grey-10), 0.3); + padding: 2rem 2rem; - padding-right: 2rem; + --s: 100px; + --c1: rgba(var(--color-grey-70-rgb), 0.4); + --c2: var(--color-white); - & > span { - position: relative; + --_g: #0000 90deg, var(--c1) 0; + background: conic-gradient(from 90deg at 2px 2px, var(--_g)), + conic-gradient(from 90deg at 1px 1px, var(--_g)), var(--c2); + background-size: + var(--s) var(--s), + calc(var(--s) / 5) calc(var(--s) / 5); + background-position: -2px -2px; - &::after { - content: ""; - position: absolute; - height: 40%; - width: 110%; - top: 70%; - left: -5%; + & > h1 { + font-size: 3.4rem; + font-weight: bold; + text-align: left; - z-index: -1; + padding-right: 2rem; - background-color: var(--color-primary); - } - } - } + & > span { + position: relative; - & > h4 { - font-size: 1.4rem; + &::after { + content: ""; + position: absolute; + height: 40%; + width: 110%; + top: 70%; + left: -5%; - text-align: right; - padding-left: 2rem; - } - } + z-index: -1; - .form { - display: flex; - flex-direction: column; - align-items: center; - gap: 1em; - - padding: 3.5em 2.5em; - - background: rgba(var(--color-grey-90-rgb), 0.4); - - &__group { - display: flex; - flex-direction: column; - gap: 0.2em; - } - - &__label { - margin-left: 0.8em; - - color: rgba(var(--color-grey-60-rgb), 0.8); - transition: all 0.3s; - } - - &__input { - padding: 0.8em; - - background-color: transparent; - border: none; - border-bottom: 2px solid var(--color-grey-70); - border-radius: 2px; - - transition: all 0.2s; - - &::placeholder { - opacity: 1; - color: rgba(var(--color-grey-60-rgb), 0.8); - } - - &:focus { - outline: none; - border-bottom: 2px solid var(--color-primary); - box-shadow: 0 1px 4px rgba(var(--color-primary-dark-rgb), 0.3); - } - } - - &__group:has(.form__input:placeholder-shown) .form__label { - opacity: 0; - transform: translateY(1rem); - } - - &__actions { - width: 100%; - display: flex; - flex-direction: column; - gap: 0.5em; - - & .submit__button { - all: unset; - width: fit-content; - font-size: 1.4rem; - text-transform: uppercase; - padding: 0.5em 1em; - border-radius: 2px; - - align-self: center; - - border: none; - color: var(--color-black); - border: 2px solid var(--color-primary); - - transition: all 0.2s; - - &:hover { - color: var(--color-white); - background-color: var(--color-primary); - cursor: pointer; - transform: translateY(-2px); - box-shadow: 0 2px 6px rgba(var(--color-primary-dark-rgb), 0.4); + background-color: var(--color-primary); + } + } } - &:active { - transform: translateY(0); + & > h4 { + font-size: 1.4rem; + + text-align: right; + padding-left: 2rem; } - } } - &__message { - opacity: 0; - height: 2.5rem; + .form { + display: flex; + flex-direction: column; + align-items: center; + gap: 1em; - align-self: flex-start; + padding: 3.5em 2.5em; - transition: opacity 0.3s ease-in; + background: rgba(var(--color-grey-90-rgb), 0.4); - &--wrong { - color: var(--color-error); - } + &__group { + display: flex; + flex-direction: column; + gap: 0.2em; + } + + &__label { + margin-left: 0.8em; + + color: rgba(var(--color-grey-60-rgb), 0.8); + transition: all 0.3s; + } + + &__input { + padding: 0.8em; + + background-color: transparent; + border: none; + border-bottom: 2px solid var(--color-grey-70); + border-radius: 2px; + + transition: all 0.2s; + + &::placeholder { + opacity: 1; + color: rgba(var(--color-grey-60-rgb), 0.8); + } + + &:focus { + outline: none; + border-bottom: 2px solid var(--color-primary); + box-shadow: 0 1px 4px rgba(var(--color-primary-dark-rgb), 0.3); + } + } + + &__group:has(.form__input:placeholder-shown) .form__label { + opacity: 0; + transform: translateY(1rem); + } + + &__actions { + width: 100%; + display: flex; + flex-direction: column; + gap: 0.5em; + + & .submit__button { + all: unset; + width: fit-content; + font-size: 1.4rem; + text-transform: uppercase; + padding: 0.5em 1em; + border-radius: 2px; + + align-self: center; + + border: none; + color: var(--color-black); + border: 2px solid var(--color-primary); + + transition: all 0.2s; + + &:hover { + color: var(--color-white); + background-color: var(--color-primary); + cursor: pointer; + transform: translateY(-2px); + box-shadow: 0 2px 6px rgba(var(--color-primary-dark-rgb), 0.4); + } + + &:active { + transform: translateY(0); + } + } + } + + &__message { + opacity: 0; + height: 2.5rem; + + align-self: flex-start; + + transition: opacity 0.3s ease-in; + + &--wrong { + color: var(--color-error); + } + } } - } } .form--error { - .form__input { - border-bottom: 2px solid var(--color-error); - } + .form__input { + border-bottom: 2px solid var(--color-error); + } - .form__message { - opacity: 1; - } + .form__message { + opacity: 1; + } } diff --git a/front/src/modules/auth/components/log-in/log-in.widget.tsx b/front/src/modules/auth/components/log-in/log-in.widget.tsx index d1849ff..f93fe5b 100644 --- a/front/src/modules/auth/components/log-in/log-in.widget.tsx +++ b/front/src/modules/auth/components/log-in/log-in.widget.tsx @@ -7,101 +7,101 @@ import { signIn, useSession } from "next-auth/react"; import { useRouter, useSearchParams } from "next/navigation"; type LogInWidgetsProps = { - afterSuccess?: Function; + afterSuccess?: Function; }; export const LogInWidget: React.FC = ({ afterSuccess }) => { - const router = useRouter(); - const searchParams = useSearchParams(); + const router = useRouter(); + const searchParams = useSearchParams(); - const callbackUrl = searchParams.get("callbackUrl"); + const callbackUrl = searchParams.get("callbackUrl"); - const [loginStatus, setLoginStatus] = useState< - "idle" | "check" | "confirm" | "error" - >("idle"); + const [loginStatus, setLoginStatus] = useState< + "idle" | "check" | "confirm" | "error" + >("idle"); - const submit = async (event: FormEvent) => { - event.preventDefault(); - setLoginStatus("check"); - const username = ( - event.currentTarget.elements.namedItem("username") as HTMLInputElement - ).value; - const password = ( - event.currentTarget.elements.namedItem("password") as HTMLInputElement - ).value; + const submit = async (event: FormEvent) => { + event.preventDefault(); + setLoginStatus("check"); + const username = ( + event.currentTarget.elements.namedItem("username") as HTMLInputElement + ).value; + const password = ( + event.currentTarget.elements.namedItem("password") as HTMLInputElement + ).value; - const result = await signIn("credentials", { - redirect: false, - username: username, - password: password, - }); + const result = await signIn("credentials", { + redirect: false, + username: username, + password: password, + }); - if (!result?.ok) { - setLoginStatus("error"); - } else { - setLoginStatus("confirm"); - } - }; + if (!result?.ok) { + setLoginStatus("error"); + } else { + setLoginStatus("confirm"); + } + }; - useEffect(() => { - if (loginStatus === "confirm") { - router.push(callbackUrl ?? "/"); - } - }, [loginStatus]); + useEffect(() => { + if (loginStatus === "confirm") { + router.push(callbackUrl ?? "/"); + } + }, [loginStatus]); - return ( - - - - Welcome to this page! - - Use your credentials to log-in - - - - - username - - + return ( + + + + Welcome to this page! + + Use your credentials to log-in + + + + + username + + + + + + password + + + + + + {loginStatus === "error" ? ( + + Wrong credentials, try again + + ) : ( + <>Loading...> + )} + + + Log-in + + + - - - password - - - - - - {loginStatus === "error" ? ( - - Wrong credentials, try again - - ) : ( - <>Loading...> - )} - - - Log-in - - - - - ); + ); }; diff --git a/front/src/modules/auth/components/sign-in-button/sign-in-button.component.tsx b/front/src/modules/auth/components/sign-in-button/sign-in-button.component.tsx index ffc1f3b..8208133 100644 --- a/front/src/modules/auth/components/sign-in-button/sign-in-button.component.tsx +++ b/front/src/modules/auth/components/sign-in-button/sign-in-button.component.tsx @@ -2,9 +2,9 @@ import { signIn } from "next-auth/react"; import styles from "./sign-in-button.module.scss"; export const SignInButton = () => { - return ( - void signIn()}> - Sign in - - ); + return ( + void signIn()}> + Sign in + + ); }; diff --git a/front/src/modules/auth/components/sign-out-button/sign-out-button.component.tsx b/front/src/modules/auth/components/sign-out-button/sign-out-button.component.tsx index bbd1ae2..f9a62f7 100644 --- a/front/src/modules/auth/components/sign-out-button/sign-out-button.component.tsx +++ b/front/src/modules/auth/components/sign-out-button/sign-out-button.component.tsx @@ -2,12 +2,12 @@ import { signOut } from "next-auth/react"; import styles from "./sign-out-button.module.scss"; export const SignOutButton = () => { - return ( - void signOut({ callbackUrl: "/" })} - > - Sign out - - ); + return ( + void signOut({ callbackUrl: "/" })} + > + Sign out + + ); }; diff --git a/front/src/modules/auth/components/user-dropdown/user-dropdown.component.tsx b/front/src/modules/auth/components/user-dropdown/user-dropdown.component.tsx index 802ffab..62c0a5e 100644 --- a/front/src/modules/auth/components/user-dropdown/user-dropdown.component.tsx +++ b/front/src/modules/auth/components/user-dropdown/user-dropdown.component.tsx @@ -3,14 +3,14 @@ import UserPanel from "../user-panel"; import { UserFrame } from "../user-frame"; export const UserDropdown = async () => { - return ( - - - - - - - - - ); + return ( + + + + + + + + + ); }; diff --git a/front/src/modules/auth/components/user-dropdown/user-dropdown.module.scss b/front/src/modules/auth/components/user-dropdown/user-dropdown.module.scss index 716371a..921c9da 100644 --- a/front/src/modules/auth/components/user-dropdown/user-dropdown.module.scss +++ b/front/src/modules/auth/components/user-dropdown/user-dropdown.module.scss @@ -1,26 +1,26 @@ .container { - position: relative; - overflow: visible; + position: relative; + overflow: visible; - .avatar__container { - height: var(--header-item-height, 4rem); - width: var(--header-item-height, 4rem); + .avatar__container { + height: var(--header-item-height, 4rem); + width: var(--header-item-height, 4rem); - font-size: 3.2rem; - } + font-size: 3.2rem; + } - .dropdown__container { - position: absolute; - right: 0; + .dropdown__container { + position: absolute; + right: 0; - opacity: 0; - visibility: hidden; + opacity: 0; + visibility: hidden; - transition: all 0.2s; - } + transition: all 0.2s; + } - &:hover > .dropdown__container { - opacity: 1; - visibility: visible; - } + &:hover > .dropdown__container { + opacity: 1; + visibility: visible; + } } diff --git a/front/src/modules/auth/components/user-frame/user-frame.component.tsx b/front/src/modules/auth/components/user-frame/user-frame.component.tsx index b2e9ad8..0669ea9 100644 --- a/front/src/modules/auth/components/user-frame/user-frame.component.tsx +++ b/front/src/modules/auth/components/user-frame/user-frame.component.tsx @@ -5,39 +5,39 @@ import { getServerSession } from "next-auth"; import SignInButton from "../sign-in-button"; export async function UserFrame() { - const session = await getServerSession(); + const session = await getServerSession(); - if (!session) { - return ; - } + if (!session) { + return ; + } - return ( - - - {getInitialsFromName(session?.user?.name || "00")} - - - - ); + return ( + + + {getInitialsFromName(session?.user?.name || "00")} + + + + ); } const getInitialsFromName = (name: string): string => { - if (name.length < 1) return "00"; + if (name.length < 1) return "00"; - // TODO: this can be done in one line probably - const words = name.split(" "); - let initials = ""; - words.forEach((word) => (initials += word[0])); - if (initials.length < 2) { - initials += name[1]; - } + // TODO: this can be done in one line probably + const words = name.split(" "); + let initials = ""; + words.forEach((word) => (initials += word[0])); + if (initials.length < 2) { + initials += name[1]; + } - return initials.slice(0, 2); + return initials.slice(0, 2); }; diff --git a/front/src/modules/auth/components/user-frame/user-frame.module.scss b/front/src/modules/auth/components/user-frame/user-frame.module.scss index f48a76a..664b96e 100644 --- a/front/src/modules/auth/components/user-frame/user-frame.module.scss +++ b/front/src/modules/auth/components/user-frame/user-frame.module.scss @@ -1,23 +1,23 @@ .frame { - position: relative; - font-size: inherit; - - width: 100%; - height: 100%; - border-radius: 50%; - overflow: hidden; - - box-shadow: 1px 1px 3px var(--color-grey-30); - box-sizing: border-box; - - & > span { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - + position: relative; font-size: inherit; - text-transform: uppercase; - color: var(--color-grey-30); - } + + width: 100%; + height: 100%; + border-radius: 50%; + overflow: hidden; + + box-shadow: 1px 1px 3px var(--color-grey-30); + box-sizing: border-box; + + & > span { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + + font-size: inherit; + text-transform: uppercase; + color: var(--color-grey-30); + } } diff --git a/front/src/modules/auth/components/user-panel/user-panel.component.tsx b/front/src/modules/auth/components/user-panel/user-panel.component.tsx index 23331de..16e3586 100644 --- a/front/src/modules/auth/components/user-panel/user-panel.component.tsx +++ b/front/src/modules/auth/components/user-panel/user-panel.component.tsx @@ -4,20 +4,20 @@ import { useSession } from "next-auth/react"; import ThemeSwitcher from "@/modules/common/components/theme-switcher"; export function UserPanel() { - const session = useSession(); + const session = useSession(); - return ( - - {session.data?.user?.name} - - {session.data?.user?.roles.map((role) => ( - - {role} - - ))} - - - - - ); + return ( + + {session.data?.user?.name} + + {session.data?.user?.roles.map((role) => ( + + {role} + + ))} + + + + + ); } diff --git a/front/src/modules/auth/components/user-panel/user-panel.module.scss b/front/src/modules/auth/components/user-panel/user-panel.module.scss index 4b8f4aa..aa0e8f1 100644 --- a/front/src/modules/auth/components/user-panel/user-panel.module.scss +++ b/front/src/modules/auth/components/user-panel/user-panel.module.scss @@ -1,39 +1,39 @@ .frame { - list-style: none; - min-width: 15rem; - display: flex; - flex-direction: column; - gap: 1.8rem 0.6rem; + list-style: none; + min-width: 15rem; + display: flex; + flex-direction: column; + gap: 1.8rem 0.6rem; - padding: 1.2rem 1.8rem; + padding: 1.2rem 1.8rem; - border-radius: 6px; - background-color: var(--color-white); - box-shadow: 0 2px 3px rgba(var(--color-grey-10-rgb), 0.2); - color: var(--color-background); + border-radius: 6px; + background-color: var(--color-white); + box-shadow: 0 2px 3px rgba(var(--color-grey-10-rgb), 0.2); + color: var(--color-background); - z-index: 10; + z-index: 10; - & .user { - font-size: 1.6rem; + & .user { + font-size: 1.6rem; - &__name { + &__name { + } + + &__roles { + list-style: none; + + display: flex; + flex-wrap: wrap; + gap: 0.4rem; + + & .role__chip { + padding: 0.4rem 0.6rem; + + border-radius: 4px; + background-color: var(--color-grey-90); + color: var(--color-grey-10); + } + } } - - &__roles { - list-style: none; - - display: flex; - flex-wrap: wrap; - gap: 0.4rem; - - & .role__chip { - padding: 0.4rem 0.6rem; - - border-radius: 4px; - background-color: var(--color-grey-90); - color: var(--color-grey-10); - } - } - } } diff --git a/front/src/modules/auth/configs/auth.options.ts b/front/src/modules/auth/configs/auth.options.ts index 2f83847..a90f6d7 100644 --- a/front/src/modules/auth/configs/auth.options.ts +++ b/front/src/modules/auth/configs/auth.options.ts @@ -2,88 +2,92 @@ import { AuthOptions, Role, User } from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; export const authOptions: AuthOptions = { - session: { - strategy: "jwt", - }, - pages: { - signIn: "/auth/log-in", - signOut: "/", - }, - providers: [ - CredentialsProvider({ - name: "Sign in", - credentials: { - username: { label: "Username", type: "text", placeholder: "yourself" }, - password: { label: "Password", type: "password" }, - }, - async authorize(credentials, req) { - const response = await fetch( - process.env.NEXT_PUBLIC_AUTH_URL + "/auth/login", - { - method: "POST", - headers: { - "Content-Type": "application/json", + session: { + strategy: "jwt", + }, + pages: { + signIn: "/auth/log-in", + signOut: "/", + }, + providers: [ + CredentialsProvider({ + name: "Sign in", + credentials: { + username: { + label: "Username", + type: "text", + placeholder: "yourself", + }, + password: { label: "Password", type: "password" }, }, - body: JSON.stringify({ - username: credentials?.username, - password: credentials?.password, - }), - }, - ); + async authorize(credentials, req) { + const response = await fetch( + process.env.NEXT_PUBLIC_AUTH_URL + "/auth/login", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + username: credentials?.username, + password: credentials?.password, + }), + }, + ); - type LoginResponse = { - access_token: string; - }; + type LoginResponse = { + access_token: string; + }; - if (response.status < 200 || response.status > 399) return null; + if (response.status < 200 || response.status > 399) return null; - const response_body = (await response.json()) as LoginResponse; + const response_body = (await response.json()) as LoginResponse; - type TokenPayload = { - sub: string; - username: string; - roles: Role[]; - picture: string; - iat: number; - exp: number; - }; + type TokenPayload = { + sub: string; + username: string; + roles: Role[]; + picture: string; + iat: number; + exp: number; + }; - const token_payload = JSON.parse( - atob(response_body.access_token.split(".")[1]), - ) as TokenPayload; + const token_payload = JSON.parse( + atob(response_body.access_token.split(".")[1]), + ) as TokenPayload; - const user: User = { - id: token_payload.username, - roles: token_payload.roles, - image: token_payload.picture, - name: token_payload.username, - apiSession: { - exp: token_payload.exp, - accessToken: response_body.access_token, - }, - }; + const user: User = { + id: token_payload.username, + roles: token_payload.roles, + image: token_payload.picture, + name: token_payload.username, + apiSession: { + exp: token_payload.exp, + accessToken: response_body.access_token, + }, + }; - return user; - }, - }), - ], - callbacks: { - async jwt({ token, user }) { - // Persist the OAuth access_token to the token right after signin - if (user) { - const { apiSession, ...cleanedUser } = user; - token.user = cleanedUser; - token.apiSession = apiSession; - } - return token; + return user; + }, + }), + ], + callbacks: { + async jwt({ token, user }) { + // Persist the OAuth access_token to the token right after signin + if (user) { + const { apiSession, ...cleanedUser } = user; + token.user = cleanedUser; + token.apiSession = apiSession; + } + return token; + }, + async session({ session, token }) { + // Send properties to the client, like an access_token from a provider. + if (token?.user && session) { + session.apiSession = token.apiSession; + session.user = token.user; + } + return session; + }, }, - async session({ session, token }) { - // Send properties to the client, like an access_token from a provider. - if (token?.user && session) { - session.apiSession = token.apiSession; - session.user = token.user; - } - return session; - }, - }, }; diff --git a/front/src/modules/auth/providers/auth.provider.tsx b/front/src/modules/auth/providers/auth.provider.tsx index 2ad16f0..8f19d58 100644 --- a/front/src/modules/auth/providers/auth.provider.tsx +++ b/front/src/modules/auth/providers/auth.provider.tsx @@ -4,5 +4,5 @@ import { SessionProvider } from "next-auth/react"; import { PropsWithChildren } from "react"; export const AuthProvider: React.FC = ({ children }) => { - return {children}; + return {children}; }; diff --git a/front/src/modules/auth/types/next-auth.d.ts b/front/src/modules/auth/types/next-auth.d.ts index d5687fc..ef3123d 100644 --- a/front/src/modules/auth/types/next-auth.d.ts +++ b/front/src/modules/auth/types/next-auth.d.ts @@ -2,29 +2,29 @@ import NextAuth, { DefaultSession } from "next-auth"; import { JWT, DefaultJWT } from "next-auth/jwt"; declare module "next-auth" { - type Role = "user" | "manager" | "admin"; - interface ApiSession { - exp?: number; - accessToken: string; - refreshToken?: string; - } - interface User { - id: string; - roles: Role[]; - image?: string; - name?: string; - apiSession?: ApiSession; - } + type Role = "user" | "manager" | "admin"; + interface ApiSession { + exp?: number; + accessToken: string; + refreshToken?: string; + } + interface User { + id: string; + roles: Role[]; + image?: string; + name?: string; + apiSession?: ApiSession; + } - interface Session extends DefaultSession { - user?: Omit; - apiSession?: ApiSession; - } + interface Session extends DefaultSession { + user?: Omit; + apiSession?: ApiSession; + } } declare module "next-auth/jwt" { - interface JWT { - user?: Omit; - apiSession?: ApiSession; - } + interface JWT { + user?: Omit; + apiSession?: ApiSession; + } } diff --git a/front/src/modules/auth/views/log-in/log-in.module.scss b/front/src/modules/auth/views/log-in/log-in.module.scss index dd69285..16b97ad 100644 --- a/front/src/modules/auth/views/log-in/log-in.module.scss +++ b/front/src/modules/auth/views/log-in/log-in.module.scss @@ -1,7 +1,7 @@ .container { - min-height: 100vh; + min-height: 100vh; - display: flex; - align-items: center; - justify-content: center; + display: flex; + align-items: center; + justify-content: center; } diff --git a/front/src/modules/auth/views/log-in/log-in.view.tsx b/front/src/modules/auth/views/log-in/log-in.view.tsx index 8de20e5..d6edbdc 100644 --- a/front/src/modules/auth/views/log-in/log-in.view.tsx +++ b/front/src/modules/auth/views/log-in/log-in.view.tsx @@ -5,11 +5,11 @@ import styles from "./log-in.module.scss"; type LogInWidgetsProps = {}; export const LogInView: React.FC = ({}) => { - return ( - - - - - - ); + return ( + + + + + + ); }; diff --git a/front/src/modules/common/components/navbar-header/navbar-header.component.tsx b/front/src/modules/common/components/navbar-header/navbar-header.component.tsx index b35ddf8..df225fb 100644 --- a/front/src/modules/common/components/navbar-header/navbar-header.component.tsx +++ b/front/src/modules/common/components/navbar-header/navbar-header.component.tsx @@ -7,13 +7,13 @@ import { PropsWithChildren } from "react"; * Receives the user component as a children in order to fetch it from the server and allow quick session information fetch * */ export const NavbarHeader = (props: PropsWithChildren) => { - return ( - - - - Your brand - - {props.children} - - ); + return ( + + + + Your brand + + {props.children} + + ); }; diff --git a/front/src/modules/common/components/navbar-header/navbar-header.module.scss b/front/src/modules/common/components/navbar-header/navbar-header.module.scss index ca86ea6..a8d2fa3 100644 --- a/front/src/modules/common/components/navbar-header/navbar-header.module.scss +++ b/front/src/modules/common/components/navbar-header/navbar-header.module.scss @@ -1,46 +1,46 @@ .header { - position: sticky; - top: 1.2rem; - left: 0; + position: sticky; + top: 1.2rem; + left: 0; - display: flex; - justify-content: space-between; - - margin: 1.2rem; - box-sizing: border-box; - border-radius: 8px; - - padding: 0.6rem 2rem; - background-color: var(--color-white); - box-shadow: 0 1px 3px rgba(var(--color-grey-10-rgb), 0.3); - color: var(--color-background); - - --header-item-height: 4.5rem; - - .logo { display: flex; - flex-direction: row; - gap: 0.6rem; - align-items: center; + justify-content: space-between; - font-size: 2.6rem; - font-weight: bold; + margin: 1.2rem; + box-sizing: border-box; + border-radius: 8px; - height: var(--header-item-height); - width: auto; + padding: 0.6rem 2rem; + background-color: var(--color-white); + box-shadow: 0 1px 3px rgba(var(--color-grey-10-rgb), 0.3); + color: var(--color-background); - & > img { - height: 100%; - width: 100%; - object-fit: contain; + --header-item-height: 4.5rem; + + .logo { + display: flex; + flex-direction: row; + gap: 0.6rem; + align-items: center; + + font-size: 2.6rem; + font-weight: bold; + + height: var(--header-item-height); + width: auto; + + & > img { + height: 100%; + width: 100%; + object-fit: contain; + } + + & > h1 { + font-size: 1.4rem; + } } - & > h1 { - font-size: 1.4rem; + & > nav { + display: flex; } - } - - & > nav { - display: flex; - } } diff --git a/front/src/modules/common/components/theme-switcher/theme-switcher.component.tsx b/front/src/modules/common/components/theme-switcher/theme-switcher.component.tsx index b27c525..a7c22de 100644 --- a/front/src/modules/common/components/theme-switcher/theme-switcher.component.tsx +++ b/front/src/modules/common/components/theme-switcher/theme-switcher.component.tsx @@ -2,19 +2,19 @@ import React from "react"; // TODO: make it consistent and link current data-theme with checked state fo the checkbox, maybe with a react state export const ThemeSwitcher = () => { - const changeHandler = () => { - const isDarkTheme = - document.documentElement.getAttribute("data-theme") === "dark"; - document.documentElement.setAttribute( - "data-theme", - isDarkTheme ? "light" : "dark", - ); - }; + const changeHandler = () => { + const isDarkTheme = + document.documentElement.getAttribute("data-theme") === "dark"; + document.documentElement.setAttribute( + "data-theme", + isDarkTheme ? "light" : "dark", + ); + }; - return ( - - - - - ); + return ( + + + + + ); }; diff --git a/front/src/modules/common/hooks/api/useQuery.ts b/front/src/modules/common/hooks/api/useQuery.ts index 147f3dc..fb07cd7 100644 --- a/front/src/modules/common/hooks/api/useQuery.ts +++ b/front/src/modules/common/hooks/api/useQuery.ts @@ -3,51 +3,51 @@ import { timedFetch } from "../../utils/timedFetch"; import { useSession } from "next-auth/react"; type QueryReturn = { - data?: T; - status?: number; - isLoading: boolean; - isError: boolean; + data?: T; + status?: number; + isLoading: boolean; + isError: boolean; }; type QueryInput = { - url: string; - options: RequestInit; - timeout?: number; + url: string; + options: RequestInit; + timeout?: number; }; export function useQuery({ - url, - options, - timeout, + url, + options, + timeout, }: QueryInput): QueryReturn { - const [response, setResponse] = useState<{ - data: DataType; - status: number; - }>(); - const [isLoading, setIsLoading] = useState(true); - const [isError, setIsError] = useState(false); + const [response, setResponse] = useState<{ + data: DataType; + status: number; + }>(); + const [isLoading, setIsLoading] = useState(true); + const [isError, setIsError] = useState(false); - const session = useSession(); - const token = session.data?.apiSession?.accessToken; - if (token) { - options.headers = { ...options.headers, Authorization: "Bearer " + token }; - } + const session = useSession(); + const token = session.data?.apiSession?.accessToken; + if (token) { + options.headers = { ...options.headers, Authorization: "Bearer " + token }; + } - useEffect(() => { - setIsLoading(true); - setIsError(false); - (async () => { - if (session.status !== "loading") { - const _response = await timedFetch(url, options, timeout); - if (_response) { - setResponse(_response); - } else { - setIsError(true); - } - setIsLoading(false); - } - })(); - }, [url, options, timeout, session.status]); + useEffect(() => { + setIsLoading(true); + setIsError(false); + (async () => { + if (session.status !== "loading") { + const _response = await timedFetch(url, options, timeout); + if (_response) { + setResponse(_response); + } else { + setIsError(true); + } + setIsLoading(false); + } + })(); + }, [url, options, timeout, session.status]); - return { ...response, isLoading, isError }; + return { ...response, isLoading, isError }; } diff --git a/front/src/modules/common/layouts/home/home.layout.tsx b/front/src/modules/common/layouts/home/home.layout.tsx index 0df89b7..e8590cc 100644 --- a/front/src/modules/common/layouts/home/home.layout.tsx +++ b/front/src/modules/common/layouts/home/home.layout.tsx @@ -5,12 +5,12 @@ import NavbarHeader from "../../components/navbar-header"; import UserDropdown from "@/modules/auth/components/user-dropdown"; export const HomeLayout: React.FC = ({ children }) => { - return ( - - - - - {children} - - ); + return ( + + + + + {children} + + ); }; diff --git a/front/src/modules/common/layouts/home/home.module.scss b/front/src/modules/common/layouts/home/home.module.scss index 4512f87..00de254 100644 --- a/front/src/modules/common/layouts/home/home.module.scss +++ b/front/src/modules/common/layouts/home/home.module.scss @@ -1,6 +1,6 @@ .container { - display: flex; - flex-direction: column; - min-height: 100vh; - background-color: var(--color-background); + display: flex; + flex-direction: column; + min-height: 100vh; + background-color: var(--color-background); } diff --git a/front/src/modules/common/layouts/root/root.layout.tsx b/front/src/modules/common/layouts/root/root.layout.tsx index dab246c..3995eb7 100644 --- a/front/src/modules/common/layouts/root/root.layout.tsx +++ b/front/src/modules/common/layouts/root/root.layout.tsx @@ -3,21 +3,21 @@ import "@/styles/main.scss"; import { ApplicationProvider } from "../../providers/application.provider"; export const metadata: Metadata = { - title: "Full stack archetype", - description: - "This is a full stack archetype supported in NextJS, NestJS and mysql", + title: "Full stack archetype", + description: + "This is a full stack archetype supported in NextJS, NestJS and mysql", }; export function RootLayout({ - children, + children, }: Readonly<{ - children: React.ReactNode; + children: React.ReactNode; }>) { - return ( - - - {children} - - - ); + return ( + + + {children} + + + ); } diff --git a/front/src/modules/common/providers/application.provider.tsx b/front/src/modules/common/providers/application.provider.tsx index d6415c9..ac67e89 100644 --- a/front/src/modules/common/providers/application.provider.tsx +++ b/front/src/modules/common/providers/application.provider.tsx @@ -3,8 +3,6 @@ import { AuthProvider } from "@/modules/auth/providers/auth.provider"; import { PropsWithChildren } from "react"; -export const ApplicationProvider: React.FC = ({ - children, -}) => { - return {children}; +export const ApplicationProvider: React.FC = ({ children }) => { + return {children}; }; diff --git a/front/src/modules/common/utils/timedFetch.ts b/front/src/modules/common/utils/timedFetch.ts index 264afd1..4d247c0 100644 --- a/front/src/modules/common/utils/timedFetch.ts +++ b/front/src/modules/common/utils/timedFetch.ts @@ -1,31 +1,31 @@ class HttpError extends Error { - constructor(public response: Response) { - super(`HTTP error ${response.status}`); - } + constructor(public response: Response) { + super(`HTTP error ${response.status}`); + } } async function timedFetch( - url: string, - options: RequestInit = {}, - timeout: number = 5000, + url: string, + options: RequestInit = {}, + timeout: number = 5000, ) { - try { - const result = await fetch(url, { - signal: AbortSignal.timeout(timeout), - ...options, - }); - if (!result.ok) { - throw new HttpError(result); + try { + const result = await fetch(url, { + signal: AbortSignal.timeout(timeout), + ...options, + }); + if (!result.ok) { + throw new HttpError(result); + } + return { + data: (await result.json()) as ResponseType, + status: result.status, + }; + } catch (error) { + if ((error as Error).name === "AbortError") { + console.log(`Fetch aborted by timeout (${timeout}ms)`); + } } - return { - data: (await result.json()) as ResponseType, - status: result.status, - }; - } catch (error) { - if ((error as Error).name === "AbortError") { - console.log(`Fetch aborted by timeout (${timeout}ms)`); - } - } } export { timedFetch }; diff --git a/front/src/modules/example/components/example-detail/example-detail.component.tsx b/front/src/modules/example/components/example-detail/example-detail.component.tsx index eb7ad3a..034be00 100644 --- a/front/src/modules/example/components/example-detail/example-detail.component.tsx +++ b/front/src/modules/example/components/example-detail/example-detail.component.tsx @@ -3,44 +3,44 @@ import styles from "./example-detail.module.scss"; import Image from "next/image"; type ExampleDetailProps = { - exampleId: number; + exampleId: number; }; type ExampleDetailType = { - id: number; - name: string; - description: string; - image: string; - created_at: string; + id: number; + name: string; + description: string; + image: string; + created_at: string; }; export const ExampleDetail: React.FC = ({ exampleId }) => { - const result = useQuery({ - url: `${process.env.NEXT_PUBLIC_BACKEND_URL}/example/${exampleId}`, - options: { headers: {} }, - timeout: 4000, - }); + const result = useQuery({ + url: `${process.env.NEXT_PUBLIC_BACKEND_URL}/example/${exampleId}`, + options: { headers: {} }, + timeout: 4000, + }); - if (result.isLoading) { - return <>Loading...>; - } + if (result.isLoading) { + return <>Loading...>; + } - if (result.isError) { - return <>Error>; - } + if (result.isError) { + return <>Error>; + } - return ( - - - - {result.data?.name} - {result.data?.description} - - - ); + return ( + + + + {result.data?.name} + {result.data?.description} + + + ); }; diff --git a/front/src/modules/example/components/example-detail/example-detail.module.scss b/front/src/modules/example/components/example-detail/example-detail.module.scss index c70de62..a4bb489 100644 --- a/front/src/modules/example/components/example-detail/example-detail.module.scss +++ b/front/src/modules/example/components/example-detail/example-detail.module.scss @@ -1,35 +1,35 @@ .container { - flex: 1; - display: flex; - justify-content: center; - align-items: center; - - & .example__card { + flex: 1; display: flex; - flex-direction: column; + justify-content: center; align-items: center; - gap: 2rem; - max-width: 250px; + & .example__card { + display: flex; + flex-direction: column; + align-items: center; + gap: 2rem; - padding: 2.5rem; + max-width: 250px; - border-radius: 4px; + padding: 2.5rem; - background-color: var(--color-grey-90); - box-shadow: 0px 2px 5px rgba(var(--color-black-rgb), 0.2); + border-radius: 4px; - & img { - border-radius: 50%; - box-shadow: 0px 2px 5px rgba(var(--color-black-rgb), 0.2); + background-color: var(--color-grey-90); + box-shadow: 0px 2px 5px rgba(var(--color-black-rgb), 0.2); + + & img { + border-radius: 50%; + box-shadow: 0px 2px 5px rgba(var(--color-black-rgb), 0.2); + } + + & h3 { + font-size: 2rem; + } + + & p { + font-size: 1.6rem; + } } - - & h3 { - font-size: 2rem; - } - - & p { - font-size: 1.6rem; - } - } } diff --git a/front/src/modules/example/components/example-detail/index.ts b/front/src/modules/example/components/example-detail/index.ts index 01b8d3a..8e2919b 100644 --- a/front/src/modules/example/components/example-detail/index.ts +++ b/front/src/modules/example/components/example-detail/index.ts @@ -1,3 +1,3 @@ -"use client" +"use client"; export { ExampleDetail } from "./example-detail.component"; diff --git a/front/src/modules/example/components/example-list/example-list.component.tsx b/front/src/modules/example/components/example-list/example-list.component.tsx index 8c772c9..7d2bd2a 100644 --- a/front/src/modules/example/components/example-list/example-list.component.tsx +++ b/front/src/modules/example/components/example-list/example-list.component.tsx @@ -6,52 +6,52 @@ import Link from "next/link"; type ExampleListProps = {}; type ExampleListType = { - results: { - id: number; - name: string; - description: string; - image: string; - created_at: string; - }[]; - count: number; + results: { + id: number; + name: string; + description: string; + image: string; + created_at: string; + }[]; + count: number; }; export const ExampleList: React.FC = ({}) => { - const result = useQuery({ - url: process.env.NEXT_PUBLIC_BACKEND_URL + "/example", - options: { headers: {} }, - timeout: 4000, - }); + const result = useQuery({ + url: process.env.NEXT_PUBLIC_BACKEND_URL + "/example", + options: { headers: {} }, + timeout: 4000, + }); - if (result.isLoading) { - return <>Loading...>; - } + if (result.isLoading) { + return <>Loading...>; + } - if (result.isError) { - return <>Error>; - } + if (result.isError) { + return <>Error>; + } - return ( - - - {result.data?.results?.map((example) => { - return ( - - - - {example.name} - {example.description} - - - ); - })} - - This could be the pagination... - - ); + return ( + + + {result.data?.results?.map((example) => { + return ( + + + + {example.name} + {example.description} + + + ); + })} + + This could be the pagination... + + ); }; diff --git a/front/src/modules/example/components/example-list/example-list.module.scss b/front/src/modules/example/components/example-list/example-list.module.scss index 03b133a..6191585 100644 --- a/front/src/modules/example/components/example-list/example-list.module.scss +++ b/front/src/modules/example/components/example-list/example-list.module.scss @@ -1,39 +1,39 @@ .container { - display: flex; - flex-direction: column; - flex: 1; - padding: 1.2rem; - padding-top: 0; - gap: 1rem; - - & ul { - flex: 1; - list-style: none; display: flex; flex-direction: column; - gap: 10px; - padding: 0.8rem; - background-color: var(--color-grey-90); - border-radius: 0.8rem; + flex: 1; + padding: 1.2rem; + padding-top: 0; + gap: 1rem; - & a > li { - display: grid; - grid-auto-flow: column; - grid-template-columns: 1fr 1fr 1fr; - align-items: center; - padding: 0.3rem 1.4rem; - width: 100%; - background-color: var(--color-white); - border-radius: 0.8rem; + & ul { + flex: 1; + list-style: none; + display: flex; + flex-direction: column; + gap: 10px; + padding: 0.8rem; + background-color: var(--color-grey-90); + border-radius: 0.8rem; - &:hover { - background-color: var(--color-primary-light); - box-shadow: 0 2px 4px rgba(var(--color-black-rgb), 0.2); - } + & a > li { + display: grid; + grid-auto-flow: column; + grid-template-columns: 1fr 1fr 1fr; + align-items: center; + padding: 0.3rem 1.4rem; + width: 100%; + background-color: var(--color-white); + border-radius: 0.8rem; - & > img { - border-radius: 50%; - } + &:hover { + background-color: var(--color-primary-light); + box-shadow: 0 2px 4px rgba(var(--color-black-rgb), 0.2); + } + + & > img { + border-radius: 50%; + } + } } - } } diff --git a/front/src/modules/example/components/example-list/index.ts b/front/src/modules/example/components/example-list/index.ts index b102a95..d04ca45 100644 --- a/front/src/modules/example/components/example-list/index.ts +++ b/front/src/modules/example/components/example-list/index.ts @@ -1,3 +1,3 @@ -"use client" +"use client"; export { ExampleList } from "./example-list.component"; diff --git a/front/src/modules/example/views/example-detail/example-detail.module.scss b/front/src/modules/example/views/example-detail/example-detail.module.scss index 7571898..ff6934a 100644 --- a/front/src/modules/example/views/example-detail/example-detail.module.scss +++ b/front/src/modules/example/views/example-detail/example-detail.module.scss @@ -1,4 +1,4 @@ .container { - display: flex; - flex: 1; + display: flex; + flex: 1; } diff --git a/front/src/modules/example/views/example-detail/example-detail.view.tsx b/front/src/modules/example/views/example-detail/example-detail.view.tsx index 28ceb63..32772f3 100644 --- a/front/src/modules/example/views/example-detail/example-detail.view.tsx +++ b/front/src/modules/example/views/example-detail/example-detail.view.tsx @@ -2,18 +2,16 @@ import { ExampleDetail } from "../../components/example-detail"; import styles from "./example-detail.module.scss"; type ExampleDetailViewProps = { - // query parameters - searchParams: { [key: string]: string | string[] | undefined }; - // url parameters - params: { exampleId: string }; + // query parameters + searchParams: { [key: string]: string | string[] | undefined }; + // url parameters + params: { exampleId: string }; }; -export const ExampleDetailView: React.FC = ({ - params, -}) => { - return ( - - - - ); +export const ExampleDetailView: React.FC = ({ params }) => { + return ( + + + + ); }; diff --git a/front/src/modules/example/views/example-list/example-list.module.scss b/front/src/modules/example/views/example-list/example-list.module.scss index 5985ddd..7018dd5 100644 --- a/front/src/modules/example/views/example-list/example-list.module.scss +++ b/front/src/modules/example/views/example-list/example-list.module.scss @@ -1,5 +1,5 @@ .container { - display: flex; - flex-direction: column; - flex: 1; + display: flex; + flex-direction: column; + flex: 1; } diff --git a/front/src/modules/example/views/example-list/example-list.view.tsx b/front/src/modules/example/views/example-list/example-list.view.tsx index d8ecd11..056af2e 100644 --- a/front/src/modules/example/views/example-list/example-list.view.tsx +++ b/front/src/modules/example/views/example-list/example-list.view.tsx @@ -4,9 +4,9 @@ import { ExampleList } from "../../components/example-list"; type ExampleListProps = {}; export const ExampleListView: React.FC = ({}) => { - return ( - - - - ); + return ( + + + + ); }; diff --git a/front/src/styles/main.scss b/front/src/styles/main.scss index 9bbdb54..5954a9a 100644 --- a/front/src/styles/main.scss +++ b/front/src/styles/main.scss @@ -2,103 +2,103 @@ // For variable definition :root { - --color-white: #fafafa; - --color-black: #101010; + --color-white: #fafafa; + --color-black: #101010; - --color-grey-10: #171717; - --color-grey-30: #242424; - --color-grey-60: #363636; - --color-grey-70: #bbbbbb; - --color-grey-90: #e9ecef; + --color-grey-10: #171717; + --color-grey-30: #242424; + --color-grey-60: #363636; + --color-grey-70: #bbbbbb; + --color-grey-90: #e9ecef; - --color-primary: #274c77; - --color-primary-light: #a3cef1; - --color-primary-dark: #052f5f; + --color-primary: #274c77; + --color-primary-light: #a3cef1; + --color-primary-dark: #052f5f; - --color-error: #e63946; + --color-error: #e63946; - // -------- RGB variants -------- // - --color-white-rgb: 250, 250, 250; - --color-black-rgb: 16, 16, 16; + // -------- RGB variants -------- // + --color-white-rgb: 250, 250, 250; + --color-black-rgb: 16, 16, 16; - --color-grey-10-rgb: 23, 23, 23; - --color-grey-30-rgb: 36, 36, 36; - --color-grey-60-rgb: 54, 54, 54; - --color-grey-70-rgb: 187, 187, 187; - --color-grey-90-rgb: 233, 236, 239; + --color-grey-10-rgb: 23, 23, 23; + --color-grey-30-rgb: 36, 36, 36; + --color-grey-60-rgb: 54, 54, 54; + --color-grey-70-rgb: 187, 187, 187; + --color-grey-90-rgb: 233, 236, 239; - --color-primary-rgb: 39, 76, 119; - --color-primary-light-rgb: 163, 206, 241; - --color-primary-dark-rgb: 5, 47, 95; + --color-primary-rgb: 39, 76, 119; + --color-primary-light-rgb: 163, 206, 241; + --color-primary-dark-rgb: 5, 47, 95; } [data-theme="dark"] { - --color-white: #101010; - --color-black: #fafafa; + --color-white: #101010; + --color-black: #fafafa; - --color-grey-10: #e9ecef; - --color-grey-30: #bbbbbb; - --color-grey-70: #242424; - --color-grey-60: #363636; - --color-grey-90: #171717; + --color-grey-10: #e9ecef; + --color-grey-30: #bbbbbb; + --color-grey-70: #242424; + --color-grey-60: #363636; + --color-grey-90: #171717; - --color-primary: #274c77; - --color-primary-light: #052f5f; - --color-primary-dark: #a3cef1; + --color-primary: #274c77; + --color-primary-light: #052f5f; + --color-primary-dark: #a3cef1; - // -------- RGB variants -------- // - --color-white-rgb: 16, 16, 16; - --color-black-rgb: 250, 250, 250; + // -------- RGB variants -------- // + --color-white-rgb: 16, 16, 16; + --color-black-rgb: 250, 250, 250; - --color-grey-10-rgb: 233, 236, 239; - --color-grey-30-rgb: 187, 187, 187; - --color-grey-60-rgb: 54, 54, 54; - --color-grey-70-rgb: 36, 36, 36; - --color-grey-90-rgb: 23, 23, 23; + --color-grey-10-rgb: 233, 236, 239; + --color-grey-30-rgb: 187, 187, 187; + --color-grey-60-rgb: 54, 54, 54; + --color-grey-70-rgb: 36, 36, 36; + --color-grey-90-rgb: 23, 23, 23; - --color-primary-rgb: 39, 76, 119; - --color-primary-light-rgb: 5, 47, 95; - --color-primary-dark-rgb: 163, 206, 241; + --color-primary-rgb: 39, 76, 119; + --color-primary-light-rgb: 5, 47, 95; + --color-primary-dark-rgb: 163, 206, 241; } *, ::after, ::before { - margin: 0; - padding: 0; - box-sizing: inherit; + margin: 0; + padding: 0; + box-sizing: inherit; } html { - font-family: "Roboto", sans-serif; - max-width: 100vw; - overflow-x: hidden; + font-family: "Roboto", sans-serif; + max-width: 100vw; + overflow-x: hidden; - font-size: 62.5%; // 1rem = 10px; 10px/16px = 62.5% - @media only screen and (min-width: 112.5em) { - font-size: 75%; - } - @media only screen and (max-width: 75em) { - font-size: 56.25%; - } - @media only screen and (max-width: 56.25em) { - font-size: 50%; - } + font-size: 62.5%; // 1rem = 10px; 10px/16px = 62.5% + @media only screen and (min-width: 112.5em) { + font-size: 75%; + } + @media only screen and (max-width: 75em) { + font-size: 56.25%; + } + @media only screen and (max-width: 56.25em) { + font-size: 50%; + } } body { - box-sizing: border-box; + box-sizing: border-box; - background-color: var(--color-white); - color: var(--color-black); + background-color: var(--color-white); + color: var(--color-black); } a { - color: inherit; - text-decoration: none; + color: inherit; + text-decoration: none; } ::selection { - background-color: var(--color-primary); - color: var(--color-white); + background-color: var(--color-primary); + color: var(--color-white); } diff --git a/front/tsconfig.json b/front/tsconfig.json index bfe478e..4cd15b6 100644 --- a/front/tsconfig.json +++ b/front/tsconfig.json @@ -1,33 +1,33 @@ { - "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./src/*"] + "compilerOptions": { + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + }, + "typeRoots": ["./src/modules/auth/types"] }, - "typeRoots": ["./src/modules/auth/types"] - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - "src/modules/**/*.d.ts" - ], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + "src/modules/**/*.d.ts" + ], + "exclude": ["node_modules"] }
+ Wrong credentials, try again +
- Wrong credentials, try again -
{result.data?.description}