fix: Settings functionality + Dashboard tab counts
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled

SETTINGS FIXES:
- Profile save now calls real API (PUT /auth/me)
- Updates store after successful profile save
- Notification preferences now functional with state
- Save preferences button added
- Preferences stored in localStorage
- Proper loading/saving states

DASHBOARD FIX:
- Portfolio data loads on mount (not just when tab active)
- Tab counts now show correct numbers
- Both Watchlist and Portfolio counts visible immediately

API:
- Added updateMe() method in api.ts
This commit is contained in:
yves.gugger
2025-12-09 09:41:49 +01:00
parent 56d5a3f194
commit ed050782b6
3 changed files with 82 additions and 8 deletions

View File

@ -111,11 +111,12 @@ export default function DashboardPage() {
}
}, [isLoading, isAuthenticated, router])
// Load portfolio data on mount (so we can show count in tab)
useEffect(() => {
if (isAuthenticated && activeTab === 'portfolio') {
if (isAuthenticated) {
loadPortfolio()
}
}, [isAuthenticated, activeTab])
}, [isAuthenticated])
const handleOpenBillingPortal = async () => {
try {

View File

@ -43,6 +43,14 @@ export default function SettingsPage() {
email: '',
})
// Notification preferences (local state - would be persisted via API in production)
const [notificationPrefs, setNotificationPrefs] = useState({
domain_availability: true,
price_alerts: true,
weekly_digest: false,
})
const [savingNotifications, setSavingNotifications] = useState(false)
// Price alerts
const [priceAlerts, setPriceAlerts] = useState<PriceAlert[]>([])
const [loadingAlerts, setLoadingAlerts] = useState(false)
@ -92,9 +100,10 @@ export default function SettingsPage() {
setSuccess(null)
try {
// In a real app, this would call an API to update the user
// For now, we'll just show success
await new Promise(resolve => setTimeout(resolve, 500))
await api.updateMe({ name: profileForm.name || undefined })
// Update store with new user info
const { checkAuth } = useStore.getState()
await checkAuth()
setSuccess('Profile updated successfully')
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to update profile')
@ -103,6 +112,32 @@ export default function SettingsPage() {
}
}
const handleSaveNotifications = async () => {
setSavingNotifications(true)
setError(null)
setSuccess(null)
try {
// Store in localStorage for now (would be API in production)
localStorage.setItem('notification_prefs', JSON.stringify(notificationPrefs))
setSuccess('Notification preferences saved')
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to save preferences')
} finally {
setSavingNotifications(false)
}
}
// Load notification preferences from localStorage
useEffect(() => {
const saved = localStorage.getItem('notification_prefs')
if (saved) {
try {
setNotificationPrefs(JSON.parse(saved))
} catch {}
}
}, [])
const handleDeletePriceAlert = async (tld: string, alertId: number) => {
setDeletingAlertId(alertId)
try {
@ -301,7 +336,12 @@ export default function SettingsPage() {
<p className="text-body-sm font-medium text-foreground">Domain Availability</p>
<p className="text-body-xs text-foreground-muted">Get notified when watched domains become available</p>
</div>
<input type="checkbox" defaultChecked className="w-5 h-5 accent-accent" />
<input
type="checkbox"
checked={notificationPrefs.domain_availability}
onChange={(e) => setNotificationPrefs({ ...notificationPrefs, domain_availability: e.target.checked })}
className="w-5 h-5 accent-accent cursor-pointer"
/>
</label>
<label className="flex items-center justify-between p-4 bg-background border border-border rounded-xl cursor-pointer hover:border-foreground/20 transition-colors">
@ -309,7 +349,12 @@ export default function SettingsPage() {
<p className="text-body-sm font-medium text-foreground">Price Alerts</p>
<p className="text-body-xs text-foreground-muted">Get notified when TLD prices change</p>
</div>
<input type="checkbox" defaultChecked className="w-5 h-5 accent-accent" />
<input
type="checkbox"
checked={notificationPrefs.price_alerts}
onChange={(e) => setNotificationPrefs({ ...notificationPrefs, price_alerts: e.target.checked })}
className="w-5 h-5 accent-accent cursor-pointer"
/>
</label>
<label className="flex items-center justify-between p-4 bg-background border border-border rounded-xl cursor-pointer hover:border-foreground/20 transition-colors">
@ -317,9 +362,24 @@ export default function SettingsPage() {
<p className="text-body-sm font-medium text-foreground">Weekly Digest</p>
<p className="text-body-xs text-foreground-muted">Receive a weekly summary of your portfolio</p>
</div>
<input type="checkbox" className="w-5 h-5 accent-accent" />
<input
type="checkbox"
checked={notificationPrefs.weekly_digest}
onChange={(e) => setNotificationPrefs({ ...notificationPrefs, weekly_digest: e.target.checked })}
className="w-5 h-5 accent-accent cursor-pointer"
/>
</label>
</div>
<button
onClick={handleSaveNotifications}
disabled={savingNotifications}
className="mt-5 px-6 py-3 bg-foreground text-background text-ui font-medium rounded-xl
hover:bg-foreground/90 disabled:opacity-50 transition-all flex items-center gap-2"
>
{savingNotifications ? <Loader2 className="w-4 h-4 animate-spin" /> : <Check className="w-4 h-4" />}
Save Preferences
</button>
</div>
{/* Active Price Alerts */}

View File

@ -130,6 +130,19 @@ class ApiClient {
}>('/auth/me')
}
async updateMe(data: { name?: string }) {
return this.request<{
id: number
email: string
name: string | null
is_active: boolean
created_at: string
}>('/auth/me', {
method: 'PUT',
body: JSON.stringify(data),
})
}
// Password Reset
async forgotPassword(email: string) {
return this.request<{ message: string; success: boolean }>('/auth/forgot-password', {