Skip to content

Commit

Permalink
Add sex filter to Adoption page
Browse files Browse the repository at this point in the history
  • Loading branch information
kellynvd committed Jan 17, 2020
1 parent ade295b commit 7235dee
Show file tree
Hide file tree
Showing 17 changed files with 176 additions and 114 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ group :development do
gem 'guard-livereload'
gem 'guard-rspec'
gem 'rubocop', '~> 0.62.0', require: false
gem 'byebug'
end

group :production do
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ GEM
font-awesome-rails
jquery-rails
builder (3.2.4)
byebug (11.0.1)
capybara (3.29.0)
addressable
mini_mime (>= 0.1.3)
Expand Down Expand Up @@ -392,6 +393,7 @@ DEPENDENCIES
aws-sdk-s3
bootstrap (>= 4.3.1)
bootstrap_sb_admin_base_v2
byebug
capybara
coffee-rails (~> 4.2)
cpf_cnpj
Expand Down
5 changes: 4 additions & 1 deletion app/controllers/v1/pets_for_adoption_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ class V1::PetsForAdoptionController < ApplicationController
skip_before_action :verify_authenticity_token

def index
pets = Pet.active
pets = pets.by_sex(params[:sex]) if params[:sex].present?

render json: {
pets: ListPets.new.all(Pet.active, params[:user_email])
pets: ListPets.new.all(pets, params[:user_email])
}.to_json
end

Expand Down
10 changes: 10 additions & 0 deletions app/javascript/actions/adoptionFilters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const types = {
SET_SEX_FILTER: 'ADOPTION_FILTERS/SET_SEX_FILTER'
};

const setSexFilter = (sex = '') => ({
type: types.SET_SEX_FILTER,
sex
});

export default setSexFilter;
49 changes: 20 additions & 29 deletions app/javascript/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,28 @@ import Navigation from "./Navigation/Navigation";

require('typeface-roboto');

const store = configureStore();

class App extends React.Component {
constructor(props) {
super(props);
this.state = {
user: {
email: this.props.userEmail,
group: this.props.userGroup,
}
};
}
render() {
const user = this.props.user;
const store = configureStore(user);

render() {
return (
<ErrorBoundary>
<Provider store={store}>
<BrowserRouter>
<Navigation user={this.state.user} />
<Switch>
<Route exact path="/" render={() => window.location.href = '/'}/>
<Route exact path="/ongs" render={() => window.location.href = '/ongs'}/>
<Route path="/new/ongs" render={() => <NgosList />}/>
<Route exact path="/new/ong/:id" component={NgoPage}/>
<Route path="/adocao" render={() => <AdoptionList userEmail={this.state.user.email} />}/>
</Switch>
</BrowserRouter>
</Provider>
</ErrorBoundary>
);
}
return (
<ErrorBoundary>
<Provider store={store}>
<BrowserRouter>
<Navigation user={user} />
<Switch>
<Route exact path="/" render={() => window.location.href = '/'} />
<Route exact path="/ongs" render={() => window.location.href = '/ongs'} />
<Route path="/new/ongs" render={() => <NgosList />} />
<Route exact path="/new/ong/:id" component={NgoPage} />
<Route path="/adocao" component={AdoptionList} />
</Switch>
</BrowserRouter>
</Provider>
</ErrorBoundary>
);
}
}

export default App
12 changes: 12 additions & 0 deletions app/javascript/components/Button/Button.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import styles from './Button.sass';

const Button = (props) => (
<button
children={props.children}
className={styles.Button}
onClick={props.onClick}
/>
);

export default Button;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.SimpleSubmitButton
.Button
width: 200px
height: 50px
border-radius: 4px
Expand All @@ -14,5 +14,5 @@
text-transform: uppercase
border: 0

.SimpleSubmitButton:hover
.Button:hover
background-color: #ff8a8a
24 changes: 11 additions & 13 deletions app/javascript/components/SelectInput/SelectInput.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import React from 'react';
import styles from './SelectInput.sass';

const SelectInput = (props) => {
return (
<div className={styles.SelectInput} style={{width: props.width, marginRight: props.marginRight}}>
<label>{props.label}</label>
<select name="color">
<option value="">{props.placeholder}</option>
{props.options && props.options.length > 0 && props.options.map(opt => {
return <option key={opt.id} value={opt.id}>{opt.name}</option>
})}
</select>
</div>
);
};
const SelectInput = (props) => (
<div className={styles.SelectInput} style={{width: props.width, marginRight: props.marginRight}}>
<label>{props.label}</label>
<select name={props.name} onChange={props.onChange}>
<option value="">{props.placeholder}</option>
{props.options && props.options.length > 0 && props.options.map(opt => {
return <option key={opt.id} value={opt.id}>{opt.name}</option>
})}
</select>
</div>
);

export default SelectInput;

This file was deleted.

59 changes: 34 additions & 25 deletions app/javascript/configureStore.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,40 @@
import { createStore, applyMiddleware } from 'redux';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import adoptionFiltersReducer from './reducers/adoptionFilters'

const initialState = { };
const appReducerDefaultState = {
user: { email: null, group: null },
};

function rootReducer(state, action) {
switch (action.type) {
case "GET_NGOS_SUCCESS":
return { ngos: action.json.ngos };
case "GET_NGO_SUCCESS":
return { ngo: action.json.ngo };
case "GET_ADOPTION_SUCCESS":
return { pets: action.json.pets };
case "GET_NGO_CITIES_SUCCESS":
return { cities: action.json.cities };
default:
return state;
}
function appReducer(state = appReducerDefaultState, action) {
switch (action.type) {
case "GET_NGOS_SUCCESS":
return { ...state, ngos: action.json.ngos };
case "GET_NGO_SUCCESS":
return { ...state, ngo: action.json.ngo };
case "GET_ADOPTION_SUCCESS":
return { ...state, pets: action.json.pets };
case "GET_NGO_CITIES_SUCCESS":
return { ...state, cities: action.json.cities };
default:
return state;
}
}

export default function configureStore() {
const store = createStore(
rootReducer,
initialState,
composeWithDevTools(
applyMiddleware(thunk)
)
);
return store;
}
const rootReducer = combineReducers({
app: appReducer,
adoptionFilters: adoptionFiltersReducer
});

export default function configureStore(user) {
const preloadedState = { app: { user } };

const store = createStore(
rootReducer,
preloadedState,
composeWithDevTools(applyMiddleware(thunk))
);

return store;
};
44 changes: 29 additions & 15 deletions app/javascript/containers/AdoptionList/AdoptionList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,28 @@ import SimpleModal from "../../components/SimpleModal/SimpleModal";
const GET_ADOPTION_REQUEST = 'GET_ADOPTION_REQUEST';
const GET_ADOPTION_SUCCESS = 'GET_ADOPTION_SUCCESS';

function fetchPetsForAdoption(userEmail) {
return dispatch => {
dispatch({type: GET_ADOPTION_REQUEST});

const params = userEmail ? "user_email=" + userEmail : null;

return fetch(`../v1/pets_for_adoption.json?` + params)
.then(response => response.json())
.then(json => dispatch(fetchPetsForAdoptionSuccess(json)))
.catch(error => console.log(error));
export function fetchPetsForAdoption() {
return (dispatch, getState) => {
const userEmail = getState().app.user.email;
const sex = getState().adoptionFilters.sex;
dispatch({type: GET_ADOPTION_REQUEST});

let params = [];
if (userEmail) {
params.push(`user_email=${userEmail}`);
}
if (sex) {
params.push(`sex=${sex}`);
}
const urlParams = params.join('&');

return (
fetch(`../v1/pets_for_adoption.json?` + urlParams)
.then(response => response.json())
.then(json => dispatch(fetchPetsForAdoptionSuccess(json)))
.catch(error => console.log(error))
);
}
}

export function fetchPetsForAdoptionSuccess(json) {
Expand All @@ -35,8 +46,7 @@ class AdoptionList extends React.Component {
};

componentWillMount() {
const {fetchPetsForAdoption, userEmail} = this.props;
fetchPetsForAdoption(userEmail);
this.props.fetchPetsForAdoption();
}

addAdoptionInterestHandler = (userEmail, pet) => {
Expand Down Expand Up @@ -105,6 +115,9 @@ class AdoptionList extends React.Component {
</div>
}
</SimpleModal>

<AdoptionFilterBox />

<div className={styles.adoptionCards}>
{pets && this.petList(pets)}
{/* Trick to align last row of cards with flexbox */}
Expand All @@ -118,10 +131,11 @@ class AdoptionList extends React.Component {
}
}

const structuredSelector = createStructuredSelector({
pets: state => state.pets,
const mapStateToProps = createStructuredSelector({
pets: state => state.app.pets,
userEmail: state => state.app.user.email
});

const mapDispatchToProps = {fetchPetsForAdoption};

export default connect(structuredSelector, mapDispatchToProps)(AdoptionList);
export default connect(mapStateToProps, mapDispatchToProps)(AdoptionList);
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import React from "react";
import styles from "./AdoptionFilterBox.sass";
import SelectInput from "../../../components/SelectInput/SelectInput";
import TextInput from "../../../components/TextInput/TextInput";
import SimpleSubmitButton from "../../../components/SimpleSubmitButton/SimpleSubmitButton";
import Button from "../../../components/Button/Button";
import {createStructuredSelector} from "reselect";
import {connect} from "react-redux";
import setSexFilter from '../../../actions/adoptionFilters';
import { fetchPetsForAdoption } from '../AdoptionList'

const GET_NGO_CITIES_REQUEST = 'GET_NGO_CITIES_REQUEST';
const GET_NGO_CITIES_SUCCESS = 'GET_NGO_CITIES_SUCCESS';
Expand Down Expand Up @@ -32,10 +34,14 @@ class AdoptionFilterBox extends React.Component {
fetchCitiesForAdoption();
}

onSexChange = (e) => {
this.props.setSexFilter(e.target.value);
};

render() {
const cities = this.props;
return (
<form className={styles.FilterBox}>
<div className={styles.FilterBox}>
<SelectInput
label='Cidade'
placeholder='Selecione uma cidade'
Expand All @@ -49,24 +55,37 @@ class AdoptionFilterBox extends React.Component {
width='300px'
marginRight='20px'
/>
<SelectInput
label='Sexo'
placeholder='Selecione um Sexo'
width='200px'
marginRight='20px'
name='sex'
options={[{ id: 'f', name: 'Fêmea' }, { id: 'm', name: 'Macho' }]}
value={this.props.adoptionFilters.sex}
onChange={this.onSexChange}
/>
<TextInput
placeholder='Procure por palavras-chaves'
width='350px'
marginRight='20px'
/>
<SimpleSubmitButton name='Procurar'/>
</form>
<Button children='Procurar' onClick={this.props.fetchPetsForAdoption} />
</div>
);
}
}


const structuredSelector = createStructuredSelector({
cities: state => state.cities,
const mapStateToProps = createStructuredSelector({
cities: state => state.app.cities,
adoptionFilters: state => state.adoptionFilters
});

const mapDispatchToProps = {fetchCitiesForAdoption};

export default connect(structuredSelector, mapDispatchToProps)(AdoptionFilterBox);

const mapDispatchToProps = {
fetchPetsForAdoption,
fetchCitiesForAdoption,
setSexFilter,
};

export default connect(mapStateToProps, mapDispatchToProps)(AdoptionFilterBox);
Loading

0 comments on commit 7235dee

Please sign in to comment.