// Einstellungen — multi-section settings sheet for the RentFlow mobile app. // Sections: Stammdaten, Bank & Steuer, Logistik, Dokumente, Erinnerungen, Darstellung. const { useState: useStateEinst, useEffect: useEffectEinst, useRef: useRefEinst } = React; // ───────────────────────────────────────────────────────────── // Section icons (stroke paths for the Icon component) // ───────────────────────────────────────────────────────────── const EINST_ICONS = { building: 'M3 21h18 M5 21V8l7-5 7 5v13 M9 21v-6h6v6 M9 9.5h.01 M15 9.5h.01 M9 12.5h.01 M15 12.5h.01', euro: 'M18 7a6 6 0 00-9 0M18 17a6 6 0 01-9 0M5 10h10M5 14h10', truck: 'M3 16h2m14 0h2M5 16a2 2 0 104 0M15 16a2 2 0 104 0M3 16V8a1 1 0 011-1h11v9M15 9h3.6a1 1 0 01.83.45L21 12v4', doc: 'M6 2h8l6 6v12a2 2 0 01-2 2H6a2 2 0 01-2-2V4a2 2 0 012-2zM14 2v6h6M9 14h6M9 18h4', bell: 'M12 2a6 6 0 016 6v4l2 3H4l2-3V8a6 6 0 016-6zM10 19a2 2 0 004 0', moon: 'M21 12.8A9 9 0 1111.2 3a7 7 0 009.8 9.8z', sun: 'M12 5V3M12 21v-2M5 12H3M21 12h-2M5.6 5.6L4.2 4.2M19.8 19.8l-1.4-1.4M5.6 18.4L4.2 19.8M19.8 4.2l-1.4 1.4M12 8a4 4 0 100 8 4 4 0 000-8z', camera: 'M4 8a2 2 0 012-2h2l2-2h4l2 2h2a2 2 0 012 2v10a2 2 0 01-2 2H6a2 2 0 01-2-2V8zM12 17a4 4 0 100-8 4 4 0 000 8z', backup: 'M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4 M7 10l5 5 5-5 M12 15V3', }; // ───────────────────────────────────────────────────────────── // Main sheet — wraps Sheet primitive and routes between list / sub-views // ───────────────────────────────────────────────────────────── function FirmenprofilSheet({ open, onClose, company, setCompany, toast, logistik, setLogistik, dark, toggleDark }) { const t = useTheme(); const [sub, setSub] = useStateEinst(null); useEffectEinst(() => { if (!open) { const id = setTimeout(() => setSub(null), 320); return () => clearTimeout(id); } }, [open]); const c = { ...DEFAULT_COMPANY, ...(company || {}) }; const set = (patch) => setCompany(prev => { const next = { ...DEFAULT_COMPANY, ...prev, ...patch }; // keep legacy `address` in sync if street/cityPostal changed if ('street' in patch || 'cityPostal' in patch) { next.address = [next.street, next.cityPostal].filter(Boolean).join('\n'); } return next; }); const l = { ...(window.DEFAULT_LOGISTIK || {}), ...(logistik || {}) }; const setL = (patch) => setLogistik && setLogistik(prev => ({ ...prev, ...patch })); let body; if (sub === 'stamm') body = setSub(null)} onClose={onClose} toast={toast}/>; else if (sub === 'bank') body = setSub(null)} onClose={onClose}/>; else if (sub === 'log') body = setSub(null)} onClose={onClose}/>; else if (sub === 'dok') body = setSub(null)} onClose={onClose}/>; else if (sub === 'rem') body = setSub(null)} onClose={onClose}/>; else if (sub === 'bkp') body = setSub(null)} onClose={onClose} toast={toast}/>; else if (sub === 'darst') body = setSub(null)} onClose={onClose}/>; else body = ; return (
{body}
); } // ───────────────────────────────────────────────────────────── // Top-level list view // ───────────────────────────────────────────────────────────── function SettingsList({ t, c, onPick, onClose }) { const sections = [ { id: 'stamm', icon: EINST_ICONS.building, color: '#007AFF', title: 'Stammdaten', sub: 'Firma & Kontakt' }, { id: 'bank', icon: EINST_ICONS.euro, color: '#34C759', title: 'Bank & Steuer', sub: 'IBAN, USt, MwSt.' }, { id: 'log', icon: EINST_ICONS.truck, color: '#FF9500', title: 'Logistik', sub: 'Lager & km-Sätze' }, { id: 'dok', icon: EINST_ICONS.doc, color: '#AF52DE', title: 'Dokumente', sub: 'Nummern & Fristen' }, { id: 'rem', icon: EINST_ICONS.bell, color: '#FF3B30', title: 'Erinnerungen', sub: 'Push & Vorlauf' }, { id: 'bkp', icon: EINST_ICONS.backup, color: '#00A39C', title: 'Datensicherung', sub: 'Export & Import' }, { id: 'darst', icon: EINST_ICONS.moon, color: '#5856D6', title: 'Darstellung', sub: 'Hell · Dunkel' }, ]; return (
{/* Header with title + Fertig */}
Einstellungen
Firma, Logistik & App-Verhalten
Fertig
{/* Firmen-Header-Karte */}
{c.logo ? : }
{c.name}
{c.owner || c.tagline || '—'}
{/* Section rows */}
{sections.map((s, i) => ( onPick(s.id)} scale={0.995}>
{s.title}
{s.sub}
))}
{/* About strip */}
RentFlow Manager · Mobile-Edition für iOS.
Verwaltung von Vermietungen, Equipment, Terminen und Finanzen — synchron zur Desktop-App.
Version 1.1.0 (build 12)
); } // ───────────────────────────────────────────────────────────── // Stammdaten — logo, contact, register & tax IDs // ───────────────────────────────────────────────────────────── function StammdatenView({ t, c, set, onBack, onClose, toast }) { const fileRef = useRefEinst(null); const onLogo = (e) => { const f = e.target.files && e.target.files[0]; if (!f) return; fileToScaledDataURL(f, 480, (url) => { if (url) { set({ logo: url }); toast && toast('Logo hochgeladen'); } else toast && toast('Bild konnte nicht geladen werden'); }); }; return (
{/* Logo card */} Logo & Identität
{c.logo ? : }
fileRef.current && fileRef.current.click()} scale={0.97}>
{c.logo ? 'Logo ersetzen' : 'Logo hochladen'}
{c.logo && ( set({ logo: '' })} scale={0.97}>
Entfernen
)}
set({ name: v })} t={t}/> set({ owner: v })} t={t}/> set({ tagline: v })} placeholder="z.B. Vermietung Tontechnik" t={t} last/>
{/* Adresse */} Anschrift set({ street: v })} placeholder="Musterstraße 12" t={t}/> set({ cityPostal: v })} placeholder="80331 München" t={t} last/> {/* Kontakt */} Kontakt set({ email: v })} type="email" t={t}/> set({ phone: v })} type="tel" t={t}/> set({ web: v })} placeholder="www.…" t={t} last/> {/* Steuer-IDs */} Register & Steuer-IDs set({ taxId: v })} placeholder="143/256/12345" hint="Vom Finanzamt vergeben." t={t}/> set({ vatId: v })} placeholder="DE123456789" hint="Für innergem. Lieferungen." t={t}/> set({ hrb: v })} placeholder="HRB 123456" hint="Nur bei eingetragener Firma." t={t}/> set({ amtsgericht: v })} placeholder="München" t={t} last/>
); } // ───────────────────────────────────────────────────────────── // Bank & Steuer // ───────────────────────────────────────────────────────────── function BankSteuerView({ t, c, set, onBack, onClose }) { return (
Bankverbindung set({ iban: v })} placeholder="DE12 3456 7890 …" t={t}/> set({ bic: v })} placeholder="BYLADEM1MUC" t={t}/> set({ bank: v })} placeholder="z.B. Sparkasse" t={t} last/> Umsatzsteuer set({ kleinunternehmer: v })} t={t}/>} /> set({ defaultVat: v })} options={[ { value: 19, label: '19 %' }, { value: 7, label: '7 %' }, { value: 0, label: '0 %' }, ]}/> } />
); } // ───────────────────────────────────────────────────────────── // Logistik settings — uses the logistik state // ───────────────────────────────────────────────────────────── function LogistikSettingsView({ t, l, setL, onBack, onClose }) { const tripOpts = [ { value: 1, label: '1×' }, { value: 2, label: '2×' }, { value: 4, label: '4×' }, ]; const factor = (typeof l.tripFactor === 'number') ? l.tripFactor : 4; const rate = Number(l.kmRate) || 0; const pauschale = Number(l.pauschale) || 0; const exampleTotal = (10 * factor * rate + pauschale).toFixed(2).replace('.', ','); return (
Lager & Startadresse setL({ lagerAddress: v })} placeholder="Bahnhofstr. 18, 82110 Germering" hint="Ausgangspunkt für km-Berechnung." t={t} last/> Lieferpreise setL({ kmRate: v })} step={0.1} suffix="€/km" t={t}/> setL({ pauschale: v })} step={1} suffix="€" t={t}/> setL({ tripFactor: v, returnTrip: v !== 1 })} options={tripOpts}/>} /> {/* Live example */}
💡
Beispiel 10 km: {exampleTotal} €
{String(rate).replace('.', ',')} €/km × {factor} Fahrten + {pauschale} € Pauschale
); } // Hide the placeholder card with the dud control (above) — clean up // Actually we don't want a duplicate row. Remove the first noisy card by overriding here: // (kept structure simple by rendering second card only) function RateEditRow({ label, value, onChange, step = 1, suffix, t }) { const [tmp, setTmp] = useStateEinst(String(value ?? '').replace('.', ',')); useEffectEinst(() => { setTmp(String(value ?? '').replace('.', ',')); }, [value]); const commit = () => { const n = Number(String(tmp).replace(',', '.')); if (!isNaN(n)) onChange(n); else setTmp(String(value ?? '').replace('.', ',')); }; return ( setTmp(e.target.value)} onBlur={commit} onKeyDown={e => { if (e.key === 'Enter') e.target.blur(); }} inputMode="decimal" style={{ width: 68, padding: '6px 8px', borderRadius: 8, border: `0.5px solid ${t.inputBorder}`, background: t.inputBg, fontSize: 14, color: t.text, outline: 'none', fontFamily: 'inherit', textAlign: 'right', boxSizing: 'border-box', fontVariantNumeric: 'tabular-nums', }}/> {suffix}
} /> ); } Object.assign(window, { FirmenprofilSheet, EINST_ICONS, previewNumber: window.previewNumber, });