Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import ChartSwitcher from './components/ChartSwitcher';
import EmptyGroupInvite from './components/EmptyGroupInvite';
import LatestExpenses from './components/LatestExpenses';
import SummaryCards from './components/SummaryCards';
import { useGroupsQuery } from './hooks/ReactQuery/Queries/useGroupsQuery';

function App() {
const { data } = useGroupsQuery();

const hasGroups = (data?.groupsLength ?? 0) > 0;

return (
<div className="flex flex-col gap-10">
<SummaryCards />
<ChartSwitcher />
<LatestExpenses />
{hasGroups ? (
<>
<SummaryCards />
<ChartSwitcher />
<LatestExpenses />
</>
) : (
<EmptyGroupInvite />
)}
</div>
);
}
Expand Down
14 changes: 0 additions & 14 deletions frontend/src/components/ChartSwitcher/ExpenseChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,6 @@ export default function ExpenseQuantityDonutChart() {
</Pie>
</PieChart>
</ResponsiveContainer>

{/* Total centralizado */}
<div className="absolute inset-0 flex flex-col items-center justify-center pointer-events-none">
<span className="text-lg font-bold text-text leading-none">
{formatBRL(total, {
minimumFractionDigits: 0,
maximumFractionDigits: 0,
style: 'decimal',
})}
</span>
<span className="text-sm text-muted-foreground leading-none">
Total
</span>
</div>
</div>
</div>
);
Expand Down
33 changes: 22 additions & 11 deletions frontend/src/components/ChartSwitcher/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,37 @@ import { FaChartLine, FaChartPie } from 'react-icons/fa';
import BalanceChart from './BalanceChart';
import ExpenseChart from './ExpenseChart';
import ButtonUI from '../ui/Button';
import { useMeDashboardQuery } from '../../hooks/ReactQuery/Queries/useMeDashboardStatsQuery';

export default function ChartSwitcher() {
const [activeChart, setActiveChart] = useState('balance');
const { data: expenseData } = useMeDashboardQuery();
const total = expenseData?.reduce((sum, item) => sum + item.quantity, 0) || 0;

const currentYear = new Date().getFullYear();
const title =
activeChart === 'balance'
? `Como Você Gastou em ${currentYear}`
: `Despesas por Categoria ( ${total} )`;

return (
<div className="w-full bg-surface p-6 rounded-2xl shadow-md border border-border/40 transition-colors duration-300 space-y-6">
{/* Cabeçalho */}
<div className="flex flex-1 justify-between items-center flex-wrap gap-3">
<div className="flex flex-1 justify-between items-center flex-wrap gap-3">
<h2 className="text-xl font-semibold text-text transition-all duration-300">
{activeChart === 'balance'
? `Como Você Gastou em (${new Date().getFullYear()})`
: 'Despesas por Categoria (Geral)'}
{title}
</h2>

{/* Alternador */}
<div className="relative flex bg-muted/20 rounded-full p-1.5 text-sm font-medium w-fit select-none">
{/* Indicador animado */}
{/* Indicador */}
<div
className={`absolute top-1 bottom-1 w-[50%] bg-primary rounded-full transition-all duration-300 ${
className={`absolute top-1 bottom-1 w-1/2 bg-primary rounded-full transition-all duration-300 ${
activeChart === 'expense' ? 'left-1/2' : 'left-1'
}`}
></div>
{/* Opção: Gastos Mensais */}
/>

{/* Opção: Resumo Anual */}
<ButtonUI
onClick={() => setActiveChart('balance')}
className={`relative z-10 w-1/2 flex items-center gap-2 px-4 py-1.5 rounded-full cursor-pointer transition-colors duration-300 ${
Expand All @@ -37,10 +45,11 @@ export default function ChartSwitcher() {
<FaChartLine size={16} />
<span>Resumo Anual</span>
</ButtonUI>
{/* Opção: Saldo Geral */}

{/* Opção: Divisão de Gastos */}
<ButtonUI
onClick={() => setActiveChart('expense')}
className={`relative z-10 w-1/2 flex items-center gap-2 px-4 py-0.5 rounded-full cursor-pointer transition-colors duration-300 ${
className={`relative z-10 w-1/2 flex items-center gap-2 px-4 py-1.5 rounded-full cursor-pointer transition-colors duration-300 ${
activeChart === 'expense'
? 'text-white'
: 'text-muted-foreground hover:text-text'
Expand All @@ -53,7 +62,8 @@ export default function ChartSwitcher() {
</div>

{/* Área dos gráficos */}
<div className="relative w-full min-h-72 sm:h-80 rounded-xl ">
<div className="relative w-full min-h-72 sm:h-80 rounded-xl">
{/* BalanceChart */}
<div
className={`absolute inset-0 transition-opacity duration-500 ease-in-out ${
activeChart === 'balance' ? 'opacity-100 z-10' : 'opacity-0 z-0'
Expand All @@ -62,6 +72,7 @@ export default function ChartSwitcher() {
<BalanceChart />
</div>

{/* ExpenseChart */}
<div
className={`absolute inset-0 transition-opacity duration-500 ease-in-out ${
activeChart === 'expense' ? 'opacity-100 z-10' : 'opacity-0 z-0'
Expand Down
49 changes: 49 additions & 0 deletions frontend/src/components/EmptyGroupInvite/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useNavigate } from 'react-router';
import ButtonUI from '../ui/Button';
import { FaUsers, FaWallet, FaChartPie } from 'react-icons/fa';

export default function EmptyGroupInvite() {
const navigate = useNavigate();

return (
<div className="w-full p-10 bg-surface border border-surface/40 rounded-2xl shadow-md text-center space-y-8 animate-fade-in">
{/* Ícone grande */}
<div className="flex flex-col items-center gap-3">
<div className="p-5 rounded-full bg-primary/15 text-primary shadow-sm">
<FaWallet size={42} />
</div>

<h2 className="text-2xl font-bold text-text tracking-tight">
Comece Sua Organização Financeira
</h2>

<p className="text-text max-w-lg leading-relaxed">
Você ainda não criou um grupo. Os grupos são a base para gerenciar
despesas, dividir valores e acompanhar sua saúde financeira.
</p>
</div>

{/* Mini indicadores financeiros (fake) para dar cara de dashboard */}
<div className="flex items-center justify-center gap-6">
<div className="select-none flex flex-col items-center p-4 rounded-xl bg-muted/20 border border-surface/20 w-32 shadow-sm">
<FaChartPie className="text-primary mb-1" size={22} />
<span className="text-sm text-text">Categorias</span>
<span className="text-base font-semibold text-text">0</span>
</div>

<div className="select-none flex flex-col items-center p-4 rounded-xl bg-muted/20 border border-surface/20 w-32 shadow-sm">
<FaUsers className="text-primary mb-1" size={22} />
<span className="text-sm text-text">Participantes</span>
<span className="text-base font-semibold text-text">0</span>
</div>
</div>

<ButtonUI
className="bg-primary cursor-pointer px-7 py-3 text-lg font-semibold rounded-xl shadow-md hover:shadow-lg transition-all text-white"
onClick={() => navigate('/groups?create')}
>
Criar meu primeiro grupo
</ButtonUI>
</div>
);
}
2 changes: 1 addition & 1 deletion frontend/src/components/forms/GroupForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { REACTQUERY_KEYS } from '../../libs/ReactQuery/keys';
import { customToast } from '../CustomToast';
import {
createGroupFormSchema,

Check failure on line 12 in frontend/src/components/forms/GroupForm.jsx

View workflow job for this annotation

GitHub Actions / Frontend (React)

'createGroupFormSchema' is defined but never used. Allowed unused vars must match /^[A-Z_]/u
validatorGroupForm,
} from '../../schemas/createGroup/form';
import { ZodError } from 'zod';
Expand Down Expand Up @@ -66,7 +66,7 @@
await mutateAsync(formData);
}
},
[isPending, isDisabled, groupName, selectedIcon, mutateAsync]
[isPending, isDisabled, groupName, description, selectedIcon, mutateAsync]
);

return (
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/pages/Expenses/ExpenseDetails/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export default function ExpenseDetails() {
<InputUI
label="Título"
name="title"
className="bg-white"
className="bg-surface"
placeholder="Título da despesa"
value={formData.title}
onChange={handleChange}
Expand All @@ -230,7 +230,7 @@ export default function ExpenseDetails() {
placeholder="Descrição da despesa..."
value={formData.description}
onChange={handleChange}
className="w-full min-h-[100px] rounded-lg border border-border bg-background px-3 py-2 text-text shadow-sm transition-all duration-200 focus:border-primary focus:ring-2 focus:ring-primary/30 placeholder:text-muted resize-none bg-white"
className="w-full min-h-[100px] rounded-lg border border-border bg-background px-3 py-2 text-text shadow-sm transition-all duration-200 focus:border-primary focus:ring-2 focus:ring-primary/30 placeholder:text-muted resize-none bg-surface"
/>
<div className="grid sm:grid-cols-2 gap-6">
<div className="flex flex-col gap-2">
Expand All @@ -252,7 +252,7 @@ export default function ExpenseDetails() {
min={getCurrentDate()}
value={formData.deadlineDate}
onChange={handleChange}
className="focus:ring-2 bg-white focus:ring-primary/50 transition-all"
className="focus:ring-2 bg-surface focus:ring-primary/50 transition-all"
/>
</div>
<div className="flex items-end">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
FiEdit3,
FiFileText,
FiSave,
FiSettings,
FiUserPlus,
FiUsers,
} from 'react-icons/fi';
Expand Down Expand Up @@ -71,15 +70,15 @@ export default function GroupSettings() {

return (
<div className="min-h-screen flex justify-center items-start p-6 sm:p-10 font-principal">
<main className="w-full max-w-3xl bg-white/80 backdrop-blur-xl border border-white/20 rounded-3xl p-8 sm:p-10 space-y-10 transition-all duration-300">
<main className="w-full max-w-3xl bg-surface/80 backdrop-blur-xl border border-surface/20 rounded-3xl p-8 sm:p-10 space-y-10 transition-all duration-300">
{/* Cabeçalho */}
<header className="relative text-center pb-6 border-b border-white/20">
<div className="absolute inset-0 blur-2xl rounded-3xl" />
<div className="relative z-10 flex flex-col items-center gap-3">
<div className="p-5 text-primary rounded-full">
<CategoryIcon categoryKey={group?.icon} className="w-15 h-15" />
</div>
<h1 className="text-3xl sm:text-4xl font-extrabold tracking-tight">
<h1 className="text-3xl text-text sm:text-4xl font-extrabold tracking-tight">
Configurações de{' '}
<span className="text-primary">{group.name}</span>
</h1>
Expand All @@ -93,7 +92,7 @@ export default function GroupSettings() {
{/* Formulário principal */}
<form onSubmit={handleSubmit} className="space-y-10" autoComplete="off">
{/* Informações básicas */}
<section className="bg-gradient-to-tr from-white/10 to-white/5 border border-white/10 rounded-2xl p-6 space-y-6 backdrop-blur-sm transition-all duration-300">
<section className="bg-linear-to-tr from-white/10 to-white/5 border border-white/10 rounded-2xl p-6 space-y-6 backdrop-blur-sm transition-all duration-300">
<FieldSection
id="groupName"
label="Nome do grupo"
Expand Down
Loading