From bce3a7c23eb03e557e9b1bf2623fa6aa0e654bab Mon Sep 17 00:00:00 2001 From: ysandler Date: Sat, 3 May 2025 16:41:47 -0500 Subject: [PATCH] feat: reject inbound hold requests --- .../(frontend)/books/[bookId]/page.client.tsx | 2 - src/app/(frontend)/page.tsx | 46 ++-- src/components/Feed/UserFeed.tsx | 3 + src/components/Manage/HoldRequests.tsx | 202 +++++++++++------- src/components/Manage/Manage.tsx | 9 +- src/serverActions/GetUserRepos.ts | 44 ++++ src/serverActions/RejectHoldRequests.ts | 31 +++ 7 files changed, 231 insertions(+), 106 deletions(-) create mode 100644 src/serverActions/GetUserRepos.ts create mode 100644 src/serverActions/RejectHoldRequests.ts diff --git a/src/app/(frontend)/books/[bookId]/page.client.tsx b/src/app/(frontend)/books/[bookId]/page.client.tsx index 4d0520b..7ccc646 100644 --- a/src/app/(frontend)/books/[bookId]/page.client.tsx +++ b/src/app/(frontend)/books/[bookId]/page.client.tsx @@ -86,8 +86,6 @@ export default function BookByIdPageClient(props: Props) { const { user } = useGlobal() - console.log(user) - const [isRequestingCopy, setIsRequestingCopy] = useState(false) const [selectedRepository, setSelectedRepository] = useState( repos.length ? repos[0] : null, diff --git a/src/app/(frontend)/page.tsx b/src/app/(frontend)/page.tsx index a702757..7aeb43d 100644 --- a/src/app/(frontend)/page.tsx +++ b/src/app/(frontend)/page.tsx @@ -90,32 +90,32 @@ export default async function HomePage() { return (
-
- {user ? ( - - - Your Feed - Search - Manage - +
+ {user ? ( + + + Your Feed + Search + Manage + - - {user && } - + + {user && } + - - - + + + - - - - - ) : ( -
- -
- )} + + + + + ) : ( +
+ +
+ )}
) diff --git a/src/components/Feed/UserFeed.tsx b/src/components/Feed/UserFeed.tsx index bc19572..ff6c302 100644 --- a/src/components/Feed/UserFeed.tsx +++ b/src/components/Feed/UserFeed.tsx @@ -42,6 +42,9 @@ const UserFeed = async (props: Props) => { isCheckedOut: { not_equals: true, }, + isRejected: { + not_equals: true, + }, }, })) as PaginatedDocs diff --git a/src/components/Manage/HoldRequests.tsx b/src/components/Manage/HoldRequests.tsx index efc7daf..59b65e9 100644 --- a/src/components/Manage/HoldRequests.tsx +++ b/src/components/Manage/HoldRequests.tsx @@ -3,101 +3,151 @@ import { Author, Book, HoldRequest, Repository, User } from '@/payload-types' import { Button } from '../ui/button' import Image from 'next/image' import ApproveHoldRequestModal from './ApproveHoldRequestModal' -import { useState } from 'react' +import { useCallback, useState } from 'react' import CheckoutFromHoldModal from './CheckoutFromHoldModal' +import rejectHoldRequest from '@/serverActions/RejectHoldRequests' +import { getUserRepos } from '@/serverActions/GetUserRepos' +import { Loader2 } from 'lucide-react' +import { toast } from 'sonner' type Props = { repos: PaginatedDocs | null + user: User } const HoldRequestNotifications = (props: Props) => { - const { repos } = props + const [repos, setRepos] = useState | null>(props.repos) const [openedModalId, setOpenedModalId] = useState(null) const totalHoldNotifications = repos?.docs.flatMap((r) => r.holdRequests?.docs).length || 0 + const [isRejectingId, setIsRejectingId] = useState() + + const handleRejectHoldClick = useCallback( + async (holdRequestId: number) => { + if (isRejectingId) return + setIsRejectingId(holdRequestId) + const rejectRequest = await rejectHoldRequest({ holdRequestId }) + + if (rejectRequest?.isRejected) { + const updatedRepos = await getUserRepos({ userId: props.user.id }) + setRepos(updatedRepos) + toast('Request was rejected') + } else { + toast('Error rejecting request') + } + + setIsRejectingId(null) + }, + [isRejectingId, setIsRejectingId, props.user.id], + ) + const holdRequestsByRepoElements = repos?.docs.map((r) => { return (
    - {r.holdRequests?.docs?.map((h) => { - const hold = h as HoldRequest - const book = hold.book as Book - const authors = book.authors as Author[] - const dateRequested = hold.dateRequested ? new Date(hold.dateRequested) : new Date() - const holdingUntilDate = hold.holdingUntilDate - ? new Date(hold.holdingUntilDate) - : new Date() - const userRequested = hold.userRequested as User - const userName = `${userRequested.firstName} ${userRequested.lastName}` + {r.holdRequests?.docs + ?.map((h) => { + const hold = h as HoldRequest + const book = hold.book as Book + const authors = book.authors as Author[] + const dateRequested = hold.dateRequested ? new Date(hold.dateRequested) : new Date() + const holdingUntilDate = hold.holdingUntilDate + ? new Date(hold.holdingUntilDate) + : new Date() + const userRequested = hold.userRequested as User + const userName = `${userRequested.firstName} ${userRequested.lastName}` - return ( -
  • -
    -
    -
    -

    {book.title}

    + if (hold.isRejected) return null + + return ( +
  • +
    +
    +
    +

    {book.title}

    +
    +

    + {authors.map((a) => a.lf).join(' | ')} +

    + {hold.isHolding ? ( + + {userName} Until + + + ) : ( + + + {userName} + + )}
    -

    - {authors.map((a) => a.lf).join(' | ')} -

    - {hold.isHolding ? ( - - {userName} Until - - - ) : ( - - - {userName} - - )} +
    - -
-
-
- - +
+
+ - {hold.isHolding ? ( - setOpenedModalId(null)} - holdRequest={hold} - /> - ) : ( - setOpenedModalId(null)} - holdRequest={hold} - /> - )} + + + {hold.isHolding ? ( + setOpenedModalId(null)} + holdRequest={hold} + /> + ) : ( + setOpenedModalId(null)} + holdRequest={hold} + /> + )} +
-
- - ) - })} + + ) + }) + .filter((element) => !!element)} ) }) diff --git a/src/components/Manage/Manage.tsx b/src/components/Manage/Manage.tsx index 89f2761..2d5a537 100644 --- a/src/components/Manage/Manage.tsx +++ b/src/components/Manage/Manage.tsx @@ -1,6 +1,6 @@ 'use client' -import { Checkout, Repository } from '@/payload-types' +import { Checkout, Repository, User } from '@/payload-types' import { PaginatedDocs } from 'payload' import RepoList from './RepoList' import HoldRequestNotifications from './HoldRequests' @@ -9,9 +9,10 @@ import CheckedOutBooks from './CheckedOutBooks' type Props = { repos: PaginatedDocs | null checkouts: PaginatedDocs | null + user: User | null } const Manage = (props: Props) => { - const { repos, checkouts } = props + const { repos, checkouts, user } = props return (
@@ -19,9 +20,7 @@ const Manage = (props: Props) => {
-
- -
+
{user && }
diff --git a/src/serverActions/GetUserRepos.ts b/src/serverActions/GetUserRepos.ts new file mode 100644 index 0000000..28eb757 --- /dev/null +++ b/src/serverActions/GetUserRepos.ts @@ -0,0 +1,44 @@ +'use server' + +import { getPayload } from 'payload' +import config from '@/payload.config' +import { PaginatedDocs } from "payload" +import { Repository } from '@/payload-types' + +type Props = { + userId: number +} +export const getUserRepos = async (props: Props) => { + const { userId } = props + + const payloadConfig = await config + const payload = await getPayload({ config: payloadConfig }) + + let userRepos: PaginatedDocs | null = null + if (userId) + userRepos = (await payload.find({ + collection: 'repositories', + depth: 3, + limit: 10, + select: { + name: true, + abbreviation: true, + image: true, + description: true, + dateOpenToPublic: true, + holdRequests: true, + }, + where: { + 'owner.id': { + equals: userId, + }, + }, + joins: { + holdRequests: { + limit: 100, + }, + }, + })) as PaginatedDocs + + return userRepos +} diff --git a/src/serverActions/RejectHoldRequests.ts b/src/serverActions/RejectHoldRequests.ts new file mode 100644 index 0000000..14ce701 --- /dev/null +++ b/src/serverActions/RejectHoldRequests.ts @@ -0,0 +1,31 @@ +'use server' + +import { getPayload } from 'payload' +import config from '@/payload.config' +import { HoldRequest } from '@/payload-types' + +type Props = { + holdRequestId: number, +} +export const rejectHoldRequest = async (props: Props): Promise => { + const { holdRequestId } = props + + const payloadConfig = await config + const payload = await getPayload({ config: payloadConfig }) + + try { + const updatedHold = await payload.update({ + collection: 'holdRequests', + id: holdRequestId, + data: { + isRejected: true, + isHolding: false, + } + }) + return updatedHold + } catch (_) { + return null + } +} + +export default rejectHoldRequest