Skip to content

Commit

Permalink
Merge pull request #310 from SandipGyawali/dev
Browse files Browse the repository at this point in the history
pagination integration for backend and frontend
  • Loading branch information
AshuKr22 authored Nov 8, 2024
2 parents 4259e29 + 191bf08 commit 4788257
Show file tree
Hide file tree
Showing 13 changed files with 630 additions and 130 deletions.
6 changes: 2 additions & 4 deletions client/.env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
#tmdb
VITE_ACCESS_KEY=

#firebase-credentials
VITE_ACCESS_KEY= "your tmdb key"
VITE_API_KEY=
VITE_AUTH_DOMAIN=
VITE_PROJECT_ID=
VITE_STORAGE_BUCKET=
VITE_MESSAGING_SENDER_ID=
VITE_APP_ID=
VITE_API_BASE_URL=
Binary file modified client/bun.lockb
Binary file not shown.
117 changes: 117 additions & 0 deletions client/src/components/ui/pagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import * as React from "react"
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react"

import { cn } from "@/lib/utils"
import { ButtonProps, buttonVariants } from "@/components/ui/button"

const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
<nav
role="navigation"
aria-label="pagination"
className={cn("mx-auto flex w-full justify-center", className)}
{...props}
/>
)
Pagination.displayName = "Pagination"

const PaginationContent = React.forwardRef<
HTMLUListElement,
React.ComponentProps<"ul">
>(({ className, ...props }, ref) => (
<ul
ref={ref}
className={cn("flex flex-row items-center gap-1", className)}
{...props}
/>
))
PaginationContent.displayName = "PaginationContent"

const PaginationItem = React.forwardRef<
HTMLLIElement,
React.ComponentProps<"li">
>(({ className, ...props }, ref) => (
<li ref={ref} className={cn("", className)} {...props} />
))
PaginationItem.displayName = "PaginationItem"

type PaginationLinkProps = {
isActive?: boolean
} & Pick<ButtonProps, "size"> &
React.ComponentProps<"a">

const PaginationLink = ({
className,
isActive,
size = "icon",
...props
}: PaginationLinkProps) => (
<a
aria-current={isActive ? "page" : undefined}
className={cn(
buttonVariants({
variant: isActive ? "outline" : "ghost",
size,
}),
className
)}
{...props}
/>
)
PaginationLink.displayName = "PaginationLink"

const PaginationPrevious = ({
className,
...props
}: React.ComponentProps<typeof PaginationLink>) => (
<PaginationLink
aria-label="Go to previous page"
size="default"
className={cn("gap-1 pl-2.5", className)}
{...props}
>
<ChevronLeft className="h-4 w-4" />
<span>Previous</span>
</PaginationLink>
)
PaginationPrevious.displayName = "PaginationPrevious"

const PaginationNext = ({
className,
...props
}: React.ComponentProps<typeof PaginationLink>) => (
<PaginationLink
aria-label="Go to next page"
size="default"
className={cn("gap-1 pr-2.5", className)}
{...props}
>
<span>Next</span>
<ChevronRight className="h-4 w-4" />
</PaginationLink>
)
PaginationNext.displayName = "PaginationNext"

const PaginationEllipsis = ({
className,
...props
}: React.ComponentProps<"span">) => (
<span
aria-hidden
className={cn("flex h-9 w-9 items-center justify-center", className)}
{...props}
>
<MoreHorizontal className="h-4 w-4" />
<span className="sr-only">More pages</span>
</span>
)
PaginationEllipsis.displayName = "PaginationEllipsis"

export {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
}
268 changes: 213 additions & 55 deletions client/src/pages/Friends/Friends.tsx

Large diffs are not rendered by default.

133 changes: 108 additions & 25 deletions client/src/pages/List/UserList.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import React, { useState, useEffect } from "react"
import React, { useEffect, useState } from "react"
import { useNavigate } from "react-router-dom"
import { useAuth } from "@/hooks/useAuth"
import { getUserData } from "@/services/userService"
import { Plus, Search } from "lucide-react"
import { fetchMovieToList } from "@/services/userService"
import { ChevronDown, ChevronLeft, ChevronRight, Plus, Search } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { toast } from "react-toastify"
import CreateList from "../CreateList/CreateList"
import { Drawer } from "@/components/ui/drawer"
import { Trash } from "lucide-react"
import { deleteList } from "@/services/userService"
import { Pagination, PaginationContent, PaginationItem } from "@/components/ui/pagination"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import { useQuery } from "@tanstack/react-query"

interface Movie {
movie_id: string
Expand All @@ -28,34 +31,53 @@ interface List {
averageRating: number
}

interface UserData {
lists: List[]
}
const image_url = "https://image.tmdb.org/t/p"

const UserLists: React.FC = () => {
const [lists, setLists] = useState<List[]>([])
// const [lists, setLists] = useState<List[]>([])
const [isCreateListOpen, setIsCreateListOpen] = useState(false)
const { user } = useAuth()
const navigate = useNavigate()
const [searchQuery, setSearchQuery] = useState("")
const [isSearchVisible, setIsSearchVisible] = useState(false)
const [pagination, setPagination] = useState<{
page: number;
limit: number;
totalPages: number;
}>({
page: 1,
limit: 5,
totalPages: 1
});

useEffect(() => {
const fetchLists = async () => {
if (user?.uid) {
try {
const userData: UserData = await getUserData(user.uid)
setLists(userData.lists)
} catch (error) {
console.error("Error fetching user lists:", error)
toast.error("Failed to fetch your lists. Please try again.")
}
const fetchLists = async () => {
if (user?.uid) {
try {
const listData: any = await fetchMovieToList(user.uid, pagination.page, pagination.limit);
return listData;
} catch (error) {
console.error("Error fetching user lists:", error)
toast.error("Failed to fetch your lists. Please try again.")
}
}
}

fetchLists()
}, [user])
const {data: lists, isLoading: listIsLoading, refetch: refetchList} = useQuery({queryKey: ["lists"], queryFn: fetchLists});

useEffect(() => {
refetchList();
}, [pagination])

useEffect(() => {
if(lists?.meta[0]) {
setPagination((prev) => ({
...prev,
totalPages: lists?.meta[0]?.totalPages ?? prev.page,
}));
}
}, [lists]);

if(listIsLoading) return <>Loading...</>

const handleListClick = (listId: string) => {
navigate(`/list/${listId}`)
Expand All @@ -75,23 +97,31 @@ const UserLists: React.FC = () => {
setSearchQuery(e.target.value)
}

const filteredLists = lists.filter((list) =>
list.name.toLowerCase().includes(searchQuery.toLowerCase())
const filteredLists = lists.data[0].lists.filter((lists : any) =>
lists.name.toLowerCase().includes(searchQuery.toLowerCase())
)

const handleDeleteList = async (listId: string) => {
console.log("list id", listId)
try {
// Call your delete service or API here
await deleteList(listId) // Assuming deleteList is your API call
setLists((prevLists) =>
prevLists.filter((list) => list.list_id !== listId)
)
refetchList()
toast.success("List deleted successfully")
} catch (error) {
console.error("Error deleting list:", error)
toast.error("Failed to delete the list. Please try again.")
}
}

// pagination section methods and variables
const _limit = [5, 15, 25, 50, 75];

const handleLimitSelect = (limit: number) => {
setPagination(prev => ({
...prev,
limit
}));
}

return (
Expand All @@ -100,6 +130,27 @@ const UserLists: React.FC = () => {
<header className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-bold">LISTS</h1>
<div className="flex items-center space-x-2">
<DropdownMenu>
<DropdownMenuLabel>Row:</DropdownMenuLabel>
<DropdownMenuTrigger asChild>
<Button className="w-fit bg-gray-800 text-white hover:bg-gray-700">
{pagination.limit || "Row Limit"}
<ChevronDown className="ml-2 h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="max-h-[300px] overflow-y-auto bg-gray-800 text-white">
{
_limit.map((lim, index) => (
<DropdownMenuItem
key={`${lim}-${index}`}
onClick={() => handleLimitSelect(lim)}
>
{lim}
</DropdownMenuItem>
))
}
</DropdownMenuContent>
</DropdownMenu>
<Button
variant="outline"
className="rounded-full"
Expand Down Expand Up @@ -131,7 +182,7 @@ const UserLists: React.FC = () => {
/>
</div>
)}
{filteredLists.map((list) => (
{filteredLists.map((list: List) => (
<div
key={list.list_id}
className="relative bg-gray-800 rounded-lg overflow-hidden cursor-pointer transition-colors hover:bg-gray-700"
Expand Down Expand Up @@ -190,6 +241,38 @@ const UserLists: React.FC = () => {
</div>
</div>
))}
<Pagination>
<PaginationContent>
<PaginationItem>
<Button
onClick={() => (
setPagination((prev) => ({
...prev,
page: prev.page - 1
}))
)}
disabled={pagination.page === 1}
>
<ChevronLeft className="w-5 h-5"/>
Previous
</Button>
</PaginationItem>
<PaginationItem>
<Button
onClick={() =>
setPagination((prev) => ({
...prev,
page: prev.page + 1
}))
}
disabled={pagination.totalPages === pagination.page}
>
Next
<ChevronRight className="w-5 h-5"/>
</Button>
</PaginationItem>
</PaginationContent>
</Pagination>
</div>
</div>
<Drawer open={isCreateListOpen} onOpenChange={setIsCreateListOpen}>
Expand Down
16 changes: 8 additions & 8 deletions client/src/services/friendsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ export function useFriends() {
const { user } = useAuth()
const queryClient = useQueryClient()

const getFriends = async () => {
const getFriends = async ({page, limit} : {page: number; limit: number}) => {
const idToken = await user?.getIdToken()
const response = await axios.get(`${API_URL}/friends`, {
const response = await axios.get(`${API_URL}/friends?page=${page}&limit=${limit}`, {
headers: { Authorization: `Bearer ${idToken}` },
})
return response.data
Expand Down Expand Up @@ -72,9 +72,9 @@ export function useFriends() {
return response.data
}

const getPendingRequests = async () => {
const getPendingRequests = async ({page, limit}: {page: number, limit: number}) => {
const idToken = await user?.getIdToken()
const response = await axios.get(`${API_URL}/friends/requests`, {
const response = await axios.get(`${API_URL}/friends/requests?page=${page}&limit=${limit}`, {
headers: { Authorization: `Bearer ${idToken}` },
})
return response.data
Expand All @@ -93,10 +93,10 @@ export function useFriends() {
}

return {
useGetFriends: () =>
useGetFriends: ({page, limit}: {page: number, limit: number}) =>
useQuery({
queryKey: ["friends"],
queryFn: getFriends,
queryFn: () => getFriends({page, limit}),
}),
useSendFriendRequest: () =>
useMutation({
Expand All @@ -120,10 +120,10 @@ export function useFriends() {
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: ["friends"] }),
}),
useGetPendingRequests: () =>
useGetPendingRequests: ({page, limit}: {page: number, limit: number}) =>
useQuery({
queryKey: ["friendRequests"],
queryFn: getPendingRequests,
queryFn: () => getPendingRequests({page, limit}),
}),
useGetFriendData: (username: string) =>
useQuery({
Expand Down
Loading

0 comments on commit 4788257

Please sign in to comment.