diff --git a/app/middleware/auth.ts b/app/middleware/auth.ts new file mode 100644 index 0000000..0e49242 --- /dev/null +++ b/app/middleware/auth.ts @@ -0,0 +1,7 @@ +export default defineNuxtRouteMiddleware(() => { + const token = useCookie('token') + + if (!token.value) { + return navigateTo('/login') + } +}) \ No newline at end of file diff --git a/app/middleware/guest.ts b/app/middleware/guest.ts new file mode 100644 index 0000000..7a12bc1 --- /dev/null +++ b/app/middleware/guest.ts @@ -0,0 +1,12 @@ +/** + * Middleware para rotas guest. + * Redireciona para a página de home se o usuário estiver autenticado. + */ + +export default defineNuxtRouteMiddleware(() => { + const token = useCookie('token') + + if (token.value) { + return navigateTo('/home') + } +}) diff --git a/app/pages/(auth)/criar-conta/index.vue b/app/pages/(auth)/criar-conta/index.vue index f6a9320..fc6422a 100644 --- a/app/pages/(auth)/criar-conta/index.vue +++ b/app/pages/(auth)/criar-conta/index.vue @@ -10,7 +10,7 @@ aria-labelledby="create-account-title">

+ class="m-0 inline-flex rounded-full bg-[rgba(244,197,168,0.56)] px-3 py-1 text-xs font-semibold uppercase leading-[1.4] tracking-[0.96px] text-[#0c0a09]"> Nova conta

+ class="inline-flex min-h-6 items-center rounded-full bg-[rgba(244,197,168,0.56)] px-2.5 py-1 text-xs font-semibold uppercase leading-none tracking-[0.96px] text-[#0c0a09]"> Cadastro

@@ -68,6 +68,13 @@ Criar Conta + +

+ Já tem uma conta? + + Fazer login + +

@@ -78,11 +85,13 @@ import { toTypedSchema } from '@vee-validate/zod' import { z } from 'zod' +definePageMeta({ middleware: 'guest' }) + const { $toast } = useNuxtApp() const isLoading = ref(false) -const toStr = (val) => (val == null ? '' : val) +const toStr = (val) => (val == null ? '' : String(val)) const schema = toTypedSchema( z.object({ @@ -94,21 +103,16 @@ const schema = toTypedSchema( async function criarConta({ email, password }) { isLoading.value = true try { - const res = await fetch('/auth/register', { + await $fetch('/auth/register', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email, password }), + body: { email, password }, }) - if (!res.ok) { - const data = await res.json().catch(() => ({})) - $toast.error(data.message ?? 'Erro ao criar conta. Tente novamente.') - return - } - - $toast.success('Conta criada com sucesso!') - } catch { - $toast.error('Erro ao criar conta. Tente novamente.') + $toast.success('Conta criada com sucesso!', { duration: 8000 }) + await navigateTo('/login') + } catch (error) { + const message = error?.data?.statusMessage + $toast.error(message ?? 'Erro ao criar conta. Tente novamente.', { duration: 8000 }) } finally { isLoading.value = false } diff --git a/app/pages/(auth)/login/index.vue b/app/pages/(auth)/login/index.vue new file mode 100644 index 0000000..53435a4 --- /dev/null +++ b/app/pages/(auth)/login/index.vue @@ -0,0 +1,133 @@ + + + diff --git a/app/pages/(protected)/home/index.vue b/app/pages/(protected)/home/index.vue new file mode 100644 index 0000000..fc4cd8a --- /dev/null +++ b/app/pages/(protected)/home/index.vue @@ -0,0 +1,11 @@ + + + diff --git a/package-lock.json b/package-lock.json index cd607ac..af6a271 100644 --- a/package-lock.json +++ b/package-lock.json @@ -82,7 +82,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -580,12 +579,36 @@ "integrity": "sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ==", "license": "MIT" }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -1465,7 +1488,6 @@ "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.4.2.tgz", "integrity": "sha512-5+IPRNX2CjkBhuWUwz0hBuLqiaJPRoKzQ+SvcdrQDbAyE+VDeFt74VpSFr5/R0ujrK4b+XnSHUJWdS72w6hsog==", "license": "MIT", - "peer": true, "dependencies": { "c12": "^3.3.3", "consola": "^3.4.2", @@ -1550,7 +1572,6 @@ "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-4.4.2.tgz", "integrity": "sha512-/q6C7Qhiricgi+PKR7ovBnJlKTL0memCbA1CzRT+itCW/oeYzUfeMdQ35mGntlBoyRPNrMXbzuSUhfDbSCU57w==", "license": "MIT", - "peer": true, "dependencies": { "@vue/shared": "^3.5.30", "defu": "^6.1.4", @@ -3169,6 +3190,19 @@ "giget": "dist/cli.mjs" } }, + "node_modules/@prisma/config/node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, "node_modules/@prisma/config/node_modules/perfect-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", @@ -3974,7 +4008,6 @@ "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.19.0" } @@ -4467,7 +4500,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4801,7 +4833,6 @@ "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", "license": "Apache-2.0", - "peer": true, "peerDependencies": { "bare-abort-controller": "*" }, @@ -4999,7 +5030,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -5101,7 +5131,6 @@ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -5281,8 +5310,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.2.tgz", "integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/cliui": { "version": "9.0.1", @@ -8269,7 +8297,6 @@ "resolved": "https://registry.npmjs.org/nuxt/-/nuxt-4.4.2.tgz", "integrity": "sha512-iWVFpr/YEqVU/CenqIHMnIkvb2HE/9f+q8oxZ+pj2et+60NljGRClCgnmbvGPdmNFE0F1bEhoBCYfqbDOCim3Q==", "license": "MIT", - "peer": true, "dependencies": { "@dxup/nuxt": "^0.4.0", "@nuxt/cli": "^3.34.0", @@ -8522,7 +8549,6 @@ "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.117.0.tgz", "integrity": "sha512-l3cbgK5wUvWDVNWM/JFU77qDdGZK1wudnLsFcrRyNo/bL1CyU8pC25vDhMHikVY29lbK2InTWsX42RxVSutUdQ==", "license": "MIT", - "peer": true, "dependencies": { "@oxc-project/types": "^0.117.0" }, @@ -8721,7 +8747,6 @@ "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz", "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", "license": "MIT", - "peer": true, "dependencies": { "@vue/devtools-api": "^7.7.7" }, @@ -8844,7 +8869,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -9388,7 +9412,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -9452,7 +9475,6 @@ "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -9560,7 +9582,6 @@ "integrity": "sha512-aRvldGE5UUJTtVmFiH3WfNFNiqFlAtePUxcI0UEGlnXCX7DqhiMT5TRYwncHFeA/Reca5W6ToXXyCMTeFPdSXA==", "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@prisma/config": "6.16.2", "@prisma/engines": "6.16.2" @@ -10074,7 +10095,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -10873,7 +10893,6 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "license": "MIT", - "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -11761,7 +11780,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -12126,7 +12144,6 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.32.tgz", "integrity": "sha512-vM4z4Q9tTafVfMAK7IVzmxg34rSzTFMyIe0UUEijUCkn9+23lj0WRfA83dg7eQZIUlgOSGrkViIaCfqSAUXsMw==", "license": "MIT", - "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.32", "@vue/compiler-sfc": "3.5.32", @@ -12416,7 +12433,6 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -12510,7 +12526,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/server/utils/auth-service.ts b/server/utils/auth-service.ts index 76832d5..f4b6ed4 100644 --- a/server/utils/auth-service.ts +++ b/server/utils/auth-service.ts @@ -326,7 +326,7 @@ export async function handleLogin(event: H3Event) { const user = await prisma.user.findUnique({ where: { email } }) if (!user || !verifyPassword(password, user.passwordHash)) { - throw createError({ statusCode: 401, statusMessage: 'Invalid credentials' }) + throw createError({ statusCode: 401, statusMessage: 'Credenciais inválidas!' }) } const accessToken = await signAccessToken(event, { sub: user.id })