From 7b89da6106c150708782d39ed2742fe416c41e89 Mon Sep 17 00:00:00 2001 From: Yassine Doghri <yassine@doghri.fr> Date: Sat, 5 Feb 2022 16:57:20 +0000 Subject: [PATCH] feat(home): sort podcasts by recent activity + add dropdown menu to choose between sorting options fixes #164 --- app/Controllers/HomeController.php | 8 +++++- app/Language/en/Home.php | 6 +++++ app/Language/fr/Home.php | 6 +++++ app/Models/PodcastModel.php | 40 ++++++++++++++++++++++++++++++ app/Resources/icons/sort.svg | 6 +++++ themes/cp_app/home.php | 27 ++++++++++++++++++-- 6 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 app/Resources/icons/sort.svg diff --git a/app/Controllers/HomeController.php b/app/Controllers/HomeController.php index aeaaff0ab7..54abb0ff8a 100644 --- a/app/Controllers/HomeController.php +++ b/app/Controllers/HomeController.php @@ -27,7 +27,12 @@ class HomeController extends BaseController return redirect()->to(rtrim(host_url(), '/') . $route); } - $allPodcasts = (new PodcastModel())->findAll(); + $sortOptions = ['activity', 'created_desc', 'created_asc']; + $sortBy = in_array($this->request->getGet('sort'), $sortOptions, true) ? $this->request->getGet( + 'sort' + ) : 'activity'; + + $allPodcasts = (new PodcastModel())->getAllPodcasts($sortBy); // check if there's only one podcast to redirect user to it if (count($allPodcasts) === 1) { @@ -38,6 +43,7 @@ class HomeController extends BaseController $data = [ 'metatags' => get_home_metatags(), 'podcasts' => $allPodcasts, + 'sortBy' => $sortBy, ]; return view('home', $data); diff --git a/app/Language/en/Home.php b/app/Language/en/Home.php index eda08142ef..26d8350231 100644 --- a/app/Language/en/Home.php +++ b/app/Language/en/Home.php @@ -10,5 +10,11 @@ declare(strict_types=1); return [ 'all_podcasts' => 'All podcasts', + 'sort_by' => 'Sort by', + 'sort_options' => [ + 'activity' => 'Recent activity', + 'created_desc' => 'Newest first', + 'created_asc' => 'Oldest first', + ], 'no_podcast' => 'No podcast found', ]; diff --git a/app/Language/fr/Home.php b/app/Language/fr/Home.php index ab847e8f41..6a0627c5f0 100644 --- a/app/Language/fr/Home.php +++ b/app/Language/fr/Home.php @@ -10,5 +10,11 @@ declare(strict_types=1); return [ 'all_podcasts' => 'Tous les podcasts', + 'sort_by' => 'Trier par', + 'sort_options' => [ + 'activity' => 'Activité récente', + 'created_desc' => 'Le plus récent d’abord', + 'created_asc' => 'Le plus ancien d’abord', + ], 'no_podcast' => 'Aucun podcast trouvé', ]; diff --git a/app/Models/PodcastModel.php b/app/Models/PodcastModel.php index 9b639d69d4..68d1e1d10b 100644 --- a/app/Models/PodcastModel.php +++ b/app/Models/PodcastModel.php @@ -166,6 +166,42 @@ class PodcastModel extends Model return $found; } + /** + * @param 'activity'|'created_asc'|'created_desc' $orderBy + * + * @return Podcast[] + */ + public function getAllPodcasts(string $orderBy = null): array + { + if ($orderBy === 'activity') { + $prefix = $this->db->getPrefix(); + + $fediverseTablePrefix = config('Fediverse') + ->tablesPrefix; + $this->select( + 'podcasts.*, MAX(' . $prefix . $fediverseTablePrefix . 'posts.published_at' . ') as max_published_at' + ) + ->join( + $fediverseTablePrefix . 'posts', + $fediverseTablePrefix . 'posts.actor_id = podcasts.actor_id', + 'left' + ) + ->where( + '`' . $prefix . $fediverseTablePrefix . 'posts`.`published_at` <= NOW()', + null, + false + )->orWhere($fediverseTablePrefix . 'posts.published_at', null) + ->groupBy('cp_podcasts.actor_id') + ->orderBy('max_published_at', 'DESC'); + } elseif ($orderBy === 'created_desc') { + $this->orderBy('created_at', 'DESC'); + } elseif ($orderBy === 'created_asc') { + $this->orderBy('created_at', 'ASC'); + } + + return $this->findAll(); + } + /** * Gets all the podcasts a given user is contributing to * @@ -378,6 +414,10 @@ class PodcastModel extends Model { $podcast = (new self())->getPodcastById(is_array($data['id']) ? $data['id'][0] : $data['id']); + // delete cache for users' podcasts + cache() + ->deleteMatching('user*podcasts'); + if ($podcast !== null) { // delete cache all podcast pages cache() diff --git a/app/Resources/icons/sort.svg b/app/Resources/icons/sort.svg new file mode 100644 index 0000000000..51df35457d --- /dev/null +++ b/app/Resources/icons/sort.svg @@ -0,0 +1,6 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <g> + <path d="M0 0H24V24H0Z" fill="none"/> + <path d="M3 18H7V16H3ZM3 6V8H21V6Zm0 7H15V11H3Z"/> + </g> +</svg> diff --git a/themes/cp_app/home.php b/themes/cp_app/home.php index 39abc5cdc6..b9c1d5422e 100644 --- a/themes/cp_app/home.php +++ b/themes/cp_app/home.php @@ -47,10 +47,33 @@ </h1> </header> <main class="container flex-1 px-4 py-10 mx-auto"> - <Heading tagName="h2" class="inline-block mb-2"><?= lang('Home.all_podcasts') ?> (<?= count( + <div class="flex flex-wrap items-center justify-between py-2 border-b border-subtle gap-x-4"> + <Heading tagName="h2" class="inline-block"><?= lang('Home.all_podcasts') ?> (<?= count( $podcasts, ) ?>)</Heading> - <div class="grid gap-4 grid-cols-cards"> + <button class="inline-flex items-center px-2 py-1 text-sm font-semibold focus:ring-accent" id="sortby-dropdown" data-dropdown="button" data-dropdown-target="sortby-dropdown-menu" aria-haspopup="true" aria-expanded="false"><?= icon('sort', 'mr-1 text-xl opacity-50') . lang('Home.sort_by') ?></button> + <DropdownMenu id="sortby-dropdown-menu" labelledby="sortby-dropdown" items="<?= esc(json_encode([ + [ + 'type' => 'link', + 'title' => ($sortBy === 'activity' ? '✓ ' : '') . lang('Home.sort_options.activity'), + 'uri' => route_to('home') . '?sort=activity', + 'class' => $sortBy === 'activity' ? 'font-semibold' : '', + ], + [ + 'type' => 'link', + 'title' => ($sortBy === 'created_desc' ? '✓ ' : '') . lang('Home.sort_options.created_desc'), + 'uri' => route_to('home') . '?sort=created_desc', + 'class' => $sortBy === 'created_desc' ? 'font-semibold' : '', + ], + [ + 'type' => 'link', + 'title' => ($sortBy === 'created_asc' ? '✓ ' : '') . lang('Home.sort_options.created_asc'), + 'uri' => route_to('home') . '?sort=created_asc', + 'class' => $sortBy === 'created_asc' ? 'font-semibold' : '', + ], + ])) ?>" /> + </div> + <div class="grid gap-4 mt-4 grid-cols-cards"> <?php if ($podcasts): ?> <?php foreach ($podcasts as $podcast): ?> <a href="<?= $podcast->link ?>" class="relative w-full h-full overflow-hidden transition shadow focus:ring-accent rounded-xl border-subtle hover:shadow-xl focus:shadow-xl group border-3"> -- GitLab