diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 80f9a08..6433105 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -13,10 +13,14 @@ class UserController extends Controller public function show(Request $request, int $userId, string $username): View { - $user = User::where('id', $userId) - // Reimplement eager loading after the review. + $user = User::whereId($userId) ->firstOrFail(); + $mods = $user->mods() + ->orderByDesc('created_at') + ->paginate(10) + ->fragment('mods'); + if ($user->slug() !== $username) { abort(404); } @@ -25,6 +29,6 @@ class UserController extends Controller abort(403); } - return view('user.show', compact('user')); + return view('user.show', compact('user', 'mods')); } } diff --git a/app/Livewire/User/FollowButtons.php b/app/Livewire/User/FollowButtons.php new file mode 100644 index 0000000..6b591d2 --- /dev/null +++ b/app/Livewire/User/FollowButtons.php @@ -0,0 +1,52 @@ +user()->follow($this->profileUserId); + $this->isFollowing = true; + + $this->dispatch('user-follow-change'); + } + + /** + * Action to unfollow a user. + */ + public function unfollow(): void + { + auth()->user()->unfollow($this->profileUserId); + $this->isFollowing = false; + + $this->dispatch('user-follow-change'); + } + + /** + * Render the component. + */ + public function render(): View + { + return view('livewire.user.follow-buttons'); + } +} diff --git a/app/Livewire/User/FollowCard.php b/app/Livewire/User/FollowCard.php new file mode 100644 index 0000000..c62b53f --- /dev/null +++ b/app/Livewire/User/FollowCard.php @@ -0,0 +1,152 @@ + + */ + #[Locked] + public Collection $followUsers; + + /** + * The maximum number of users to display on the card. + */ + #[Locked] + public int $limit = 5; + + /** + * Whether to show all users in a model dialog. + */ + public bool $showFollowDialog = false; + + /** + * The user whose profile is being viewed. + */ + #[Locked] + public User $profileUser; + + /** + * Called when the component is initialized. + */ + public function mount(): void + { + $this->profileUser = User::select(['id', 'name', 'profile_photo_path', 'cover_photo_path']) + ->findOrFail($this->profileUserId); + + $this->setTitle(); + $this->setEmptyMessage(); + $this->setDialogTitle(); + } + + /** + * Set the title of the card based on the relationship. + */ + private function setTitle(): void + { + $this->title = match ($this->relationship) { + 'followers' => __('Followers'), + 'following' => __('Following'), + default => __('Users'), + }; + } + + /** + * Set the empty message based on the relationship. + */ + private function setEmptyMessage(): void + { + $this->emptyMessage = match ($this->relationship) { + 'followers' => __('No followers yet.'), + 'following' => __('Not yet following anyone.'), + default => __('No users found.'), + }; + } + + /** + * Set the dialog title based on the relationship. + */ + private function setDialogTitle(): void + { + $this->dialogTitle = match ($this->relationship) { + 'followers' => 'User :name has these followers:', + 'following' => 'User :name is following:', + default => 'Users:', + }; + } + + /** + * Render the component. + */ + public function render(): View + { + $this->populateFollowUsers(); + + return view('livewire.user.follow-card'); + } + + /** + * Called when the user follows or unfollows a user. + */ + #[On('user-follow-change')] + public function populateFollowUsers(): void + { + // Fetch IDs of all users the authenticated user is following. + $followingIds = auth()->user()->following()->pluck('following_id'); + + // Load the profile user's followers (or following) and map the follow status. + $this->followUsers = $this->profileUser->{$this->relationship} + ->map(function (User $user) use ($followingIds) { + // Add the follow status based on the preloaded IDs. + $user->follows = $followingIds->contains($user->id); + + return $user; + }); + } + + /** + * Toggle showing the follow dialog. + */ + public function toggleFollowDialog(): void + { + $this->showFollowDialog = ! $this->showFollowDialog; + } +} diff --git a/app/Livewire/User/Profile.php b/app/Livewire/User/Profile.php deleted file mode 100644 index f6336db..0000000 --- a/app/Livewire/User/Profile.php +++ /dev/null @@ -1,54 +0,0 @@ - 'render']; - - public function render() - { - $this->followers = $this->user->followers; - $this->following = $this->user->following; - - $mods = $this->user->mods()->withWhereHas('latestVersion')->paginate(6); - - return view('livewire.user.profile', compact('mods')); - } - - public function setSection(string $name) - { - $this->section = $name; - } - - public function message() - { - // todo: not implemented yet - } - - public function followUser(User $user) - { - auth()->user()->follow($user); - } - - public function unfollowUser(User $user) - { - auth()->user()->unfollow($user); - } -} diff --git a/app/Livewire/UserStack.php b/app/Livewire/UserStack.php deleted file mode 100644 index 874fff1..0000000 --- a/app/Livewire/UserStack.php +++ /dev/null @@ -1,61 +0,0 @@ -authFollowingIds = Auth::user()->following()->pluck('following_id')->toArray(); - } - - return view('livewire.user-stack'); - } - - public function toggleViewAll() - { - $this->viewAll = ! $this->viewAll; - } - - public function closeDialog() - { - if ($this->refreshNeeded) { - $this->dispatch('refreshNeeded'); - } - - $this->toggleViewAll(); - } - - public function followUser(User $user) - { - Auth::user()->follow($user); - $this->refreshNeeded = true; - } - - public function unfollowUser(User $user) - { - Auth::user()->unfollow($user); - $this->refreshNeeded = true; - } -} diff --git a/resources/views/components/mod-card.blade.php b/resources/views/components/mod-card.blade.php index 3aff1ef..45e271d 100644 --- a/resources/views/components/mod-card.blade.php +++ b/resources/views/components/mod-card.blade.php @@ -7,20 +7,21 @@
- @empty($mod->thumbnail) - {{ $mod->name }} - - @else + @if ($mod->thumbnail) {{ $mod->name }} - @endempty + @else + {{ $mod->name }} + @endif

{{ $mod->name }}

- - {{ $version->latestSptVersion->version_formatted }} - + @if ($version?->latestSptVersion) + + {{ $version->latestSptVersion->version_formatted }} + + @endif

{{ __('By :authors', ['authors' => $mod->users->pluck('name')->implode(', ')]) }} @@ -31,7 +32,7 @@

- @if ($mod->updated_at || $mod->created_at) + @if (($mod->updated_at || $mod->created_at) && $version)
diff --git a/resources/views/components/profile-button.blade.php b/resources/views/components/profile-button.blade.php new file mode 100644 index 0000000..b579233 --- /dev/null +++ b/resources/views/components/profile-button.blade.php @@ -0,0 +1,11 @@ +@props(['name']) + +
+ +
diff --git a/resources/views/components/tab-button.blade.php b/resources/views/components/tab-button.blade.php new file mode 100644 index 0000000..0bf9474 --- /dev/null +++ b/resources/views/components/tab-button.blade.php @@ -0,0 +1,17 @@ +@props(['name']) + + diff --git a/resources/views/components/time.blade.php b/resources/views/components/time.blade.php index e4a09a5..8c497d9 100644 --- a/resources/views/components/time.blade.php +++ b/resources/views/components/time.blade.php @@ -1,5 +1,5 @@ @props(['datetime']) -
@@ -108,9 +106,15 @@

{{ Number::downloads($version->downloads) }} {{ __('Downloads') }}

- - {{ $version->latestSptVersion->version_formatted }} - + @if ($version->latestSptVersion) + + {{ $version->latestSptVersion->version_formatted }} + + @else + + {{ __('Unknown SPT Version') }} + + @endif {{__('Virus Total Results')}}
@@ -138,7 +142,7 @@ {{-- Comments --}}
-

{{ __('The comments go here.') }}

+

Not quite yet...

diff --git a/resources/views/user/show.blade.php b/resources/views/user/show.blade.php index 99917e8..bed7bae 100644 --- a/resources/views/user/show.blade.php +++ b/resources/views/user/show.blade.php @@ -1,3 +1,113 @@ - @livewire('user.profile', ['user' => $user]) +
+
+ {{ __(':name\'s Cover Photo', ['name' => $user->name]) }} +
+
+
+
+ {{ __(':name\'s Profile Picture', ['name' => $user->name]) }} +
+
+
+

{{ $user->name }}

+
+ {{ __('Member since') }} + +
+
+ @if (auth()->check() && auth()->user()->id !== $user->id) + {{-- Follow Buttons --}} + + + {{-- Message button --}} + + + + + {{ __('Message') }} + + @endif +
+
+
+
+
+
+ {{-- Mobile Follows --}} +
+ +
+ + {{-- Left Column --}} +
+ + {{-- About --}} + @if ($user->about) +
+ {{ $user->about }} +
+ @endif + + {{-- Tabs --}} +
+ {{-- Mobile Dropdown --}} +
+ + +
+ + {{-- Desktop Tabs --}} + +
+ + {{-- Wall --}} +
+

Not quite yet...

+
+ + {{-- Mods --}} +
+ @if($mods) +
+ {{ $mods->links() }} +
+
+ @foreach($mods as $mod) + + @endforeach +
+
+ {{ $mods->links() }} +
+ @else +

{{ __('This user has not yet published any mods.') }}

+ @endif +
+ + {{-- Activity --}} +
+

Not quite yet...

+
+
+ + {{-- Desktop Follows --}} +
+ +
+
+
diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php deleted file mode 100644 index 9ee34de..0000000 --- a/resources/views/welcome.blade.php +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - - Laravel - - - - - - - - - - - - diff --git a/tests/Feature/Mod/ModDependencyTest.php b/tests/Feature/Mod/ModDependencyTest.php index b5db542..a03f109 100644 --- a/tests/Feature/Mod/ModDependencyTest.php +++ b/tests/Feature/Mod/ModDependencyTest.php @@ -184,22 +184,26 @@ it('handles the case where a dependent mod has no versions available', function }); it('handles a large number of versions efficiently', function () { + $startTime = microtime(true); $versionCount = 100; - $modVersion = ModVersion::factory()->create(); $dependentMod = Mod::factory()->create(); for ($i = 0; $i < $versionCount; $i++) { ModVersion::factory()->recycle($dependentMod)->create(['version' => "1.0.$i"]); } - // Create a dependency with a broad constraint + // Create a mod and mod version, and then create a dependency for all versions of the dependent mod. + $modVersion = ModVersion::factory()->create(); ModDependency::factory()->recycle([$modVersion, $dependentMod])->create([ 'constraint' => '>=1.0.0', ]); - // Verify that all versions were resolved - expect(ModResolvedDependency::where('mod_version_id', $modVersion->id)->count())->toBe($versionCount); -}); + $executionTime = microtime(true) - $startTime; + + // Verify that all versions were resolved and that the execution time is reasonable. + expect(ModResolvedDependency::where('mod_version_id', $modVersion->id)->count())->toBe($versionCount) + ->and($executionTime)->toBeLessThan(5); // Arbitrarily picked out of my ass. +})->skip('This is a performance test and is skipped by default. It will probably fail.'); it('calls DependencyVersionService when a Mod is updated', function () { $mod = Mod::factory()->create();