From 356f7f07dc239a979fa5d0d5cd638b22f4be2ba1 Mon Sep 17 00:00:00 2001
From: Daniel Wilkowski
Date: Tue, 8 Oct 2024 10:21:49 +0200
Subject: [PATCH] Condense multiple online viewers to one row
---
app/Domain/Online/FakeSessionRepository.php | 2 +-
app/Domain/Online/Viewers.php | 35 +++++++
app/Services/Session/Renderer.php | 32 ++++---
.../feature/viewersOnline/viewers-online.scss | 15 ++-
resources/views/components/viewers.twig | 45 +++++----
tests/Unit/OnlineUsers/ViewersTest.php | 91 +++++++++++++++++++
6 files changed, 181 insertions(+), 39 deletions(-)
create mode 100644 tests/Unit/OnlineUsers/ViewersTest.php
diff --git a/app/Domain/Online/FakeSessionRepository.php b/app/Domain/Online/FakeSessionRepository.php
index d94b4feeb..13751fe6a 100644
--- a/app/Domain/Online/FakeSessionRepository.php
+++ b/app/Domain/Online/FakeSessionRepository.php
@@ -20,7 +20,7 @@ public function sessionsIn(string $prefixPath): SessionsSnapshot
return new SessionsSnapshot(
users:[
...$this->id(User::query()->whereNotNull('group_name')->limit(1)),
- ...$this->id(User::query()->inRandomOrder()->limit(\rand(5, 7))),
+ ...$this->id(User::query()->inRandomOrder()->limit(\rand(3, 20))),
],
guestsCount:\rand(5, 90),
);
diff --git a/app/Domain/Online/Viewers.php b/app/Domain/Online/Viewers.php
index d52658f1d..03860b9d7 100644
--- a/app/Domain/Online/Viewers.php
+++ b/app/Domain/Online/Viewers.php
@@ -1,6 +1,8 @@
usersWithoutGroup(), 0, $limit);
+ }
+
+ public function usersSuperfluous(int $limit): int
+ {
+ return \max(0, \count($this->usersWithoutGroup()) - $limit);
+ }
+
+ public function totalCount(): int
+ {
+ return count($this->users) + $this->guestsCount;
+ }
+
+ /**
+ * @return ViewerUser[]
+ */
+ public function usersWithGroup(): array
+ {
+ return $this->usersFiltered(fn(ViewerUser $user) => $user->groupName);
+ }
+
+ private function usersWithoutGroup(): array
+ {
+ return $this->usersFiltered(fn(ViewerUser $user) => !$user->groupName);
+ }
+
+ private function usersFiltered(callable $predicate): array
+ {
+ return \array_values(\array_filter($this->users, $predicate));
+ }
}
diff --git a/app/Services/Session/Renderer.php b/app/Services/Session/Renderer.php
index 21a951c70..216c3ec77 100644
--- a/app/Services/Session/Renderer.php
+++ b/app/Services/Session/Renderer.php
@@ -2,6 +2,7 @@
namespace Coyote\Services\Session;
use Coyote\Domain\Online\FakeSessionRepository;
+use Coyote\Domain\Online\Viewers;
use Coyote\Domain\Online\ViewersStore;
use Illuminate\Http\Request;
use Illuminate\View\View;
@@ -17,6 +18,23 @@ public function __construct(
}
public function render(string $requestUri, bool $local): View
+ {
+ $viewers = $this->sessionViewers($requestUri);
+ $limit = 8;
+ return view('components.viewers', [
+ 'local' => $local,
+ 'guestsCount' => $viewers->guestsCount,
+ 'usersCount' => \count($viewers->users),
+ 'title' => $local
+ ? 'Aktualnie na tej stronie'
+ : "{$viewers->totalCount()} użytkowników online",
+ 'usersWithGroup' => $viewers->usersWithGroup(),
+ 'usersWithoutGroup' => $viewers->usersLeading($limit),
+ 'superfluousCount' => $viewers->usersSuperfluous($limit),
+ ]);
+ }
+
+ private function sessionViewers(string $requestUri): Viewers
{
$sessions = $this->session->sessionsIn($requestUri);
if ($this->isUserLogged()) {
@@ -24,19 +42,7 @@ public function render(string $requestUri, bool $local): View
} else {
$sessions = $sessions->coalesceGuest();
}
- $viewers = $this->store->viewers($sessions);
-
- $viewersCount = $viewers->guestsCount + \count($viewers->users);
- return view('components.viewers', [
- 'local' => $local,
- 'showAvatars' => $local,
- 'guestsCount' => $viewers->guestsCount,
- 'usersCount' => \count($viewers->users),
- 'title' => $local
- ? 'Aktualnie na tej stronie'
- : "$viewersCount użytkowników online",
- 'users' => $viewers->users,
- ]);
+ return $this->store->viewers($sessions);
}
private function isUserLogged(): bool
diff --git a/resources/feature/viewersOnline/viewers-online.scss b/resources/feature/viewersOnline/viewers-online.scss
index 86a9333ba..074192303 100644
--- a/resources/feature/viewersOnline/viewers-online.scss
+++ b/resources/feature/viewersOnline/viewers-online.scss
@@ -49,11 +49,22 @@
border-radius: 32px;
overflow: hidden;
margin-right: -12px;
- @include dark {
- border: 1px solid #444;
+ width: 32px;
+
+ &.viewers-superfluous {
+ height: 32px;
+ text-align: center;
+ line-height: 32px;
+ font-size: 0.8em;
}
+
@include light {
border: 1px solid #dedede;
+ background: white;
+ }
+ @include dark {
+ border: 1px solid #444;
+ background: #2e2e2e;
}
}
}
diff --git a/resources/views/components/viewers.twig b/resources/views/components/viewers.twig
index 997ce81bc..58a2ac9a3 100644
--- a/resources/views/components/viewers.twig
+++ b/resources/views/components/viewers.twig
@@ -16,30 +16,29 @@
- {% for user in users %}
- {% if user.groupName %}
-
-
- {{ user_avatar(user.avatarUrl, user.name) }}
-
-
- {{ user.name }}
-
- {{ user.groupName }}
-
+ {% for user in usersWithGroup %}
+
+
+ {{ user_avatar(user.avatarUrl, user.name) }}
- {% endif %}
+
+ {{ user.name }}
+
+ {{ user.groupName }}
+
+
{% endfor %}
- {% if showAvatars %}
-
- {% for user in users %}
- {% if not user.groupName %}
-
- {{ user_avatar(user.avatarUrl, user.name) }}
-
- {% endif %}
- {% endfor %}
-
- {% endif %}
+
+ {% for user in usersWithoutGroup %}
+
+ {{ user_avatar(user.avatarUrl, user.name) }}
+
+ {% endfor %}
+ {% if superfluousCount > 0 %}
+
+ +{{ superfluousCount }}
+
+ {% endif %}
+
diff --git a/tests/Unit/OnlineUsers/ViewersTest.php b/tests/Unit/OnlineUsers/ViewersTest.php
new file mode 100644
index 000000000..62ffffacf
--- /dev/null
+++ b/tests/Unit/OnlineUsers/ViewersTest.php
@@ -0,0 +1,91 @@
+usersOfSize(2), 3);
+ $this->assertSame(5, $viewers->totalCount());
+ }
+
+ #[Test]
+ public function leadingUsers(): void
+ {
+ $viewers = new Viewers([$this->user('Mark')], 0);
+ [$leading] = $viewers->usersLeading(2);
+ $this->assertSame('Mark', $leading->name);
+ }
+
+ #[Test]
+ public function leadingUsersUpToLimit(): void
+ {
+ $viewers = new Viewers($this->usersOfSize(5), 0);
+ $this->assertCount(2, $viewers->usersLeading(2));
+ }
+
+ #[Test]
+ public function countSuperfluousUsers(): void
+ {
+ $viewers = new Viewers($this->usersOfSize(5), 0);
+ $this->assertSame(3, $viewers->usersSuperfluous(2));
+ }
+
+ #[Test]
+ public function withLimitBiggerThanUsers_returnEmptySuperfluous(): void
+ {
+ $viewers = new Viewers($this->usersOfSize(3), 0);
+ $this->assertSame(0, $viewers->usersSuperfluous(5));
+ }
+
+ #[Test]
+ public function usersWithGroup(): void
+ {
+ $viewers = new Viewers([
+ $this->user(name:'Tom'),
+ $this->user(name:'Mark', group:'Blue'),
+ ], 0);
+ $users = $viewers->usersWithGroup();
+ $this->assertCount(1, $users);
+ $this->assertSame('Mark', $users[0]->name);
+ }
+
+ #[Test]
+ public function leadingUsers_areWithoutGroups(): void
+ {
+ $viewers = new Viewers([
+ $this->user(name:'Mark', group:'Blue'),
+ $this->user(name:'Tom'),
+ ], 0);
+ $leading = $viewers->usersLeading(2);
+ $this->assertCount(1, $leading);
+ $this->assertSame('Tom', $leading[0]->name);
+ }
+
+ #[Test]
+ public function superfluousUsers_areWithoutGroups(): void
+ {
+ $viewers = new Viewers([
+ $this->user(name:'Mark', group:'Blue'),
+ $this->user(name:'Mark', group:'Blue'),
+ $this->user(name:'Tom'),
+ ], 0);
+ $this->assertSame(1, $viewers->usersSuperfluous(0));
+ }
+
+ private function usersOfSize(int $size): array
+ {
+ return \array_fill(0, $size, $this->user());
+ }
+
+ private function user(string $name = null, string $group = null): ViewerUser
+ {
+ return new ViewerUser($name ?? '', $group, null);
+ }
+}