diff --git a/Internal/de/PROJECT_CONTEXT.md b/Internal/de/PROJECT_CONTEXT.md index 02dc2d3..71dfedc 100644 --- a/Internal/de/PROJECT_CONTEXT.md +++ b/Internal/de/PROJECT_CONTEXT.md @@ -50,6 +50,7 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter. Kernbereiche sind l - In `Profil-Levels` gibt es zusätzlich eine Liste von Nutzern, die in den letzten 30 Tagen mindestens den Rang `Säule der Väter-Community` erreicht haben. - System-Level bleiben getrennt als Rollen `Forum-Admin`, `Site-Admin` und `SiteOwner`. - Die Vergabe von System-Leveln läuft im Bereich `Community-Admin` jetzt über eine Benutzersuche statt über rohe Benutzer-IDs; `Site-Admins` bleiben auf die bestehende Rollenlogik begrenzt. +- Kategorien liegen nicht mehr unter `System`, sondern in einem eigenen Mitgliederbereichspunkt `Kategorien`; dort werden nur neue Kategorien angezeigt und per Vorschlagsfeld mit bestehenden Kategorien aus der Datenbank zusammengeführt. ## Technischer Rahmen - eigener Front-Controller in `public/index.php` diff --git a/Internal/de/PROJECT_STRUCTURE.md b/Internal/de/PROJECT_STRUCTURE.md index ebced59..df35623 100644 --- a/Internal/de/PROJECT_STRUCTURE.md +++ b/Internal/de/PROJECT_STRUCTURE.md @@ -24,6 +24,7 @@ Stand: 2026-08-10 - neue Listing-/Ort-Basis: `src/App/ListingCatalog.php` - Kalender-Export und abonnierbarer Feed: `src/App/CalendarSync.php` plus `public/page/calendar/export.php` und `public/page/calendar/feed.php` - UI für getrennte Bereiche `Events` und `Orte & Veranstaltungen` im Mitgliederbereich: `partials/landing/account/dashboard.php` +- eigener Mitgliederbereichspunkt `Kategorien` für neue Kategorien und deren Zusammenführung per Vorschlagsfeld: `partials/landing/account/dashboard.php`, `src/App/AccountPages.php`, `src/App/ListingCatalog.php` - Preis-, Bild- und Ortseingabe für Orte und Veranstaltungen sowie reduzierte Event-Maske: `partials/landing/account/dashboard.php` plus Speicherung in `src/App/ListingCatalog.php` - Freigaben sowie Änderungs- und Löschanfragen für Orte und Veranstaltungen: `src/App/ListingCatalog.php`, `partials/landing/account/dashboard.php`, `partials/landing/account/community-admin.php` - Rollenvergabe per Benutzersuche im Community-Admin: `partials/landing/account/community-admin.php`, `src/App/CommunityAccess.php` diff --git a/Internal/en/PROJECT_CONTEXT.md b/Internal/en/PROJECT_CONTEXT.md index 582bad9..3c84cb8 100644 --- a/Internal/en/PROJECT_CONTEXT.md +++ b/Internal/en/PROJECT_CONTEXT.md @@ -50,6 +50,7 @@ Papa-Kind-Treff is a PHP-based platform for fathers. Core areas are local events - `Profile Levels` also includes a list of users who reached at least the rank `Pillar of the Fathers Community` within the last 30 days. - System levels remain separate as the roles `Forum Admin`, `Site Admin`, and `SiteOwner`. - System-level assignment in `Community Admin` now runs through user search instead of raw user IDs; site admins remain limited by the existing role rules. +- Categories no longer live under `System`, but in their own member-area section `Categories`; that area only shows newly created categories and merges them into existing database categories through a suggestion field. ## Technical Frame - custom front controller in `public/index.php` diff --git a/Internal/en/PROJECT_STRUCTURE.md b/Internal/en/PROJECT_STRUCTURE.md index f30c3e7..e2504df 100644 --- a/Internal/en/PROJECT_STRUCTURE.md +++ b/Internal/en/PROJECT_STRUCTURE.md @@ -24,6 +24,7 @@ Updated: 2026-08-10 - new listing/place base: `src/App/ListingCatalog.php` - calendar export and subscribable feed: `src/App/CalendarSync.php` plus `public/page/calendar/export.php` and `public/page/calendar/feed.php` - separated `Events` and `Places & Events` UI in member area: `partials/landing/account/dashboard.php` +- dedicated member-area section `Categories` for new categories and merging through a suggestion field: `partials/landing/account/dashboard.php`, `src/App/AccountPages.php`, `src/App/ListingCatalog.php` - pricing, image upload, and place/address input for places and event-style entries plus a reduced own-event form: `partials/landing/account/dashboard.php` with persistence in `src/App/ListingCatalog.php` - approvals as well as change and deletion requests for places and event-style entries: `src/App/ListingCatalog.php`, `partials/landing/account/dashboard.php`, `partials/landing/account/community-admin.php` - role assignment via user search in community admin: `partials/landing/account/community-admin.php`, `src/App/CommunityAccess.php` diff --git a/README.md b/README.md index c3444d8..263b737 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter mit Fokus auf: - In `Profil-Levels` kann der `SiteOwner` Community-Level pflegen, Benutzer suchen und Community-Punkte manuell mit Begründung erhöhen - In `Profil-Levels` werden zusätzlich Nutzer angezeigt, die in den letzten 30 Tagen mindestens den Rang `Säule der Väter-Community` erreicht haben - Im Bereich `Community-Admin` läuft die Rollenvergabe jetzt über eine Benutzersuche statt über rohe Benutzer-IDs; `Site-Admins` bleiben dabei auf die vorhandene Rollenlogik begrenzt +- Kategorien wurden aus `System` in den eigenen Mitgliederbereichspunkt `Kategorien` verschoben; dort werden nur neue Kategorien angezeigt und per Vorschlagsfeld mit bestehenden Kategorien aus der Datenbank zusammengeführt - neue interne Grundstruktur: `listing_places`, `listings`, `listing_occurrences`, `listing_prices`, `listing_benefits` - Seiten-Admins haben zusätzlich eine System-Sektion für globale Wartungs- und Diensteschalter - Im Mitgliederbereich ist `Events` jetzt wieder auf echte eigene Events und Event-Teilnahmen beschränkt diff --git a/partials/landing/account/dashboard.php b/partials/landing/account/dashboard.php index 9bfb02c..6fed6a0 100755 --- a/partials/landing/account/dashboard.php +++ b/partials/landing/account/dashboard.php @@ -148,6 +148,7 @@ if (!empty($canManageProfileLevels)) { $showEventTypeChoice = !$editing && (($section ?? 'events') === 'places') && $requestedCreateListingKind === null; $modalSectionTarget = ($editingListing || ($section ?? '') === 'places') ? 'places' : 'events'; if (!empty($canManageSystemSettings)) { + $sectionLinks['categories'] = 'Kategorien'; $sectionLinks['system'] = 'System'; } ?> @@ -946,44 +947,56 @@ if (!empty($canManageSystemSettings)) {
  • Fehlende Tabellen:
  • + + + -
    - Kategorien prüfen und zusammenführen -

    Neue Kategorien werden automatisch angelegt. Hier kannst du sie prüfen und bei Bedarf mit einer bestehenden Kategorie zusammenführen.

    - -
    - -
    -
    -
    - - - Neu - -
    - Slug: · Einträge: · Orte: · Eigene Events: -
    -
    + +
    + +

    Aktuell gibt es keine neuen Kategorien.

    +
    diff --git a/src/App/AccountPages.php b/src/App/AccountPages.php index 6a124ad..bea2670 100755 --- a/src/App/AccountPages.php +++ b/src/App/AccountPages.php @@ -183,6 +183,7 @@ final class AccountPages $allowedSections = ['profile', 'children', 'events', 'places', 'community', 'settings']; if ($canManageSystemSettings) { $allowedSections[] = 'system'; + $allowedSections[] = 'categories'; } if ($canManageProfileLevels) { $allowedSections[] = 'profile-levels'; @@ -328,9 +329,13 @@ final class AccountPages if (!$canManageSystemSettings || !$listingCatalog) { throw new \RuntimeException('Keine Berechtigung für die Kategorien-Verwaltung.'); } + $targetCategorySlug = $listingCatalog->resolveExistingCategorySlug((string)($_POST['target_category_input'] ?? '')); + if ($targetCategorySlug === null) { + throw new \RuntimeException('Bitte wähle eine vorhandene Zielkategorie aus den Vorschlägen.'); + } $listingCatalog->mergeCategories( (string)($_POST['source_category_slug'] ?? ''), - (string)($_POST['target_category_slug'] ?? '') + $targetCategorySlug ); $info = 'Kategorie zusammengeführt.'; } elseif ($action === 'child_add' || $action === 'child_update') { @@ -852,7 +857,10 @@ final class AccountPages $restoreEventDraftActive = $section === 'events' && ((string)($_GET['restore_event_draft'] ?? '')) === '1' && self::hasStoredEventDraft(); $restoredEventDraft = $restoreEventDraftActive ? self::getStoredEventDraft() : null; $listingCategories = $listingCatalog ? $listingCatalog->listCategories(['general', 'place', 'food', 'event', 'family']) : []; - $categoryReviewItems = $listingCatalog && $canManageSystemSettings ? $listingCatalog->listCategoryReviewItems() : []; + $categoryReviewItems = $listingCatalog && $canManageSystemSettings ? array_values(array_filter( + $listingCatalog->listCategoryReviewItems(), + static fn(array $item): bool => !empty($item['needs_review']) + )) : []; $placeSuggestions = $listingCatalog ? $listingCatalog->listPlaceSuggestions(60) : []; $eventLocationOptions = $listingCatalog ? $listingCatalog->listEventLocationOptions(120) : []; $stmt = $pdo?->prepare( diff --git a/src/App/ListingCatalog.php b/src/App/ListingCatalog.php index 209ffcd..8080135 100644 --- a/src/App/ListingCatalog.php +++ b/src/App/ListingCatalog.php @@ -368,6 +368,29 @@ final class ListingCatalog } } + public function resolveExistingCategorySlug(string $input): ?string + { + $this->ensureSchema(); + $input = trim($input); + if ($input === '') { + return null; + } + + $stmt = $this->pdo->prepare( + 'SELECT slug + FROM listing_categories + WHERE slug = :slug OR LOWER(title) = LOWER(:title) + ORDER BY sort_order ASC, id ASC + LIMIT 1' + ); + $stmt->execute([ + 'slug' => $input, + 'title' => $input, + ]); + $slug = $stmt->fetchColumn(); + return $slug !== false ? (string)$slug : null; + } + public function listPublishedDirectoryEntries(): array { $this->ensureSchema();