Rollen Freigaben Push und Beleg Upload ueberarbeiten
All checks were successful
CI / Build (push) Successful in 2m6s
CI / Deploy (push) Successful in 2m11s

This commit is contained in:
jan
2026-05-01 15:50:37 +02:00
parent f947908f0e
commit 549c8f16c6
34 changed files with 1354 additions and 172 deletions

View File

@@ -10,6 +10,7 @@ import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded";
import EuroRoundedIcon from "@mui/icons-material/EuroRounded";
import ReceiptLongRoundedIcon from "@mui/icons-material/ReceiptLongRounded";
import TaskAltRoundedIcon from "@mui/icons-material/TaskAltRounded";
import UploadFileRoundedIcon from "@mui/icons-material/UploadFileRounded";
import {
Box,
Button,
@@ -49,6 +50,7 @@ type BudgetColumnProps = {
onApprove: (expenseId: string, approvalType: "CHAIR_A" | "CHAIR_B" | "FINANCE") => Promise<void>;
onMarkPaid: (expenseId: string) => Promise<void>;
onDocument: (expenseId: string, proofUrl?: string) => Promise<void>;
onUploadProof: (expenseId: string, file: File) => Promise<string>;
onSaveWorkingGroup: (groupId: string, name: string) => Promise<void>;
onDeleteWorkingGroup: (groupId: string, groupName: string) => Promise<void>;
onSaveBudget: (budgetId: string, name: string, totalBudget: string, colorCode: string) => Promise<void>;
@@ -140,6 +142,7 @@ export function BudgetColumn({
onApprove,
onMarkPaid,
onDocument,
onUploadProof,
onSaveWorkingGroup,
onDeleteWorkingGroup,
onSaveBudget,
@@ -153,6 +156,7 @@ export function BudgetColumn({
const [isEditingGroup, setIsEditingGroup] = useState(false);
const [groupDraftName, setGroupDraftName] = useState(group.name);
const [proofUrlDrafts, setProofUrlDrafts] = useState<Record<string, string>>({});
const [proofFileDrafts, setProofFileDrafts] = useState<Record<string, File | null>>({});
const [expandedRecurringExpenses, setExpandedRecurringExpenses] = useState<Record<string, boolean>>({});
const budgetCardWidth = 352;
@@ -771,7 +775,17 @@ export function BudgetColumn({
size="small"
variant="contained"
disabled={busy}
onClick={() => onApprove(expense.id, approvalType)}
onClick={() => {
if (
!window.confirm(
`Freigabe wirklich setzen?\n\nAusgabe: ${expense.title}\nBetrag: ${formatCurrency(expense.amount)}\nRolle: ${approvalLabel(approvalType)}\n\nMit deiner Freigabe bestaetigst du, dass du die Ausgabe plausibel geprueft hast und die Verantwortung fuer diesen Freigabeschritt uebernimmst.`
)
) {
return;
}
onApprove(expense.id, approvalType);
}}
>
Freigeben als {approvalLabel(approvalType)}
</Button>
@@ -818,25 +832,54 @@ export function BudgetColumn({
{expense.paidAt && !expense.documentedAt && canDocumentExpense(viewer.role) ? (
<Stack direction={{ xs: "column", sm: "row" }} gap={1}>
<TextField
label="Beleg-URL"
value={proofUrlDrafts[expense.id] ?? expense.proofUrl ?? ""}
onChange={(event) =>
setProofUrlDrafts((current) => ({
...current,
[expense.id]: event.target.value
}))
}
label="Beleg"
value={proofFileDrafts[expense.id]?.name ?? expense.proofUrl ?? ""}
InputProps={{ readOnly: true }}
size="small"
fullWidth
/>
<Button component="label" size="small" variant="outlined" startIcon={<UploadFileRoundedIcon />} disabled={busy}>
Datei
<input
hidden
type="file"
accept="image/*,application/pdf"
onChange={(event) =>
setProofFileDrafts((current) => ({
...current,
[expense.id]: event.target.files?.[0] ?? null
}))
}
/>
</Button>
<Button component="label" size="small" variant="outlined" disabled={busy}>
Kamera
<input
hidden
type="file"
accept="image/*"
capture="environment"
onChange={(event) =>
setProofFileDrafts((current) => ({
...current,
[expense.id]: event.target.files?.[0] ?? null
}))
}
/>
</Button>
<Button
size="small"
variant="contained"
color="success"
disabled={busy}
onClick={() =>
onDocument(expense.id, proofUrlDrafts[expense.id] ?? expense.proofUrl ?? undefined)
}
onClick={async () => {
const proofFile = proofFileDrafts[expense.id];
const proofUrl = proofFile
? await onUploadProof(expense.id, proofFile)
: proofUrlDrafts[expense.id] ?? expense.proofUrl ?? undefined;
await onDocument(expense.id, proofUrl);
}}
>
Dokumentieren
</Button>