Skip to content

Commit

Permalink
Ft log points validation (#212)
Browse files Browse the repository at this point in the history
* Redux Saga setup

* Clean Saga examples

* Onboading screen

* log points

* merge conflicts

* Log society activity points

* Log points reducer tests

* log activity points action tests

* log activity points generators and component tests

* refactor and implement review feedback

* remove evaluation

* update branch

* add expects blocks to my tests

* team feedback implementation

* improve test coverage

* improve test coverage

* improve tests

* toast component

* Remove unnecessary code

* logged activity should be added to the user activity list

* Rename file

* test componentDidUpdate

* add snapshot

* toast component

* add modal inputs validation

* commit

* fix failing test

* clean branch

* fix failing CI build

* tests

* test

* test

* fix date format

* resolve conflict
  • Loading branch information
Kachulio1 committed Apr 23, 2019
1 parent 6f6c03e commit 0ffa863
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 30 deletions.
27 changes: 13 additions & 14 deletions src/app/Dashboard/components/LogPointsModalContainer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import Dialog from '@material-ui/core/Dialog';
import { format } from 'date-fns';
import TextField from '@material-ui/core/TextField';
Expand Down Expand Up @@ -150,6 +149,7 @@ export class LogPointsModal extends Component {
categories={categories}
categoryId={categoryOption}
/>
{errors.categoryOption && <span className='validation-error'>{errors.categoryOption}</span>}
<TextField
id='filled-number'
name='numberOfParticipants'
Expand All @@ -161,19 +161,17 @@ export class LogPointsModal extends Component {
margin='normal'
fullWidth
/>
<TextField
required
id='date'
label='Date'
type='date'
value={activityDate}
margin='normal'
InputLabelProps={{
shrink: true,
}}
fullWidth
onChange={this.handleChange('activityDate')}
/>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<DatePicker
margin='normal'
fullWidth
label='Date'
value={activityDate}
maxDate={today}
minDate={minDate}
onChange={this.handleDateChange}
/>
</MuiPickersUtilsProvider>
<TextField
required
id='standard-description'
Expand All @@ -183,6 +181,7 @@ export class LogPointsModal extends Component {
value={description}
onChange={this.handleChange('description')}
/>
{errors.description && <span className='validation-error'>{errors.description}</span>}
<div>
<ButtonComponent type='button' className='btn-points'>
{selectCategory.value}
Expand Down
47 changes: 43 additions & 4 deletions src/app/Redemptions/components/RedemptionsContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { getUserInfo, getToken, dollarsToPointsConverter } from '../../utils';

import RedeemPointsModal from './RedeemPointsDialogComponent';
import RedemptionsComponent from './RedemptionsComponent';
import { ButtonComponent, LoaderComponent, SocietyStatsComponent } from '../../common/components';
import LogPointsComponent from '../../Dashboard/components/LogPointsModalContainer';
import {
ButtonComponent, LoaderComponent, SocietyStatsComponent, ToastMessageComponent,
} from '../../common/components';

export class RedemptionsContainer extends Component {
static defaultProps = {
Expand All @@ -17,6 +20,8 @@ export class RedemptionsContainer extends Component {
fetchUserActivites: null,
fetchSocietyInfoRequest: null,
fetchSocietyRedemptionsRequest: null,
successMessage: '',
showToastMessage: false,
};

static propTypes = {
Expand All @@ -26,6 +31,8 @@ export class RedemptionsContainer extends Component {
fetchUserActivites: PropTypes.func,
fetchSocietyInfoRequest: PropTypes.func,
fetchSocietyRedemptionsRequest: PropTypes.func,
successMessage: PropTypes.string,
showToastMessage: PropTypes.bool,
};

initialState = {
Expand All @@ -40,6 +47,7 @@ export class RedemptionsContainer extends Component {

state = {
...this.initialState,
logPoints: false,
};

componentDidMount() {
Expand All @@ -65,6 +73,13 @@ export class RedemptionsContainer extends Component {
this.setState({ openRedeemPointsModal: bool });
};

logPointsModal = () => {
const { logPoints } = this.state;
this.setState({
logPoints: !logPoints,
});
};

handleChange = (event) => {
const { name, value } = event.target;
if (name === 'usdValue') {
Expand Down Expand Up @@ -120,10 +135,16 @@ export class RedemptionsContainer extends Component {

render() {
const {
date, errors, center, points, reason, usdValue, openRedeemPointsModal,
date, errors, center, points, reason, usdValue, openRedeemPointsModal, logPoints,
} = this.state;
const { society, societyName } = this.props;
const {
society, societyName, successMessage, showToastMessage,
} = this.props;
let redemptionsHtml = <LoaderComponent className='loader' />;
let logPointsComponent;
if (logPoints) {
logPointsComponent = <LogPointsComponent open={logPoints} close={this.logPointsModal} />;
}
if (societyName) {
const {
usedPoints, pointsEarned, remainingPoints, activitiesLogged, redemptions,
Expand All @@ -144,8 +165,23 @@ export class RedemptionsContainer extends Component {
</div>
<div className='user-dashboard__actions user-dashboard__actions--society col-sm-12'>
<h3 className='user-dashboard__title'>Latest Activities</h3>
<ToastMessageComponent
className='success'
show={showToastMessage}
>
<div>
<span className='success-message'>{successMessage}</span>
<span className='checkmark'>
<div className='checkmark_stem' />
<div className='checkmark_kick' />
</span>
</div>
</ToastMessageComponent>
<div>
<ButtonComponent className='button__add'>
<ButtonComponent
className='button__add button__points'
onClick={this.logPointsModal}
>
<span className='fa fa-plus' />
<span>Log Points</span>
</ButtonComponent>
Expand Down Expand Up @@ -174,6 +210,7 @@ export class RedemptionsContainer extends Component {
onClose={() => this.showRedeemPointsModal(false)}
handleRedemptionSubmit={this.handleRedemptionSubmit}
/>
{logPointsComponent}
<RedemptionsComponent activities={redemptions} />
</div>
);
Expand All @@ -185,6 +222,8 @@ export class RedemptionsContainer extends Component {
const mapStateToProps = ({ society, dashboard }) => ({
society,
societyName: dashboard.society,
successMessage: dashboard.activity.message,
showToastMessage: dashboard.showToastMessage,
});

const mapDispatchToProps = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { mount } from 'enzyme';
import { mount, shallow } from 'enzyme';

import { RedemptionsContainer } from '../RedemptionsContainer';

Expand Down Expand Up @@ -30,6 +30,7 @@ describe('<RedemptionsContainer />', () => {
fetchSocietyRedemptionsRequest: jest.fn(),
};
const shallowWrapper = mount(<RedemptionsContainer {...props} />);
const wrapper = shallow(<RedemptionsContainer {...props} />);

it('has a 3 ButtonComponents', () => {
expect(shallowWrapper.find('ButtonComponent')).toHaveLength(3);
Expand Down Expand Up @@ -118,4 +119,11 @@ describe('<RedemptionsContainer />', () => {
shallowWrapper.setProps({ societyName: 'phoenix', society: { phoenix: { redemptions: [] }} });
expect(spy).toHaveBeenCalled();
});

it('should open the Log Points Modal', () => {
const instance = wrapper.instance();
expect(instance.state.logPoints).toBe(false);
wrapper.find('.button__points').simulate('click');
expect(instance.state.logPoints).toBe(true);
});
});
47 changes: 43 additions & 4 deletions src/app/Societies/components/SocietiesContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { connect } from 'react-redux';

import { actions } from '../operations';
import SocietyActivities from './SocietyActivitiesComponent';
import { ButtonComponent, TabsComponent, SocietyStatsComponent } from '../../common/components';
import LogPointsComponent from '../../Dashboard/components/LogPointsModalContainer';
import {
ButtonComponent, TabsComponent, SocietyStatsComponent, ToastMessageComponent,
} from '../../common/components';

export class SocietiesContainer extends Component {
static defaultProps = {
Expand All @@ -16,17 +19,22 @@ export class SocietiesContainer extends Component {
society: {},
fetchSocietyInfoRequest: null,
fetchSocietyRedemptionsRequest: null,
successMessage: '',
showToastMessage: false,
};

static propTypes = {
match: PropTypes.shape({}),
society: PropTypes.shape({}),
fetchSocietyInfoRequest: PropTypes.func,
fetchSocietyRedemptionsRequest: PropTypes.func,
successMessage: PropTypes.string,
showToastMessage: PropTypes.bool,
};

state = {
selectedTab: 'activities',
logPoints: false,
};

componentDidMount() {
Expand Down Expand Up @@ -64,13 +72,22 @@ export class SocietiesContainer extends Component {
this.setState({ selectedTab: tabName });
};

logPointsModal = () => {
const { logPoints } = this.state;
this.setState({
logPoints: !logPoints,
});
};

render() {
const { selectedTab } = this.state;
const { selectedTab, logPoints } = this.state;
const {
society,
match: {
params: { society: societyName },
},
successMessage,
showToastMessage,
} = this.props;
const {
usedPoints, pointsEarned, redemptions, remainingPoints, activitiesLogged, loggedActivities,
Expand All @@ -79,6 +96,10 @@ export class SocietiesContainer extends Component {
];
const societyData = selectedTab === 'activities' ? loggedActivities : redemptions;
const tabNames = ['activities', 'redemptions'];
let logPointsComponent;
if (logPoints) {
logPointsComponent = <LogPointsComponent open={logPoints} close={this.logPointsModal} />;
}
return (
<div>
<div className='profile-overview profile-overview--society'>
Expand All @@ -92,9 +113,24 @@ export class SocietiesContainer extends Component {
/>
</div>
<div className='user-dashboard__actions user-dashboard__actions--society col-sm-12'>
<ToastMessageComponent
className='success'
show={showToastMessage}
>
<div>
<span className='success-message'>{successMessage}</span>
<span className='checkmark'>
<div className='checkmark_stem' />
<div className='checkmark_kick' />
</span>
</div>
</ToastMessageComponent>
<TabsComponent selectedTab={selectedTab} changeSelectedTab={this.changeSelectedTab} tabNames={tabNames} />
<div>
<ButtonComponent className='button__add'>
<ButtonComponent
className='button__add'
onClick={this.logPointsModal}
>
<span className='fa fa-plus' />
<span>Log Points</span>
</ButtonComponent>
Expand All @@ -104,15 +140,18 @@ export class SocietiesContainer extends Component {
</ButtonComponent>
</div>
</div>
{logPointsComponent}
<SocietyActivities activities={societyData} selectedTab={selectedTab} />
</div>
);
}
}

const mapStateToProps = ({ society }) => ({
const mapStateToProps = ({ society, dashboard }) => ({
loading: society.loading,
society,
successMessage: dashboard.activity.message,
showToastMessage: dashboard.showToastMessage,
});

const mapDispatchToProps = {
Expand Down
7 changes: 7 additions & 0 deletions src/app/Societies/components/tests/SocietiesContainer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,11 @@ describe('<SocietiesContainer />', () => {
shallowWrapper.setProps({ match: { params: { society: 'istelle' }} });
expect(spy).toHaveBeenCalled();
});

it('should open the Log Points Modal', () => {
const instance = shallowWrapper.instance();
expect(instance.state.logPoints).toBe(false);
shallowWrapper.find('.button__add').simulate('click');
expect(instance.state.logPoints).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ const VerifyActivitiesComponent = ({ activities }) => {
} else {
tableBodyHtml = activities.map((activity) => {
const {
id, owner, date, description, points, category,
id, owner, activityDate, description, points, category,
} = activity;
return (
<tr key={id} className='myactivities__table__row'>
<td>{owner}</td>
<td>{format(new Date(date), 'MMM dd yyyy')}</td>
<td>{format(new Date(activityDate), 'MMM dd yyyy')}</td>
<td>{category}</td>
<td>{points}</td>
<td>
Expand Down
Loading

0 comments on commit 0ffa863

Please sign in to comment.