forked from MyZubster-Ecosystem/myzubster
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTreasuryView.js
More file actions
131 lines (115 loc) 路 4.83 KB
/
Copy pathTreasuryView.js
File metadata and controls
131 lines (115 loc) 路 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import React, { useState, useEffect } from 'react';
import './TreasuryView.css';
const TX_ICONS = { deposit: '馃摜', withdrawal: '馃摛', transfer: '馃攧', reward: '馃巵' };
const TreasuryView = ({ ownerId }) => {
const [treasuries, setTreasuries] = useState([]);
const [selected, setSelected] = useState(null);
const [txs, setTxs] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => { fetchTreasuries(); }, []);
const fetchTreasuries = async () => {
try {
const res = await fetch('/api/dao/treasury?ownerId=' + ownerId);
const data = await res.json();
if (data.success) { setTreasuries(data.data); if (data.data.length > 0) setSelected(data.data[0]); }
} catch (e) { console.error(e); }
setLoading(false);
};
useEffect(() => {
if (selected) fetchTransactions(selected.id);
}, [selected]);
const fetchTransactions = async (id) => {
const res = await fetch('/api/dao/treasury/' + id + '/transactions');
const data = await res.json();
if (data.success) setTxs(data.data);
};
const handleDeposit = async (e) => {
e.preventDefault();
const fd = new FormData(e.target);
await fetch('/api/dao/treasury/' + selected.id + '/deposit', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: parseFloat(fd.get('amount')), from: fd.get('from') || 'manual' }),
});
fetchTreasuries();
e.target.reset();
};
const handleWithdraw = async (e) => {
e.preventDefault();
const fd = new FormData(e.target);
const amount = parseFloat(fd.get('amount'));
if (amount > (selected?.balance || 0)) { alert('Fondi insufficienti'); return; }
await fetch('/api/dao/treasury/' + selected.id + '/withdraw', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ amount, to: fd.get('to') || 'manual' }),
});
fetchTreasuries();
e.target.reset();
};
const handleCreateTreasury = async (e) => {
e.preventDefault();
const fd = new FormData(e.target);
await fetch('/api/dao/treasury', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: fd.get('name'), ownerId, currency: fd.get('currency') || 'XMR' }),
});
fetchTreasuries();
e.target.reset();
};
if (loading) return <div className="tv-loading">Caricamento...</div>;
return (
<div className="treasury-view">
<h2>馃彟 Treasury</h2>
{treasuries.length === 0 ? (
<form className="tv-create" onSubmit={handleCreateTreasury}>
<input name="name" placeholder="Nome treasury" required />
<select name="currency"><option value="XMR">XMR</option><option value="USD">USD</option></select>
<button type="submit">Crea Treasury</button>
</form>
) : (
<>
<div className="tv-tabs">
{treasuries.map(t => (
<button key={t.id} className={selected?.id === t.id ? 'active' : ''} onClick={() => setSelected(t)}>
{t.name} ({t.balance} {t.currency})
</button>
))}
</div>
{selected && (
<div className="tv-detail">
<div className="tv-balance">
<span className="tv-balance-amount">{selected.balance}</span>
<span className="tv-balance-currency">{selected.currency}</span>
</div>
<div className="tv-forms">
<form onSubmit={handleDeposit}>
<h4>馃摜 Deposito</h4>
<input name="amount" type="number" step="0.01" min="0.01" placeholder="Importo" required />
<input name="from" placeholder="Da (opzionale)" />
<button type="submit">Deposita</button>
</form>
<form onSubmit={handleWithdraw}>
<h4>馃摛 Prelievo</h4>
<input name="amount" type="number" step="0.01" min="0.01" placeholder="Importo" required />
<input name="to" placeholder="A (opzionale)" />
<button type="submit">Preleva</button>
</form>
</div>
<h4>馃搵 Transazioni ({txs.length})</h4>
<div className="tv-tx-list">
{txs.slice().reverse().map((tx, i) => (
<div key={i} className="tv-tx">
<span className="tv-tx-icon">{TX_ICONS[tx.type]}</span>
<span className="tv-tx-type">{tx.type}</span>
<span className="tv-tx-amount">{tx.amount} {selected.currency}</span>
<span className="tv-tx-date">{new Date(tx.createdAt).toLocaleDateString('it-IT')}</span>
</div>
))}
</div>
</div>
)}
</>
)}
</div>
);
};
export default TreasuryView;