// screens-desktop.jsx — adapter and missing desktop-only screens for the new desktop bundle
function desktopListings(ctx = {}) {
return Array.isArray(ctx.listings) ? ctx.listings : (window.LISTINGS || []);
}
function desktopSearches(ctx = {}) {
return Array.isArray(ctx.searches) ? ctx.searches : (window.SEARCHES || []);
}
function desktopNotifications(ctx = {}) {
return Array.isArray(ctx.notifications) ? ctx.notifications : (window.NOTIFICATIONS || []);
}
function desktopJobs(ctx = {}) {
return ctx.admin?.jobs || window.JOBS || [];
}
function desktopEvaluationMap(ctx = {}) {
return ctx.evaluations || window.AI_EVALS || {};
}
function desktopEvaluationFor(ctx = {}, id) {
const map = desktopEvaluationMap(ctx);
return map[String(id)] || map[id] || null;
}
function desktopInvestmentItems(ctx = {}) {
return ctx.investor?.evaluations || window.INVESTOR?.evaluations || [];
}
function desktopListingId(listing = {}) {
return listing.id ?? listing.adId ?? listing.ad_id ?? null;
}
function desktopFindListing(ctx = {}, id = null) {
if (id == null) return null;
const key = String(id);
const direct = desktopListings(ctx).find(item => (
String(desktopListingId(item)) === key ||
String(item.adId || '') === key ||
String(item.evaluationId || '') === key
));
if (direct) return direct;
const investment = desktopInvestmentItems(ctx).find(item => (
String(item.adId || '') === key ||
String(item.id || '') === key ||
String(desktopListingId(item.listing || {})) === key
));
return investment?.listing || null;
}
function desktopEvaluationForListing(ctx = {}, listing = {}) {
const id = desktopListingId(listing);
const direct = desktopEvaluationFor(ctx, id);
if (direct) return direct;
const investment = desktopInvestmentItems(ctx).find(item => (
String(item.adId || '') === String(id) ||
String(desktopListingId(item.listing || {})) === String(id)
));
return investment?.evaluation || null;
}
function desktopPhotos(listing = {}) {
const fallback = [
'data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201200%20800%22%3E%3Crect%20width%3D%221200%22%20height%3D%22800%22%20fill%3D%22%23E8E0D2%22%2F%3E%3Cpath%20d%3D%22M447%20497l89-112%2069%2082%2050-61%2098%20121H447z%22%20fill%3D%22%23B9A98F%22%2F%3E%3Ccircle%20cx%3D%22729%22%20cy%3D%22318%22%20r%3D%2242%22%20fill%3D%22%23CDBFAD%22%2F%3E%3Ctext%20x%3D%22600%22%20y%3D%22612%22%20text-anchor%3D%22middle%22%20font-family%3D%22Arial%2C%20sans-serif%22%20font-size%3D%2238%22%20fill%3D%22%237A6A56%22%3EBild%20nicht%20verfügbar%3C%2Ftext%3E%3C%2Fsvg%3E',
];
const photos = Array.isArray(listing.photos) && listing.photos.length ? listing.photos : fallback;
return [0, 1, 2, 3].map(i => photos[i] || photos[0] || fallback[i]);
}
function desktopSearchPlatforms(search = {}) {
return search.platforms || search.providers || ['kleinanzeigen'];
}
function desktopSearchKeywords(search = {}) {
return search.keywords || search.requireKeywords || [];
}
function desktopSearchExcludeKeywords(search = {}) {
return search.excludeKeywords || [];
}
function desktopMatchesQuery(item = {}, query = '') {
const q = String(query || '').trim().toLowerCase();
if (!q) return true;
const text = [
item.id,
item.adId,
item.taskId,
item.searchId,
item.name,
item.title,
item.city,
item.district,
item.address,
item.plz,
item.platform,
item.sourceUrl,
item.description,
item.body,
item.file,
...(Array.isArray(item.features) ? item.features : []),
...(Array.isArray(item.keywords) ? item.keywords : []),
...(Array.isArray(item.platforms) ? item.platforms : []),
].filter(Boolean).join(' ').toLowerCase();
return text.includes(q);
}
function desktopFilterByQuery(items = [], query = '') {
return String(query || '').trim() ? items.filter(item => desktopMatchesQuery(item, query)) : items;
}
function desktopFeatureText(listing = {}) {
return [
listing.title,
listing.description,
...(Array.isArray(listing.features) ? listing.features : []),
].filter(Boolean).join(' ').toLowerCase();
}
function desktopFirstName(user = {}) {
return (user.name || 'ImmoBot').split(/\s+/)[0] || 'ImmoBot';
}
function desktopUsedQuota(taskLimit = {}) {
const max = taskLimit?.max_evaluations_per_day || 100;
const remaining = taskLimit?.remaining_evaluations == null ? max : taskLimit.remaining_evaluations;
return Math.max(0, max - remaining);
}
function fmtMetricPrice(value) {
const n = Number(value || 0);
if (!n) return '—';
if (Math.abs(n) >= 1000000) return `${(n / 1000000).toLocaleString('de-DE', { maximumFractionDigits: 1 })} Mio. €`;
return fmtPriceShort(n);
}
function fmtPct(value) {
if (value == null || value === '') return '—';
return `${Number(value).toLocaleString('de-DE', { maximumFractionDigits: 2 })}%`;
}
function desktopSyncGlobals(ctx = {}) {
window.LISTINGS = desktopListings(ctx);
window.SEARCHES = desktopSearches(ctx);
window.NOTIFICATIONS = desktopNotifications(ctx);
window.JOBS = desktopJobs(ctx);
window.AI_EVALS = desktopEvaluationMap(ctx);
}
function desktopActiveFor(route) {
if (['mietenDashboard', 'mietenResults', 'searchBuilderMiete'].includes(route)) return 'miete';
if (['investor', 'compare'].includes(route)) return 'investor';
if (route === 'portfolio') return 'merk';
if (route === 'notifications') return 'mitt';
if (['swipe', 'discover'].includes(route)) return 'entd';
if (route === 'admin') return 'jobs';
if (route === 'exports') return 'export';
if (['profile', 'security'].includes(route)) return 'profile';
return 'kauf';
}
function DesktopRouteScreen({ ctx, current }) {
desktopSyncGlobals(ctx);
const [searchQuery, setSearchQuery] = React.useState('');
const active = desktopActiveFor(current.name);
const setRoute = (route, tab, params = null) => {
if (tab) ctx.setTab?.(tab);
ctx.reset(route, params);
};
const onNav = (id) => {
const map = {
kauf: ['dashboard', 'immobilien'],
miete: ['mietenDashboard', 'mieten'],
investor: ['investor', 'investor'],
merk: ['portfolio', 'portfolio'],
mitt: ['notifications', 'notifications'],
entd: ['discover', 'immobilien'],
jobs: ['admin', 'profile'],
export: ['exports', 'profile'],
profile: ['profile', 'profile'],
newSearch: ['searchBuilder', 'immobilien'],
};
const next = map[id] || map.kauf;
setRoute(next[0], next[1]);
};
const handleSearchSubmit = (value) => {
const q = String(value || searchQuery || '').trim();
if (!q) return;
const listing = desktopListings(ctx).find(item => desktopMatchesQuery(item, q));
if (listing) {
ctx.navigate('listing', { id: listing.id });
return;
}
const search = desktopSearches(ctx).find(item => desktopMatchesQuery(item, q));
if (search) {
const route = search.category === 'miete' ? 'mietenResults' : 'results';
ctx.navigate(route, { searchId: search.id });
}
};
const topBarProps = {
notifBadge: ctx.notifBadge || 0,
searchValue: searchQuery,
onSearchChange: setSearchQuery,
onSearchSubmit: handleSearchSubmit,
onNotifications: () => onNav('mitt'),
};
const common = {
active,
onNav,
ctx,
searchQuery,
setSearchQuery,
topBarProps,
onNewSearch: () => setRoute('searchBuilder', 'immobilien'),
onOpenAdmin: () => setRoute('admin', 'profile'),
onOpenResults: (searchId) => {
const searches = desktopSearches(ctx);
const search = searches.find(s => String(s.id) === String(searchId)) || searches.find(s => s.category === 'kauf') || searches[0];
const route = search?.category === 'miete' ? 'mietenResults' : 'results';
ctx.navigate(route, { searchId: search?.id || searchId });
},
onOpenDetail: (id) => ctx.navigate('listing', { id }),
onOpenAI: (id) => ctx.navigate('aiEval', { id: id || current.params?.id }),
onSetResultsView: (view, search) => {
const route = search?.category === 'miete' ? 'mietenResults' : 'results';
ctx.navigate(route, { searchId: search?.id || current.params?.searchId, view }, true);
},
onRefresh: (search) => ctx.refreshSearch?.(search.taskId || search.id),
onEvaluate: (search) => ctx.evaluateSearch?.(search.taskId || search.id),
onExport: (search) => ctx.exportSearch?.(search.taskId || search.id),
onReload: () => ctx.reloadAdmin?.(),
};
switch (current.name) {
case 'searchBuilder':
return ;
case 'searchBuilderMiete':
return ;
case 'results':
case 'mietenResults':
return ;
case 'listing':
return ;
case 'aiEval':
return ;
case 'mietenDashboard':
return ;
case 'swipe':
case 'discover':
return ;
case 'investor':
return ;
case 'compare':
return ;
case 'portfolio':
return ;
case 'notifications':
return ;
case 'profile':
return ;
case 'security':
return ;
case 'admin':
return ;
case 'exports':
return ;
default:
return ;
}
}
function DesktopEmpty({ active = 'kauf', onNav = () => {}, ctx = {}, title, subtitle, icon }) {
return (
{icon}
{title}
{subtitle && {subtitle}
}
);
}
function DesktopSearchBuilderScreen({ ctx, type = 'kauf', active = 'kauf', onNav = () => {}, topBarProps = {} }) {
const [form, setForm] = React.useState({
name: '',
city: 'Berlin',
radius: 10,
priceMin: type === 'kauf' ? 250000 : 800,
priceMax: type === 'kauf' ? 650000 : 1800,
roomsMin: 2,
roomsMax: 4,
areaMin: 50,
areaMax: 140,
keywords: '',
excludeKeywords: '',
});
const [message, setMessage] = React.useState(null);
const update = (key, value) => setForm(v => ({ ...v, [key]: value }));
const submit = async () => {
setMessage(null);
const created = await ctx.addSearch({
type,
property_type: 'wohnung',
city: form.city,
radius: Number(form.radius),
price_min: Number(form.priceMin),
price_max: Number(form.priceMax),
rooms_min: Number(form.roomsMin),
rooms_max: Number(form.roomsMax),
area_min: Number(form.areaMin),
area_max: Number(form.areaMax),
require_keywords: form.keywords.split(',').map(s => s.trim()).filter(Boolean),
exclude_keywords: form.excludeKeywords.split(',').map(s => s.trim()).filter(Boolean),
active: true,
run_now: true,
});
const route = type === 'miete' ? 'mietenResults' : 'results';
ctx.navigate(route, { searchId: created?.id }, true);
};
return (
} onClick={submit}>Suche starten}
{...topBarProps}
/>
update('name', v)} />
update('city', v)} />
update('radius', v)} />
update('roomsMin', v)} onRight={v => update('roomsMax', v)} />
update('priceMin', v)} onRight={v => update('priceMax', v)} />
update('areaMin', v)} onRight={v => update('areaMax', v)} />
update('keywords', v)} placeholder="balkon, altbau" />
update('excludeKeywords', v)} placeholder="wbs, tausch" />
{message && {message}
}
Abbrechen
} onClick={submit}>Speichern und suchen
);
}
function DField({ label, children }) {
return (
);
}
function DInput({ value, onChange, type = 'text', placeholder }) {
return (
onChange(e.target.value)}
style={{ width: '100%', border: '1px solid var(--border)', background: 'var(--surface)', borderRadius: 10, padding: '11px 12px', fontFamily: 'var(--font-sans)', fontSize: 13, color: 'var(--ink)' }}
/>
);
}
function DRange({ left, right, onLeft, onRight }) {
return (
);
}
function DesktopCollectionScreen({ active, onNav, ctx, kind, onOpenDetail, onNewSearch, searchQuery = '', topBarProps = {} }) {
const listings = desktopListings(ctx);
const favList = listings.filter(l => ctx.favs?.has(String(l.id)) || ctx.favs?.has(l.id));
const configs = {
rentals: {
crumb: ['Arbeitsbereich', 'Mieten'],
title: 'Miet-Suchen',
subtitle: 'Aktive Mietprofile und neue Treffer',
listings: listings.filter(l => l.type === 'miete'),
action: } onClick={() => ctx.reset('searchBuilderMiete')}>Neue Mietsuche,
},
portfolio: {
crumb: ['Arbeitsbereich', 'Merkliste'],
title: 'Merkliste',
subtitle: 'Gespeicherte Objekte mit aktualisierten Bewertungen',
listings: favList,
action: } onClick={ctx.exportPortfolio}>Portfolio CSV,
},
discover: {
crumb: ['Arbeitsbereich', 'Entdecken'],
title: 'Entdecken',
subtitle: 'Neue Vorschläge aus Ihren Suchmustern',
listings: listings.filter(l => l.aiScore).sort((a, b) => (b.aiScore || 0) - (a.aiScore || 0)).slice(0, 12),
action: } onClick={onNewSearch}>Neue Suche,
},
};
const cfg = configs[kind];
const [showTopOnly, setShowTopOnly] = React.useState(false);
const shownListings = desktopFilterByQuery(cfg.listings, searchQuery)
.filter(l => !showTopOnly || Number(l.aiScore || 0) >= 80);
return (
{kind !== 'portfolio' && } onClick={() => setShowTopOnly(v => !v)}>Top-Score}{cfg.action}>}
{...topBarProps}
/>
{shownListings.length ? (
{shownListings.map(l => )}
) : (
Noch keine Einträge
Sobald passende Inserate vorhanden sind, erscheinen sie hier.
)}
);
}
function DesktopNotificationsScreen({ active, onNav, ctx, searchQuery = '', topBarProps = {} }) {
React.useEffect(() => { ctx.loadNotificationSettings?.().catch(() => {}); }, []);
const notifications = desktopFilterByQuery(desktopNotifications(ctx), searchQuery);
const allNotifications = desktopNotifications(ctx);
const markAll = () => ctx.setNotifications?.(allNotifications.map(n => ({ ...n, read: true })));
const click = (n) => {
if (n.listingId) ctx.navigate('listing', { id: n.listingId });
else if (n.searchId) ctx.navigate('results', { searchId: n.searchId });
};
return (
} onClick={markAll}>Alle gelesen} {...topBarProps} />
{notifications.map((n, i) => (
))}
Browser-Push
{ctx.notificationSettings?.hasSubscriptions ? `${ctx.notificationSettings.subscriptions.length} Gerät(e) verbunden.` : 'Noch kein Gerät verbunden.'}
{(ctx.notificationSettings?.subscriptions || []).map(device => (
{device.label}
{device.endpointPreview}
ctx.revokePushSubscription?.(device.endpoint)}>Entfernen
))}
Test senden
Alle entfernen
);
}
function DesktopExportsScreen({ active, onNav, ctx, searchQuery = '', topBarProps = {} }) {
const rows = desktopFilterByQuery(desktopSearches(ctx).map(s => ({
id: s.taskId || s.id,
file: `${s.name || 'suche'}-${s.id}.csv`,
type: 'CSV',
created: s.lastRun ? fmtDateTime(s.lastRun) : 'Noch nicht gelaufen',
size: `${s.matches || 0} Zeilen`,
name: s.name,
city: s.city,
})), searchQuery).slice(0, 6);
return (
} onClick={ctx.exportPortfolio}>Portfolio exportieren} {...topBarProps} />
DateiTypErstelltUmfang
{rows.map((row, i) => (
{row.file}
{row.type}
{row.created}
{row.size}
} onClick={() => ctx.exportSearch?.(row.id)} />
))}
);
}
function investorListingKey(item = {}) {
return String(item.adId || desktopListingId(item.listing) || item.id || '');
}
function investorTopMetric(metrics = {}) {
const entries = [
['gross_yield', metrics?.gross_yield],
['net_yield', metrics?.net_yield],
['cap_rate', metrics?.cap_rate],
['cash_on_cash', metrics?.cash_on_cash],
].filter(([, value]) => value != null && !Number.isNaN(Number(value)));
if (!entries.length) return null;
entries.sort((a, b) => Number(b[1]) - Number(a[1]));
return entries[0];
}
function InvestorScreen({ ctx, active = 'investor', onNav = () => {}, searchQuery = '', topBarProps = {} }) {
const [loaded, setLoaded] = React.useState(false);
React.useEffect(() => {
if (!loaded) {
setLoaded(true);
ctx.loadInvestor?.().catch(() => {});
}
}, [loaded]);
const data = ctx.investor || {};
const items = (data.evaluations || []).filter(item => (
desktopMatchesQuery(item, searchQuery) || desktopMatchesQuery(item.listing || {}, searchQuery)
));
const summary = data.summary || {};
const locations = data.locations || [];
const distribution = data.distribution || {};
const topDeals = items.slice(0, 12);
const heroDeal = topDeals[0] || null;
const goListing = (item) => ctx.navigate('listing', { id: investorListingKey(item) });
const avgNet = summary.averageNetYield ?? null;
const avgGross = summary.averageGrossYield ?? null;
const annualIncome = summary.estimatedAnnualIncome ?? data.portfolio?.summary?.estimatedAnnualIncome ?? null;
const bestCashflow = items.reduce((best, item) => {
const value = Number(item.metrics?.monthly_cash_flow?.net_cash_flow ?? -Infinity);
return value > (best.value ?? -Infinity) ? { item, value } : best;
}, {});
const bestYield = items.reduce((best, item) => {
const metric = investorTopMetric(item.metrics || {});
const value = metric ? Number(metric[1]) : -Infinity;
return value > (best.value ?? -Infinity) ? { item, value, key: metric?.[0] } : best;
}, {});
if (!ctx.isDesktop) {
return (
Investment Cockpit
Investor
Deal-Pipeline
{summary.count || items.length || 0} Objekte
Top-Score {summary.topScore || '—'} · Ø Score {summary.averageScore || '—'} · Volumen {fmtMetricPrice(summary.totalValue)}
-Infinity ? fmtMetricPrice(bestCashflow.value) : '—'} label="Top Cashflow/Mon." delta={bestCashflow.item?.listing?.city || '—'} />
Top-Deals
Nach Score, Rendite und Risiko priorisiert
{topDeals.map((item, i) => goListing(item)} />)}
{!topDeals.length && } title="Noch keine Investmentdaten" subtitle="Sobald Kaufobjekte bewertet sind, erscheinen hier Rendite, Risiko und Cashflow." />}
);
}
return (
} onClick={ctx.exportPortfolio}>CSV} onClick={() => ctx.navigate('compare', { ids: (data.compare?.ids || topDeals.slice(0, 4).map(x => x.id)).slice(0, 4) })}>Top 4 vergleichen>} {...topBarProps} />
Investment Radar
Die besten Objekte zuerst.
Kombiniert KI-Score, Renditeannahmen, Cashflow, CapEx, Leerstandsrisiko und Standortsignale zu einer schnellen Investment-Priorisierung.
{heroDeal &&
}
Portfolio-Qualität
Priorisierte Deal-Liste
Score · Yield · Cashflow · Risiko · CapEx
{items.length} Bewertungen
RangObjektPreisNettoCashflowRisikoScore
{topDeals.map((item, i) => goListing(item)} last={i === topDeals.length - 1} />)}
{!topDeals.length && Noch keine Investment-Bewertungen vorhanden.
}
Investment-These
{heroDeal?.evaluation?.investment_thesis || heroDeal?.evaluation?.summary || 'Noch keine Investment-These vorhanden.'}
{heroDeal?.evaluation?.next_steps?.length > 0 && {heroDeal.evaluation.next_steps.slice(0, 4).map((step, idx) =>
{idx + 1}{step}
)}
}
Top-Lagen
{locations.slice(0, 6).map(loc =>
)}
{!locations.length &&
Noch keine Standortdaten.
}
Due-Diligence Fokus
);
}
function InvestorHeroMetric({ label, value, accent = false }) {
return ;
}
function InvestorMini({ label, value, dark = false }) {
return ;
}
function TinyBars({ title, data = {} }) {
const max = Math.max(1, ...Object.values(data || { x: 1 }));
return {title}
{Object.entries(data).map(([label, count]) =>
)}
;
}
function LocationBar({ loc }) {
return {loc.city}{loc.count} · {loc.share}%
;
}
function InvestorChecklist({ items = [] }) {
const risks = items.flatMap(item => (item.evaluation?.risks || item.evaluation?.key_risks || []).slice(0, 2)).slice(0, 5);
const list = risks.length ? risks : ['Mietannahmen prüfen', 'Hausgeld/Nebenkosten verifizieren', 'Energieausweis und Sanierungsbedarf prüfen'];
return {list.map((text, i) =>
{i + 1}{text}
)}
;
}
function InvestorMobileCard({ item, rank, onOpen }) {
const l = item.listing || {};
const e = item.evaluation || {};
const m = item.metrics || {};
const cash = m.monthly_cash_flow?.net_cash_flow;
const risks = (e.risks || e.key_risks || []).slice(0, 2);
return ;
}
function InvestorRow({ item, rank, onOpen, last }) {
const l = item.listing || {};
const e = item.evaluation || {};
const m = item.metrics || {};
const cash = m.monthly_cash_flow?.net_cash_flow;
const risk = (e.risks || e.key_risks || [])[0] || (m.vacancy_risk_pct ? `Leerstand ${fmtPct(m.vacancy_risk_pct)}` : 'Keine Hauptrisiken');
return (
);
}
function InvestorCompareScreen({ ctx, active = 'investor', onNav = () => {}, ids = [], topBarProps = {} }) {
const [payload, setPayload] = React.useState(null);
React.useEffect(() => {
ctx.loadInvestorCompare?.(ids).then(setPayload).catch(() => {});
}, [ids.join(',')]);
const items = payload?.items || ctx.investor?.compare?.items || [];
const content = (
ObjektPreisScoreBruttoCap Rate
{items.map((item, i) => )}
);
if (!ctx.isDesktop) return {content}
;
return (
);
}
function DesktopProfileScreen({ ctx, active = 'profile', onNav = () => {}, topBarProps = {} }) {
const user = ctx.user || {};
const inquiryRef = React.useRef(null);
const [form, setForm] = React.useState(() => ({
name: user.name || '',
email: user.email || '',
telegram_chat_id: user.telegram_chat_id || '',
ebay_userid: user.ebay_userid || '',
ebay_contactname: user.ebay_contactname || '',
ebay_email: user.ebay_email || '',
ebay_password: '',
default_reply_message: user.default_reply_message || '',
rental_profile: { ...RENTAL_PROFILE_DEFAULTS, ...(user.rental_profile || {}) },
}));
const [message, setMessage] = React.useState(null);
const update = (key, value) => setForm(v => ({ ...v, [key]: value }));
const updateRentalProfile = (key, value) => setForm(v => ({
...v,
rental_profile: { ...RENTAL_PROFILE_DEFAULTS, ...(v.rental_profile || {}), [key]: value },
}));
const save = async () => {
setMessage(null);
await ctx.updateProfile?.(form);
setMessage('Gespeichert');
update('ebay_password', '');
};
React.useEffect(() => {
const shouldScroll = sessionStorage.getItem('immobotScrollInquiryProfile') === '1' || window.location.hash.includes('inquiry=1');
if (!shouldScroll) return;
sessionStorage.removeItem('immobotScrollInquiryProfile');
setTimeout(() => inquiryRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' }), 120);
}, []);
return (
} onClick={() => ctx.navigate('security')}>Sicherheit} onClick={ctx.signOut}>Abmelden>} {...topBarProps} />
{user.initials || 'I'}
{user.name || 'ImmoBot Nutzer'}
{user.email}
Kontingent
Basisdaten
update('name', v)} />
update('email', v)} type="email" />
update('telegram_chat_id', v)} />
update('ebay_contactname', v)} />
update('ebay_userid', v)} />
update('ebay_email', v)} type="email" />
update('default_reply_message', v)} />
Anfrageprofil
{message && {message}
}
Profil speichern
);
}
function AccountSecurityScreen({ ctx, active = 'profile', onNav = () => {}, topBarProps = {} }) {
const [form, setForm] = React.useState({ current_password: '', password: '', password_confirmation: '' });
const [deletePassword, setDeletePassword] = React.useState('');
const [message, setMessage] = React.useState(null);
const update = (key, value) => setForm(v => ({ ...v, [key]: value }));
const save = async () => {
setMessage(null);
await ctx.updatePassword?.(form);
setMessage('Passwort aktualisiert.');
setForm({ current_password: '', password: '', password_confirmation: '' });
};
const remove = async () => {
if (confirm('Konto wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.')) {
await ctx.deleteProfile?.(deletePassword);
}
};
if (!ctx.isDesktop) {
return (
update('current_password', v)} type="password" />
update('password', v)} type="password" />
update('password_confirmation', v)} type="password" />
);
}
return (
Passwort ändern
update('current_password', v)} />
update('password', v)} />
update('password_confirmation', v)} />
{message &&
{message}
}
Passwort speichern
Konto löschen
Löscht das Konto, Suchen und gespeicherte Einstellungen dauerhaft.
} onClick={remove}>Konto löschen
);
}
Object.assign(window, {
DesktopRouteScreen,
InvestorScreen,
InvestorCompareScreen,
AccountSecurityScreen,
fmtMetricPrice,
fmtPct,
});