v1.0.2
Wygląd
This commit is contained in:
@@ -15,6 +15,12 @@ server {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Always revalidate the HTML shell so it never points at a stale, no-longer-existing
|
||||
# hashed JS/CSS bundle after a new deploy.
|
||||
location = /index.html {
|
||||
add_header Cache-Control "no-cache";
|
||||
}
|
||||
|
||||
location ~* \.(?:js|css|png|jpg|jpeg|svg|woff2?)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useBalance, useSummary, useSettleUp } from '../api/queries.js';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useBalance, useSummary } from '../api/queries.js';
|
||||
import { useHouseholdContext } from '../household/HouseholdContext.jsx';
|
||||
import CategoryPieChart from '../components/CategoryPieChart.jsx';
|
||||
import Icon from '../components/Icon.jsx';
|
||||
@@ -8,10 +9,10 @@ function memberName(members, id) {
|
||||
}
|
||||
|
||||
export default function Dashboard() {
|
||||
const navigate = useNavigate();
|
||||
const { activeHousehold: household } = useHouseholdContext();
|
||||
const { data: balance } = useBalance();
|
||||
const { data: summary } = useSummary();
|
||||
const settleUp = useSettleUp();
|
||||
|
||||
const members = household?.members || [];
|
||||
const currency = household?.currency || 'PLN';
|
||||
@@ -40,12 +41,8 @@ export default function Dashboard() {
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
className="btn-primary btn-center"
|
||||
disabled={settleUp.isPending}
|
||||
onClick={() => settleUp.mutate()}
|
||||
>
|
||||
{settleUp.isPending ? 'Rozliczanie…' : 'Rozlicz się'}
|
||||
<button className="btn-primary btn-center" onClick={() => navigate('/settlements')}>
|
||||
Rozlicz się
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useHouseholdContext } from '../household/HouseholdContext.jsx';
|
||||
import { useBalance, useSettleUp, useSettlements, useCreateManualSettlement } from '../api/queries.js';
|
||||
import PayerToggle from '../components/PayerToggle.jsx';
|
||||
@@ -26,12 +26,23 @@ export default function Settlements() {
|
||||
const [error, setError] = useState('');
|
||||
const [success, setSuccess] = useState(false);
|
||||
const [editingSettlement, setEditingSettlement] = useState(null);
|
||||
const initializedRef = useRef(false);
|
||||
|
||||
// Prefill the form from the first suggested transfer as soon as the balance is
|
||||
// known, so the user starts from "who actually owes whom" instead of a blank guess.
|
||||
useEffect(() => {
|
||||
if (!fromUserId && members[0]) setFromUserId(members[0].id);
|
||||
if (!toUserId && members[1]) setToUserId(members[1].id);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [members.length]);
|
||||
if (initializedRef.current || !balance) return;
|
||||
initializedRef.current = true;
|
||||
const suggestion = balance.transactions?.[0];
|
||||
if (suggestion) {
|
||||
setFromUserId(suggestion.from);
|
||||
setToUserId(suggestion.to);
|
||||
setAmount(String(suggestion.amount));
|
||||
} else if (members[0] && members[1]) {
|
||||
setFromUserId(members[0].id);
|
||||
setToUserId(members[1].id);
|
||||
}
|
||||
}, [balance, members]);
|
||||
|
||||
const toOptions = members.filter((m) => m.id !== fromUserId);
|
||||
|
||||
@@ -43,6 +54,12 @@ export default function Settlements() {
|
||||
}
|
||||
}
|
||||
|
||||
function applySuggestion(tx) {
|
||||
setFromUserId(tx.from);
|
||||
setToUserId(tx.to);
|
||||
setAmount(String(tx.amount));
|
||||
}
|
||||
|
||||
async function handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
setError('');
|
||||
@@ -77,12 +94,12 @@ export default function Settlements() {
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p>Sugerowane rozliczenie</p>
|
||||
<p>Sugerowane rozliczenie (dotknij, aby wypełnić formularz poniżej)</p>
|
||||
<div className="settlement-transactions">
|
||||
{balance.transactions.map((tx, i) => (
|
||||
<p key={i} className="amount owed">
|
||||
<button key={i} type="button" className="amount owed suggestion-btn" onClick={() => applySuggestion(tx)}>
|
||||
{memberName(members, tx.from)} → {memberName(members, tx.to)}: {tx.amount.toFixed(2)} {currency}
|
||||
</p>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
|
||||
@@ -232,7 +232,7 @@ input, select, button, textarea { font-family: inherit; font-size: 1rem; color:
|
||||
}
|
||||
|
||||
.btn-full { width: 100%; display: block; }
|
||||
.btn-center { width: fit-content; margin: 0 auto; }
|
||||
.btn-center { width: fit-content; margin: 16px auto 0; }
|
||||
|
||||
.theme-toggle { display: flex; gap: 8px; }
|
||||
.theme-toggle .tab { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; }
|
||||
@@ -264,6 +264,15 @@ input, select, button, textarea { font-family: inherit; font-size: 1rem; color:
|
||||
.settlement-tile .amount.owed { color: var(--danger); }
|
||||
.settlement-transactions { display: flex; flex-direction: column; gap: 4px; }
|
||||
.settlement-transactions .amount { font-size: 1.3rem; margin: 0; }
|
||||
.suggestion-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
border-radius: 8px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
.suggestion-btn:hover, .suggestion-btn:focus-visible { background: var(--accent-bg); }
|
||||
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
|
||||
@@ -24,6 +24,8 @@ export default defineConfig({
|
||||
},
|
||||
workbox: {
|
||||
navigateFallbackDenylist: [/^\/api\//],
|
||||
clientsClaim: true,
|
||||
skipWaiting: true,
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: ({ url }) => url.pathname.startsWith('/api/') && url.pathname !== '/api/expenses',
|
||||
|
||||
Reference in New Issue
Block a user