Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
digibib
deichman
Commits
a3b14df1
Commit
a3b14df1
authored
Feb 23, 2021
by
David Björkheim
Browse files
DEICH-5554
Deichman.no: Add publication selector for reservation
parent
05d352c0
Changes
13
Hide whitespace changes
Inline
Side-by-side
deichman.no/components/HilightedWorkDetails/HighlightedWorkDetails.js
View file @
a3b14df1
...
...
@@ -187,8 +187,8 @@ function topContributorDetails({ contributors, mediaType }) {
}
function
_groupDetails
(
contributorGroup
)
{
const
contributorElements
=
contributorGroup
.
items
.
map
(
({
link
=
null
,
agent
=
{}
})
=>
const
contributorElements
=
contributorGroup
?.
items
.
map
(
({
link
=
null
,
agent
=
{}
})
=>
link
?
(
<
Link
as
=
{
link
.
as
}
href
=
{
link
.
href
}
key
=
{
link
.
as
}
>
<
a
>
{
agent
.
name
}
<
/a
>
...
...
@@ -196,8 +196,8 @@ function _groupDetails(contributorGroup) {
)
:
(
<
span
>
{
agent
.
name
}
<
/span
>
)
);
const
title
=
translations
[
contributorGroup
.
role
];
)
||
[]
;
const
title
=
translations
[
(
contributorGroup
?
.
role
)
];
return
{
title
:
contributorElements
.
length
>
1
?
pluraliseString
(
title
)
:
title
,
description
:
(
...
...
deichman.no/components/ReservationForm/ReservationForm.js
View file @
a3b14df1
...
...
@@ -7,6 +7,7 @@ import { Block, Button, Select, Hr } from "@digibib/deichman-ui";
import
{
translations
as
TRANSLATIONS
}
from
"
../../constants/translations
"
;
import
PublicationImage
from
"
../PublicationImage
"
;
import
{
getWaitingPeriodText
}
from
"
../../utilities/datetime
"
;
import
{
sortBy
}
from
"
lodash
"
;
const
ReservationForm
=
({
isLoggedIn
,
...
...
@@ -17,11 +18,10 @@ const ReservationForm = ({
onClose
,
completed
,
isSubmitting
,
recordId
,
publication
=
{}
,
limitedToBranches
,
error
,
reservationWork
,
workData
,
onRedirectClose
})
=>
{
// Return login form if not authorised
...
...
@@ -34,22 +34,11 @@ const ReservationForm = ({
fetchFavouritesOnLogin
fetchKohaBranchesOnLogin
showCancel
redirectModalData
=
{{
type
:
"
reservation
"
,
recordId
}}
onCancel
=
{
onClose
}
/
>
);
}
const
getSelectedPublication
=
()
=>
{
const
biblionumber
=
reservationWork
?.
currentItem
?.
biblionumber
?.
toString
();
// Select the correct publication by matching recordId and biblionumber
return
workData
?.
publications
.
find
(
obj
=>
obj
.
recordId
===
biblionumber
);
};
const
renderQueueInformation
=
()
=>
{
const
currentItem
=
reservationWork
?.
currentItem
;
const
priority
=
currentItem
?.
pri
;
...
...
@@ -66,8 +55,7 @@ const ReservationForm = ({
// Return success message if reservation completed
if
(
completed
&&
!
error
)
{
const
{
mainTitle
,
mediaType
,
sellingPoint
,
imageObj
}
=
getSelectedPublication
()
||
{};
const
{
mainTitle
,
mediaType
,
sellingPoint
,
imageObj
}
=
publication
;
return
(
<
div
className
=
"
reservation-success-form
"
>
...
...
@@ -123,17 +111,7 @@ const ReservationForm = ({
);
}
// Sort brances by name (text)
function
compareName
(
a
,
b
)
{
if
(
a
.
text
<
b
.
text
)
{
return
-
1
;
}
if
(
a
.
text
>
b
.
text
)
{
return
1
;
}
return
0
;
}
const
sortedBranches
=
branches
.
sort
(
compareName
);
const
sortedBranches
=
sortBy
(
branches
,
[
"
text
"
]);
return
(
<
form
onSubmit
=
{
onSubmit
}
>
...
...
deichman.no/components/Reservations
Manag
er/Reservation
sManag
er.js
→
deichman.no/components/Reservations
Contain
er/Reservation
Contain
er.js
View file @
a3b14df1
import
React
,
{
Fragment
}
from
"
react
"
;
import
ReactDOM
from
"
react-dom
"
;
import
PropTypes
from
"
prop-types
"
;
import
autoBind
from
"
auto-bind
"
;
import
{
connect
}
from
"
react-redux
"
;
...
...
@@ -10,8 +11,6 @@ import {
remoteReservePublication
,
resetReservationError
}
from
"
../../store/reservation
"
;
import
{
toggleReservations
}
from
"
../../store/application
"
;
import
{
publicationByRecordId
}
from
"
../../store/resources
"
;
import
{
fetchKohaBranches
,
kohaBranchesForDropdownSelector
...
...
@@ -21,22 +20,28 @@ import ReservationForm from "../ReservationForm";
import
RemoteReservationForm
from
"
../RemoteReservationForm
"
;
import
{
Modal
}
from
"
@digibib/deichman-ui
"
;
import
"
./styles.css
"
;
import
ReservationSelector
from
"
./ReservationSelector
"
;
import
{
setBodyFreeze
}
from
"
../../utilities/accessibility
"
;
let
modalRoot
;
/**
* Responsible for reserving items from the catalog
* -> Shows loginform if user is not logged in
* -> Then shows remote/reservation-form
*/
class
Reservation
sManag
er
extends
React
.
Component
{
class
Reservation
Contain
er
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
autoBind
(
this
);
this
.
state
=
{
shouldRender
:
this
.
props
.
isVisible
,
selectedBranchId
:
false
,
reservationCompleted
:
false
,
borrowerId
:
""
borrowerId
:
""
,
recordId
:
null
,
show
:
false
};
this
.
el
=
document
.
createElement
(
"
div
"
);
}
static
getDerivedStateFromProps
(
nextProps
,
prevState
)
{
...
...
@@ -68,19 +73,25 @@ class ReservationsManager extends React.Component {
}
componentDidMount
()
{
setBodyFreeze
(
true
);
this
.
props
.
fetchKohaBranches
();
setTimeout
(()
=>
this
.
setState
({
show
:
true
}),
100
);
modalRoot
=
document
.
getElementById
(
"
modalRoot
"
);
modalRoot
.
appendChild
(
this
.
el
);
}
componentDidUpdate
(
prevProps
)
{
// Prevent rendering of contents if not visible, but still allow for
// transition when showing/hiding by adding slight unmount-delay
if
(
prevProps
.
isVisible
&&
!
this
.
props
.
isVisible
)
{
setTimeout
(()
=>
this
.
setState
({
shouldRender
:
false
}),
300
);
}
else
if
(
!
prevProps
.
isVisible
&&
this
.
props
.
isVisible
)
{
this
.
setState
({
shouldRender
:
true
});
// eslint-disable-line react/no-did-update-set-state
componentDidUpdate
()
{
if
(
!
this
.
state
.
recordId
&&
this
.
props
.
publications
.
length
===
1
)
{
const
recordId
=
this
.
props
.
publications
[
0
].
recordId
;
this
.
setState
({
recordId
});
}
}
componentWillUnmount
()
{
setBodyFreeze
(
false
);
modalRoot
&&
modalRoot
.
removeChild
(
this
.
el
);
}
handleChangeBranch
(
e
)
{
this
.
setState
({
selectedBranchId
:
e
.
target
.
value
...
...
@@ -96,15 +107,14 @@ class ReservationsManager extends React.Component {
handleCloseModal
(
redirect
)
{
return
e
=>
{
e
.
preventDefault
();
this
.
props
.
toggleReservations
();
this
.
setState
({
show
:
false
});
// Delay error reset until modal has faded out
setTimeout
(()
=>
{
this
.
props
.
onClose
();
this
.
props
.
resetReservationError
();
this
.
setState
({
reservationCompleted
:
false
,
borrowerId
:
""
});
},
300
);
if
(
redirect
)
{
...
...
@@ -118,15 +128,18 @@ class ReservationsManager extends React.Component {
async
handleSubmit
(
e
)
{
e
.
preventDefault
();
const
{
publication
:
{
recordId
,
branchcode
}
=
{}
}
=
this
.
props
;
const
publication
=
this
.
props
.
publications
.
find
(
pub
=>
pub
.
recordId
===
this
.
state
.
recordId
);
const
branchCode
=
publication
.
branchcode
;
const
isRemoteReservation
=
this
.
props
.
userCategory
===
"
IL
"
;
const
onlyAtRiksen
=
branch
c
ode
===
"
frik
"
;
const
onlyAtRiksen
=
branch
C
ode
===
"
frik
"
;
if
(
isRemoteReservation
)
{
const
{
borrowerId
}
=
this
.
state
;
try
{
await
this
.
props
.
remoteReservePublication
(
recordId
,
null
,
//
recordId,
borrowerId
,
onlyAtRiksen
);
...
...
@@ -141,26 +154,27 @@ class ReservationsManager extends React.Component {
}
else
{
const
{
selectedBranchId
}
=
this
.
state
;
await
this
.
props
.
reservePublication
(
recordId
,
selectedBranchId
);
await
this
.
props
.
reservePublication
(
publication
.
recordId
,
selectedBranchId
);
this
.
setState
({
reservationCompleted
:
true
});
}
}
setPublication
(
recordId
)
{
this
.
setState
({
recordId
});
}
render
()
{
const
{
borrowerId
,
reservationCompleted
,
selectedBranchId
}
=
this
.
state
;
const
{
work
,
isVisible
,
branches
,
publication
:
{
recordId
,
formats
=
[],
items
=
[],
numHolds
=
null
,
title
}
=
{},
copies
,
publications
,
reservationApi
:
{
error
:
reservationError
,
inProgress
:
reservationInProgress
...
...
@@ -171,11 +185,11 @@ class ReservationsManager extends React.Component {
// Check if user is a remote user
const
isRemoteReservation
=
this
.
props
.
userCategory
===
"
IL
"
;
// Get number of active holds
let
currentPublicationNumHolds
=
0
;
if
(
numHolds
!==
null
)
{
currentPublicationNumHolds
=
Number
(
numHolds
)
;
}
const
publication
=
publications
.
find
(
pub
=>
pub
.
recordId
===
this
.
state
.
recordId
);
const
{
recordId
,
formats
=
[],
title
}
=
publication
||
{}
;
const
{
items
=
[],
numHolds
=
null
}
=
copies
[
recordId
]
||
{};
// Check if currentPublicationPickupBranches
let
limitedToBranches
=
[];
...
...
@@ -183,79 +197,91 @@ class ReservationsManager extends React.Component {
limitedToBranches
=
items
.
map
(
item
=>
item
.
branchcode
);
}
return
(
<
FocusTrap
active
=
{
this
.
state
.
shouldRender
}
focusTrapOptions
=
{{
initialFocus
:
"
#reservation-trap
"
}}
>
<
Modal
name
=
"
Reserver
"
visible
=
{
isVisible
}
onClose
=
{
this
.
handleCloseModal
(
false
)}
sizeW
=
"
40rem
"
showClose
return
ReactDOM
.
createPortal
(
<
div
className
=
"
reservation-wrapper
"
>
<
FocusTrap
active
=
{
this
.
state
.
show
}
focusTrapOptions
=
{{
initialFocus
:
"
#reservation-trap
"
}}
>
<
div
className
=
"
focus-trap-target
"
id
=
"
reservation-trap
"
tabIndex
=
"
-1
"
<
Modal
name
=
"
Reserver
"
visible
=
{
this
.
state
.
show
}
onClose
=
{
this
.
handleCloseModal
(
false
)}
sizeW
=
"
40rem
"
showClose
>
{
this
.
state
.
shouldRender
?
(
<
div
className
=
"
focus-trap-target reservation-content
"
id
=
"
reservation-trap
"
tabIndex
=
"
-1
"
>
<
Fragment
>
{
isRemoteReservation
?
(
<
RemoteReservationForm
borrowerId
=
{
borrowerId
}
onChangeBorrowerId
=
{
this
.
handleChangeBorrowerId
}
onClose
=
{
this
.
handleCloseModal
(
false
)}
isSubmitting
=
{
reservationInProgress
}
isLoggedIn
=
{
isLoggedIn
}
completed
=
{
reservationCompleted
}
error
=
{
reservationError
}
recordId
=
{
recordId
}
numHolds
=
{
currentPublicationNumHolds
}
publicationTitle
=
{
title
}
onSubmit
=
{
this
.
handleSubmit
}
/
>
)
:
(
<
ReservationForm
allBranches
=
{
branches
}
selectedBranchId
=
{
selectedBranchId
}
onChangeBranch
=
{
this
.
handleChangeBranch
}
onClose
=
{
this
.
handleCloseModal
(
false
)}
isSubmitting
=
{
reservationInProgress
}
isLoggedIn
=
{
isLoggedIn
}
completed
=
{
reservationCompleted
}
error
=
{
reservationError
}
recordId
=
{
recordId
}
limitedToBranches
=
{
limitedToBranches
}
onSubmit
=
{
this
.
handleSubmit
}
reservationWork
=
{
work
}
onRedirectClose
=
{
this
.
handleCloseModal
(
true
)}
{
!
publication
&&
(
<
ReservationSelector
onClick
=
{
this
.
setPublication
}
copies
=
{
copies
}
publications
=
{
publications
}
currentPublication
=
{
this
.
props
.
currentPublication
}
/
>
)}
{
publication
&&
(
<>
{
isRemoteReservation
?
(
<
RemoteReservationForm
borrowerId
=
{
borrowerId
}
onChangeBorrowerId
=
{
this
.
handleChangeBorrowerId
}
onClose
=
{
this
.
handleCloseModal
(
false
)}
isSubmitting
=
{
reservationInProgress
}
isLoggedIn
=
{
isLoggedIn
}
completed
=
{
reservationCompleted
}
error
=
{
reservationError
}
recordId
=
{
recordId
}
numHolds
=
{
`
${
Number
(
numHolds
)}
`
}
publicationTitle
=
{
title
}
onSubmit
=
{
this
.
handleSubmit
}
/
>
)
:
(
<
ReservationForm
allBranches
=
{
branches
}
selectedBranchId
=
{
selectedBranchId
}
onChangeBranch
=
{
this
.
handleChangeBranch
}
onClose
=
{
this
.
handleCloseModal
(
false
)}
isSubmitting
=
{
reservationInProgress
}
isLoggedIn
=
{
isLoggedIn
}
completed
=
{
reservationCompleted
}
error
=
{
reservationError
}
publication
=
{
publication
}
limitedToBranches
=
{
limitedToBranches
}
onSubmit
=
{
this
.
handleSubmit
}
reservationWork
=
{
work
}
onRedirectClose
=
{
this
.
handleCloseModal
(
true
)}
/
>
)}
<
/
>
)}
<
/Fragment
>
)
:
(
""
)}
<
/div
>
<
/Modal
>
<
/FocusTrap
>
<
/div
>
<
/Modal
>
<
/FocusTrap
>
<
/div>
,
this
.
el
);
}
}
Reservation
sManag
er
.
defaultProps
=
{
Reservation
Contain
er
.
defaultProps
=
{
data
:
{},
homeBranch
:
""
,
userCategory
:
""
};
Reservation
sManag
er
.
propTypes
=
{
Reservation
Contain
er
.
propTypes
=
{
isVisible
:
PropTypes
.
bool
.
isRequired
,
isLoggedIn
:
PropTypes
.
bool
.
isRequired
,
data
:
PropTypes
.
object
,
copies
:
PropTypes
.
object
,
branches
:
PropTypes
.
array
.
isRequired
,
homeBranch
:
PropTypes
.
string
,
userCategory
:
PropTypes
.
string
,
...
...
@@ -270,15 +296,11 @@ ReservationsManager.propTypes = {
};
function
mapStateToProps
(
state
)
{
const
{
reservations
}
=
state
.
application
;
const
{
reservationApi
,
work
}
=
state
.
reservation
;
const
{
homeBranch
,
category
}
=
state
.
auth
.
userData
;
const
{
isLoggedIn
}
=
state
.
auth
;
return
{
isVisible
:
reservations
.
visible
,
data
:
reservations
.
data
,
publication
:
publicationByRecordId
(
state
,
reservations
.
data
.
recordId
),
branches
:
kohaBranchesForDropdownSelector
(
state
),
reservationApi
,
homeBranch
,
...
...
@@ -295,12 +317,11 @@ function mapDispatchToProps(dispatch) {
fetchKohaBranches
:
()
=>
dispatch
(
fetchKohaBranches
()),
remoteReservePublication
:
(
recordId
,
userId
,
onlyAtRiksen
)
=>
dispatch
(
remoteReservePublication
(
recordId
,
userId
,
onlyAtRiksen
)),
resetReservationError
:
()
=>
dispatch
(
resetReservationError
()),
toggleReservations
:
()
=>
dispatch
(
toggleReservations
())
resetReservationError
:
()
=>
dispatch
(
resetReservationError
())
};
}
export
default
connect
(
mapStateToProps
,
mapDispatchToProps
)(
Reservation
sManag
er
);
)(
Reservation
Contain
er
);
deichman.no/components/ReservationsContainer/ReservationSelector.js
0 → 100644
View file @
a3b14df1
import
{
Block
}
from
"
@digibib/deichman-ui
"
;
import
React
from
"
react
"
;
import
{
useDispatch
,
useSelector
}
from
"
react-redux
"
;
import
{
toggleDetails
,
toggleFavourites
}
from
"
../../store/application
"
;
import
PublicationList
from
"
../PublicationList
"
;
export
default
function
ReservationSelector
({
publications
,
currentPublication
=
{},
copies
=
{},
onClick
})
{
const
dispatch
=
useDispatch
();
const
favourites
=
useSelector
(
state
=>
state
.
favourites
.
biblioNumbers
);
const
onFavourite
=
recordId
=>
dispatch
(
toggleFavourites
({
recordId
}));
const
onShowDetails
=
publication
=>
dispatch
(
toggleDetails
({
publication
}));
const
userCategory
=
useSelector
(
state
=>
state
.
auth
.
userData
.
category
);
const
tjenesteKatalogUrl
=
useSelector
(
state
=>
state
.
application
.
urls
.
tjenestekatalog
);
const
decoratedPublications
=
publications
.
map
(
pub
=>
{
const
copyInfo
=
copies
[
pub
.
recordId
]
||
{};
return
{
...
pub
,
...
copyInfo
};
});
return
(
<
Block
top
=
{
4
}
>
<
h2
>
Velg
en
utgave
<
/h2
>
<
PublicationList
items
=
{
decoratedPublications
}
favourites
=
{
favourites
}
parent
=
{
currentPublication
.
work
}
onReserve
=
{
onClick
}
onFavourite
=
{
onFavourite
}
onShowDetails
=
{
onShowDetails
}
userCategory
=
{
userCategory
}
tjenesteKatalogUrl
=
{
tjenesteKatalogUrl
}
/
>
<
/Block
>
);
}
deichman.no/components/ReservationsContainer/styles.css
0 → 100644
View file @
a3b14df1
.reservation-wrapper
{
.modal__inner
{
@media
(--medium)
{
max-height
:
50vh
;
}
}
}
deichman.no/components/ReservationsManager/index.js
deleted
100644 → 0
View file @
05d352c0
import
ReservationsManager
from
"
./ReservationsManager
"
;
export
default
ReservationsManager
;
deichman.no/components/ReservePublicationWidget/ReservPublicationWidget.js
0 → 100644
View file @
a3b14df1
import
React
,
{
useState
}
from
"
react
"
;
import
{
Button
,
Select
}
from
"
@digibib/deichman-ui
"
;
import
{
AUDIO_BOOK
,
BOOK
,
COMIC_BOOK
,
FILM
,
GAME
,
LANGUAGE_COURSE
,
MUSIC_RECORDING
}
from
"
../../constants/mediaTypes
"
;
import
{
translations
as
TRANSLATIONS
}
from
"
../../constants/translations
"
;
import
"
./styles.css
"
;
const
titles
=
{
default
:
"
Bestill utgivelsen
"
,
[
BOOK
]:
"
Bestill boken
"
,
[
AUDIO_BOOK
]:
"
Bestill lydboken
"
,
[
COMIC_BOOK
]:
"
Bestill tegneserien
"
,
[
MUSIC_RECORDING
]:
"
Bestill musikken (CD)
"
,
[
FILM
]:
"
Bestill filmen
"
,
[
GAME
]:
"
Bestill spillet
"
};
//Since we shall not show all fields even though we have data we need to be able to filter them some how. This map provides us with which field that should be shown
const
availableFields
=
{
default
:
[],
[
BOOK
]:
[
"
language
"
],
[
AUDIO_BOOK
]:
[
"
language
"
,
"
format
"
],
[
COMIC_BOOK
]:
[
"
language
"
],
[
MUSIC_RECORDING
]:
[],
[
FILM
]:
[
"
format
"
],
[
GAME
]:
[
"
platform
"
],
[
LANGUAGE_COURSE
]:
[
"
format
"
]
};
import
{
matchMedia
}
from
"
../../utilities/media
"
;
import
{
uniqBy
}
from
"
lodash
"
;
import
ReservationContainer
from
"
../ReservationsContainer/ReservationContainer
"
;
import
{
useEffect
}
from
"
react
"
;
export
default
function
ReservePublicationWidget
({
publications
,
currentPublication
})
{
const
{
languages
,
formats
,
platforms
}
=
currentPublication
;
const
[
language
,
setLanguage
]
=
useState
(
languages
?.[
0
]);
const
[
format
,
setFormat
]
=
useState
(
formats
?.[
0
]);
const
[
platform
,
setPlatform
]
=
useState
(
platforms
?.[
0
]);
const
[
copies
,
setCopies
]
=
useState
({});
const
[
reservationPublications
,
setReservationPublications
]
=
useState
([]);
const
mediaType
=
currentPublication
.
mediaType
;
const
title
=
matchMedia
(
titles
,
mediaType
);
const
showFields
=
matchMedia
(
availableFields
,
mediaType
);
useEffect
(
()
=>
{
getCopies
(
currentPublication
).
then
(
newCopies
=>
setCopies
(
newCopies
));
},
[
currentPublication
]
);
const
onReserve
=
choices
=>
{
setReservationPublications
(
publications
.
filter
(
pub
=>
pub
.
mediaType
===
mediaType
)
.
filter
(
pub
=>
choices
.
every
(({
selected
:
value
,
choice
})
=>
pub
[
choice
].
includes
(
value
)
)
)
);
};
const
reserveChoices
=
[
{
selected
:
language
,
choice
:
"
languages
"
,
onChange
:
e
=>
setLanguage
(
e
.
target
.
value
),
alternatives
:
uniqBy
(
publications
.
filter
(
pub
=>