Run SQL to create user and transaction tables.
This commit is contained in:
parent
e59656824f
commit
c05ba05353
33
src/App.tsx
33
src/App.tsx
@ -4,12 +4,14 @@ import { Toaster } from "@/components/ui/toaster";
|
|||||||
import { Toaster as Sonner } from "@/components/ui/sonner";
|
import { Toaster as Sonner } from "@/components/ui/sonner";
|
||||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
|
||||||
import Index from "./pages/Index";
|
import Index from "./pages/Index";
|
||||||
import Transacoes from "./pages/Transacoes";
|
import Transacoes from "./pages/Transacoes";
|
||||||
import Categorias from "./pages/Categorias";
|
import Categorias from "./pages/Categorias";
|
||||||
import Calendario from "./pages/Calendario";
|
import Calendario from "./pages/Calendario";
|
||||||
|
import Auth from "./pages/Auth";
|
||||||
import NotFound from "./pages/NotFound";
|
import NotFound from "./pages/NotFound";
|
||||||
|
import ProtectedRoute from "./components/auth/ProtectedRoute";
|
||||||
|
|
||||||
// Create a client
|
// Create a client
|
||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
@ -30,11 +32,30 @@ const App = () => {
|
|||||||
<Sonner />
|
<Sonner />
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Index />} />
|
{/* Rota inicial redireciona para autenticação ou dashboard */}
|
||||||
<Route path="/transacoes" element={<Transacoes />} />
|
<Route path="/" element={<Navigate to="/auth" replace />} />
|
||||||
<Route path="/categorias" element={<Categorias />} />
|
|
||||||
<Route path="/calendario" element={<Calendario />} />
|
{/* Rota de autenticação */}
|
||||||
{/* Adicione novas rotas acima desta linha */}
|
<Route path="/auth" element={<Auth />} />
|
||||||
|
|
||||||
|
{/* Rotas protegidas que exigem autenticação */}
|
||||||
|
<Route path="/transacoes" element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<Transacoes />
|
||||||
|
</ProtectedRoute>
|
||||||
|
} />
|
||||||
|
<Route path="/categorias" element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<Categorias />
|
||||||
|
</ProtectedRoute>
|
||||||
|
} />
|
||||||
|
<Route path="/calendario" element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<Calendario />
|
||||||
|
</ProtectedRoute>
|
||||||
|
} />
|
||||||
|
|
||||||
|
{/* Rota 404 */}
|
||||||
<Route path="*" element={<NotFound />} />
|
<Route path="*" element={<NotFound />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
|||||||
42
src/components/auth/ProtectedRoute.tsx
Normal file
42
src/components/auth/ProtectedRoute.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
import { ReactNode, useEffect, useState } from 'react';
|
||||||
|
import { Navigate } from 'react-router-dom';
|
||||||
|
import { useToast } from "@/components/ui/use-toast";
|
||||||
|
|
||||||
|
interface ProtectedRouteProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
|
||||||
|
const [isAutenticado, setIsAutenticado] = useState<boolean | null>(null);
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Verifica se o usuário está autenticado
|
||||||
|
const autenticado = localStorage.getItem('autenticado') === 'true';
|
||||||
|
setIsAutenticado(autenticado);
|
||||||
|
|
||||||
|
if (!autenticado) {
|
||||||
|
toast({
|
||||||
|
title: "Acesso restrito",
|
||||||
|
description: "Faça login para acessar esta página",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [toast]);
|
||||||
|
|
||||||
|
// Mostra um carregamento enquanto verifica a autenticação
|
||||||
|
if (isAutenticado === null) {
|
||||||
|
return <div className="flex items-center justify-center min-h-screen">Carregando...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redireciona para a tela de login se não estiver autenticado
|
||||||
|
if (!isAutenticado) {
|
||||||
|
return <Navigate to="/auth" replace />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renderiza o conteúdo protegido se estiver autenticado
|
||||||
|
return <>{children}</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProtectedRoute;
|
||||||
@ -71,15 +71,32 @@ export function TransactionForm({ onSuccess, onCancel }: TransactionFormProps) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Obtém o ID do usuário logado
|
||||||
|
const userId = localStorage.getItem('userId');
|
||||||
|
if (!userId) {
|
||||||
|
toast({
|
||||||
|
title: "Erro de autenticação",
|
||||||
|
description: "Você precisa estar logado para adicionar transações",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
setIsSubmitting(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Ajusta o valor para ser positivo ou negativo com base no tipo
|
// Ajusta o valor para ser positivo ou negativo com base no tipo
|
||||||
const valorFinal = data.tipo.toLowerCase() === 'receita'
|
const valorFinal = data.tipo.toLowerCase() === 'receita'
|
||||||
? Math.abs(valorNumerico)
|
? Math.abs(valorNumerico)
|
||||||
: Math.abs(valorNumerico);
|
: Math.abs(valorNumerico);
|
||||||
|
|
||||||
|
// Cria o nome da tabela dinâmica para este usuário
|
||||||
|
const tabelaTransacoes = `transacoes_${userId}`;
|
||||||
|
|
||||||
|
// Insere a transação na tabela específica do usuário
|
||||||
const { error } = await supabase
|
const { error } = await supabase
|
||||||
.from('transacoes')
|
.from(tabelaTransacoes)
|
||||||
.insert([
|
.insert([
|
||||||
{
|
{
|
||||||
|
user: userId,
|
||||||
estabelecimento: data.estabelecimento,
|
estabelecimento: data.estabelecimento,
|
||||||
valor: valorFinal,
|
valor: valorFinal,
|
||||||
detalhes: data.detalhes,
|
detalhes: data.detalhes,
|
||||||
|
|||||||
60
src/components/layout/Header.tsx
Normal file
60
src/components/layout/Header.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { LogOut, User } from 'lucide-react';
|
||||||
|
import { useToast } from "@/components/ui/use-toast";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuLabel,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
|
||||||
|
const Header = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { toast } = useToast();
|
||||||
|
const [userName, setUserName] = useState(() => {
|
||||||
|
return localStorage.getItem('userName') || 'Usuário';
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
// Limpar informações de sessão
|
||||||
|
localStorage.removeItem('autenticado');
|
||||||
|
localStorage.removeItem('userId');
|
||||||
|
localStorage.removeItem('userName');
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Logout realizado",
|
||||||
|
description: "Você foi desconectado com sucesso"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Redirecionar para a página de login
|
||||||
|
navigate('/auth');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex justify-end items-center p-4 border-b">
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button variant="ghost" className="flex items-center gap-2">
|
||||||
|
<User size={18} />
|
||||||
|
<span>{userName}</span>
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end">
|
||||||
|
<DropdownMenuLabel>Minha conta</DropdownMenuLabel>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuItem onClick={handleLogout} className="text-red-500 cursor-pointer">
|
||||||
|
<LogOut className="mr-2 h-4 w-4" />
|
||||||
|
<span>Sair</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Header;
|
||||||
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import Sidebar from '@/components/layout/Sidebar';
|
import Sidebar from '@/components/layout/Sidebar';
|
||||||
|
import Header from '@/components/layout/Header';
|
||||||
import { useToast } from "@/components/ui/use-toast";
|
import { useToast } from "@/components/ui/use-toast";
|
||||||
import { Menu } from 'lucide-react';
|
import { Menu } from 'lucide-react';
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@ -44,9 +45,12 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
|||||||
) : (
|
) : (
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
)}
|
)}
|
||||||
<main className="flex-1 overflow-auto p-4 md:p-6 pt-10 md:pt-6">
|
<div className="flex flex-col flex-1 overflow-hidden">
|
||||||
{children}
|
<Header />
|
||||||
</main>
|
<main className="flex-1 overflow-auto p-4 md:p-6">
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
|
||||||
|
"use client"
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
||||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
import { Check, ChevronRight, Circle } from "lucide-react"
|
||||||
|
|||||||
@ -156,11 +156,42 @@ export type Database = {
|
|||||||
}
|
}
|
||||||
Relationships: []
|
Relationships: []
|
||||||
}
|
}
|
||||||
|
usuarios: {
|
||||||
|
Row: {
|
||||||
|
created_at: string
|
||||||
|
email: string
|
||||||
|
empresa: string | null
|
||||||
|
id: string
|
||||||
|
nome: string
|
||||||
|
senha: string
|
||||||
|
}
|
||||||
|
Insert: {
|
||||||
|
created_at?: string
|
||||||
|
email: string
|
||||||
|
empresa?: string | null
|
||||||
|
id?: string
|
||||||
|
nome: string
|
||||||
|
senha: string
|
||||||
|
}
|
||||||
|
Update: {
|
||||||
|
created_at?: string
|
||||||
|
email?: string
|
||||||
|
empresa?: string | null
|
||||||
|
id?: string
|
||||||
|
nome?: string
|
||||||
|
senha?: string
|
||||||
|
}
|
||||||
|
Relationships: []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Views: {
|
Views: {
|
||||||
[_ in never]: never
|
[_ in never]: never
|
||||||
}
|
}
|
||||||
Functions: {
|
Functions: {
|
||||||
|
autenticar_usuario: {
|
||||||
|
Args: { email_login: string; senha_login: string }
|
||||||
|
Returns: string
|
||||||
|
}
|
||||||
binary_quantize: {
|
binary_quantize: {
|
||||||
Args: { "": string } | { "": unknown }
|
Args: { "": string } | { "": unknown }
|
||||||
Returns: unknown
|
Returns: unknown
|
||||||
@ -226,6 +257,10 @@ export type Database = {
|
|||||||
Args: { "": string } | { "": unknown } | { "": unknown }
|
Args: { "": string } | { "": unknown } | { "": unknown }
|
||||||
Returns: string
|
Returns: string
|
||||||
}
|
}
|
||||||
|
registrar_usuario: {
|
||||||
|
Args: { nome: string; empresa: string; email: string; senha: string }
|
||||||
|
Returns: string
|
||||||
|
}
|
||||||
sparsevec_out: {
|
sparsevec_out: {
|
||||||
Args: { "": unknown }
|
Args: { "": unknown }
|
||||||
Returns: unknown
|
Returns: unknown
|
||||||
|
|||||||
255
src/pages/Auth.tsx
Normal file
255
src/pages/Auth.tsx
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import { useToast } from "@/components/ui/use-toast";
|
||||||
|
import { supabase } from "@/integrations/supabase/client";
|
||||||
|
|
||||||
|
const Auth = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { toast } = useToast();
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
// Estado do formulário de login
|
||||||
|
const [loginEmail, setLoginEmail] = useState('');
|
||||||
|
const [loginSenha, setLoginSenha] = useState('');
|
||||||
|
|
||||||
|
// Estado do formulário de cadastro
|
||||||
|
const [nome, setNome] = useState('');
|
||||||
|
const [empresa, setEmpresa] = useState('');
|
||||||
|
const [email, setEmail] = useState('');
|
||||||
|
const [senha, setSenha] = useState('');
|
||||||
|
const [confirmaSenha, setConfirmaSenha] = useState('');
|
||||||
|
|
||||||
|
// Função para fazer login
|
||||||
|
const handleLogin = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Tenta autenticar o usuário através da função RPC do Supabase
|
||||||
|
const { data, error } = await supabase.rpc('autenticar_usuario', {
|
||||||
|
email_login: loginEmail,
|
||||||
|
senha_login: loginSenha
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error || !data) {
|
||||||
|
throw new Error(error?.message || "Falha ao autenticar. Verifique seu email e senha.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Se encontrou um usuário válido, redireciona para a página de transações
|
||||||
|
if (data) {
|
||||||
|
// Armazenar informações de sessão (simplificado para este exemplo)
|
||||||
|
localStorage.setItem('autenticado', 'true');
|
||||||
|
localStorage.setItem('userId', data);
|
||||||
|
toast({
|
||||||
|
title: "Login realizado com sucesso",
|
||||||
|
description: "Bem-vindo de volta!"
|
||||||
|
});
|
||||||
|
navigate('/transacoes');
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: "Falha no login",
|
||||||
|
description: "Email ou senha incorretos",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erro ao fazer login:", error);
|
||||||
|
toast({
|
||||||
|
title: "Erro ao fazer login",
|
||||||
|
description: "Verifique suas credenciais e tente novamente",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Função para cadastrar usuário
|
||||||
|
const handleCadastro = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Validações básicas
|
||||||
|
if (!nome || !email || !senha) {
|
||||||
|
toast({
|
||||||
|
title: "Campos obrigatórios",
|
||||||
|
description: "Por favor preencha todos os campos obrigatórios",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (senha !== confirmaSenha) {
|
||||||
|
toast({
|
||||||
|
title: "Senhas não conferem",
|
||||||
|
description: "A senha e a confirmação de senha devem ser iguais",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Registrar o usuário usando a função RPC do Supabase
|
||||||
|
const { data, error } = await supabase.rpc('registrar_usuario', {
|
||||||
|
nome,
|
||||||
|
empresa,
|
||||||
|
email,
|
||||||
|
senha
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
toast({
|
||||||
|
title: "Cadastro realizado",
|
||||||
|
description: "Sua conta foi criada com sucesso!"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fazer login automaticamente após o cadastro
|
||||||
|
const { data: loginData, error: loginError } = await supabase.rpc('autenticar_usuario', {
|
||||||
|
email_login: email,
|
||||||
|
senha_login: senha
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loginError) throw loginError;
|
||||||
|
|
||||||
|
if (loginData) {
|
||||||
|
localStorage.setItem('autenticado', 'true');
|
||||||
|
localStorage.setItem('userId', loginData);
|
||||||
|
navigate('/transacoes');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error("Erro ao cadastrar:", error);
|
||||||
|
toast({
|
||||||
|
title: "Erro no cadastro",
|
||||||
|
description: error.message || "Não foi possível completar o cadastro",
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center min-h-screen bg-gray-50 px-4">
|
||||||
|
<Card className="w-full max-w-md">
|
||||||
|
<CardHeader className="space-y-1 text-center">
|
||||||
|
<CardTitle className="text-2xl font-bold">Finanças Pessoais</CardTitle>
|
||||||
|
<CardDescription>Gerencie suas finanças de forma simples e eficiente</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Tabs defaultValue="login" className="w-full">
|
||||||
|
<TabsList className="grid w-full grid-cols-2 mb-4">
|
||||||
|
<TabsTrigger value="login">Login</TabsTrigger>
|
||||||
|
<TabsTrigger value="cadastro">Cadastro</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="login">
|
||||||
|
<form onSubmit={handleLogin} className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Input
|
||||||
|
id="login-email"
|
||||||
|
placeholder="Email"
|
||||||
|
type="email"
|
||||||
|
value={loginEmail}
|
||||||
|
onChange={(e) => setLoginEmail(e.target.value)}
|
||||||
|
disabled={isLoading}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Input
|
||||||
|
id="login-senha"
|
||||||
|
placeholder="Senha"
|
||||||
|
type="password"
|
||||||
|
value={loginSenha}
|
||||||
|
onChange={(e) => setLoginSenha(e.target.value)}
|
||||||
|
disabled={isLoading}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button type="submit" className="w-full" disabled={isLoading}>
|
||||||
|
{isLoading ? "Entrando..." : "Entrar"}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="cadastro">
|
||||||
|
<form onSubmit={handleCadastro} className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Input
|
||||||
|
id="nome"
|
||||||
|
placeholder="Nome completo"
|
||||||
|
value={nome}
|
||||||
|
onChange={(e) => setNome(e.target.value)}
|
||||||
|
disabled={isLoading}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Input
|
||||||
|
id="empresa"
|
||||||
|
placeholder="Empresa (opcional)"
|
||||||
|
value={empresa}
|
||||||
|
onChange={(e) => setEmpresa(e.target.value)}
|
||||||
|
disabled={isLoading}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Input
|
||||||
|
id="email"
|
||||||
|
placeholder="Email"
|
||||||
|
type="email"
|
||||||
|
value={email}
|
||||||
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
|
disabled={isLoading}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Input
|
||||||
|
id="senha"
|
||||||
|
placeholder="Senha"
|
||||||
|
type="password"
|
||||||
|
value={senha}
|
||||||
|
onChange={(e) => setSenha(e.target.value)}
|
||||||
|
disabled={isLoading}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Input
|
||||||
|
id="confirma-senha"
|
||||||
|
placeholder="Confirme a senha"
|
||||||
|
type="password"
|
||||||
|
value={confirmaSenha}
|
||||||
|
onChange={(e) => setConfirmaSenha(e.target.value)}
|
||||||
|
disabled={isLoading}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button type="submit" className="w-full" disabled={isLoading}>
|
||||||
|
{isLoading ? "Cadastrando..." : "Cadastrar"}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</CardContent>
|
||||||
|
<CardFooter className="flex flex-col space-y-2">
|
||||||
|
<p className="text-sm text-center text-muted-foreground">
|
||||||
|
Ao continuar, você concorda com nossos termos de serviço e políticas de privacidade.
|
||||||
|
</p>
|
||||||
|
</CardFooter>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Auth;
|
||||||
@ -4,8 +4,17 @@ import { Transaction } from "@/types/financialTypes";
|
|||||||
|
|
||||||
export async function getTransacoes(): Promise<Transaction[]> {
|
export async function getTransacoes(): Promise<Transaction[]> {
|
||||||
console.log("Buscando transações do Supabase...");
|
console.log("Buscando transações do Supabase...");
|
||||||
|
|
||||||
|
const userId = localStorage.getItem('userId');
|
||||||
|
if (!userId) {
|
||||||
|
console.error('Usuário não autenticado');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabelaTransacoes = `transacoes_${userId}`;
|
||||||
|
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('transacoes')
|
.from(tabelaTransacoes)
|
||||||
.select('*')
|
.select('*')
|
||||||
.order('quando', { ascending: false });
|
.order('quando', { ascending: false });
|
||||||
|
|
||||||
@ -32,8 +41,17 @@ export async function getTransacoes(): Promise<Transaction[]> {
|
|||||||
|
|
||||||
export async function getTransactionSummary() {
|
export async function getTransactionSummary() {
|
||||||
console.log("Buscando resumo das transações...");
|
console.log("Buscando resumo das transações...");
|
||||||
|
|
||||||
|
const userId = localStorage.getItem('userId');
|
||||||
|
if (!userId) {
|
||||||
|
console.error('Usuário não autenticado');
|
||||||
|
return { receitas: 0, despesas: 0, saldo: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabelaTransacoes = `transacoes_${userId}`;
|
||||||
|
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('transacoes')
|
.from(tabelaTransacoes)
|
||||||
.select('tipo, valor');
|
.select('tipo, valor');
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -64,9 +82,17 @@ export async function getTransactionSummary() {
|
|||||||
export async function getCategorySummary() {
|
export async function getCategorySummary() {
|
||||||
console.log("Buscando resumo de categorias...");
|
console.log("Buscando resumo de categorias...");
|
||||||
|
|
||||||
|
const userId = localStorage.getItem('userId');
|
||||||
|
if (!userId) {
|
||||||
|
console.error('Usuário não autenticado');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabelaTransacoes = `transacoes_${userId}`;
|
||||||
|
|
||||||
// Buscar todas as transações que são despesas, independente da capitalização
|
// Buscar todas as transações que são despesas, independente da capitalização
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('transacoes')
|
.from(tabelaTransacoes)
|
||||||
.select('categoria, valor, tipo');
|
.select('categoria, valor, tipo');
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -115,8 +141,17 @@ export async function getCategorySummary() {
|
|||||||
|
|
||||||
export async function getMonthlyData() {
|
export async function getMonthlyData() {
|
||||||
console.log("Buscando dados mensais...");
|
console.log("Buscando dados mensais...");
|
||||||
|
|
||||||
|
const userId = localStorage.getItem('userId');
|
||||||
|
if (!userId) {
|
||||||
|
console.error('Usuário não autenticado');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabelaTransacoes = `transacoes_${userId}`;
|
||||||
|
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('transacoes')
|
.from(tabelaTransacoes)
|
||||||
.select('quando, valor, tipo');
|
.select('quando, valor, tipo');
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user