feat: verschlüsselte Integrationseinstellungen, Haushaltsmitglieder mit Ersteller, Backup-Download
This commit is contained in:
1 parent
a1195223e0
commit
267f4fcf70
21 files changed
+724
-30
No files matched your search
@@ -31,6 +31,8 @@ export default function NewVoucherPage() {
|
||||
const [serverError, setServerError] = useState("");
|
||||
const [contacts, setContacts] = useState<{ id: number; name: string }[]>([]);
|
||||
const [contactIds, setContactIds] = useState<number[]>([]);
|
||||
const [members, setMembers] = useState<{ id: number; name: string }[]>([]);
|
||||
const [memberId, setMemberId] = useState("");
|
||||
const [reminderDays, setReminderDays] = useState<number[]>([...DEFAULT_REMINDER_DAYS]);
|
||||
const [candidates, setCandidates] = useState<LogoCandidate[]>([]);
|
||||
const [logoSearching, setLogoSearching] = useState(false);
|
||||
@@ -43,6 +45,10 @@ export default function NewVoucherPage() {
|
||||
.then((r) => (r.ok ? r.json() : []))
|
||||
.then(setContacts)
|
||||
.catch(() => {});
|
||||
fetch("/api/members")
|
||||
.then((r) => (r.ok ? r.json() : []))
|
||||
.then(setMembers)
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
function set(name: string, value: string) {
|
||||
@@ -101,7 +107,7 @@ export default function NewVoucherPage() {
|
||||
const res = await fetch("/api/vouchers", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ ...input, contactIds, reminderDays, providerDomain: selectedLogo?.domain ?? null }),
|
||||
body: JSON.stringify({ ...input, contactIds, reminderDays, providerDomain: selectedLogo?.domain ?? null, memberId: memberId === "" ? null : Number(memberId) }),
|
||||
});
|
||||
if (!res.ok) {
|
||||
const data = await res.json().catch(() => ({}));
|
||||
@@ -121,6 +127,30 @@ export default function NewVoucherPage() {
|
||||
<h1 className="mt-2 text-2xl font-semibold tracking-tight">Gutschein anlegen</h1>
|
||||
<p className="mt-1 text-sm text-muted">Alle Angaben lassen sich später noch ändern.</p>
|
||||
<form onSubmit={onSubmit} className="mt-5 rounded-card border border-line bg-white p-5 sm:p-6" noValidate>
|
||||
<div className="mb-4">
|
||||
<label htmlFor="memberId" className="block text-[13px] font-semibold">
|
||||
Angelegt von
|
||||
</label>
|
||||
{members.length === 0 ? (
|
||||
<p className="mt-1.5 text-[13px] text-muted">
|
||||
Noch keine Haushaltsmitglieder. Lege sie unter <Link href="/settings" className="font-semibold text-brand-700 underline">Einstellungen</Link> an.
|
||||
</p>
|
||||
) : (
|
||||
<select
|
||||
id="memberId"
|
||||
value={memberId}
|
||||
onChange={(e) => setMemberId(e.target.value)}
|
||||
className={`${inputClass} appearance-none`}
|
||||
>
|
||||
<option value="">Nicht erfasst</option>
|
||||
{members.map((m) => (
|
||||
<option key={m.id} value={m.id}>
|
||||
{m.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
</div>
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
{FIELDS.map((f) => (
|
||||
<div key={f.name} className={f.name === "notiz" ? "sm:col-span-2" : undefined}>
|
||||
|
||||
Reference in new issue
Block a user