Commit 76cc833a authored by Maksym Tishchenko's avatar Maksym Tishchenko Committed by Matija Obreza
Browse files

Adding to Cart

- support for two browser windows
- updated list and details pages to listen to updates of local storage.
- updated availability check function.
- buttons now work on details page
- fixed adding to local storage cart bug
- fixed checkboxes
- cart buttons on details/list pages.
- changed addToCart and removeFromCart to receive string.
parent f9fb8843
......@@ -4,25 +4,52 @@ import { AccessionService } from '@genesys/client/service';
import { Property } from 'ui/common/Property';
import AccessionDetails from '@genesys/client/model/accession/AccessionDetails';
import { WithTranslation, withTranslation } from 'react-i18next';
import { LocalStorageCart } from 'utilities';
interface IAccessionDetailsPageState {
accession: AccessionDetails;
cartItems: string[];
}
interface IAccessionDetailsPage {
match: any;
apiUrl: string;
}
class AccessionDetailsPage extends React.Component<IAccessionDetailsPage & WithTranslation, any> {
class AccessionDetailsPage extends React.Component<IAccessionDetailsPage & WithTranslation, IAccessionDetailsPageState> {
public constructor(props) {
super(props);
}
public state = {
accession: null as AccessionDetails,
accession: null,
cartItems: LocalStorageCart.getCartItemsLS(),
};
public componentDidMount() {
this.loadData(this.props.match.params.uuid);
if (typeof window !== 'undefined') {
window.addEventListener('storage', this.handleLocalStorageUpdate);
this.receiveData();
}
}
public componentWillUnmount() {
if (typeof window !== 'undefined') {
window.removeEventListener('storage', this.handleLocalStorageUpdate);
}
}
private handleLocalStorageUpdate = (e: StorageEvent) => {
if (e.key === LocalStorageCart.LS_KEY) {
this.receiveData();
}
};
private receiveData = () => {
this.setState({ cartItems: LocalStorageCart.getCartItemsLS() });
};
private loadData = (uuid: string): Promise<void> => {
return AccessionService
.getDetailsByUuid(uuid)
......@@ -35,8 +62,35 @@ class AccessionDetailsPage extends React.Component<IAccessionDetailsPage & WithT
});
};
public render() {
private addToCart = (e: React.MouseEvent<HTMLButtonElement>) => {
LocalStorageCart.addToCart(e.currentTarget.getAttribute('data-uuid'));
this.setState( { cartItems: LocalStorageCart.getCartItemsLS() } )
};
private removeFromCart = (e: React.MouseEvent<HTMLButtonElement>) => {
LocalStorageCart.removeFromCart(e.currentTarget.getAttribute('data-uuid'));
this.setState( { cartItems: LocalStorageCart.getCartItemsLS() } )
}
private renderAddToCart = () => {
const { accession } = this.state;
const { t } = this.props;
const canAddToCart = !(accession.details.historic === true || accession.details.available === false || accession.details.institute.allowMaterialRequests === true);
return <button
type="button"
disabled={ !canAddToCart }
name={ `button-add-${accession.details.uuid}` }
data-uuid={ accession.details.uuid }
className="btn btn-primary"
onClick={ this.addToCart }
>
{ canAddToCart ? t('cart.addToCart') : t('list.notAvailable') }
</button>
}
public render() {
const { accession, cartItems } = this.state;
const { apiUrl, t } = this.props;
let propertyIndex = 0;
......@@ -146,6 +200,21 @@ class AccessionDetailsPage extends React.Component<IAccessionDetailsPage & WithT
)) }
</>
}
<div className="pt-4">
{cartItems.includes(this.props.match.params.uuid) ?
<button
type="button"
name={ `button-remove-${accession.details.uuid}` }
data-uuid={ accession.details.uuid }
className="btn btn-primary"
onClick={ this.removeFromCart }
>
{ t('cart.removeFromCart') }
</button>
:
this.renderAddToCart()
}
</div>
</>
);
}
......
......@@ -15,6 +15,7 @@ interface IAccessionListPageState {
filter: AccessionFilter;
accessions: FilteredPage<Accession>;
selected: string[];
cartItems: string[];
isAllSelected: boolean;
}
......@@ -32,14 +33,35 @@ class AccessionListPage extends React.Component<IAccessionListPageProps & WithTr
accessions: null,
selected: [],
isAllSelected: false,
cartItems: LocalStorageCart.getCartItemsLS(),
}
}
public componentDidMount() {
const { current, filterCode } = this.parseLocationSearch(this.props.location);
this.loadData(filterCode || this.state.filter, current ? { page: current } : {});
if (typeof window !== 'undefined') {
window.addEventListener('storage', this.handleLocalStorageUpdate);
this.receiveData();
}
}
public componentWillUnmount() {
if (typeof window !== 'undefined') {
window.removeEventListener('storage', this.handleLocalStorageUpdate);
}
}
private handleLocalStorageUpdate = (e: StorageEvent) => {
if (e.key === LocalStorageCart.LS_KEY) {
this.receiveData();
}
};
private receiveData = () => {
this.setState({ cartItems: LocalStorageCart.getCartItemsLS() });
};
public componentDidUpdate(prevProps) {
const { current: currentPage, filterCode } = this.parseLocationSearch(this.props.location);
const { current: prevPage, filterCode: prevFilterCode } = this.parseLocationSearch(prevProps.location);
......@@ -89,13 +111,53 @@ class AccessionListPage extends React.Component<IAccessionListPageProps & WithTr
private addSelectedToCart = () => {
LocalStorageCart.addToCart(this.state.selected);
this.setState({ selected: [], isAllSelected: false });
this.setState({ selected: [], isAllSelected: false, cartItems: LocalStorageCart.getCartItemsLS() });
};
private addToCart = (e: React.MouseEvent<HTMLButtonElement>) => {
LocalStorageCart.addToCart(e.currentTarget.getAttribute('data-uuid'));
this.setState( { cartItems: LocalStorageCart.getCartItemsLS() } )
};
private removeFromCart = (e: React.MouseEvent<HTMLButtonElement>) => {
LocalStorageCart.removeFromCart(e.currentTarget.getAttribute('data-uuid'));
this.setState( { cartItems: LocalStorageCart.getCartItemsLS() } )
}
private canAddToCart = (accession) => {
return !(accession.historic === true || accession.available === false || accession.institute.allowMaterialRequests === true);
}
private renderCartButton = (accession, i) => {
const { t } = this.props;
const { cartItems } = this.state;
if (!this.canAddToCart(accession)) {
return <span>{t('list.notAvailable')}</span>
}
if ( cartItems.includes(accession.uuid)) {
return <button
type="button"
name={ `button-remove-${accession.uuid}-${i}` }
data-uuid={ accession.uuid }
onClick={ this.removeFromCart }
className="btn btn-primary"
>
{ t('cart.removeFromCart') }
</button>
}
return <button
type="button"
name={ `button-add-${accession.uuid}-${i}` }
data-uuid={ accession.uuid }
onClick={ this.addToCart }
className="btn btn-primary"
>
{ t('cart.addToCart') }
</button>
}
private onToggleAll = () => {
this.setState((prevState) => ({
isAllSelected: !prevState.isAllSelected,
selected: !prevState.isAllSelected ? prevState.accessions.content.map((acc) => acc.uuid) : [],
selected: !prevState.isAllSelected ? prevState.accessions.content.map((acc) => this.canAddToCart(acc) && acc.uuid) : [],
}));
};
......@@ -140,20 +202,23 @@ class AccessionListPage extends React.Component<IAccessionListPageProps & WithTr
<th>{ t('accession.taxonomy') }</th>
<th>{ t('accession.countryOfOrigin') }</th>
<th>{ t('accession.sampStat') }</th>
<th>{ t('list.availability') }</th>
</tr>
</thead>
<tbody>
{ accessions.content.map((a, i) => (
<tr key={ a.id } className={ selectedUUIDs.has(a.uuid) ? 'table-primary' : '' }>
<td>
<input
type="checkbox"
name={ `checkbox-${a.uuid}-${i}` }
data-uuid={ a.uuid }
checked={ selectedUUIDs.has(a.uuid) }
onChange={ this.toggleRowSelect }
className="align-middle"
/>
{this.canAddToCart(a) &&
<input
type="checkbox"
name={ `checkbox-${a.uuid}-${i}` }
data-uuid={ a.uuid }
checked={ selectedUUIDs.has(a.uuid) }
onChange={ this.toggleRowSelect }
className="align-middle"
/>
}
</td>
<td>{ a.cropName }</td>
<td><Link to={ `/a/${a.uuid}` }>{ a.accessionNumber }</Link></td>
......@@ -161,6 +226,9 @@ class AccessionListPage extends React.Component<IAccessionListPageProps & WithTr
<td><span dangerouslySetInnerHTML={ { __html: a.taxonomy.taxonNameHtml } } /></td>
<td>{ a.countryOfOrigin && a.countryOfOrigin.name }</td>
<td>{ a.sampStat && t(`accession.sampleStatus.${a.sampStat}`) }</td>
<td>
{this.renderCartButton(a, i)}
</td>
</tr>
)) }
</tbody>
......
......@@ -10,6 +10,10 @@
"notFound": "Not Found",
"errorHappened": "Error happened while processing request"
},
"list": {
"availability": "Availability",
"notAvailable": "Not Available"
},
"estimatedNumberOfItems": "{{count, number}} {{what, lowercase}}",
"accession": {
"model": "Accession",
......
......@@ -40,28 +40,39 @@ export class LocalStorageCart {
return items && items.length ? items : [];
};
public static addToCart = (items: string[]) => {
// console.log('add to cart: ', items);
public static addToCart = (what: string | string[]) => {
// console.log('add to cart: ', what);
const cartUuids = LocalStorageCart.getCartItemsLS();
if (cartUuids.length === 0) {
return localStorage.setItem(LocalStorageCart.LS_KEY, JSON.stringify(items));
return localStorage.setItem(LocalStorageCart.LS_KEY, JSON.stringify(Array.isArray(what) ? what : [what]));
}
const uuidsSet = new Set(cartUuids);
items.forEach((id) => {
if (uuidsSet.has(id)) {
return;
}
uuidsSet.add(id);
});
if (typeof what === 'string') {
uuidsSet.add(what);
}
if (Array.isArray(what)) {
what.forEach((id) => {
if (uuidsSet.has(id)) {
return;
}
uuidsSet.add(id);
});
}
const cart = [];
uuidsSet.forEach((id) => cart.push(id));
localStorage.setItem(LocalStorageCart.LS_KEY, JSON.stringify(cart));
};
public static removeFromCart = (uuids: string[]) => {
public static removeFromCart = (what: string | string[]) => {
const cartUuids = LocalStorageCart.getCartItemsLS();
const updatedCartItems = cartUuids.filter((cartUuid) => !uuids.some((uuidToRemove) => cartUuid === uuidToRemove));
let updatedCartItems;
if (typeof what === 'string') {
updatedCartItems = cartUuids.filter((cartUuid) => cartUuid !== what);
}
if (typeof what === 'object') {
updatedCartItems = cartUuids.filter((cartUuid) => !what.some((uuidToRemove) => cartUuid === uuidToRemove));
}
localStorage.setItem(LocalStorageCart.LS_KEY, JSON.stringify(updatedCartItems));
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment