Skip to content

Commit

Permalink
Merge pull request #49 from MetaPhase-Consulting/feature/TM-279-disab…
Browse files Browse the repository at this point in the history
…led-bid-button

Disabled state for Bid List button
  • Loading branch information
mjoyce91 committed Jan 7, 2019
2 parents c94fc92 + 4663d21 commit 3b249d6
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 48 deletions.
32 changes: 22 additions & 10 deletions src/Components/BidListButton/BidListButton.jsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,50 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import FontAwesome from 'react-fontawesome';
import { get } from 'lodash';
import { existsInNestedObject } from '../../utilities';
import { BID_RESULTS } from '../../Constants/PropTypes';

class BidListButton extends Component {

constructor(props) {
super(props);
this.getBidData = this.getBidData.bind(this);
this.toggleSaved = this.toggleSaved.bind(this);
}

getIsSaved() {
// Is the id in the array? If so, return true
getBidData() {
const { compareArray, id } = this.props;
return existsInNestedObject(id, compareArray);
const exists = existsInNestedObject(id, compareArray);
return {
isSaved: exists,
canDelete: get(exists, 'can_delete', false),
};
}

toggleSaved() {
const { toggleBidPosition, id } = this.props;
const { disabled, toggleBidPosition, id } = this.props;
const { isSaved } = this.getBidData();
// pass the id and the "remove" param
toggleBidPosition(id, this.getIsSaved());
if (!disabled) {
toggleBidPosition(id, isSaved);
}
}

render() {
// is the bid currently saved?
// save value and avoid interrogating the array more than once
const bidIsSaved = this.getIsSaved();
const text = bidIsSaved ? 'Remove from Bid List' : 'Add to Bid List';
const iconClass = bidIsSaved ? 'minus-circle' : 'plus-circle';
const { isSaved, canDelete } = this.getBidData();
const text = isSaved ? 'Remove from Bid List' : 'Add to Bid List';
const iconClass = isSaved ? 'minus-circle' : 'plus-circle';
const style = {
pointerEvents: this.props.isLoading ? 'none' : 'inherit',
};
const { className } = this.props;
const { className, disabled } = this.props;
const disabled$ = disabled || !canDelete;
const disabledClass = disabled$ ? 'usa-button-disabled' : '';
return (
<button className={className} style={style} onClick={this.toggleSaved}>
<button className={`${disabledClass} ${className}`} style={style} onClick={this.toggleSaved} disabled={disabled$}>
<span className="button-icon">
<FontAwesome name={iconClass} />
</span>
Expand All @@ -50,12 +60,14 @@ BidListButton.propTypes = {
compareArray: BID_RESULTS,
isLoading: PropTypes.bool,
className: PropTypes.string,
disabled: PropTypes.bool,
};

BidListButton.defaultProps = {
compareArray: [],
isLoading: false,
className: 'bid-list-button',
disabled: false,
};

export default BidListButton;
15 changes: 15 additions & 0 deletions src/Components/BidListButton/BidListButton.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ describe('BidListButtonComponent', () => {
sinon.assert.calledOnce(spy);
});

it('is disabled and correctly styled when disabled === true', () => {
const spy = sinon.spy();
const wrapper = shallow(
<BidListButton
id={1}
toggleBidPosition={spy}
compareArray={bidListFalse}
isLoading={false}
disabled
/>,
);
wrapper.find('.usa-button-disabled').simulate('click');
sinon.assert.notCalled(spy);
});

it('matches snapshot when the user can add the position', () => {
const wrapper = shallow(
<BidListButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

exports[`BidListButtonComponent matches snapshot when the user can add the position 1`] = `
<button
className="bid-list-button"
className="usa-button-disabled bid-list-button"
disabled={true}
onClick={[Function]}
style={
Object {
Expand All @@ -25,7 +26,8 @@ exports[`BidListButtonComponent matches snapshot when the user can add the posit

exports[`BidListButtonComponent matches snapshot when the user can remove the position 1`] = `
<button
className="bid-list-button"
className="usa-button-disabled bid-list-button"
disabled={true}
onClick={[Function]}
style={
Object {
Expand Down
31 changes: 22 additions & 9 deletions src/Components/PositionTitle/PositionTitle.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ import React from 'react';
import PropTypes from 'prop-types';
import Helmet from 'react-helmet';
import { get } from 'lodash';
import FontAwesome from 'react-fontawesome';
import { Tooltip } from 'react-tippy';
import OBCUrl from '../OBCUrl';
import BidListButton from '../../Containers/BidListButton';
import Favorite from '../../Containers/Favorite';
import BidCount from '../BidCount';
import { POSITION_DETAILS, BID_LIST, USER_PROFILE } from '../../Constants/PropTypes';
import { getAssetPath, propOrDefault, getPostName, getBidStatisticsObject } from '../../utilities';
import { NO_POST } from '../../Constants/SystemMessages';
import { getAssetPath, propOrDefault, getPostName } from '../../utilities';
import { CANNOT_BID_DEFAULT, CANNOT_BID_SUFFIX, NO_POST } from '../../Constants/SystemMessages';

const seal = getAssetPath('/assets/img/us-flag.jpg');

const PositionTitle = ({ details, bidList, userProfile, bidListToggleIsLoading }) => {
const obcId = propOrDefault(details, 'post.obc_id');
const stats = getBidStatisticsObject(details.bid_statistics);
const availablilityText = get(details, 'availability.reason') ?
`${details.availability.reason}${CANNOT_BID_SUFFIX}` : CANNOT_BID_DEFAULT;
return (
<div className="position-details-header-container">
<Helmet>
Expand Down Expand Up @@ -54,16 +56,27 @@ const PositionTitle = ({ details, bidList, userProfile, bidListToggleIsLoading }
src={seal}
/>
</div>
<div className="offset-bid-button-container offset-bid-count-container">
<div className="usa-grid-full position-title-bid-count">
<BidCount bidStatistics={stats} label="Bid Count" altStyle />
</div>
</div>
<div className="offset-bid-button-container">
{
!get(details, 'availability.availability', true) &&
<div className="unavailable-tooltip">
<Tooltip
title={availablilityText}
arrow
position="bottom"
tabIndex="0"
theme="light"
>
<FontAwesome name="question-circle" />
{'Why can\'t I add this position to my bid list?'}
</Tooltip>
</div>
}
<BidListButton
compareArray={bidList.results}
id={details.id}
isLoading={bidListToggleIsLoading}
disabled={!get(details, 'availability.availability', true)}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,34 +72,12 @@ exports[`PositionTitleComponent matches snapshot 1`] = `
src="/assets/img/us-flag.jpg"
/>
</div>
<div
className="offset-bid-button-container offset-bid-count-container"
>
<div
className="usa-grid-full position-title-bid-count"
>
<BidCount
altStyle={true}
bidStatistics={
Object {
"at_skill": 0,
"bidcycle": 1,
"id": 1,
"in_grade": 0,
"in_grade_at_skill": 0,
"total_bids": 3,
}
}
hideLabel={false}
label="Bid Count"
/>
</div>
</div>
<div
className="offset-bid-button-container"
>
<Connect(BidListButtonContainer)
compareArray={Array []}
disabled={false}
id={6}
isLoading={false}
/>
Expand Down
3 changes: 3 additions & 0 deletions src/Constants/SystemMessages.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,6 @@ export const NEW_SAVED_SEARCH_SUCCESS = name =>
`New search with the name "${name}" has been saved! You can go to your profile to view all of your saved searches.`;
export const UPDATED_SAVED_SEARCH_SUCCESS = name =>
`Your saved search with the name "${name}" has been updated! You can go to your profile to view all of your saved searches.`;

export const CANNOT_BID_SUFFIX = ', but can be favorited for the future.';
export const CANNOT_BID_DEFAULT = `This position is not available to bid on${CANNOT_BID_SUFFIX}`;
11 changes: 10 additions & 1 deletion src/sass/_details.scss
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,18 @@
left: 65%;
position: absolute;

.unavailable-tooltip {
font-size: 1.3rem;
text-decoration: underline;

.fa {
margin-right: 5px;
}
}

.bid-list-button,
a {
box-shadow: $button-box-shadow;
box-shadow: $button-box-shadow !important;
padding: 1em 3em;

@media screen and (max-width: $screen-xs-max) {
Expand Down
11 changes: 11 additions & 0 deletions src/sass/_tooltip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,14 @@
.tippy-tooltip--regular {
font-size: .8em;
}

.tippy-popper {
.tippy-tooltip.light-theme {
background-color: $blue-primary;
color: $color-white;
}
}

.tippy-popper[x-placement^=bottom] .tippy-tooltip.light-theme [x-arrow] {
border-bottom: 7px solid $blue-primary;
}
6 changes: 4 additions & 2 deletions src/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,12 @@ export const existsInArray = (ref, array) => {
// for checking if a position is in the user's bid list
export const existsInNestedObject = (ref, array, prop = 'position', nestedProp = 'id') => {
let found = false;
array.forEach((i) => {
array.some((i) => {
if (i[prop] && i[prop][nestedProp] === ref) {
found = true;
found = i;
return true;
}
return false;
});
return found;
};
Expand Down
3 changes: 2 additions & 1 deletion src/utilities.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ describe('formQueryString', () => {

describe('existsInNestedObject', () => {
it('can return true when something exists in a nested object', () => {
expect(existsInNestedObject(1, [{ position: { id: 1 } }])).toBe(true);
const arr = [{ position: { id: 1 } }];
expect(existsInNestedObject(1, arr)).toEqual(arr[0]);
});

it('can return false when something does not exist in a nested object', () => {
Expand Down

0 comments on commit 3b249d6

Please sign in to comment.