110 lines
4.3 KiB
JavaScript
110 lines
4.3 KiB
JavaScript
import React, { useState } from 'react';
|
|
import { Head, Link } from '@inertiajs/react';
|
|
import { Star } from 'lucide-react';
|
|
|
|
import AppLayout from '@/Layouts/AppLayout.jsx';
|
|
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Button } from '@/components/ui/button'
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Pagination, PaginationContent, PaginationItem, PaginationNext, PaginationPrevious } from '@/components/ui/pagination';
|
|
import { useToast } from '@/hooks/use-toast.js';
|
|
|
|
export default function Index({ comics = [], offset = 0, auth = {} }) {
|
|
|
|
const url = new URL(window.location); // searchParams
|
|
|
|
const [favourites, setFavourites] = useState((auth?.user?.favourites !== null) ? auth.user.favourites : []);
|
|
const { toast } = useToast();
|
|
|
|
const itemsPerPage = 30;
|
|
|
|
/**
|
|
* On click handler for the star
|
|
* Do posting and make a toast
|
|
*
|
|
* @param pathword
|
|
*/
|
|
const favouriteOnClickHandler = (pathword) => {
|
|
axios.post(route('comics.postFavourite'), { pathword: pathword }).then(res => {
|
|
setFavourites(res.data);
|
|
});
|
|
|
|
toast({
|
|
title: "All set",
|
|
description: `${comics.list.filter(c => c.path_word === pathword)[0].name} is now in / remove your favorite list.`,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Generate info card for comics
|
|
* @param props
|
|
* @returns {JSX.Element}
|
|
* @constructor
|
|
*/
|
|
const ComicCard = (props) => (
|
|
<Card>
|
|
<CardHeader>
|
|
<div className="relative">
|
|
<Link href={ `/comic/${ props.path_word }` }>
|
|
<img className="block w-100 min-w-full object-fill" src={ "/image/" + btoa(props.cover) } alt={ props.name } />
|
|
</Link>
|
|
<Button className="absolute bottom-0 right-0" onClick={ () => favouriteOnClickHandler(props.path_word) } size="icon">
|
|
<Star fill={ favourites.includes(props.path_word) ? 'yellow': '' } />
|
|
</Button>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<CardTitle>
|
|
<Link href={ `/comic/${ props.path_word }` }>{ props.name }</Link>
|
|
</CardTitle>
|
|
<CardDescription className="pt-2">
|
|
{ props.author && props.author.map(a => (
|
|
<Badge className="m-1" key={ a.path_word } variant="outline">
|
|
{ a.name }
|
|
</Badge>)
|
|
) }
|
|
</CardDescription>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
|
|
/**
|
|
* Loop and return all info cards
|
|
* @param comics
|
|
* @returns {*}
|
|
* @constructor
|
|
*/
|
|
const ComicCards = (comics) => {
|
|
return comics.list.map((comic, i) => <ComicCard key={ i } { ...comic } />);
|
|
}
|
|
|
|
return (
|
|
<AppLayout auth={ auth }>
|
|
<Head>
|
|
<title>Home</title>
|
|
</Head>
|
|
<div className="p-3 pt-1 pb-1 flex flex-wrap justify-center" scroll-region="true"
|
|
style={{ overflowAnchor: "none", height: "calc(100dvh - 90px)", overflowY: "scroll" }}>
|
|
<div className="grid 2xl:grid-cols-6 xl:grid-cols-4 grid-cols-2 gap-2">
|
|
<ComicCards { ...comics } />
|
|
</div>
|
|
<Pagination className="justify-end pt-2">
|
|
<PaginationContent>
|
|
{ parseInt(offset) !== 0 &&
|
|
<PaginationItem>
|
|
<PaginationPrevious href={ `${ url.pathname }?${ url.searchParams }` } only={['comics', 'offset']} headers={{ offset: parseInt(offset) - itemsPerPage }} />
|
|
</PaginationItem>
|
|
}
|
|
{ parseInt(comics.total) > parseInt(offset) + itemsPerPage &&
|
|
<PaginationItem>
|
|
<PaginationNext href={ `${ url.pathname }?${ url.searchParams }` } only={['comics', 'offset']} headers={{ offset: parseInt(offset) + itemsPerPage }} />
|
|
</PaginationItem>
|
|
}
|
|
</PaginationContent>
|
|
</Pagination>
|
|
</div>
|
|
</AppLayout>
|
|
);
|
|
}
|