From eb087e457c3b2c1dfafa9cd5a79b90a20e74f843 Mon Sep 17 00:00:00 2001 From: ribardej Date: Wed, 15 Oct 2025 10:06:22 +0200 Subject: [PATCH] feat(frontend): improved and centered UI --- 7project/frontend/src/App.css | 43 +---- 7project/frontend/src/api.ts | 2 +- 7project/frontend/src/main.tsx | 1 + 7project/frontend/src/pages/Dashboard.tsx | 155 +++++++++--------- .../frontend/src/pages/LoginRegisterPage.tsx | 78 +++++---- 5 files changed, 127 insertions(+), 152 deletions(-) diff --git a/7project/frontend/src/App.css b/7project/frontend/src/App.css index b9d355d..c776d1c 100644 --- a/7project/frontend/src/App.css +++ b/7project/frontend/src/App.css @@ -1,42 +1 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} +/* App-level styles moved to ui.css for a cleaner layout. */ diff --git a/7project/frontend/src/api.ts b/7project/frontend/src/api.ts index ff2d679..95933d4 100644 --- a/7project/frontend/src/api.ts +++ b/7project/frontend/src/api.ts @@ -88,7 +88,7 @@ export async function createTransaction(input: CreateTransactionInput): Promise< } export async function getTransactions(): Promise { - const res = await fetch(`${getBaseUrl()}/transactions/`, { + const res = await fetch(`${getBaseUrl()}/transactions/`, { headers: { 'Content-Type': 'application/json', ...authHeaders() }, }); if (!res.ok) throw new Error('Failed to load transactions'); diff --git a/7project/frontend/src/main.tsx b/7project/frontend/src/main.tsx index bef5202..d8e0921 100644 --- a/7project/frontend/src/main.tsx +++ b/7project/frontend/src/main.tsx @@ -1,6 +1,7 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import './index.css' +import './ui.css' import App from './App.tsx' createRoot(document.getElementById('root')!).render( diff --git a/7project/frontend/src/pages/Dashboard.tsx b/7project/frontend/src/pages/Dashboard.tsx index f606fdb..2c6b05f 100644 --- a/7project/frontend/src/pages/Dashboard.tsx +++ b/7project/frontend/src/pages/Dashboard.tsx @@ -36,9 +36,7 @@ export default function Dashboard({ onLogout }: { onLogout: () => void }) { } } - useEffect(() => { - loadAll(); - }, []); + useEffect(() => { loadAll(); }, []); const last10 = useMemo(() => { const sorted = [...transactions].sort((a, b) => b.id - a.id); @@ -56,9 +54,7 @@ export default function Dashboard({ onLogout }: { onLogout: () => void }) { return arr; }, [last10, minAmount, maxAmount, filterCategoryId, searchText]); - function categoryNameById(id: number) { - return categories.find(c => c.id === id)?.name || `#${id}`; - } + function categoryNameById(id: number) { return categories.find(c => c.id === id)?.name || `#${id}`; } async function handleCreate(e: React.FormEvent) { e.preventDefault(); @@ -71,85 +67,90 @@ export default function Dashboard({ onLogout }: { onLogout: () => void }) { try { const created = await createTransaction(payload); setTransactions(prev => [created, ...prev]); - // reset form - setAmount(''); - setDescription(''); - setSelectedCategoryId(''); + setAmount(''); setDescription(''); setSelectedCategoryId(''); } catch (err: any) { alert(err?.message || 'Failed to create transaction'); } } return ( -
-
-

Dashboard

- -
- -
-

Add Transaction

-
- setAmount(e.target.value)} required /> - setDescription(e.target.value)} /> - - -
-
- -
-

Filters

-
- setMinAmount(e.target.value)} /> - setMaxAmount(e.target.value)} /> - - setSearchText(e.target.value)} /> +
+ +
+
+

Dashboard

+
+ Signed in + +
-
+
+
+

Add Transaction

+
+ setAmount(e.target.value)} required /> + setDescription(e.target.value)} /> + + +
+
-
-

Latest Transactions (last 10)

- {loading ? ( -
Loading…
- ) : error ? ( -
{error}
- ) : filtered.length === 0 ? ( -
No transactions
- ) : ( - - - - - - - - - - - {filtered.map(t => ( - - - - - - - ))} - -
IDAmountDescriptionCategories
{t.id}{formatAmount(t.amount)}{t.description || ''} - {t.category_ids.map(id => categoryNameById(id)).join(', ')} -
- )} -
+
+

Filters

+
+ setMinAmount(e.target.value)} /> + setMaxAmount(e.target.value)} /> + + setSearchText(e.target.value)} /> +
+
+ +
+

Latest Transactions (last 10)

+ {loading ? ( +
Loading…
+ ) : error ? ( +
{error}
+ ) : filtered.length === 0 ? ( +
No transactions
+ ) : ( + + + + + + + + + + + {filtered.map(t => ( + + + + + + + ))} + +
IDAmountDescriptionCategories
{t.id}{formatAmount(t.amount)}{t.description || ''}{t.category_ids.map(id => categoryNameById(id)).join(', ')}
+ )} +
+
+
); } diff --git a/7project/frontend/src/pages/LoginRegisterPage.tsx b/7project/frontend/src/pages/LoginRegisterPage.tsx index e265167..ce333d0 100644 --- a/7project/frontend/src/pages/LoginRegisterPage.tsx +++ b/7project/frontend/src/pages/LoginRegisterPage.tsx @@ -1,6 +1,7 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { login, register } from '../api'; + export default function LoginRegisterPage({ onLoggedIn }: { onLoggedIn: () => void }) { const [mode, setMode] = useState<'login' | 'register'>('login'); const [email, setEmail] = useState(''); @@ -31,41 +32,54 @@ export default function LoginRegisterPage({ onLoggedIn }: { onLoggedIn: () => vo } } + // Add this useEffect hook + useEffect(() => { + // When the component mounts, add a class to the body + document.body.classList.add('auth-page'); + + // When the component unmounts, remove the class + return () => { + document.body.classList.remove('auth-page'); + }; + }, []); // The empty array ensures this runs only once + + // The JSX no longer needs the wrapper div return ( -
-

{mode === 'login' ? 'Login' : 'Register'}

-
- - +
+
+

{mode === 'login' ? 'Welcome back' : 'Create your account'}

+
+ + +
-
-
- -
-
- -
- {mode === 'register' && ( - <> -
- + +
+ + setEmail(e.target.value)} /> +
+
+ + setPassword(e.target.value)} /> +
+ {mode === 'register' && ( +
+
+ + setFirstName(e.target.value)} /> +
+
+ + setLastName(e.target.value)} /> +
-
- -
- - )} - {error &&
{error}
} - + )} + {error &&
{error}
} +
+ +
); } +