feat(frontend): implemented CSAS button responsiveness

This commit is contained in:
ribardej
2025-11-12 15:31:30 +01:00
parent 186b4fd09a
commit e164b185e0
2 changed files with 48 additions and 2 deletions

View File

@@ -133,6 +133,9 @@ export type User = {
is_active: boolean; is_active: boolean;
is_superuser: boolean; is_superuser: boolean;
is_verified: boolean; is_verified: boolean;
// Optional JSON config object for user-level integrations and settings
// Example: { csas: "{\"expires_at\": 1761824615, ...}" } or { csas: { expires_at: 1761824615, ... } }
config?: Record<string, any> | null;
}; };
export async function getMe(): Promise<User> { export async function getMe(): Promise<User> {

View File

@@ -1,5 +1,5 @@
import { useEffect, useMemo, useState, useCallback } from 'react'; import { useEffect, useMemo, useState, useCallback } from 'react';
import { type Category, type Transaction, type BalancePoint, deleteTransaction, getCategories, getTransactions, createTransaction, updateTransaction, getBalanceSeries } from '../api'; import { type Category, type Transaction, type BalancePoint, type User, getMe, deleteTransaction, getCategories, getTransactions, createTransaction, updateTransaction, getBalanceSeries } from '../api';
import AccountPage from './AccountPage'; import AccountPage from './AccountPage';
import AppearancePage from './AppearancePage'; import AppearancePage from './AppearancePage';
import BalanceChart from './BalanceChart'; import BalanceChart from './BalanceChart';
@@ -118,6 +118,49 @@ export default function Dashboard({ onLogout }: { onLogout: () => void }) {
const [isMockModalOpen, setMockModalOpen] = useState(false); const [isMockModalOpen, setMockModalOpen] = useState(false);
const [isGenerating, setIsGenerating] = useState(false); const [isGenerating, setIsGenerating] = useState(false);
// Current user and CSAS connection status
const [me, setMe] = useState<User | null>(null);
const [csasConnected, setCsasConnected] = useState(false);
useEffect(() => {
(async () => {
try {
const u = await getMe();
setMe(u);
// Determine CSAS connection validity
const csas = (u as any)?.config?.csas;
let obj: any = null;
if (csas) {
if (typeof csas === 'string') {
try { obj = JSON.parse(csas); } catch {}
} else if (typeof csas === 'object') {
obj = csas;
}
}
let exp: number | null = null;
const raw = obj?.expires_at;
if (typeof raw === 'number') {
exp = raw;
} else if (typeof raw === 'string') {
const asNum = Number(raw);
if (!Number.isNaN(asNum)) {
exp = asNum;
} else {
const ms = Date.parse(raw);
if (!Number.isNaN(ms)) exp = Math.floor(ms / 1000);
}
}
if (exp && exp > Math.floor(Date.now() / 1000)) {
setCsasConnected(true);
} else {
setCsasConnected(false);
}
} catch (e) {
// ignore, user may not be loaded; keep button enabled
}
})();
}, []);
// Start CSAS (George) OAuth after login // Start CSAS (George) OAuth after login
async function startOauthCsas() { async function startOauthCsas() {
const base = BACKEND_URL.replace(/\/$/, ''); const base = BACKEND_URL.replace(/\/$/, '');
@@ -364,7 +407,7 @@ export default function Dashboard({ onLogout }: { onLogout: () => void }) {
<h3>Bank connections</h3> <h3>Bank connections</h3>
<div className="connection-row"> <div className="connection-row">
<p className="muted" style={{ margin: 0 }}>Connect your CSAS (George) account.</p> <p className="muted" style={{ margin: 0 }}>Connect your CSAS (George) account.</p>
<button className="btn primary" onClick={startOauthCsas}>Connect CSAS (George)</button> <button className="btn primary" onClick={startOauthCsas} disabled={csasConnected}>{csasConnected ? 'Successfully connected to CSAS' : 'Connect CSAS (George)'}</button>
</div> </div>
<div className="connection-row"> <div className="connection-row">
<p className="muted" style={{ margin: 0 }}>Generate data from a mock bank.</p> <p className="muted" style={{ margin: 0 }}>Generate data from a mock bank.</p>