diff --git a/app/Http/Controllers/CMS/CMSSidebarController.php b/app/Http/Controllers/CMS/CMSSidebarController.php index db03885..aaa74b8 100755 --- a/app/Http/Controllers/CMS/CMSSidebarController.php +++ b/app/Http/Controllers/CMS/CMSSidebarController.php @@ -68,9 +68,24 @@ class CMSSidebarController extends Controller $data['active'] = isset($data['active']) ? true : false; $data['show_at'] = isset($data['show_at']) ? $data['show_at'] : null; - $widget->fill($data)->save(); + $component = isset($data['component']) ? $data['component'] : null; - $widget->save(); + if (in_array($component, [SidebarWidget::HOMEPAGE_PLANNABLE_TRIPS, SidebarWidget::HOMEPAGE_POPULAR_TRIPS])) { + $pageIds = isset($data['homepage_page_ids']) ? array_values(array_filter($data['homepage_page_ids'])) : []; + $newPageIds = isset($data['homepage_new_page_ids']) ? array_values(array_filter($data['homepage_new_page_ids'])) : []; + + $data['html'] = json_encode([ + 'page_ids' => $pageIds, + 'new_page_ids' => array_values(array_intersect($pageIds, $newPageIds)), + 'new_badge_active' => false, + ]); + } elseif ($component === SidebarWidget::NEWS_SIDEBAR_WIDGET && isset($data['homepage_news_limit'])) { + $data['html'] = json_encode([ + 'news_limit' => max(1, min(12, (int) $data['homepage_news_limit'])), + ]); + } + + $widget->fill($data)->save(); \Session()->flash('alert-save', '1'); return redirect(route('cms_sidebar_detail', [$widget->id])); diff --git a/app/Models/SidebarWidget.php b/app/Models/SidebarWidget.php index fcb8440..39ea6a6 100644 --- a/app/Models/SidebarWidget.php +++ b/app/Models/SidebarWidget.php @@ -32,6 +32,10 @@ use Illuminate\Database\Eloquent\Model; */ class SidebarWidget extends Model { + const HOMEPAGE_PLANNABLE_TRIPS = 'homepagePlannableTrips'; + const HOMEPAGE_POPULAR_TRIPS = 'homepagePopularTrips'; + const NEWS_SIDEBAR_WIDGET = 'newsSidebarWidget'; + protected static $shows = [ 'home' => 'Startseite', @@ -54,7 +58,9 @@ class SidebarWidget extends Model 'travelGuideSidebarWidget' => 'Reiseführer', 'travelMagazineSidebarWidget' => 'Reisemagazin', 'offersSidebarWidget' => 'Angebote', - 'newsSidebarWidget' => 'News', + self::NEWS_SIDEBAR_WIDGET => 'News', + self::HOMEPAGE_PLANNABLE_TRIPS => 'Startseite: Aktuell planbare Reisen', + self::HOMEPAGE_POPULAR_TRIPS => 'Startseite: Beliebte Kulturreisen', ]; @@ -105,23 +111,256 @@ class SidebarWidget extends Model return rtrim($ret, ", "); } + public function getComponentLabel() + { + if (!$this->component) { + return 'Nur HTML'; + } + return isset(self::$components[$this->component]) ? self::$components[$this->component] : $this->component; + } + public function isHomepageTripsComponent() + { + return in_array($this->component, [self::HOMEPAGE_PLANNABLE_TRIPS, self::HOMEPAGE_POPULAR_TRIPS]); + } + public function isNewsComponent() + { + return $this->component === self::NEWS_SIDEBAR_WIDGET; + } + + public function isStructuredConfigComponent() + { + return $this->isHomepageTripsComponent() || $this->isNewsComponent(); + } + + public function getConfig() + { + $config = json_decode($this->html, true); + + if (!is_array($config)) { + $config = []; + } + + $config['page_ids'] = isset($config['page_ids']) && is_array($config['page_ids']) + ? array_values(array_filter($config['page_ids'])) + : []; + $config['new_page_ids'] = isset($config['new_page_ids']) && is_array($config['new_page_ids']) + ? array_values(array_filter($config['new_page_ids'])) + : []; + $config['new_badge_active'] = !empty($config['new_badge_active']); + $config['news_limit'] = isset($config['news_limit']) ? max(1, min(12, (int) $config['news_limit'])) : 3; + + return $config; + } + + public function getHomepageConfig() + { + return $this->getConfig(); + } + + public function getHomepagePageIds() + { + return $this->getHomepageConfig()['page_ids']; + } + + public function getHomepageNewPageIds() + { + return array_map('intval', $this->getHomepageConfig()['new_page_ids']); + } + + public function getHomepageNewBadgeActive() + { + return $this->getHomepageConfig()['new_badge_active']; + } + + public function getHomepageNewsLimit() + { + return $this->getConfig()['news_limit']; + } + + public static function getHomepageTravelPageOptions($selectedIds = []) + { + $selectedIds = array_map('intval', (array) $selectedIds); + $items = self::getHomepageTravelPageItems($selectedIds); + $groupedItems = []; + + foreach ($items as $item) { + $groupedItems[$item['country_group']][] = $item; + } + + uksort($groupedItems, function ($a, $b) { + return strnatcasecmp(self::getHomepageSortValue($a), self::getHomepageSortValue($b)); + }); + + $ret = ''; + foreach ($groupedItems as $countryGroup => $groupItems) { + $ret .= ''."\n"; + + foreach ($groupItems as $item) { + $attr = $item['selected'] ? 'selected="selected"' : ''; + $label = e($item['label']); + $ret .= ''."\n"; + } + + $ret .= ''."\n"; + } + + return $ret; + } + + public static function getHomepageTravelPageItems($selectedIds = []) + { + $selectedIds = array_map('intval', (array) $selectedIds); + $pages = Page::with([ + 'travel_program_content.travel_program_countries.travel_country', + 'travel_program_content.travel_country_content', + ]) + ->where('status', 1) + ->whereNotNull('travel_program') + ->where('travel_program', '>', 0) + ->whereHas('travel_program_content', function ($query) { + $query->where('status', 1); + }) + ->orderBy('title') + ->get() + ->unique('travel_program'); + + $items = []; + foreach ($pages as $page) { + $countryGroup = self::getHomepageTravelPageCountryLabel($page); + $items[] = [ + 'id' => (int) $page->id, + 'label' => self::getHomepageTravelPageLabel($page), + 'country_group' => $countryGroup, + 'sort_title' => $page->title, + 'selected' => in_array((int) $page->id, $selectedIds), + ]; + } + + usort($items, function ($a, $b) { + $countryCompare = strnatcasecmp( + self::getHomepageSortValue($a['country_group']), + self::getHomepageSortValue($b['country_group']) + ); + if ($countryCompare !== 0) { + return $countryCompare; + } + + return strnatcasecmp(self::getHomepageSortValue($a['sort_title']), self::getHomepageSortValue($b['sort_title'])); + }); + + return $items; + } + + public function getHomepageSelectedTravelPageItems() + { + $selectedIds = array_map('intval', $this->getHomepagePageIds()); + + if (empty($selectedIds)) { + return []; + } + + $newPageIds = $this->getHomepageNewPageIds(); + $pages = Page::with([ + 'travel_program_content.travel_program_countries.travel_country', + 'travel_program_content.travel_country_content', + ]) + ->whereIn('id', $selectedIds) + ->where('status', 1) + ->whereHas('travel_program_content', function ($query) { + $query->where('status', 1); + }) + ->get() + ->keyBy('id'); + + $items = []; + $usedTravelPrograms = []; + foreach ($selectedIds as $pageId) { + if (!$pages->has($pageId)) { + continue; + } + + $page = $pages->get($pageId); + $travelProgramId = (int) $page->travel_program; + if (in_array($travelProgramId, $usedTravelPrograms)) { + continue; + } + $usedTravelPrograms[] = $travelProgramId; + + $items[] = [ + 'id' => (int) $page->id, + 'label' => self::getHomepageTravelPageLabel($page), + 'is_new' => in_array((int) $page->id, $newPageIds), + ]; + } + + return $items; + } + + protected static function getHomepageTravelPageLabel(Page $page) + { + $country = self::getHomepageTravelPageCountryLabel($page); + $travelProgram = $page->travel_program_content; + $programId = $travelProgram ? $travelProgram->id : $page->travel_program; + + return $country.' | Reise, '.$page->title.' (#'.$programId.')'; + } + + protected static function getHomepageTravelPageCountryLabel(Page $page) + { + $countryNames = self::getHomepageTravelPageCountryNames($page); + + return !empty($countryNames) ? implode(', ', $countryNames) : 'Ohne Reiseland'; + } + + protected static function getHomepageTravelPageCountryNames(Page $page) + { + $travelProgram = $page->travel_program_content; + $countryNames = []; + + if ($travelProgram && $travelProgram->travel_program_countries) { + foreach ($travelProgram->travel_program_countries as $programCountry) { + if ($programCountry->travel_country && $programCountry->travel_country->name) { + $countryNames[] = $programCountry->travel_country->name; + } + } + } + + if (empty($countryNames) && $travelProgram && $travelProgram->travel_country_content) { + $countryNames[] = $travelProgram->travel_country_content->name; + } + + $countryNames = array_unique($countryNames); + usort($countryNames, function ($a, $b) { + return strnatcasecmp(self::getHomepageSortValue($a), self::getHomepageSortValue($b)); + }); + + return $countryNames; + } + + protected static function getHomepageSortValue($value) + { + return str_replace( + ['Ä', 'Ö', 'Ü', 'ä', 'ö', 'ü', 'ß'], + ['Ae', 'Oe', 'Ue', 'ae', 'oe', 'ue', 'ss'], + (string) $value + ); + } /* * public function getVotesDetailAttribute($details) -{ - return json_decode($details, true); -} -then when you will call $store->votes_detail you will get the expected result. - -After that you can use mutators to convert an array back to JSON when it is saved back in the DB. Define the method setVotesDetailAttribute($value) as follows: - -public function setVotesDetailsAttribute($value) -{ - $this->attributes['votes_detail'] = json_encode($value); -} - */ - + { + * return json_decode($details, true); + } + * then when you will call $store->votes_detail you will get the expected result. + * + * After that you can use mutators to convert an array back to JSON when it is saved back in the DB. Define the method setVotesDetailAttribute($value) as follows: + * + * public function setVotesDetailsAttribute($value) + * { + * $this->attributes['votes_detail'] = json_encode($value); + * } + */ } diff --git a/app/Models/TravelProgram.php b/app/Models/TravelProgram.php index 19253cb..8bb854a 100644 --- a/app/Models/TravelProgram.php +++ b/app/Models/TravelProgram.php @@ -295,6 +295,16 @@ class TravelProgram extends Model return $this->hasOne(TravelProgramCountry::class, 'program_id'); } + public function travel_program_countries() + { + return $this->hasMany(TravelProgramCountry::class, 'program_id'); + } + + public function travel_country_content() + { + return $this->belongsTo(TravelCountry::class, 'travel_country'); + } + public function travel_program_destination() { //return $this->hasOne(TravelProgramDestination::class, 'program_id'); diff --git a/resources/views/cms/sidebar/detail.blade.php b/resources/views/cms/sidebar/detail.blade.php index cfd55b5..87a0a10 100755 --- a/resources/views/cms/sidebar/detail.blade.php +++ b/resources/views/cms/sidebar/detail.blade.php @@ -38,15 +38,82 @@
- {!! \App\Models\SidebarWidget::getComponentsOptions($widget->component) !!}
-
+
{{ Form::textarea('html', $widget->html, ['class' => 'form-control']) }} + + Wird nur genutzt, wenn keine feste Komponente ausgewählt ist oder die Komponente eigene HTML-Inhalte erwartet. + +
+
+
+
+ Diese Auswahl steuert die Startseiten-Bereiche „Aktuell planbare Reisen" und „Beliebte Kulturreisen". + Die Reihenfolge entspricht der Reihenfolge der ausgewählten Einträge. +
+
+
+ +
+ + + + +
+ + Wenn keine Reisen hinzugefügt sind, nutzt die DEV-Startseite die automatische Prioritätslogik. + +
+
+
+
+ +
+ @foreach($widget->getHomepageSelectedTravelPageItems() as $selectedPage) +
+ + + {{ $loop->iteration }} + {{ $selectedPage['label'] }} + + + + + + + + + +
+ @endforeach +
+
+
+
+
+
+ Die Reisenews werden weiterhin automatisch aus dem News-Bereich geladen. Hier wird nur gesteuert, + wie viele Einträge in der Sidebar erscheinen. +
+
+
+ + +
@@ -67,6 +134,97 @@ {!! Form::close() !!} + + {{--