Skip to content

Commit

Permalink
add display meta-properties
Browse files Browse the repository at this point in the history
  • Loading branch information
Petter Andersson committed Apr 16, 2024
1 parent 96e8b36 commit 9a3ddcd
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 27 deletions.
23 changes: 20 additions & 3 deletions src/adverts/advert-meta/advert-meta.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { normalizeRoles } from '../../login'
import type { HaffaUser } from '../../login/types'
import { isClaimOverdue } from '../advert-mutations/claims/mappers'
import {
getClaimReturnInfo,
hasCollects,
hasReservations,
isClaimOverdue,
} from '../advert-mutations/claims/mappers'
import { AdvertClaimType, AdvertType } from '../types'
import type { Advert, AdvertMeta } from '../types'

Expand Down Expand Up @@ -30,6 +35,10 @@ export const getAdvertMeta = (
const isNotArchived = !advert.archivedAt
const isArchived = !isNotArchived
const isOnMyWaitList = advert.waitlist.includes(user.id)
const isLendingAdvert = advert.lendingPeriod > 0
const canBook = isLendingAdvert && quantity - claimCount > 0
const isReservedBySome = hasReservations(advert.claims)
const isCollectedBySome = hasCollects(advert.claims)

const {
canEditOwnAdverts,
Expand Down Expand Up @@ -67,7 +76,7 @@ export const getAdvertMeta = (
canUnarchive:
isArchived && canArchiveOwnAdverts && (mine || canManageAllAdverts),
canRemove: canRemoveOwnAdverts && (mine || canManageAllAdverts),
canBook: false, // type === AdvertType.borrow,
canBook,
canReserve: isNotArchived && quantity > claimCount && canReserveAdverts,
canCancelReservation: myReservationCount > 0 && canReserveAdverts,
canCollect:
Expand All @@ -86,6 +95,10 @@ export const getAdvertMeta = (
canReturn: canManageReturns && hasSingleCollectClaim(advert),
reservedyMe: myReservationCount,
collectedByMe: myCollectedCount,
isLendingAdvert,
isReservedBySome,
isCollectedBySome,
returnInfo: getClaimReturnInfo(advert.claims, advert.lendingPeriod),
claims,
}
}
Expand All @@ -99,7 +112,7 @@ export const getAdvertMeta = (
canUnarchive:
isArchived && canArchiveOwnAdverts && (mine || canManageAllAdverts),
canRemove: canRemoveOwnAdverts && (mine || canManageAllAdverts),
canBook: false, // type === AdvertType.borrow,
canBook,
canReserve: false,
canCancelReservation: false,
canCollect: false,
Expand All @@ -109,6 +122,10 @@ export const getAdvertMeta = (
canReturn: false,
reservedyMe: myReservationCount,
collectedByMe: myCollectedCount,
isLendingAdvert,
isReservedBySome,
isCollectedBySome,
returnInfo: [],
claims: [],
}
}
64 changes: 41 additions & 23 deletions src/adverts/advert-meta/tests/can-book.spec.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,47 @@
import { getAdvertMeta } from '..'
import { makeAdmin } from '../../../login'
import { HaffaUser } from '../../../login/types'
import type { HaffaUser } from '../../../login/types'
import { createEmptyAdvert } from '../../mappers'
import { AdvertType } from '../../types'

const haffaUser: HaffaUser = {
id: 'test@user.se',
roles: { canCollectAdverts: true },
}

describe('getAdvertMeta::canBook', () => {
const unbookables = [
createEmptyAdvert({ quantity: 1, type: AdvertType.recycle }),
createEmptyAdvert({ quantity: 1, type: AdvertType.borrow }),
createEmptyAdvert({
quantity: 1,
type: AdvertType.recycle,
createdBy: 'someone@else',
}),
createEmptyAdvert({
quantity: 1,
type: AdvertType.borrow,
createdBy: 'someone@else',
}),
]
it('bookings are never supported', () => {
unbookables.forEach(advert =>
expect(
getAdvertMeta(advert, makeAdmin({ id: 'some@admin' })).canBook
).toBe(false)
)
it('cannot be booked if lending period is zero', () => {
expect(
getAdvertMeta(
createEmptyAdvert({
lendingPeriod: 0,
quantity: 1,
createdBy: 'someone@else',
}),
haffaUser
).canBook
).toBe(false)
})
it('cannot be booked if quantity is zero', () => {
expect(
getAdvertMeta(
createEmptyAdvert({
lendingPeriod: 5,
quantity: 0,
createdBy: 'someone@else',
}),
haffaUser
).canBook
).toBe(false)
})
it('can be booked if quantity is more than zero and lending period is set', () => {
expect(
getAdvertMeta(
createEmptyAdvert({
lendingPeriod: 5,
quantity: 1,
createdBy: 'someone@else',
}),
haffaUser
).canBook
).toBe(true)
})
})
51 changes: 51 additions & 0 deletions src/adverts/advert-meta/tests/return-info-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { getAdvertMeta } from '..'
import type { HaffaUser } from '../../../login/types'
import { createEmptyAdvert } from '../../mappers'
import type { AdvertClaim } from '../../types'
import { AdvertClaimType } from '../../types'

const haffaUser: HaffaUser = {
id: 'test@user.se',
roles: { canCollectAdverts: true },
}

describe('getAdvertMeta::returnInfo', () => {
const createClaim = (defaults?: Partial<AdvertClaim>): AdvertClaim => ({
by: 'test@user',
at: 'new Date().toISOString()',
quantity: 1,
type: AdvertClaimType.collected,
events: [],
...defaults,
})

it('sorts bookings in correct order', () => {
const advert = createEmptyAdvert({
lendingPeriod: 10,
quantity: 0,
claims: [
createClaim({ at: '2024-01-05', quantity: 1 }),
createClaim({ at: '2024-01-01', quantity: 2 }),
],
})
const meta = getAdvertMeta(advert, haffaUser)

expect(meta.returnInfo).toStrictEqual([
{ at: '2024-01-11T00:00:00.000Z', quantity: 2 },
{ at: '2024-01-15T00:00:00.000Z', quantity: 1 },
])
})
it('ignores claims of type reservation', () => {
const advert = createEmptyAdvert({
lendingPeriod: 10,
quantity: 0,
claims: [
createClaim({ at: '2024-01-05' }),
createClaim({ at: '2024-01-06', type: AdvertClaimType.reserved }),
],
})
const meta = getAdvertMeta(advert, haffaUser)

expect(meta.returnInfo).toHaveLength(1)
})
})
32 changes: 31 additions & 1 deletion src/adverts/advert-mutations/claims/mappers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { type AdvertClaim, type AdvertClaimEvent } from '../../types'
import { AdvertClaimType } from '../../types'
import type {
AdvertReturnInfo,
AdvertClaim,
AdvertClaimEvent,
} from '../../types'

const sanitizeInterval = (interval: number) => (interval < 0 ? 0 : interval)
/**
Expand Down Expand Up @@ -55,3 +60,28 @@ export const isClaimOverdue = (
// No limitation on validity
return false
}

export const getClaimReturnInfo = (claims: AdvertClaim[], daysValid: number) =>
claims
.reduce<AdvertReturnInfo[]>((p, c) => {
if (c.type === AdvertClaimType.collected && daysValid > 0) {
const at = new Date(c.at)
at.setDate(at.getDate() + sanitizeInterval(daysValid))

return [
...p,
{
at: at.toISOString(),
quantity: c.quantity,
},
]
}
return [...p]
}, [])
.sort((a, b) => a.at.localeCompare(b.at))

export const hasReservations = (claims: AdvertClaim[]) =>
claims.filter(claim => claim.type === AdvertClaimType.reserved).length > 0

export const hasCollects = (claims: AdvertClaim[]) =>
claims.filter(claim => claim.type === AdvertClaimType.collected).length > 0
9 changes: 9 additions & 0 deletions src/adverts/adverts.gql.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,18 @@ export const advertsGqlSchema = /* GraphQL */ `
canReturn: Boolean!
reservedyMe: Int!
collectedByMe: Int!
isLendingAdvert: Boolean!
isReservedBySome: Boolean!
isCollectedBySome: Boolean!
returnInfo: [AdvertReturnInfo]!
claims: [AdvertClaim]!
}
type AdvertReturnInfo {
at: String
quantity: Int
}
type AdvertLocation {
name: String
adress: String
Expand Down
8 changes: 8 additions & 0 deletions src/adverts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export interface AdvertMetaClaim extends AdvertClaim {
canConvert: boolean
isOverdue: boolean
}
export interface AdvertReturnInfo {
at: string
quantity: number
}
export interface AdvertMeta {
reservableQuantity: number
collectableQuantity: number
Expand All @@ -68,6 +72,10 @@ export interface AdvertMeta {
canReturn: boolean
reservedyMe: number
collectedByMe: number
isLendingAdvert: boolean
isReservedBySome: boolean
isCollectedBySome: boolean
returnInfo: AdvertReturnInfo[]
claims: AdvertMetaClaim[]
}

Expand Down

0 comments on commit 9a3ddcd

Please sign in to comment.