Boersenchecker UI2
All checks were successful
Deploy / deploy-staging (push) Successful in 5s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-04-23 00:03:06 +02:00
parent 327f40adec
commit ac3ac0803b
2 changed files with 60 additions and 45 deletions

View File

@@ -100,7 +100,7 @@
Alpha Vantage Mindestabstand: <?= e((string) $alphaMinIntervalMinutes) ?> Min. Alpha Vantage Mindestabstand: <?= e((string) $alphaMinIntervalMinutes) ?> Min.
</div> </div>
<div class="muted" style="margin-top:.35rem;"> <div class="muted" style="margin-top:.35rem;">
API-Key und Timeout werden ueber <a class="nav-link" href="/modules/setup/boersenchecker">Modul-Setup</a> gepflegt. API-Key und Timeout werden ueber <a class="bc-button bc-button--secondary" href="/modules/setup/boersenchecker">Modul-Setup</a> gepflegt.
</div> </div>
<div class="muted" style="margin-top:.75rem;"> <div class="muted" style="margin-top:.75rem;">
Standard-Berichtswahrung: <?= e($defaultReportCurrency) ?> · Max. Alter: <?= e((string) $fxMaxAgeHours) ?>h Standard-Berichtswahrung: <?= e($defaultReportCurrency) ?> · Max. Alter: <?= e((string) $fxMaxAgeHours) ?>h
@@ -288,7 +288,7 @@
<div style="margin-top:1rem;" class="grid"> <div style="margin-top:1rem;" class="grid">
<?php if ($portfolios === []): ?> <?php if ($portfolios === []): ?>
<div class="card"> <div class="bc-panel">
<div class="muted">Noch keine Depots vorhanden.</div> <div class="muted">Noch keine Depots vorhanden.</div>
</div> </div>
<?php else: ?> <?php else: ?>
@@ -297,19 +297,19 @@
$portfolioId = (int) $portfolio['id']; $portfolioId = (int) $portfolio['id'];
$stats = $portfolioStats[$portfolioId] ?? ['positions' => 0, 'invested' => 0.0, 'current' => 0.0, 'gain' => null, 'has_invested' => false, 'has_current' => false]; $stats = $portfolioStats[$portfolioId] ?? ['positions' => 0, 'invested' => 0.0, 'current' => 0.0, 'gain' => null, 'has_invested' => false, 'has_current' => false];
?> ?>
<div class="card" style="background:var(--panel-2);"> <div class="bc-panel">
<div style="display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap;"> <div style="display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap;">
<div> <div>
<strong><?= e((string) $portfolio['name']) ?></strong> <strong><?= e((string) $portfolio['name']) ?></strong>
<div class="muted"><?= e((string) $portfolio['base_currency']) ?> · <?= e((string) $stats['positions']) ?> Position(en)</div> <div class="muted"><?= e((string) $portfolio['base_currency']) ?> · <?= e((string) $stats['positions']) ?> Position(en)</div>
</div> </div>
<div style="display:flex; gap:10px; flex-wrap:wrap;"> <div style="display:flex; gap:10px; flex-wrap:wrap;">
<a class="nav-link" href="/module/boersenchecker/depotverwaltung?owner_sub=<?= urlencode((string) $ownerSub) ?>&edit_portfolio=<?= e((string) $portfolioId) ?>">Bearbeiten</a> <a class="bc-button bc-button--secondary" href="/module/boersenchecker/depotverwaltung?owner_sub=<?= urlencode((string) $ownerSub) ?>&edit_portfolio=<?= e((string) $portfolioId) ?>">Bearbeiten</a>
<form method="post" onsubmit="return confirm('Depot wirklich loeschen?')"> <form method="post" onsubmit="return confirm('Depot wirklich loeschen?')">
<input type="hidden" name="action" value="delete_portfolio"> <input type="hidden" name="action" value="delete_portfolio">
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>"> <input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
<input type="hidden" name="portfolio_id" value="<?= e((string) $portfolioId) ?>"> <input type="hidden" name="portfolio_id" value="<?= e((string) $portfolioId) ?>">
<button class="nav-link" type="submit">Loeschen</button> <button class="bc-button bc-button--secondary" type="submit">Loeschen</button>
</form> </form>
</div> </div>
</div> </div>
@@ -317,15 +317,15 @@
<div class="muted" style="margin-top:.65rem;"><?= e((string) $portfolio['notes']) ?></div> <div class="muted" style="margin-top:.65rem;"><?= e((string) $portfolio['notes']) ?></div>
<?php endif; ?> <?php endif; ?>
<div class="grid" style="margin-top:1rem; grid-template-columns:repeat(auto-fit, minmax(140px, 1fr)); gap:10px;"> <div class="grid" style="margin-top:1rem; grid-template-columns:repeat(auto-fit, minmax(140px, 1fr)); gap:10px;">
<div class="card"> <div class="bc-stat">
<div class="muted">Investiert</div> <div class="muted">Investiert</div>
<strong><?= $stats['has_invested'] ? e($fmtNumber((float) $stats['invested'])) . ' ' . e((string) $portfolio['base_currency']) : 'n/a' ?></strong> <strong><?= $stats['has_invested'] ? e($fmtNumber((float) $stats['invested'])) . ' ' . e((string) $portfolio['base_currency']) : 'n/a' ?></strong>
</div> </div>
<div class="card"> <div class="bc-stat">
<div class="muted">Aktuell</div> <div class="muted">Aktuell</div>
<strong><?= $stats['has_current'] ? e($fmtNumber((float) $stats['current'])) . ' ' . e((string) $portfolio['base_currency']) : 'n/a' ?></strong> <strong><?= $stats['has_current'] ? e($fmtNumber((float) $stats['current'])) . ' ' . e((string) $portfolio['base_currency']) : 'n/a' ?></strong>
</div> </div>
<div class="card"> <div class="bc-stat">
<div class="muted">Gewinn / Verlust</div> <div class="muted">Gewinn / Verlust</div>
<strong><?= $stats['gain'] !== null ? e($fmtNumber((float) $stats['gain'])) . ' ' . e((string) $portfolio['base_currency']) : 'n/a' ?></strong> <strong><?= $stats['gain'] !== null ? e($fmtNumber((float) $stats['gain'])) . ' ' . e((string) $portfolio['base_currency']) : 'n/a' ?></strong>
</div> </div>
@@ -335,13 +335,13 @@
<?php endif; ?> <?php endif; ?>
</div> </div>
<div class="card" style="margin-top:1rem;"> <div class="bc-panel" style="margin-top:1rem;">
<strong>Positionen</strong> <strong>Positionen</strong>
<?php if ($positions === []): ?> <?php if ($positions === []): ?>
<div class="muted" style="margin-top:.75rem;">Noch keine Positionen vorhanden.</div> <div class="muted" style="margin-top:.75rem;">Noch keine Positionen vorhanden.</div>
<?php else: ?> <?php else: ?>
<div style="overflow:auto; margin-top:.75rem;"> <div class="bc-table-shell" style="margin-top:.75rem;">
<table style="width:100%; border-collapse:collapse;"> <table class="bc-table">
<thead> <thead>
<tr style="text-align:left; border-bottom:1px solid var(--border);"> <tr style="text-align:left; border-bottom:1px solid var(--border);">
<th style="padding:8px;">Depot</th> <th style="padding:8px;">Depot</th>
@@ -398,19 +398,19 @@
</td> </td>
<td style="padding:8px;"> <td style="padding:8px;">
<div style="display:flex; gap:8px; flex-wrap:wrap;"> <div style="display:flex; gap:8px; flex-wrap:wrap;">
<a class="nav-link" href="/module/boersenchecker/depotverwaltung?owner_sub=<?= urlencode((string) $ownerSub) ?>&edit_position=<?= e((string) $position['id']) ?>">Bearbeiten</a> <a class="bc-button bc-button--secondary" href="/module/boersenchecker/depotverwaltung?owner_sub=<?= urlencode((string) $ownerSub) ?>&edit_position=<?= e((string) $position['id']) ?>">Bearbeiten</a>
<a class="nav-link" href="/module/boersenchecker/depotverwaltung?owner_sub=<?= urlencode((string) $ownerSub) ?>&instrument_id=<?= e((string) $position['instrument_id']) ?>">Kurs erfassen</a> <a class="bc-button bc-button--secondary" href="/module/boersenchecker/depotverwaltung?owner_sub=<?= urlencode((string) $ownerSub) ?>&instrument_id=<?= e((string) $position['instrument_id']) ?>">Kurs erfassen</a>
<form method="post"> <form method="post">
<input type="hidden" name="action" value="refresh_alpha_vantage_position"> <input type="hidden" name="action" value="refresh_alpha_vantage_position">
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>"> <input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
<input type="hidden" name="position_id" value="<?= e((string) $position['id']) ?>"> <input type="hidden" name="position_id" value="<?= e((string) $position['id']) ?>">
<button class="nav-link" type="submit">API-Kurs</button> <button class="bc-button bc-button--secondary" type="submit">API-Kurs</button>
</form> </form>
<form method="post" onsubmit="return confirm('Position wirklich loeschen?')"> <form method="post" onsubmit="return confirm('Position wirklich loeschen?')">
<input type="hidden" name="action" value="delete_position"> <input type="hidden" name="action" value="delete_position">
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>"> <input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
<input type="hidden" name="position_id" value="<?= e((string) $position['id']) ?>"> <input type="hidden" name="position_id" value="<?= e((string) $position['id']) ?>">
<button class="nav-link" type="submit">Loeschen</button> <button class="bc-button bc-button--secondary" type="submit">Loeschen</button>
</form> </form>
</div> </div>
</td> </td>

View File

@@ -1,21 +1,34 @@
<div class="card"> <div class="bc-app">
<div class="bc-module-nav"> <div class="bc-grid-bg">
<a class="bc-module-tab" href="/module/boersenchecker">Ueberblick</a> <div class="bc-shell bc-stack">
<a class="bc-module-tab" href="/module/boersenchecker/depotverwaltung">Depotverwaltung</a> <header class="bc-hero">
<a class="bc-module-tab is-active" href="/module/boersenchecker/aktienverwaltung">Aktienverwaltung</a> <div class="bc-hero-top">
<div class="bc-hero-copy">
<div class="bc-eyebrow">Boersenchecker Modul</div>
<h1 class="bc-title">Aktienverwaltung</h1>
<p class="bc-text">Stammdaten der Aktien pflegen, Symbole suchen und manuelle Kurse verwalten.</p>
</div> </div>
<div class="pill">Boersenchecker</div> <div class="bc-hero-controls">
<h1 style="margin-top:.75rem;">Aktienverwaltung</h1> <a class="bc-button bc-button--ghost" href="/">Zur Startseite</a>
<p class="muted">Aktien aus deinen Depots bearbeiten und manuelle Kurse pflegen.</p> <a class="bc-button bc-button--secondary" href="/modules/setup/boersenchecker">Setup</a>
</div>
</div>
<div class="bc-tabs">
<a class="bc-button bc-button--tab" href="/module/boersenchecker">Ueberblick</a>
<a class="bc-button bc-button--tab" href="/module/boersenchecker/depotverwaltung">Depotverwaltung</a>
<a class="bc-button bc-button--tab-active" href="/module/boersenchecker/aktienverwaltung">Aktienverwaltung</a>
</div>
</header>
<?php if ($error): ?> <?php if ($error): ?>
<div class="card" style="margin-top:1rem; border-color:#ffb4a8; background:#fff5f3; color:#7a2114;"><?= e($error) ?></div> <div class="bc-alert bc-alert--error"><?= e($error) ?></div>
<?php elseif ($notice): ?> <?php elseif ($notice): ?>
<div class="card" style="margin-top:1rem; border-color:var(--accent-2);"><?= e($notice) ?></div> <div class="bc-alert bc-alert--success"><?= e($notice) ?></div>
<?php endif; ?> <?php endif; ?>
<div class="grid" style="margin-top:1rem;"> <div class="grid" style="margin-top:1rem;">
<div class="card" style="background:var(--panel-2);"> <div class="bc-panel">
<strong>Aktie waehlen</strong> <strong>Aktie waehlen</strong>
<form method="get" style="margin-top:.75rem;"> <form method="get" style="margin-top:.75rem;">
<label class="setup-field muted"> <label class="setup-field muted">
@@ -31,7 +44,7 @@
</form> </form>
</div> </div>
<div class="card" style="background:var(--panel-2);"> <div class="bc-panel">
<strong>Symbolsuche</strong> <strong>Symbolsuche</strong>
<form method="post" style="margin-top:.75rem; display:flex; gap:10px; flex-wrap:wrap; align-items:end;"> <form method="post" style="margin-top:.75rem; display:flex; gap:10px; flex-wrap:wrap; align-items:end;">
<input type="hidden" name="action" value="search_symbol"> <input type="hidden" name="action" value="search_symbol">
@@ -40,11 +53,11 @@
<span>Suchbegriff</span> <span>Suchbegriff</span>
<input type="text" name="search_keywords" value="<?= e($searchKeywords) ?>" placeholder="z.B. Apple, AAPL, Allianz" required> <input type="text" name="search_keywords" value="<?= e($searchKeywords) ?>" placeholder="z.B. Apple, AAPL, Allianz" required>
</label> </label>
<button class="cta-button" type="submit">Suchen</button> <button class="bc-button bc-button--primary" type="submit">Suchen</button>
</form> </form>
<?php if ($searchResults !== []): ?> <?php if ($searchResults !== []): ?>
<div style="overflow:auto; margin-top:1rem;"> <div class="bc-table-shell" style="margin-top:1rem;">
<table style="width:100%; border-collapse:collapse;"> <table class="bc-table">
<tbody> <tbody>
<?php foreach ($searchResults as $result): ?> <?php foreach ($searchResults as $result): ?>
<tr style="border-bottom:1px solid var(--border);"> <tr style="border-bottom:1px solid var(--border);">
@@ -53,7 +66,7 @@
<td style="padding:8px;"><?= e((string) ($result['region'] ?? '')) ?></td> <td style="padding:8px;"><?= e((string) ($result['region'] ?? '')) ?></td>
<td style="padding:8px;"><?= e((string) ($result['currency'] ?? '')) ?></td> <td style="padding:8px;"><?= e((string) ($result['currency'] ?? '')) ?></td>
<td style="padding:8px;"> <td style="padding:8px;">
<a class="nav-link" href="/module/boersenchecker/aktienverwaltung?instrument_id=<?= e((string) $selectedInstrumentId) ?>&symbol_candidate=<?= urlencode((string) ($result['symbol'] ?? '')) ?>&instrument_name_candidate=<?= urlencode((string) ($result['name'] ?? '')) ?>&market_candidate=<?= urlencode((string) ($result['region'] ?? '')) ?>&quote_currency_candidate=<?= urlencode((string) ($result['currency'] ?? '')) ?>"> <a class="bc-button bc-button--secondary" href="/module/boersenchecker/aktienverwaltung?instrument_id=<?= e((string) $selectedInstrumentId) ?>&symbol_candidate=<?= urlencode((string) ($result['symbol'] ?? '')) ?>&instrument_name_candidate=<?= urlencode((string) ($result['name'] ?? '')) ?>&market_candidate=<?= urlencode((string) ($result['region'] ?? '')) ?>&quote_currency_candidate=<?= urlencode((string) ($result['currency'] ?? '')) ?>">
Uebernehmen Uebernehmen
</a> </a>
</td> </td>
@@ -66,7 +79,7 @@
</div> </div>
</div> </div>
<div class="card" style="margin-top:1rem; background:var(--panel-2);"> <div class="bc-panel" style="margin-top:1rem;">
<strong>Aktie bearbeiten</strong> <strong>Aktie bearbeiten</strong>
<?php if (!$selectedInstrument || empty($selectedInstrument['id'])): ?> <?php if (!$selectedInstrument || empty($selectedInstrument['id'])): ?>
<div class="muted" style="margin-top:.75rem;">Keine Aktie vorhanden.</div> <div class="muted" style="margin-top:.75rem;">Keine Aktie vorhanden.</div>
@@ -82,17 +95,17 @@
<label class="setup-field muted"><span>Markt</span><input type="text" name="market" value="<?= e((string) (($selectedInstrument['market'] ?? '') ?: ($_GET['market_candidate'] ?? ''))) ?>"></label> <label class="setup-field muted"><span>Markt</span><input type="text" name="market" value="<?= e((string) (($selectedInstrument['market'] ?? '') ?: ($_GET['market_candidate'] ?? ''))) ?>"></label>
<label class="setup-field muted"><span>Kurswaehrung</span><input type="text" name="quote_currency" value="<?= e((string) (($selectedInstrument['quote_currency'] ?? $defaultReportCurrency) ?: ($_GET['quote_currency_candidate'] ?? $defaultReportCurrency))) ?>"></label> <label class="setup-field muted"><span>Kurswaehrung</span><input type="text" name="quote_currency" value="<?= e((string) (($selectedInstrument['quote_currency'] ?? $defaultReportCurrency) ?: ($_GET['quote_currency_candidate'] ?? $defaultReportCurrency))) ?>"></label>
</div> </div>
<button class="cta-button" type="submit">Aktie speichern</button> <button class="bc-button bc-button--primary" type="submit">Aktie speichern</button>
</form> </form>
<form method="post" style="margin-top:.75rem;"> <form method="post" style="margin-top:.75rem;">
<input type="hidden" name="action" value="refresh_alpha_vantage_instrument"> <input type="hidden" name="action" value="refresh_alpha_vantage_instrument">
<input type="hidden" name="instrument_id" value="<?= e((string) ($selectedInstrument['id'] ?? 0)) ?>"> <input type="hidden" name="instrument_id" value="<?= e((string) ($selectedInstrument['id'] ?? 0)) ?>">
<button class="nav-link" type="submit">Aktuellen API-Kurs abrufen</button> <button class="bc-button bc-button--secondary" type="submit">Aktuellen API-Kurs abrufen</button>
</form> </form>
<?php endif; ?> <?php endif; ?>
</div> </div>
<div class="card" style="margin-top:1rem; background:var(--panel-2);"> <div class="bc-panel" style="margin-top:1rem;">
<strong>Manuellen Kurs eingeben</strong> <strong>Manuellen Kurs eingeben</strong>
<?php if (!$selectedInstrument || empty($selectedInstrument['id'])): ?> <?php if (!$selectedInstrument || empty($selectedInstrument['id'])): ?>
<div class="muted" style="margin-top:.75rem;">Keine Aktie vorhanden.</div> <div class="muted" style="margin-top:.75rem;">Keine Aktie vorhanden.</div>
@@ -106,18 +119,18 @@
<label class="setup-field muted"><span>Zeitpunkt</span><input type="datetime-local" name="quoted_at" value="<?= e(date('Y-m-d\TH:i')) ?>" required></label> <label class="setup-field muted"><span>Zeitpunkt</span><input type="datetime-local" name="quoted_at" value="<?= e(date('Y-m-d\TH:i')) ?>" required></label>
<label class="setup-field muted"><span>Quelle</span><input type="text" name="quote_source" value="manual"></label> <label class="setup-field muted"><span>Quelle</span><input type="text" name="quote_source" value="manual"></label>
</div> </div>
<button class="cta-button" type="submit">Kurs speichern</button> <button class="bc-button bc-button--primary" type="submit">Kurs speichern</button>
</form> </form>
<?php endif; ?> <?php endif; ?>
</div> </div>
<div class="card" style="margin-top:1rem;"> <div class="bc-panel" style="margin-top:1rem;">
<strong>Kursverlauf</strong> <strong>Kursverlauf</strong>
<?php if ($quotes === []): ?> <?php if ($quotes === []): ?>
<div class="muted" style="margin-top:.75rem;">Keine Kursdaten vorhanden.</div> <div class="muted" style="margin-top:.75rem;">Keine Kursdaten vorhanden.</div>
<?php else: ?> <?php else: ?>
<div style="overflow:auto; margin-top:.75rem;"> <div class="bc-table-shell" style="margin-top:.75rem;">
<table style="width:100%; border-collapse:collapse;"> <table class="bc-table">
<tbody> <tbody>
<?php foreach ($quotes as $quote): ?> <?php foreach ($quotes as $quote): ?>
<tr style="border-bottom:1px solid var(--border);"> <tr style="border-bottom:1px solid var(--border);">
@@ -129,7 +142,7 @@
<input type="hidden" name="action" value="delete_quote"> <input type="hidden" name="action" value="delete_quote">
<input type="hidden" name="instrument_id" value="<?= e((string) $selectedInstrumentId) ?>"> <input type="hidden" name="instrument_id" value="<?= e((string) $selectedInstrumentId) ?>">
<input type="hidden" name="quote_id" value="<?= e((string) $quote['id']) ?>"> <input type="hidden" name="quote_id" value="<?= e((string) $quote['id']) ?>">
<button class="nav-link" type="submit">Loeschen</button> <button class="bc-button bc-button--secondary" type="submit">Loeschen</button>
</form> </form>
</td> </td>
</tr> </tr>
@@ -140,3 +153,5 @@
<?php endif; ?> <?php endif; ?>
</div> </div>
</div> </div>
</div>
</div>