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
31 changes: 18 additions & 13 deletions frontend/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,16 @@ export function Layout({ children, onSettingsClick }: LayoutProps) {
return (
<div className="min-h-screen">
<header className="sticky top-0 z-40 bg-sand-50/80 dark:bg-charcoal-950/80 backdrop-blur-md border-b border-sand-200 dark:border-charcoal-800">
<div className="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
<span className="text-xl font-semibold tracking-tight text-charcoal-800 dark:text-sand-100">
<div className="max-w-6xl mx-auto px-4 py-3 sm:py-4 flex items-center justify-between">
<span className="text-lg sm:text-xl font-semibold tracking-tight text-charcoal-800 dark:text-sand-100">
payme
</span>
{user && (
<span className="text-sm text-charcoal-600 dark:text-charcoal-300">
<span className="hidden sm:inline text-sm text-charcoal-600 dark:text-charcoal-300">
Welcome, {user.username}
</span>
)}
<div className="flex items-center gap-2">
<div className="flex items-center gap-1 sm:gap-2">
{user && (
<>
<input
Expand All @@ -93,47 +93,52 @@ export function Layout({ children, onSettingsClick }: LayoutProps) {
/>
<button
onClick={handleImportClick}
className="p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 transition-colors cursor-pointer"
className="p-2 sm:p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 transition-colors cursor-pointer touch-manipulation"
title="Import data"
aria-label="Import data"
>
<Upload size={18} />
</button>
<button
onClick={handleExport}
className="p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 transition-colors cursor-pointer"
className="p-2 sm:p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 transition-colors cursor-pointer touch-manipulation"
title="Export data"
aria-label="Export data"
>
<Download size={18} />
</button>
</>
)}
<button
onClick={toggle}
className="p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 transition-colors cursor-pointer"
className="p-2 sm:p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 transition-colors cursor-pointer touch-manipulation"
aria-label="Toggle theme"
>
{isDark ? <Sun size={18} /> : <Moon size={18} />}
</button>
{user && onSettingsClick && (
<button
onClick={onSettingsClick}
className="p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 transition-colors cursor-pointer"
className="p-2 sm:p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 transition-colors cursor-pointer touch-manipulation"
title="Settings"
aria-label="Settings"
>
<Settings size={18} />
</button>
)}
{user && (
<button
onClick={logout}
className="p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 transition-colors cursor-pointer"
className="p-2 sm:p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 transition-colors cursor-pointer touch-manipulation"
aria-label="Logout"
>
<LogOut size={18} />
</button>
)}
</div>
</div>
</header>
<main className="max-w-6xl mx-auto px-4 py-8">{children}</main>
<main className="max-w-6xl mx-auto px-4 py-4 sm:py-8">{children}</main>

<Modal isOpen={showImportConfirm} onClose={() => setShowImportConfirm(false)} title="Import Data">
<div className="space-y-4">
Expand All @@ -147,11 +152,11 @@ export function Layout({ children, onSettingsClick }: LayoutProps) {
<div>{pendingImport.months.length} months</div>
</div>
)}
<div className="flex gap-2">
<Button onClick={confirmImport} disabled={importing}>
<div className="flex flex-col sm:flex-row gap-2">
<Button onClick={confirmImport} disabled={importing} className="w-full sm:w-auto">
{importing ? "Importing..." : "Replace My Data"}
</Button>
<Button variant="ghost" onClick={() => setShowImportConfirm(false)}>
<Button variant="ghost" onClick={() => setShowImportConfirm(false)} className="w-full sm:w-auto">
Cancel
</Button>
</div>
Expand Down
18 changes: 10 additions & 8 deletions frontend/src/components/MonthNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,18 @@ export function MonthNav({
if (!selectedMonth) return null;

return (
<div className="flex items-center justify-between mb-8">
<div className="flex items-center gap-4">
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 mb-6 sm:mb-8">
<div className="flex items-center gap-2 sm:gap-4">
<button
onClick={goPrev}
disabled={currentIndex >= months.length - 1}
className="p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 disabled:opacity-30 transition-colors"
className="p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 disabled:opacity-30 transition-colors touch-manipulation"
aria-label="Previous month"
>
<ChevronLeft size={20} />
</button>
<div className="text-center">
<div className="text-2xl font-semibold text-charcoal-900 dark:text-sand-50">
<div className="text-xl sm:text-2xl font-semibold text-charcoal-900 dark:text-sand-50">
{MONTH_NAMES[selectedMonth.month - 1]} {selectedMonth.year}
</div>
<div className="text-xs text-charcoal-500 dark:text-charcoal-400 flex items-center justify-center gap-1">
Expand All @@ -74,21 +75,22 @@ export function MonthNav({
<button
onClick={goNext}
disabled={currentIndex <= 0}
className="p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 disabled:opacity-30 transition-colors"
className="p-2 hover:bg-sand-200 dark:hover:bg-charcoal-800 disabled:opacity-30 transition-colors touch-manipulation"
aria-label="Next month"
>
<ChevronRight size={20} />
</button>
</div>

<div className="flex items-center gap-2">
<div className="flex items-center gap-2 w-full sm:w-auto">
{selectedMonth.is_closed && (
<Button variant="ghost" size="sm" onClick={onDownloadPdf}>
<Button variant="ghost" size="sm" onClick={onDownloadPdf} className="flex-1 sm:flex-none">
<FileDown size={16} className="mr-2" />
PDF
</Button>
)}
{canClose && (
<Button variant="primary" size="sm" onClick={onClose}>
<Button variant="primary" size="sm" onClick={onClose} className="flex-1 sm:flex-none">
Close Month
</Button>
)}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/Summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,20 @@ export function Summary({ totalIncome, totalFixed, totalSpent, remaining, extraC
<div className="text-xs text-charcoal-500 dark:text-charcoal-400 mb-1">
{item.label}
</div>
<div className={`text-xl font-semibold ${item.color}`}>
<div className={`text-lg sm:text-xl font-semibold ${item.color}`}>
${Math.abs(item.value).toFixed(2)}
{item.label === "Remaining" && item.value < 0 && (
<span className="text-xs ml-1">deficit</span>
)}
</div>
</div>
<item.icon size={20} className={item.color} />
<item.icon size={18} className={`${item.color} sm:w-5 sm:h-5`} />
</div>
</Card>
);

return (
<div className={`grid grid-cols-2 gap-4 ${extraCard ? "lg:grid-cols-5" : "lg:grid-cols-4"}`}>
<div className={`grid grid-cols-2 gap-3 sm:gap-4 ${extraCard ? "lg:grid-cols-5" : "lg:grid-cols-4"}`}>
{items.map(renderCard)}
{extraCard}
{itemsAfter.map(renderCard)}
Expand Down
40 changes: 22 additions & 18 deletions frontend/src/pages/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,27 +61,31 @@ export function Dashboard({ onSettingsClick }: DashboardProps) {

return (
<Layout onSettingsClick={onSettingsClick}>
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-4">
<MonthNav
months={months}
selectedMonthId={selectedMonthId}
onSelect={selectMonth}
onClose={closeMonth}
onDownloadPdf={downloadPdf}
/>
<div className="w-36">
<SavingsCard onSavingsChange={handleSavingsChange} />
<div className="space-y-4 mb-4">
<MonthNav
months={months}
selectedMonthId={selectedMonthId}
onSelect={selectMonth}
onClose={closeMonth}
onDownloadPdf={downloadPdf}
/>
<div className="flex flex-col sm:flex-row items-stretch sm:items-center justify-between gap-4">
<div className="flex flex-col sm:flex-row gap-3 sm:gap-4 w-full sm:w-auto">
<div className="w-full sm:w-36">
<SavingsCard onSavingsChange={handleSavingsChange} />
</div>
<div className="w-full sm:w-36">
<ProjectedSavingsCard
savings={savings}
remaining={summary.remaining}
onAnalyzeClick={() => setShowVarianceModal(true)}
/>
</div>
</div>
<div className="w-36">
<ProjectedSavingsCard
savings={savings}
remaining={summary.remaining}
onAnalyzeClick={() => setShowVarianceModal(true)}
/>
<div className="hidden lg:block">
<Stats />
</div>
</div>
<Stats />
</div>

<div className="space-y-6">
Expand Down
23 changes: 12 additions & 11 deletions frontend/src/pages/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,19 @@ export function Settings({ onBack }: SettingsProps) {
<div className="max-w-2xl mx-auto">
<button
onClick={onBack}
className="mb-6 flex items-center gap-2 text-sm text-charcoal-600 dark:text-charcoal-400 hover:text-charcoal-900 dark:hover:text-sand-100 transition-colors"
className="mb-4 sm:mb-6 flex items-center gap-2 text-sm text-charcoal-600 dark:text-charcoal-400 hover:text-charcoal-900 dark:hover:text-sand-100 transition-colors touch-manipulation"
>
<ArrowLeft size={16} />
Back to Dashboard
</button>

<h1 className="text-2xl font-semibold mb-8 text-charcoal-800 dark:text-sand-100">
<h1 className="text-xl sm:text-2xl font-semibold mb-6 sm:mb-8 text-charcoal-800 dark:text-sand-100">
Settings
</h1>

<div className="space-y-8">
<div className="bg-sand-100 dark:bg-charcoal-900 p-6 border border-sand-200 dark:border-charcoal-800">
<h2 className="text-lg font-medium mb-4 text-charcoal-800 dark:text-sand-100">
<div className="space-y-6 sm:space-y-8">
<div className="bg-sand-100 dark:bg-charcoal-900 p-4 sm:p-6 border border-sand-200 dark:border-charcoal-800">
<h2 className="text-base sm:text-lg font-medium mb-4 text-charcoal-800 dark:text-sand-100">
Change Username
</h2>
<form onSubmit={handleChangeUsername} className="space-y-4">
Expand All @@ -140,8 +140,8 @@ export function Settings({ onBack }: SettingsProps) {
</form>
</div>

<div className="bg-sand-100 dark:bg-charcoal-900 p-6 border border-sand-200 dark:border-charcoal-800">
<h2 className="text-lg font-medium mb-4 text-charcoal-800 dark:text-sand-100">
<div className="bg-sand-100 dark:bg-charcoal-900 p-4 sm:p-6 border border-sand-200 dark:border-charcoal-800">
<h2 className="text-base sm:text-lg font-medium mb-4 text-charcoal-800 dark:text-sand-100">
Change Password
</h2>
<form onSubmit={handleChangePassword} className="space-y-4">
Expand Down Expand Up @@ -181,8 +181,8 @@ export function Settings({ onBack }: SettingsProps) {
</form>
</div>

<div className="bg-terracotta-50 dark:bg-charcoal-900 p-6 border-2 border-terracotta-300 dark:border-terracotta-800">
<h2 className="text-lg font-medium mb-2 text-terracotta-800 dark:text-terracotta-300">
<div className="bg-terracotta-50 dark:bg-charcoal-900 p-4 sm:p-6 border-2 border-terracotta-300 dark:border-terracotta-800">
<h2 className="text-base sm:text-lg font-medium mb-2 text-terracotta-800 dark:text-terracotta-300">
Danger Zone
</h2>
<p className="text-sm text-charcoal-600 dark:text-charcoal-400 mb-4">
Expand Down Expand Up @@ -229,8 +229,8 @@ export function Settings({ onBack }: SettingsProps) {
{deleteError && (
<p className="text-sm text-terracotta-600">{deleteError}</p>
)}
<div className="flex gap-2">
<Button variant="danger" onClick={handleClearData} disabled={deleteLoading}>
<div className="flex flex-col sm:flex-row gap-2">
<Button variant="danger" onClick={handleClearData} disabled={deleteLoading} className="w-full sm:w-auto">
{deleteLoading ? "Deleting..." : "Yes, Delete Everything"}
</Button>
<Button
Expand All @@ -241,6 +241,7 @@ export function Settings({ onBack }: SettingsProps) {
setDeleteError("");
}}
disabled={deleteLoading}
className="w-full sm:w-auto"
>
Cancel
</Button>
Expand Down