Skip to content
This repository was archived by the owner on Aug 8, 2019. It is now read-only.

Commit cdef835

Browse files
author
Frank Davis Condezo Fabian
authored
Merge pull request #29 from codeableorg/feature-list-club-favorites
Feature list club favorites
2 parents 6e613b8 + edcaf67 commit cdef835

11 files changed

Lines changed: 175 additions & 38 deletions

File tree

api/app/controllers/clubs_controller.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ class ClubsController < ApplicationController
22
before_action :set_club, only: [:show, :update, :destroy]
33

44
def index
5-
render json: Club.all
5+
if params[:favorites].present?
6+
render json: current_user.clubs
7+
else
8+
render json: Club.all
9+
end
610
end
711

812
def show

api/app/models/user.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ class User < ApplicationRecord
44
has_many :bookings
55

66
has_many :favorites, dependent: :destroy
7+
has_many :clubs, through: :favorites
78

89
validates :email, :name, :role, presence: true
910
validates :email, uniqueness: true

client/src/actions/action-hooks.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React from "react";
22
import { useDispatch } from "react-redux";
3-
43
import {
54
setClubs,
5+
setClubsFavorites,
66
setSportFields,
77
setFavorite,
88
setUnfavorite
@@ -13,6 +13,11 @@ export function useSetClubs() {
1313
return React.useCallback(clubs => dispatch(setClubs(clubs)), [dispatch]);
1414
}
1515

16+
export function useSetClubsFavorites() {
17+
const dispatch = useDispatch();
18+
return React.useCallback(clubs => dispatch(setClubsFavorites(clubs)), [dispatch]);
19+
}
20+
1621
export function useSetFavorite() {
1722
const dispatch = useDispatch();
1823
return React.useCallback(club => dispatch(setFavorite(club)), [dispatch]);

client/src/actions/actions.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ export function setClubs(clubs) {
22
return { type: "SET_CLUBS", payload: clubs };
33
}
44

5+
export function setClubsFavorites(clubs) {
6+
return { type: "SET_CLUBS_FAVORITES", payload: clubs };
7+
}
8+
59
export function setFavorite(clubs) {
610
return { type: "FAVORITED", payload: clubs };
711
}

client/src/components/club.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,14 @@ function Club({ club }) {
7575
>
7676
{club.favorited_count > 0 && club.favorited_count}
7777
</span>
78-
<MapPin width="18px" height="18px" css={styleMapPin} />
79-
<span>
80-
{club.distance !== 0 ? `${club.distance / 1000.0}km` : null}
81-
</span>
78+
{club.distance && (
79+
<>
80+
<MapPin width="18px" height="18px" css={styleMapPin} />
81+
<span>
82+
{club.distance !== 0 ? `${club.distance / 1000.0}km` : null}
83+
</span>
84+
</>
85+
)}
8286
</div>
8387
</div>
8488
</Card>

client/src/components/navbar.js

Lines changed: 68 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,80 @@
11
/** @jsx jsx */
2+
import React from "react";
23
import { jsx } from "@emotion/core";
34
import { Link } from "@reach/router";
45

56
function Navbar() {
7+
const styleMenu = {
8+
textDecoration: "none",
9+
color: "inherit",
10+
padding: "15px",
11+
borderRight: "1px solid #ddd",
12+
flex: "auto",
13+
":last-child": {
14+
border: "none"
15+
}
16+
};
17+
618
return (
7-
<nav
8-
css={{
9-
background: "#fff",
10-
borderBottom: "1px solid #e5edef",
11-
padding: "15px",
12-
marginBottom: "2em"
13-
}}
14-
>
15-
<div
19+
<>
20+
<nav
1621
css={{
17-
maxWidth: "900px",
18-
margin: "auto"
22+
background: "#fff",
23+
borderBottom: "1px solid #e5edef",
24+
padding: "15px",
25+
marginBottom: "2em",
26+
flex: 1
1927
}}
2028
>
21-
<Link to="/" css={{ textDecoration: "none" }}>
22-
<h2
23-
css={{
24-
textDecoration: "none",
25-
margin: "0",
26-
fontSize: "35px",
27-
fontWeight: "500",
28-
backgroundImage:
29-
"-webkit-gradient(linear, 0% 0%, 25% 100%,from(#c5e9a1), to(#00b7c6))",
30-
WebkitBackgroundClip: "text",
31-
WebkitTextFillColor: "transparent"
32-
}}
33-
>
34-
Kampu
35-
</h2>
36-
</Link>
37-
</div>
38-
</nav>
29+
<div
30+
css={{
31+
maxWidth: "900px",
32+
margin: "auto"
33+
}}
34+
>
35+
<Link to="/" css={{ textDecoration: "none" }}>
36+
<h2
37+
css={{
38+
textDecoration: "none",
39+
margin: "0",
40+
fontSize: "35px",
41+
fontWeight: "500",
42+
backgroundImage:
43+
"-webkit-gradient(linear, 0% 0%, 25% 100%,from(#c5e9a1), to(#00b7c6))",
44+
WebkitBackgroundClip: "text",
45+
WebkitTextFillColor: "transparent"
46+
}}
47+
>
48+
Kampu
49+
</h2>
50+
</Link>
51+
</div>
52+
<div
53+
css={{
54+
position: "fixed",
55+
display: "flex",
56+
bottom: "1px",
57+
background: "#fff",
58+
border: "1px solid #ddd",
59+
right: "0",
60+
left: "0",
61+
alignItems: "center",
62+
justifyContent: "space-around",
63+
textAlign: "center"
64+
}}
65+
>
66+
<Link to="/" css={styleMenu}>
67+
Home
68+
</Link>
69+
<Link to="/favorites" css={styleMenu}>
70+
Heart
71+
</Link>
72+
<Link to="/" css={styleMenu}>
73+
Profile
74+
</Link>
75+
</div>
76+
</nav>
77+
</>
3978
);
4079
}
4180

client/src/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import OwnerHome from "./views/owner-home";
1414
import CreateClub from "./views/create-club";
1515
import CreateSportField from "./views/create-sport-field";
1616
import OwnerSportField from "./views/owner-sport-field";
17+
import Favorites from "./views/favorites";
1718
import Navbar from "./components/navbar";
1819
import { register } from "./service-worker";
1920

@@ -26,6 +27,7 @@ function App() {
2627
maxWidth: "900px",
2728
margin: "0 auto",
2829
boxSizing: "border-box",
30+
marginBottom: "80px",
2931
"@media (max-width: 720px)": {
3032
padding: "0px 15px"
3133
}
@@ -48,7 +50,11 @@ function App() {
4850
<OwnerHome path="/owner" />
4951
<CreateClub path="/create-club" />
5052
<CreateSportField path="/create-sport-field" />
53+
<<<<<<< HEAD
5154
<OwnerSportField path="/owner-sport-field/:id" />
55+
=======
56+
<Favorites path="/favorites" />
57+
>>>>>>> Get favorite clubs
5258
</Router>
5359
</main>
5460
</>

client/src/reducers/index.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,37 @@ export function sportFieldsReducer(state = initialState.sportFields, action) {
4343
}
4444
}
4545

46+
export function favoriteClubsReducer(
47+
state = initialState.favoriteClubs,
48+
action
49+
) {
50+
switch (action.type) {
51+
case "SET_CLUBS_FAVORITES": {
52+
return action.payload;
53+
}
54+
case "FAVORITED":
55+
case "UNFAVORITED": {
56+
return state.map(club => {
57+
if (club.id === action.payload.id) {
58+
return {
59+
...club,
60+
favorited: action.payload.favorited,
61+
favorited_count: action.payload.favorited_count
62+
};
63+
}
64+
return club;
65+
});
66+
}
67+
default: {
68+
return state;
69+
}
70+
}
71+
}
72+
4673
const reducer = combineReducers({
4774
clubs: clubsReducer,
48-
sportFields: sportFieldsReducer
75+
sportFields: sportFieldsReducer,
76+
favoriteClubs: favoriteClubsReducer
4977
});
5078

5179
export default reducer;

client/src/selectors/selectors.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ function useClubs() {
44
return useSelector(state => state.clubs, shallowEqual);
55
}
66

7+
function useClubsFavorites() {
8+
return useSelector(state => state.favoriteClubs, shallowEqual);
9+
}
10+
711
function useSportFields() {
812
return useSelector(state => state.sportFields, shallowEqual);
913
}
1014

11-
export { useClubs, useSportFields };
15+
export { useClubs, useSportFields, useClubsFavorites };

client/src/services/club.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ async function getClubs() {
2626
return response.json();
2727
}
2828

29+
async function getFavoriteClubs() {
30+
const response = await fetch(`${apiUrl}/clubs?favorites=true`, {
31+
credentials: "include"
32+
});
33+
34+
if (!response.ok) throw new Error(response.statusText);
35+
return response.json();
36+
}
37+
2938
async function favorite(clubId) {
3039
const response = await fetch(`${apiUrl}/clubs/${clubId}/favorites`, {
3140
credentials: "include",
@@ -48,4 +57,4 @@ async function unfavorite(clubId) {
4857
return response.json();
4958
}
5059

51-
export { getClubs, postClub, favorite, unfavorite };
60+
export { getClubs, postClub, favorite, unfavorite, getFavoriteClubs };

0 commit comments

Comments
 (0)