This commit is contained in:
Rayan Konecny 2026-04-27 22:32:51 -03:00
parent 63c9f720ad
commit 227b492bc3
10 changed files with 115 additions and 24 deletions

9
.claude/settings.json Normal file
View file

@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Bash(xargs cat *)",
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(json.dumps\\(d.get\\('exports', {}\\), indent=2\\)\\)\")",
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(json.dumps\\({k: v for k, v in d.items\\(\\) if k not in ['dependencies', 'devDependencies', 'peerDependencies']}, indent=2\\)\\)\")"
]
}
}

View file

@ -2,7 +2,7 @@ import { Response } from 'express';
import { AuthRequest } from '../middlewares/auth.middleware.js';
import * as usersService from '../services/users.service.js';
export async function getMe(req: AuthRequest, res: Response) {
export async function get(req: AuthRequest, res: Response): Promise<void> {
try {
const user = await usersService.getUser(req.userId!);
res.json(user);
@ -11,7 +11,7 @@ export async function getMe(req: AuthRequest, res: Response) {
}
}
export async function updateMe(req: AuthRequest, res: Response) {
export async function update(req: AuthRequest, res: Response): Promise<void> {
const parsed = usersService.updateUserSchema.safeParse(req.body);
if (!parsed.success) {
res.status(400).json({ error: parsed.error.flatten() });
@ -26,7 +26,8 @@ export async function updateMe(req: AuthRequest, res: Response) {
}
}
export async function deleteMe(req: AuthRequest, res: Response) {
export async function remove(req: AuthRequest, res: Response): Promise<void> {
try {
await usersService.deleteUser(req.userId!);
res.status(204).send();

View file

@ -6,8 +6,8 @@ const router = Router();
router.use(authenticate);
router.get('/me', usersController.getMe);
router.put('/me', usersController.updateMe);
router.delete('/me', usersController.deleteMe);
router.get('/me', usersController.get);
router.put('/me', usersController.update);
router.delete('/me', usersController.remove);
export default router;

View file

@ -30,7 +30,6 @@
"react-native-worklets": "0.5.1"
},
"devDependencies": {
"@types/react": "~19.1.0",
"react-test-renderer": "19.1.0",
"typescript": "~5.9.2"
}

View file

@ -31,7 +31,6 @@
"react-native-worklets": "0.5.1"
},
"devDependencies": {
"@types/react": "~19.1.0",
"react-test-renderer": "19.1.0",
"typescript": "~5.9.2"
},

View file

@ -14,19 +14,29 @@ import {
import { Button } from "@/components/Button";
import { Input } from "@/components/Input";
import { Link } from "expo-router";
import { api, setAuthToken } from "@/server/api";
// Página de login
export default function IndexPage() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [loading, setLoading] = useState(false);
function handleSignIn() {
async function handleSignIn() {
if (!email.trim() || !password.trim()) {
Alert.alert("Entrar", "Por favor, preencha todos os campos.");
return;
}
Alert.alert("Bem-vindo", `Acessando com o e-mail ${email}`);
try {
setLoading(true);
const { data } = await api.post("/auth/login", { email, password });
setAuthToken(data.accessToken);
} catch (err: any) {
const message = err.response?.data?.error ?? "Erro ao fazer login.";
Alert.alert("Erro", message);
} finally {
setLoading(false);
}
}
return (
@ -54,6 +64,7 @@ export default function IndexPage() {
<Input
placeholder="E-mail"
keyboardType="email-address"
autoCapitalize="none"
onChangeText={setEmail}
/>
@ -63,7 +74,11 @@ export default function IndexPage() {
onChangeText={setPassword}
/>
<Button label="Entrar" onPress={handleSignIn} />
<Button
label={loading ? "Entrando..." : "Entrar"}
onPress={handleSignIn}
disabled={loading}
/>
</View>
<Text style={styles.footerText}>
@ -93,7 +108,7 @@ const styles = StyleSheet.create({
title: {
marginTop: 62,
fontSize: 32,
fontWeight: 900,
fontWeight: "900",
color: "#e7e7e7",
},
subtitle: {
@ -111,6 +126,6 @@ const styles = StyleSheet.create({
},
footerLink: {
color: "#007AFF",
fontWeight: 700,
fontWeight: "700",
},
});

View file

@ -1,4 +1,7 @@
import { useState } from "react";
import {
Alert,
Image,
KeyboardAvoidingView,
Platform,
@ -10,14 +13,46 @@ import {
import { Button } from "@/components/Button";
import { Input } from "@/components/Input";
import { Link } from "expo-router";
import { Link, useRouter } from "expo-router";
import { api } from "@/server/api";
// Página de cadastro
export default function Signup() {
const router = useRouter();
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [loading, setLoading] = useState(false);
async function handleSignUp() {
if (!name.trim() || !email.trim() || !password.trim() || !confirmPassword.trim()) {
Alert.alert("Cadastrar", "Por favor, preencha todos os campos.");
return;
}
if (password !== confirmPassword) {
Alert.alert("Cadastrar", "As senhas não coincidem.");
return;
}
try {
setLoading(true);
await api.post("/auth/register", { name, email, password });
Alert.alert("Sucesso", "Conta criada com sucesso!", [
{ text: "OK", onPress: () => router.replace("/") },
]);
} catch (err: any) {
const message = err.response?.data?.error ?? "Erro ao criar conta.";
Alert.alert("Erro", message);
} finally {
setLoading(false);
}
}
return (
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.select({ ios: "padding", android: "height" })}
behavior={Platform.OS === "ios" ? "padding" : "height"}
>
<ScrollView
contentContainerStyle={{ flexGrow: 1 }}
@ -34,11 +69,24 @@ export default function Signup() {
<Text style={styles.subtitle}>Crie sua conta para acessar.</Text>
<View style={styles.form}>
<Input placeholder="Nome" />
<Input placeholder="E-mail" keyboardType="email-address" />
<Input placeholder="Senha" secureTextEntry />
<Input placeholder="Confirmar Senha" secureTextEntry />
<Button label="Cadastrar" />
<Input placeholder="Nome" onChangeText={setName} />
<Input
placeholder="E-mail"
keyboardType="email-address"
autoCapitalize="none"
onChangeText={setEmail}
/>
<Input placeholder="Senha" secureTextEntry onChangeText={setPassword} />
<Input
placeholder="Confirmar Senha"
secureTextEntry
onChangeText={setConfirmPassword}
/>
<Button
label={loading ? "Cadastrando..." : "Cadastrar"}
onPress={handleSignUp}
disabled={loading}
/>
</View>
<Text style={styles.footerText}>

View file

@ -0,0 +1,18 @@
import axios from 'axios';
import { Platform } from 'react-native';
const BASE_URL = Platform.OS === 'android'
? 'http://10.0.2.2:4000'
: 'http://localhost:4000';
export const api = axios.create({
baseURL: BASE_URL,
});
export function setAuthToken(token: string | null) {
if (token) {
api.defaults.headers.common.Authorization = `Bearer ${token}`;
} else {
delete api.defaults.headers.common.Authorization;
}
}

View file

@ -2,8 +2,10 @@
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true,
"skipLibCheck": true,
"paths": {
"@/*": ["./src/*"]
"@/*": ["./src/*"],
"expo-router/src/*": ["./node_modules/expo-router/build/*"]
}
},
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]