From 118d0a23f7eef137a460446d1531da912ef0a9cc Mon Sep 17 00:00:00 2001 From: Clemens Creutzburg Date: Mon, 30 Mar 2026 17:39:44 +0200 Subject: [PATCH] =?UTF-8?q?Anpassung=20des=20Men=C3=BCs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- saas-app/public/app-support.php | 57 +---- saas-app/public/index.php | 12 +- saas-app/public/support/index.php | 1 - saas-app/public/surveys/index.php | 1 - saas-app/public/tenant-shell.php | 323 ------------------------ saas-app/public/tenants/roles/index.php | 1 - 6 files changed, 12 insertions(+), 383 deletions(-) delete mode 100644 saas-app/public/tenant-shell.php diff --git a/saas-app/public/app-support.php b/saas-app/public/app-support.php index 6fb3c28..f374443 100644 --- a/saas-app/public/app-support.php +++ b/saas-app/public/app-support.php @@ -352,57 +352,6 @@ function app_primary_role_label(?array $auth): string return $labels[0] ?? 'Mitglied'; } -/** - * @return array - */ -function app_tenant_nav_items(?array $auth, array $features = []): array -{ - if (!is_array($auth)) { - return [ - ['href' => '/', 'label' => 'Start'], - ['href' => '/login/', 'label' => 'Anmeldung'], - ['href' => '/admin/login/', 'label' => 'Betreiber'], - ]; - } - - $items = [ - ['href' => '/dashboard/', 'label' => 'Dashboard'], - ['href' => '/content/', 'label' => 'Hinweise'], - ['href' => '/support/', 'label' => 'Support'], - ['href' => '/surveys/', 'label' => 'Umfragen'], - ]; - - if (app_can_manage_tenant($auth)) { - $items[] = ['href' => '/members/', 'label' => 'Mitglieder']; - } - - if (app_can_manage_finance($auth)) { - $items[] = ['href' => '/ledger/', 'label' => 'Buchungen']; - $items[] = ['href' => '/payments/', 'label' => 'Einzahlungen']; - } - - if (app_can_manage_tenant($auth)) { - $items[] = ['href' => '/tenants/roles/', 'label' => 'Rollen']; - } - - if (app_can_manage_tenant($auth) && !empty($features['tenant_settings'])) { - $items[] = ['href' => '/settings/', 'label' => 'Einstellungen']; - } - - if ( - app_can_manage_tenant($auth) - && ( - !empty($features['pdf_export']) - || !empty($features['paper_strike_entry']) - || !empty($features['basic_exports']) - ) - ) { - $items[] = ['href' => '/exports/', 'label' => 'Exporte']; - } - - return $items; -} - /** * @param array $roles */ @@ -442,7 +391,7 @@ function app_tenant_navigation_items(?array $auth, array $license = []): array $features = is_array($license['features'] ?? null) ? $license['features'] : []; $canManage = app_can_manage_tenant($auth); - $canFinance = $canManage || app_auth_has_any_role($auth, ['finance_admin']); + $canFinance = app_can_manage_finance($auth); $hasExports = !empty($features['pdf_export']) || !empty($features['paper_strike_entry']) || !empty($features['basic_exports']); $items = [ @@ -2675,8 +2624,8 @@ function app_handle_tenant_action(PDO $pdo, array $auth): void return; } - if (!app_can_manage_tenant($auth)) { - app_flash('Für diese Aktion brauchst du Tenant-Admin-Rechte.', 'warning'); + if (!app_can_manage_finance($auth)) { + app_flash('Für diese Aktion brauchst du Finanz- oder Tenant-Rechte.', 'warning'); app_redirect('/dashboard/'); } diff --git a/saas-app/public/index.php b/saas-app/public/index.php index 451ad85..ddcb7f8 100644 --- a/saas-app/public/index.php +++ b/saas-app/public/index.php @@ -208,10 +208,16 @@ if ($auth !== null && $pdo instanceof PDO) { $loginState = $loginFlow['state'] ?? []; $loginStep = (string) ($loginState['step'] ?? 'discover'); $selectedMembership = $loginState['selected_membership'] ?? null; -$restrictedPages = ['members', 'ledger', 'payments', 'settings', 'exports']; +$restrictedPages = [ + 'members' => static fn(array $user): bool => app_can_manage_tenant($user), + 'ledger' => static fn(array $user): bool => app_can_manage_finance($user), + 'payments' => static fn(array $user): bool => app_can_manage_finance($user), + 'settings' => static fn(array $user): bool => app_can_manage_tenant($user), + 'exports' => static fn(array $user): bool => app_can_manage_tenant($user), +]; -if ($auth !== null && in_array($page, $restrictedPages, true) && !app_can_manage_tenant($auth)) { - app_flash('Dieser Bereich ist nur für Tenant-Admins verfügbar.', 'warning'); +if ($auth !== null && isset($restrictedPages[$page]) && !$restrictedPages[$page]($auth)) { + app_flash('Dieser Bereich ist für deine Rolle nicht freigegeben.', 'warning'); app_redirect('/dashboard/'); } diff --git a/saas-app/public/support/index.php b/saas-app/public/support/index.php index 069b883..a9f9fab 100644 --- a/saas-app/public/support/index.php +++ b/saas-app/public/support/index.php @@ -7,7 +7,6 @@ if (session_status() !== PHP_SESSION_ACTIVE) { } require_once __DIR__ . '/../app-support.php'; -require_once __DIR__ . '/../tenant-shell.php'; require_once __DIR__ . '/../../app/Modules/Support/bootstrap.php'; if (!isset($_SESSION['support_csrf'])) { diff --git a/saas-app/public/surveys/index.php b/saas-app/public/surveys/index.php index 9ab5ec5..0511231 100644 --- a/saas-app/public/surveys/index.php +++ b/saas-app/public/surveys/index.php @@ -10,7 +10,6 @@ if (session_status() !== PHP_SESSION_ACTIVE) { } require_once dirname(__DIR__) . '/app-support.php'; -require_once dirname(__DIR__) . '/tenant-shell.php'; require_once dirname(__DIR__, 2) . '/app/Modules/Surveys/Domain/Survey.php'; require_once dirname(__DIR__, 2) . '/app/Modules/Surveys/Domain/SurveyQuestion.php'; require_once dirname(__DIR__, 2) . '/app/Modules/Surveys/Domain/SurveyPublication.php'; diff --git a/saas-app/public/tenant-shell.php b/saas-app/public/tenant-shell.php deleted file mode 100644 index b1168fe..0000000 --- a/saas-app/public/tenant-shell.php +++ /dev/null @@ -1,323 +0,0 @@ - - :root{ - --bg:#f4efe4; - --card:#fffdf8; - --card-soft:#f7f1e5; - --ink:#25180f; - --muted:#63584a; - --brand:#005e3f; - --brand-strong:#00452f; - --accent:#c18a00; - --line:rgba(37,24,15,.14); - --shadow:0 16px 36px rgba(37,24,15,.08); - --radius:18px; - } - *{box-sizing:border-box} - body{ - margin:0; - color:var(--ink); - font-family:"Aptos","Segoe UI",sans-serif; - background:linear-gradient(180deg,#f9f6ef 0%,var(--bg) 100%); - } - a{color:inherit;text-decoration:none} - .tenant-shell{width:min(1240px,calc(100vw - 32px));margin:20px auto 40px} - .tenant-header, - .tenant-nav, - .tenant-context, - .hero, - .card, - .panel, - .table-card, - .note, - .alert{ - border:1px solid var(--line); - border-radius:var(--radius); - background:var(--card); - box-shadow:var(--shadow); - } - .tenant-header{ - display:flex; - justify-content:space-between; - align-items:flex-start; - gap:16px; - padding:18px 22px; - margin-bottom:14px; - } - .tenant-brand{display:grid;gap:4px} - .tenant-brand__title, - .hero__title, - .card h2, - .card h3, - .panel h2, - .panel h3, - .table-card h2, - .table-card h3{ - margin:0; - font-family:Georgia,serif; - letter-spacing:-.02em; - } - .tenant-brand__title{font-size:1.18rem} - .tenant-brand__subtitle, - .muted, - p{color:var(--muted)} - .tenant-toolbar, - .tenant-nav__items, - .hero__actions, - .hero__meta, - .actions, - .context, - .stack-inline{ - display:flex; - flex-wrap:wrap; - gap:10px; - align-items:center; - } - .tenant-nav{ - display:flex; - flex-wrap:wrap; - gap:14px; - align-items:center; - padding:14px 18px; - margin-bottom:14px; - background:var(--card-soft); - } - .tenant-nav__label{ - font-size:.86rem; - font-weight:800; - letter-spacing:.12em; - text-transform:uppercase; - color:var(--accent); - } - .tenant-nav__items{gap:8px} - .tenant-nav__link, - .button, - button{ - display:inline-flex; - align-items:center; - justify-content:center; - padding:10px 14px; - border-radius:999px; - border:1px solid transparent; - font:inherit; - font-weight:700; - cursor:pointer; - } - .tenant-nav__link{ - background:#fff; - color:var(--brand-strong); - border-color:rgba(0,94,63,.12); - } - .tenant-nav__link.is-active, - .button, - button{ - background:var(--brand); - color:#fff; - } - .button.secondary{ - background:#fff; - color:var(--brand-strong); - border-color:rgba(0,94,63,.18); - } - .tenant-context{ - display:flex; - flex-wrap:wrap; - gap:10px; - align-items:center; - padding:14px 18px; - margin-bottom:18px; - } - .badge, - .pill{ - display:inline-flex; - align-items:center; - gap:8px; - padding:6px 11px; - border-radius:999px; - border:1px solid rgba(0,94,63,.12); - background:#fff; - color:var(--brand-strong); - font-size:.84rem; - font-weight:700; - } - .badge--solid, - .badge--success{background:rgba(0,94,63,.1);color:var(--brand-strong)} - .badge--warning{background:rgba(193,138,0,.14);color:#8c6500} - .badge--danger{background:rgba(154,31,31,.12);color:#9a1f1f} - .badge--neutral{background:rgba(0,94,63,.06);color:var(--brand-strong)} - .hero{ - display:grid; - gap:18px; - padding:24px; - margin-bottom:18px; - background:linear-gradient(180deg,#fffdf8 0%,#f9f4ea 100%); - } - .hero--split{grid-template-columns:minmax(0,1.2fr) minmax(280px,.8fr)} - .hero__content, - .hero__aside, - .stack{display:grid;gap:14px} - .hero__kicker, - .card__eyebrow, - .eyebrow{ - margin:0 0 8px; - font-size:.8rem; - font-weight:800; - text-transform:uppercase; - letter-spacing:.12em; - color:var(--accent); - } - .hero__title{font-size:clamp(1.9rem,4vw,3rem);line-height:1.05} - .hero__lead{margin:0;max-width:64ch;line-height:1.6} - .grid{display:grid;gap:18px} - .grid--2{grid-template-columns:repeat(2,minmax(0,1fr))} - .grid--3{grid-template-columns:repeat(3,minmax(0,1fr))} - .grid--4{grid-template-columns:repeat(4,minmax(0,1fr))} - .split{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(360px,.9fr);gap:18px} - .card,.panel,.table-card{padding:22px} - .table-card__header{display:flex;justify-content:space-between;gap:12px;align-items:flex-start;margin-bottom:16px;flex-wrap:wrap} - .table{overflow-x:auto} - table{width:100%;border-collapse:collapse;min-width:720px} - th,td{padding:12px 10px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top} - th{font-size:.82rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)} - input,select,textarea{ - width:100%; - padding:12px 14px; - border-radius:14px; - border:1px solid rgba(37,24,15,.15); - background:#fff; - color:var(--ink); - font:inherit; - } - label{display:flex;flex-direction:column;gap:8px;font-weight:700} - textarea{min-height:120px} - .metric{ - padding:18px; - border-radius:16px; - border:1px solid var(--line); - background:#fff; - display:grid; - gap:8px; - } - .metric__label{color:var(--muted)} - .metric__value{font-size:1.9rem;font-weight:800} - .status{ - display:inline-flex; - align-items:center; - padding:6px 10px; - border-radius:999px; - background:rgba(0,94,63,.1); - color:var(--brand-strong); - font-weight:700; - font-size:.84rem; - } - .status--warning{background:rgba(193,138,0,.14);color:#8c6500} - .status--success{background:rgba(0,94,63,.12);color:var(--brand-strong)} - .status--danger{background:rgba(154,31,31,.12);color:#9a1f1f} - .note, - .alert{ - padding:14px 16px; - } - .alert-success{background:rgba(0,94,63,.08)} - .alert-warning{background:rgba(193,138,0,.1)} - .alert-error{background:rgba(154,31,31,.1)} - .timeline{display:grid;gap:12px} - .timeline__item{ - padding:14px 16px; - border-radius:16px; - border:1px solid rgba(37,24,15,.08); - background:#fff; - } - .timeline__title{margin:0 0 6px;font-weight:800;color:var(--ink)} - .timeline__meta{margin:0;color:var(--muted);line-height:1.55} - .tenant-footer{ - margin-top:18px; - text-align:center; - color:var(--muted); - font-size:.92rem; - } - @media(max-width:980px){ - .tenant-header, - .tenant-nav{flex-direction:column;align-items:flex-start} - .hero--split, - .grid--2, - .grid--3, - .grid--4, - .split{grid-template-columns:1fr} - table{min-width:0} - } - -HTML; -} - -function tenant_shell_path_is_active(string $currentPath, string $href): bool -{ - $normalize = static function (string $path): string { - $value = parse_url($path, PHP_URL_PATH); - $value = is_string($value) ? rtrim($value, '/') : ''; - - return $value === '' ? '/' : $value; - }; - - return $normalize($currentPath) === $normalize($href); -} - -function tenant_shell_render_header(array $auth, string $currentPath, array $tenantLicense = [], string $title = 'Kaffeeliste', string $subtitle = 'Mandantenbereich'): string -{ - $navItems = app_tenant_navigation_items($auth, $tenantLicense); - $tenantName = (string) ($auth['tenant_name'] ?? 'Tenant'); - $displayName = (string) ($auth['display_name'] ?? 'Benutzer'); - $roleLabel = app_primary_role_label($auth); - $planName = (string) ($tenantLicense['plan_name'] ?? 'Free'); - - ob_start(); - ?> -
-
-

-

-
-
- - - -
-
- -
- - - - - - Global-Admin im Tenant - -
-