Skip to content

Commit

Permalink
Merge pull request #404 from NYPL/SCC-3762/hold-confirmation-server-f…
Browse files Browse the repository at this point in the history
…unctions

SCC-3762 - Hold Confirmation Server Functions
  • Loading branch information
EdwinGuzman authored Nov 26, 2024
2 parents c07deff + 4a1929c commit 5d8940a
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 12 deletions.
70 changes: 64 additions & 6 deletions pages/hold/confirmation/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ import {
SITE_NAME,
HOLD_PAGE_HEADING,
EDD_PAGE_HEADING,
PATHS,
} from "../../../src/config/constants"

import HoldConfirmationFAQ from "../../../src/components/HoldPages/HoldConfirmationFAQ"
// import HoldItemDetails from "../../../src/components/HoldPages/HoldItemDetails"

import { fetchHoldDetails } from "../../../src/server/api/hold"

import initializePatronTokenAuth, {
doRedirectBasedOnNyplAccountRedirects,
getLoginRedirect,
} from "../../../src/server/auth"

interface HoldConfirmationPageProps {
isEDD?: boolean
}
Expand Down Expand Up @@ -57,11 +65,61 @@ export default function HoldConfirmationPage({
)
}

export async function getServerSideProps({ query }) {
const { pickupLocation } = query
return {
props: {
isEDD: pickupLocation === "edd",
},
export async function getServerSideProps({ req, res, query }) {
const { pickupLocation, requestId } = query
// authentication redirect
const patronTokenResponse = await initializePatronTokenAuth(req.cookies)
const isAuthenticated = patronTokenResponse.isTokenValid
const redirectTrackerCookie = req.cookies["nyplAccountRedirects"]
const redirectCount = parseInt(redirectTrackerCookie, 10) || 0
const redirectBasedOnNyplAccountRedirects =
doRedirectBasedOnNyplAccountRedirects(redirectCount)

// If we end up not authenticated 3 times after redirecting to the login url, don't redirect.
if (redirectBasedOnNyplAccountRedirects && !isAuthenticated) {
res.setHeader(
"Set-Cookie",
`nyplAccountRedirects=${
redirectCount + 1
}; Max-Age=10; path=/; domain=.nypl.org;`
)
const redirect = getLoginRedirect(
req,
`${PATHS.HOLD_CONFIRMATION}?pickupLocation=${pickupLocation}&requestId=${requestId}`
)

return {
redirect: {
destination: redirect,
permanent: false,
},
}
}

const patronId = patronTokenResponse?.decodedPatron?.sub

try {
const { patronId: patronIdFromResponse } = await fetchHoldDetails(requestId)

if (patronId !== patronIdFromResponse) {
throw new Error(
"Error in HoldConfirmationPage getServerSideProps: Logged in patron Id doesn't match the patron Id in the hold request."
)
}

return {
props: {
isEDD: pickupLocation === "edd",
},
}
} catch (error) {
console.log(error)

return {
redirect: {
destination: PATHS["404"],
permanent: false,
},
}
}
}
9 changes: 8 additions & 1 deletion pages/hold/request/[id]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import { SITE_NAME, BASE_URL, PATHS } from "../../../../src/config/constants"
import useLoading from "../../../../src/hooks/useLoading"

import { fetchBib } from "../../../../src/server/api/bib"
import { fetchDeliveryLocations } from "../../../../src/server/api/hold"
import {
fetchDeliveryLocations,
fetchHoldRequestEligibility,
} from "../../../../src/server/api/hold"

import initializePatronTokenAuth, {
doRedirectBasedOnNyplAccountRedirects,
Expand Down Expand Up @@ -210,6 +213,10 @@ export async function getServerSideProps({ params, req, res }) {
try {
const patronId = patronTokenResponse?.decodedPatron?.sub

// TODO: implement this function
const holdRequestEligibility = await fetchHoldRequestEligibility(patronId)
console.log("holdRequestEligibility", holdRequestEligibility)

// fetch bib and item
const [bibId, itemId] = id.split("-")

Expand Down
63 changes: 58 additions & 5 deletions src/server/api/hold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import nyplApiClient from "../nyplApiClient"
import type {
EDDRequestParams,
HoldPostResult,
HoldDetailsResult,
} from "../../types/holdPageTypes"
import type {
DeliveryLocation,
Expand All @@ -12,6 +13,7 @@ import type {
import type {
DiscoveryHoldPostParams,
HoldRequestParams,
PatronEligibilityStatus,
} from "../../types/holdPageTypes"

import {
Expand Down Expand Up @@ -95,15 +97,12 @@ export async function postHoldRequest(
try {
const client = await nyplApiClient()
const holdPostResult = await client.post("/hold-requests", holdPostParams)
const { id: requestId } = holdPostResult.data
const requestId = holdPostResult?.data?.id

if (!requestId) {
console.error(
"postHoldRequest failed, no id returned from Discovery API",
holdPostResult
)
return {
status: 400,
errorMessage: holdPostResult?.data?.message,
}
}

Expand All @@ -113,6 +112,7 @@ export async function postHoldRequest(
requestId,
}
} catch (error) {
console.log("error", error)
console.error(
`Error posting hold request in postHoldRequest server function, itemId: ${itemId}`,
error.message
Expand All @@ -124,6 +124,59 @@ export async function postHoldRequest(
}
}

/**
* Getter function for hold request details.
*/
// TODO: Add return type
export async function fetchHoldDetails(
requestId: string
): Promise<HoldDetailsResult> {
try {
const client = await nyplApiClient()
const holdDetailsResult = await client.get(`/hold-requests/${requestId}`)
const { id, pickupLocation, patron } = holdDetailsResult.data

return {
requestId: id,
patronId: patron,
pickupLocation,
status: 200,
}
} catch (error) {
console.error(
`Error fetching hold request details in fetchHoldRequestDetails server function, requestId: ${requestId}`,
error.message
)

return { status: 400 }
}
}

/**
* Getter function for hold request eligibility for patrons.
*/
export async function fetchHoldRequestEligibility(
patronId: string
): Promise<PatronEligibilityStatus> {
const eligibilityEndpoint = `/patrons/${patronId}/hold-request-eligibility`

try {
const client = await nyplApiClient()
const eligibilityResult = await client.get(eligibilityEndpoint, {
cache: false,
})

return eligibilityResult as PatronEligibilityStatus
} catch (error) {
console.error(
`Error fetching hold request eligibility in fetchHoldRequestEligibility server function, patronId: ${patronId}`,
error.message
)

return { eligibility: false }
}
}

/**
* Post EDD requests to discovery API.
*/
Expand Down
19 changes: 19 additions & 0 deletions src/types/holdPageTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,25 @@ export interface HoldPostResult {
pickupLocation?: NYPLocationKey | "edd"
formInvalid?: boolean
requestId?: string
errorMessage?: string
}

export interface HoldDetailsResult {
status: HTTPStatusCode
pickupLocation?: NYPLocationKey | "edd"
patronId?: string
requestId?: string
errorMessage?: string
}

export interface PatronEligibilityStatus {
eligibility: boolean
expired?: boolean
blocked?: boolean
moneyOwed?: boolean
ptypeDisallowsHolds?: boolean
reachedHoldLimit?: boolean
hasIssues?: boolean
}

export interface DiscoveryHoldPostParams {
Expand Down

0 comments on commit 5d8940a

Please sign in to comment.