Commit f30e5c92 authored by deb355529's avatar deb355529
Browse files

DEICH-5502 DEICH-5504 deichman.no: modified min-side/bestillinger.js, made new...

DEICH-5502 DEICH-5504 deichman.no: modified min-side/bestillinger.js, made new MyHolds component, and added Holds to mye dashboard
parent ed156bca
......@@ -14,6 +14,7 @@ import {
} from "../../utilities/datetime";
import "./styles.css";
import { getPublicationIdFromUri } from "../../utilities/string";
const HoldCard = ({
data,
......@@ -54,9 +55,8 @@ const HoldCard = ({
) {
changePickupBranchAllowed = false;
}
const publicationId = uri.replace("http://data.deichman.no/publication/", "");
const publicationId = getPublicationIdFromUri(uri);
const selectedBranchObj = branches.find(b => b.value === branchCode) || {};
const query = {}; // TODO
// TEMP: Remove Hovedbiblioteket as pickup branch
const filteredBranches = branches.map(b => {
......@@ -152,24 +152,25 @@ const HoldCard = ({
{!isRemote && queuePlace > 0 && !suspendUntil && (
<Fragment>
<Block bottom={2}>
<div>
<p className="overline">Status</p>
</Block>
</div>
<p>Du er nr {queuePlace} i køen.</p>
<Block top={1}>
<Text gray>({getWaitingPeriodText(estimate.estimate)})</Text>
</Block>
<Block top={4}>
<Button onClick={() => onToggleSuspend(id)}>Sett vent</Button>
<Button
onClick={() => onToggleSuspend(id)}>Sett vent</Button>
</Block>
</Fragment>
)}
{!isRemote && suspendUntil && (
<Fragment>
<Block bottom={2}>
<div>
<p className="overline">Status</p>
</Block>
</div>
<p>Satt vent til {prettyDayFromISO(suspendUntil)}</p>
<Block top={4}>
<Button onClick={() => onToggleSuspend(id, true)}>
......@@ -198,7 +199,7 @@ const HoldCard = ({
</Fragment>
)}
<Block top={2}>
<Block top={4}>
<Text error>
<button type="button" className="link" onClick={() => onCancel(id)}>
Avbestill
......
......@@ -67,6 +67,10 @@
&__actions {
grid-area: actions;
}
button {
background-color: transparent;
}
}
/* Print styles for loanlist */
......
import React, { Component } from "react";
import autoBind from "auto-bind";
import PropTypes from "prop-types";
import HoldCard from "../HoldCard";
import { Block } from "@digibib/deichman-ui";
import "./styles.css";
import classNames from "classnames";
class HoldList extends Component {
constructor(props) {
......@@ -22,13 +21,19 @@ class HoldList extends Component {
branches,
onCancel,
onToggleSuspend,
onChangePickupBranch
onChangePickupBranch,
isCompact
} = this.props;
const holdList = classNames({
"hold-list": true,
"hold-list--compact": isCompact
});
return (
<section className="hold-list">
<section className={holdList}>
<h3>{headline}</h3>
<Block top={6} bottom={6}>
<Block top={6}>
<ul className="hold-list__items">
{items.map(item => (
<li className="hold-list__item" key={item.id}>
......@@ -56,7 +61,8 @@ HoldList.defaultProps = {
items: [],
branches: [],
onToggleSuspend: () => {}, // no-op
onChangePickupBranch: () => {} // no-op,
onChangePickupBranch: () => {}, // no-op,
isCompact: false
};
HoldList.propTypes = {
......@@ -66,7 +72,8 @@ HoldList.propTypes = {
branches: PropTypes.arrayOf(PropTypes.object),
onCancel: PropTypes.func.isRequired,
onToggleSuspend: PropTypes.func,
onChangePickupBranch: PropTypes.func
onChangePickupBranch: PropTypes.func,
isCompact: PropTypes.bool
};
export default HoldList;
.hold-list {
display: block;
.select {
border: 1px solid var(--col-gray-6)
}
&__items {
margin: var(--spacing-6) 0 var(--spacing-6) 0;
}
......@@ -21,3 +25,34 @@
background-color: var(--col-white);
}
}
.hold-list--compact {
.hold-list__items {
margin: 0;
}
.hold-list__item {
padding: 0 0 var(--spacing-4) 0;
margin: var(--spacing-6) 0;
border-bottom: 1px solid var(--col-gray-3);
border-radius: 0;
}
.hold-list__item:last-child {
margin: 0;
}
.hold-card__image {
width: 110px;
}
img {
height: 165px;
}
@media (--medium) {
.hold-card {
grid-template-columns: 110px auto 25%;
}
}
}
import React, { Fragment, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import {
cancelReservation,
changePickupBranch,
suspendReservation
} from "../../../store/reservation";
import ConfirmDialog from "../../ConfirmDialog";
import { freezeBody, unfreezeBody } from "../../../store/application";
import SuspendDateModal from "../../SuspendDateModal";
import PropTypes from "prop-types";
import HoldList from "../../HoldList";
import { formatDateToKoha } from "../../../utilities/datetime";
const MyHolds = props => {
const [showCancelHolsModal, setShowCancelHolsModal] = useState(false);
const [showSuspendHoldsModal, setShowSuspendHoldsModal] = useState(false);
const [validSuspendDate, setValidSuspendDate] = useState(false);
const [holdIdToCancel, setHoldIdToCancel] = useState(null);
const [holdIdToSuspend, setHoldIdToSuspend] = useState(null);
const [holdSuspendDate, setHoldSuspendDate] = useState("");
const dispatch = useDispatch();
const { loanerCategory } = useSelector(state => state.profile.personalInformation);
const handleSuspendDateChange = date => {
setValidSuspendDate(date !== "");
setHoldSuspendDate(formatDateToKoha(date));
};
const handleChangePickupBranch = (id, branchCode) => {
dispatch(changePickupBranch(id, branchCode));
};
const handleConfirmCancelHold = () => {
dispatch(cancelReservation(holdIdToCancel));
setShowCancelHolsModal(false);
dispatch(unfreezeBody());
};
const handleToggleSuspend = (id, suspended) => {
if (suspended) {
// Resume suspended hold
dispatch(suspendReservation(id, true));
return;
}
setShowSuspendHoldsModal(true);
setHoldIdToSuspend(id);
dispatch(freezeBody());
};
const handleSuspendHold = () => {
dispatch(suspendReservation(holdIdToSuspend, false, holdSuspendDate));
setShowSuspendHoldsModal(false);
dispatch(unfreezeBody());
};
const handleCancel = id => {
setShowCancelHolsModal(true);
setHoldIdToCancel(id);
dispatch(freezeBody());
};
const handleCloseModal = () => {
setShowCancelHolsModal(false);
setShowSuspendHoldsModal(false);
dispatch(unfreezeBody());
};
return (
<Fragment>
<HoldList
headline={props.headline}
items={props.list}
branches={props.branches}
loanerCategory={loanerCategory}
onToggleSuspend={handleToggleSuspend}
onChangePickupBranch={handleChangePickupBranch}
onCancel={handleCancel}
isCompact={props.isCompact}
/>
<ConfirmDialog
isVisible={showCancelHolsModal}
title="Avbestill"
subTitle="Er du sikker?"
onConfirm={handleConfirmCancelHold}
onCancel={handleCloseModal}
/>
<SuspendDateModal
isVisible={showSuspendHoldsModal}
validSuspendDate={validSuspendDate}
holdSuspendDate={holdSuspendDate}
onChangeDate={handleSuspendDateChange}
onSubmit={handleSuspendHold}
onClose={handleCloseModal}
/>
</Fragment>
);
};
MyHolds.propTypes = {
list: PropTypes.array.isRequired,
headline: PropTypes.string.isRequired,
branches: PropTypes.array.isRequired,
isCompact: PropTypes.bool
};
export default MyHolds;
import React, { Fragment, useEffect } from "react";
import { Block, Icon } from "@digibib/deichman-ui";
import { useDispatch, useSelector } from "react-redux";
import MyHolds from "./MyHolds";
import Link from "next/link";
import {
fetchKohaBranches,
kohaBranchesForDropdownSelector
} from "../../../store/libraries";
const MyHoldsDashboard = () => {
const { holds, pickups, remoteHolds } = useSelector(
state => state.profile.loansAndReservations
);
const branches = useSelector(state => kohaBranchesForDropdownSelector(state));
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchKohaBranches());
}, []);
const holdsAndRemoteHolds = [...holds, ...remoteHolds];
const isReservations = pickups.length > 0 || holdsAndRemoteHolds.length > 0;
return (
<Fragment>
{isReservations && (
<Block className="card gray my-holds">
{pickups.length > 0 && (
<MyHolds
list={pickups}
headline={`Klar til henting (${pickups.length})`}
branches={branches}
isCompact
/>
)}
{pickups.length < 1 && (
<MyHolds
list={holdsAndRemoteHolds.slice(0, 2)}
headline={`Mine bestillinger (${holdsAndRemoteHolds.length})`}
branches={branches}
isCompact
/>
)}
<Block top={4}>
<Icon type="arrow-large-right" />
<Link href="/min-side/bestillinger">
<a>Se alle bestillinger</a>
</Link>
</Block>
</Block>
)}
</Fragment>
);
};
export default MyHoldsDashboard;
......@@ -24,7 +24,6 @@ const PressReaderBlock = props => {
tidsskrifter over 70 forskjellige språk.
</p>
</Block>
<Block top={4} />
<Block top={4}>
<CtaWrapper>
......
......@@ -132,6 +132,14 @@ h3 {
}
}
/*** MyHolds ***/
.my-holds {
.icon {
vertical-align: text-bottom;
margin-right: var(--spacing-2);
}
}
.my-page {
@media (min-width: 1080px) {
.grid {
......
......@@ -8,10 +8,14 @@ const PublicationTitle = ({ data }) => {
subtitle,
partTitle,
partNumber,
untranscribedTitle
untranscribedTitle,
title
} = data;
if (!mainTitle) {
if (title) {
return <span>{title}</span>;
}
return <span>Ingen tittel</span>;
}
......
/* eslint-disable jsx-a11y/label-has-for */
/* eslint-disable jsx-a11y/label-has-associated-control */
import React, { Fragment } from "react";
import PropTypes from "prop-types";
import autoBind from "auto-bind";
import { connect } from "react-redux";
import React, { Fragment, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { withAuthSync } from "../../utilities/auth";
import { loggedInPages } from "../../constants/navItems";
import {
cancelReservation,
suspendReservation,
changePickupBranch
} from "../../store/reservation";
import { freezeBody, unfreezeBody } from "../../store/application";
import { fetchAllProfileData } from "../../store/profile";
import {
fetchKohaBranches,
kohaBranchesForDropdownSelector
} from "../../store/libraries";
import Head from "../../components/Head";
import SubNav from "../../components/SubNav";
import HoldList from "../../components/HoldList";
import ConfirmDialog from "../../components/ConfirmDialog";
import SuspendDateModal from "../../components/SuspendDateModal";
import { Container, Block } from "@digibib/deichman-ui";
import MyHolds from "../../components/MyOverview/MyHolds/MyHolds";
const initialState = {
cancelHoldModalVisible: false,
suspendHoldModalVisible: false,
validSuspendDate: false,
holdIdToCancel: undefined,
holdIdToSuspend: undefined,
holdSuspendDate: ""
};
class MyHolds extends React.Component {
constructor(props) {
super(props);
autoBind(this);
this.state = initialState;
}
componentDidMount() {
// TODO don't fetch if allready in state
this.props.fetchAllProfileData();
this.props.fetchKohaBranches();
}
// Format to Koha date format
formatDateToKoha(date) {
const d = date.getDate();
const m = date.getMonth() + 1;
const y = date.getFullYear();
return `${y}-${m <= 9 ? `0${m}` : m}-${d <= 9 ? `0${d}` : d}`;
}
handleSuspendDateChange(date) {
this.setState({
validSuspendDate: date !== "",
holdSuspendDate: this.formatDateToKoha(date)
});
}
const MyHoldsPage = () => {
const dispatch = useDispatch();
const branches = useSelector(state => kohaBranchesForDropdownSelector(state));
const profile = useSelector(state => state.profile);
handlerChangePickupBranch(reserveId, branchCode) {
this.props.changePickupBranch(reserveId, branchCode);
}
useEffect(() => {
dispatch(fetchAllProfileData());
dispatch(fetchKohaBranches());
}, []);
doCancelHold() {
const { holdIdToCancel } = this.state;
const isLoading = profile.isRequestingLoansAndReservations;
const {holds, pickups, remoteHolds} = profile.loansAndReservations;
const noReservations = pickups < 1 && holds < 1 && remoteHolds.length < 1 && !isLoading;
this.setState(initialState);
this.props.cancelReservation(holdIdToCancel);
this.props.unfreezeBody();
}
handleToggleSuspend(reserveId, suspended) {
if (suspended) {
// Resume suspended hold
this.setState(initialState);
this.props.suspendReservation(reserveId, true);
return;
}
this.setState({
suspendHoldModalVisible: true,
holdIdToSuspend: reserveId
});
this.props.freezeBody();
}
handleSuspendHold(e) {
e.preventDefault();
const { holdIdToSuspend, holdSuspendDate } = this.state;
this.setState(initialState);
this.props.suspendReservation(holdIdToSuspend, false, holdSuspendDate);
this.props.unfreezeBody();
}
handleCancel(reserveId) {
this.setState({
cancelHoldModalVisible: true,
holdIdToCancel: reserveId
});
this.props.freezeBody();
}
handleCloseModal(e) {
e.preventDefault();
this.setState(initialState);
this.props.unfreezeBody();
}
filterIsHoldsPending(holds) {
const filterIsHoldsPending = holds => {
/* Conditional splitting of array. Divides into 2 sub arrays */
return [...holds].reduce((result, element) => {
const bucket = element?.estimate?.pending === 1 && !element.suspendUntil ? 1 : 0;
result[bucket].push(element);
return result;
}, [[], []]);
}
render() {
const { profile = {}, branches = [] } = this.props;
const {
cancelHoldModalVisible,
suspendHoldModalVisible,
holdSuspendDate,
validSuspendDate
} = this.state;
const {
holds = [],
pickups = [],
remoteHolds = []
} = profile.loansAndReservations;
const [holdsIsNotPending, holdsIsPending] = this.filterIsHoldsPending(holds);
const { loanerCategory } = profile.personalInformation;
const isLoading = profile.isRequestingLoansAndReservations;
const noReservations =
pickups.length < 1 &&
holds.length < 1 &&
remoteHolds.length < 1 &&
!isLoading;
return (
<Fragment>
<Head title="Min side - Deichman.no" />
<SubNav items={loggedInPages} />
<Container>
<Block top={8} bottom={8} responsive>
{noReservations && <p>Du har for tiden ingen bestillinger.</p>}
};
{pickups.length > 0 && (
<HoldList
headline="Klar til henting"
items={pickups}
branches={branches}
loanerCategory={loanerCategory}
onCancel={this.handleCancel}
/>
)}
{holdsIsPending.length > 0 && (
<HoldList
headline="På vei til bibliotek"
items={holdsIsPending}
branches={branches}
loanerCategory={loanerCategory}
onToggleSuspend={this.handleToggleSuspend}
onChangePickupBranch={this.handlerChangePickupBranch}
onCancel={this.handleCancel}
/>
)}
{holdsIsNotPending.length > 0 && (
<HoldList
headline={`Venteliste (${holdsIsNotPending?.length})`}
items={holdsIsNotPending}
const [holdsIsNotPending, holdsIsPending] = filterIsHoldsPending(holds);
const lists = [
{
list: pickups,
headline: "Klar til henting"
},
{
list: holdsIsPending,
headline: "På vei til bibliotek"
},
{
list: holdsIsNotPending,
headline: `Venteliste (${holdsIsNotPending.length})`
},
{