Skip to content

Commit 3bb2c02

Browse files
committed
Shortlist refactoring
1 parent 993d91a commit 3bb2c02

File tree

4 files changed

+48
-37
lines changed

4 files changed

+48
-37
lines changed

app/Http/Controllers/PuppyController.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
use Illuminate\Http\Request;
88
use Illuminate\Support\Facades\Storage;
99
use Inertia\Inertia;
10-
use App\Actions\OptimizeWebpImageAction;
10+
use Intervention\Image\Laravel\Facades\Image;
11+
use Illuminate\Support\Str;
1112

1213
class PuppyController extends Controller
1314
{
@@ -31,6 +32,9 @@ public function index(Request $request)
3132
->paginate(9)
3233
->withQueryString()
3334
),
35+
'likedPuppies' => $request->user()
36+
? PuppyResource::collection($request->user()->likedPuppies)
37+
: [],
3438
'filters' => [
3539
'search' => $search,
3640
],
@@ -42,7 +46,7 @@ public function index(Request $request)
4246
// ------------------------------
4347
public function like(Request $request, Puppy $puppy)
4448
{
45-
sleep(1);
49+
usleep(200000);
4650
$puppy->likedBy()->toggle($request->user()->id);
4751
return back();
4852
}
@@ -52,7 +56,7 @@ public function like(Request $request, Puppy $puppy)
5256
// ------------------------------
5357
public function store(Request $request)
5458
{
55-
sleep(2);
59+
usleep(200000);
5660
// Validate the data
5761
$request->validate([
5862
'name' => 'required|string|max:255',
@@ -64,11 +68,20 @@ public function store(Request $request)
6468
$image_url = null;
6569
if ($request->hasFile('image')) {
6670

67-
$optimized = (new OptimizeWebpImageAction())->handle($request->file('image'));
71+
// Image optimization
72+
$image = Image::read($request->file('image'));
6873

69-
$path = 'puppies/' . $optimized['fileName'];
74+
// Scale down only
75+
if ($image->width() > 1000) {
76+
$image->scale(width: 1000);
77+
}
78+
79+
$webpEncoded = $image->toWebp(quality: 95)->toString();
80+
81+
$fileName = Str::random() . '.webp';
82+
$path = 'puppies/' . $fileName;
7083

71-
$stored = Storage::disk('public')->put($path, $optimized['webpString']);
84+
$stored = Storage::disk('public')->put($path, $webpEncoded);
7285

7386
if (!$stored) {
7487
return back()->withErrors(['image' => 'Failed to upload image.']);

app/Http/Resources/PuppyResource.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ public function toArray(Request $request): array
1919
'name' => $this->name,
2020
'trait' => $this->trait,
2121
'imageUrl' => $this->image_url,
22-
'likedBy' => UserResource::collection($this->whenLoaded('likedBy'))->pluck('id'),
22+
'likedBy' => $this->whenLoaded('likedBy', function () {
23+
return $this->likedBy->pluck('id');
24+
}),
2325
'user' => UserResource::make($this->whenLoaded('user'))
2426
];
2527
}

resources/js/components/Shortlist.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,28 @@ import { Puppy, SharedData } from '../types';
55
// TODO: Make sure all the liked puppies are showing, not just the ones from the current page.
66
export function Shortlist({ puppies }: { puppies: Puppy[] }) {
77
const { auth } = usePage<SharedData>().props;
8+
const firstFivePuppies = puppies.slice(0, 5);
9+
const extraPuppiesCount = puppies.length - firstFivePuppies.length;
10+
811
return (
912
<div>
1013
<h2 className="flex items-center gap-2 font-medium">
1114
<span>Your shortlist</span>
1215
<Heart className="fill-pink-500 stroke-pink-500" />
1316
</h2>
1417
<ul className="mt-4 flex flex-wrap gap-4">
15-
{puppies
16-
.filter((pup) => pup.likedBy.includes(auth.user?.id))
17-
.map((puppy) => (
18-
<li
19-
key={puppy.id}
20-
className="relative flex items-center overflow-clip rounded-md bg-white shadow-sm ring ring-black/5 transition duration-100 starting:scale-0 starting:opacity-0"
21-
>
22-
<img height={32} width={32} alt={puppy.name} className="aspect-square w-8 object-cover" src={puppy.imageUrl} />
23-
<p className="px-3 text-sm text-slate-800">{puppy.name}</p>
24-
<DeleteButton id={puppy.id} />
25-
</li>
26-
))}
18+
{firstFivePuppies.map((puppy) => (
19+
<li
20+
key={puppy.id}
21+
className="relative flex items-center overflow-clip rounded-md bg-white shadow-sm ring ring-black/5 transition duration-100 starting:scale-0 starting:opacity-0"
22+
>
23+
<img height={32} width={32} alt={puppy.name} className="aspect-square w-8 object-cover" src={puppy.imageUrl} />
24+
<p className="px-3 text-sm text-slate-800">{puppy.name}</p>
25+
<DeleteButton id={puppy.id} />
26+
</li>
27+
))}
28+
29+
{extraPuppiesCount > 0 && <li className="self-center text-sm text-slate-800">+{extraPuppiesCount} more</li>}
2730
</ul>
2831
</div>
2932
);

resources/js/pages/puppies/index.tsx

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,22 @@ import { Filters, PaginatedResponse, Puppy, SharedData } from '@/types';
1010
import { usePage } from '@inertiajs/react';
1111
import { useRef } from 'react';
1212

13-
export default function App({ puppies, filters }: { puppies: PaginatedResponse<Puppy>; filters: Filters }) {
13+
export default function App({ puppies, likedPuppies, filters }: { puppies: PaginatedResponse<Puppy>; likedPuppies: Puppy[]; filters: Filters }) {
14+
const { auth } = usePage<SharedData>().props;
15+
const mainRef = useRef<HTMLElement>(null);
1416
return (
1517
<PageWrapper>
1618
<Container>
1719
<Header />
18-
<Main paginatedPuppies={puppies} filters={filters} />
20+
<main ref={mainRef} className="scroll-mt-6">
21+
<div className="mt-24 grid gap-8 sm:grid-cols-2">
22+
<Search filters={filters} />
23+
{auth.user && <Shortlist puppies={likedPuppies} />}
24+
</div>
25+
<PuppiesList puppies={puppies} />
26+
{auth.user && <NewPuppyForm mainRef={mainRef} />}
27+
</main>
1928
</Container>
2029
</PageWrapper>
2130
);
2231
}
23-
24-
function Main({ paginatedPuppies, filters }: { paginatedPuppies: PaginatedResponse<Puppy>; filters: Filters }) {
25-
const { auth } = usePage<SharedData>().props;
26-
const mainRef = useRef<HTMLElement>(null);
27-
28-
return (
29-
<main ref={mainRef} className="scroll-mt-6">
30-
<div className="mt-24 grid gap-8 sm:grid-cols-2">
31-
<Search filters={filters} />
32-
{auth.user && <Shortlist puppies={paginatedPuppies.data} />}
33-
</div>
34-
<PuppiesList puppies={paginatedPuppies} />
35-
{auth.user && <NewPuppyForm mainRef={mainRef} />}
36-
</main>
37-
);
38-
}

0 commit comments

Comments
 (0)