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

Commit 6c217a3

Browse files
author
Lian Nivin
authored
Merge pull request #37 from codeableorg/feature-information-club
Add Information for clubs
2 parents 4fc0928 + 86f3667 commit 6c217a3

9 files changed

Lines changed: 235 additions & 4 deletions

File tree

api/app/models/club.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
class Club < ApplicationRecord
22
has_one_attached :image
33
has_many :favorites
4+
has_many :sport_fields
45

56
validates :name, presence: true
67
validates :address, presence: true

api/app/serializers/club_serializer.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class ClubSerializer < ActiveModel::Serializer
22
include Rails.application.routes.url_helpers
33

4-
attributes :id, :name, :address, :image, :schedule, :favorited, :favorited_count, :district, :latitude, :longitude
4+
attributes :id, :name, :address, :image, :schedule, :favorited, :favorited_count, :district, :latitude, :longitude, :sport_fields
55

66
def image
77
# rails_blob_path(object.image, only_path: true) if object.image.attached?

client/src/components/club.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Card } from "./ui";
55
import { Heart, MapPin } from "./icons";
66
import { favorite, unfavorite } from "../services/club";
77
import { useSetFavorite, useSetUnfavorite } from "../actions/action-hooks";
8+
import { Link } from "@reach/router";
89

910
function Club({ club }) {
1011
const setFavorite = useSetFavorite();
@@ -50,7 +51,12 @@ function Club({ club }) {
5051
}}
5152
/>
5253
<div>
53-
<h3>{club.name}</h3>
54+
<Link
55+
to={`/clubs/${club.id}`}
56+
css={{ textDecoration: "none", color: "inherit" }}
57+
>
58+
<h3>{club.name}</h3>
59+
</Link>
5460
<div>Address: {club.address}</div>
5561
<div>Price: {club.price}</div>
5662
<div

client/src/components/icons.js

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,62 @@ function MapPin(props) {
3939
);
4040
}
4141

42-
export { Heart, MapPin };
42+
function Ball(props) {
43+
return (
44+
<svg
45+
height="480pt"
46+
viewBox="0 0 480 480"
47+
width="480pt"
48+
xmlns="http://www.w3.org/2000/svg"
49+
{...props}
50+
>
51+
<path d="m240 0c-132.546875 0-240 107.453125-240 240s107.453125 240 240 240 240-107.453125 240-240c-.148438-132.484375-107.515625-239.851562-240-240zm8.566406 69.191406 83.433594-33.351562c9.46875 4.285156 18.628906 9.222656 27.414062 14.777344l.21875.136718c8.632813 5.46875 16.882813 11.519532 24.695313 18.109375l.671875.585938c3.503906 2.984375 6.910156 6.074219 10.222656 9.261719.417969.410156.855469.800781 1.273438 1.21875 3.472656 3.390624 6.835937 6.886718 10.089844 10.484374.269531.304688.527343.625.796874.929688 2.855469 3.199219 5.601563 6.511719 8.265626 9.878906.640624.800782 1.28125 1.601563 1.902343 2.402344 2.890625 3.742188 5.6875 7.550781 8.328125 11.480469l-16.632812 70.703125-81.832032 27.28125-78.828124-63.074219zm-186.125 34.480469c.621094-.800781 1.253906-1.601563 1.894532-2.398437 2.632812-3.339844 5.355468-6.597657 8.167968-9.777344.304688-.335938.585938-.679688.886719-1.015625 3.234375-3.605469 6.582031-7.097657 10.050781-10.480469.398438-.390625.796875-.800781 1.214844-1.160156 3.285156-3.167969 6.664062-6.238282 10.136719-9.207032l.800781-.671874c7.742188-6.542969 15.914062-12.554688 24.460938-18l.3125-.199219c8.734374-5.542969 17.835937-10.472657 27.25-14.761719l83.816406 33.191406v80.800782l-78.832032 63.0625-81.832031-27.230469-16.632812-70.703125c2.664062-3.921875 5.429687-7.722656 8.304687-11.449219zm-9.640625 259.089844c-2.351562-3.585938-4.601562-7.238281-6.746093-10.960938l-.519532-.898437c-2.132812-3.703125-4.152344-7.46875-6.054687-11.292969l-.066407-.121094c-4.007812-8.046875-7.527343-16.328125-10.535156-24.800781v-.078125c-1.421875-4-2.71875-8.097656-3.917968-12.21875l-.433594-1.519531c-1.097656-3.871094-2.09375-7.785156-2.984375-11.742188-.078125-.386718-.175781-.753906-.253907-1.136718-1.964843-8.9375-3.375-17.984376-4.226562-27.097657l48.839844-58.605469 81.265625 27.085938 23.585937 94.335938-38.753906 51.5625zm240.472657 94.78125c-4 .992187-8.105469 1.847656-12.210938 2.617187-.574219.113282-1.160156.207032-1.734375.3125-3.496094.625-7.03125 1.160156-10.574219 1.597656-.945312.121094-1.882812.25-2.824218.363282-3.289063.382812-6.609376.671875-9.9375.910156-1.046876.070312-2.082032.175781-3.128907.242188-4.253906.261718-8.542969.414062-12.863281.414062-3.957031 0-7.890625-.105469-11.800781-.3125-.472657 0-.925781-.078125-1.398438-.113281-3.480469-.199219-6.945312-.460938-10.402343-.796875l-.398438-.074219c-7.574219-.820313-15.105469-2.023437-22.558594-3.597656l-47.320312-74.089844 38.144531-50.863281h111.46875l38.769531 51.199218zm165.496093-169.542969c-.082031.382812-.175781.753906-.257812 1.136719-.894531 3.953125-1.890625 7.867187-2.984375 11.742187l-.429688 1.519532c-1.203125 4.121093-2.496094 8.203124-3.921875 12.21875v.078124c-3.007812 8.472657-6.523437 16.753907-10.535156 24.800782l-.066406.121094c-1.914063 3.828124-3.929688 7.59375-6.054688 11.292968l-.519531.898438c-2.132812 3.734375-4.378906 7.378906-6.734375 10.945312l-78.929687 12.445313-39.023438-51.519531 23.574219-94.3125 81.265625-27.085938 48.839844 58.605469c-.847657 9.117187-2.257813 18.171875-4.222657 27.113281zm0 0" />
52+
</svg>
53+
);
54+
}
55+
56+
function Moon(props) {
57+
return (
58+
<svg
59+
xmlns="http://www.w3.org/2000/svg"
60+
width="24"
61+
height="24"
62+
viewBox="0 0 24 24"
63+
fill="none"
64+
stroke="currentColor"
65+
strokeWidth="2"
66+
strokeLinecap="round"
67+
strokeLinejoin="round"
68+
{...props}
69+
>
70+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
71+
</svg>
72+
);
73+
}
74+
function Sun(props) {
75+
return (
76+
<svg
77+
xmlns="http://www.w3.org/2000/svg"
78+
width="24"
79+
height="24"
80+
viewBox="0 0 24 24"
81+
fill="none"
82+
stroke="currentColor"
83+
strokeWidth="2"
84+
strokeLinecap="round"
85+
strokeLinejoin="round"
86+
{...props}
87+
>
88+
<circle cx="12" cy="12" r="5" />
89+
<line x1="12" y1="1" x2="12" y2="3" />
90+
<line x1="12" y1="21" x2="12" y2="23" />
91+
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
92+
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
93+
<line x1="1" y1="12" x2="3" y2="12" />
94+
<line x1="21" y1="12" x2="23" y2="12" />
95+
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
96+
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
97+
</svg>
98+
);
99+
}
100+
export { Heart, MapPin, Sun, Moon, Ball };
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/** @jsx jsx */
2+
import { jsx } from "@emotion/core";
3+
import React from "react";
4+
import { Text, Card } from "../components/ui";
5+
import { Sun, Moon, Ball } from "./icons";
6+
7+
function SportfieldInfo({ sportField }) {
8+
return (
9+
<Card
10+
css={{
11+
flex: "1",
12+
margin: "1em",
13+
"@media screen and (max-width: 760px)": {
14+
margin: "1em 0"
15+
}
16+
}}
17+
>
18+
<Text css={{ textAlign: "center" }}> {sportField.name}</Text>
19+
20+
<Text css={{ display: "flex", justifyContent: "center" }}>
21+
<Text>
22+
<Ball css={{ width: "20px", height: "20px" }} />
23+
</Text>
24+
<Text>{sportField.description}</Text>
25+
</Text>
26+
27+
<Text>Price</Text>
28+
29+
<Text css={{ display: "flex", justifyContent: "space-between" }}>
30+
<Text css={{ display: "flex" }}>
31+
<Text>
32+
<Sun />
33+
</Text>
34+
<Text>${sportField.price_day}</Text>
35+
</Text>
36+
<Text css={{ display: "flex" }}>
37+
<Text>
38+
<Moon />
39+
</Text>
40+
<Text>${sportField.price_night}</Text>
41+
</Text>
42+
</Text>
43+
</Card>
44+
);
45+
}
46+
47+
export default SportfieldInfo;

client/src/components/ui.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,22 @@ function Label({ styles, ...props }) {
281281
);
282282
}
283283

284+
function Text({ styles, ...props }) {
285+
return (
286+
<span
287+
{...props}
288+
css={{
289+
display: "block",
290+
fontWeight: "300",
291+
padding: "0 8px 8px 0",
292+
fontSize: "16px",
293+
lineHeight: "24px",
294+
color: "#888888"
295+
}}
296+
/>
297+
);
298+
}
299+
284300
function Input({ styles, ...props }) {
285301
return (
286302
<input
@@ -304,6 +320,7 @@ export {
304320
Input,
305321
TextArea,
306322
Label,
323+
Text,
307324
Select,
308325
Title,
309326
SecondaryButton,

client/src/index.js

Lines changed: 2 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 Clubs from "./views/clubs";
1718
import Favorites from "./views/favorites";
1819
import Navbar from "./components/navbar";
1920
import { register } from "./service-worker";
@@ -52,6 +53,7 @@ function App() {
5253
<CreateSportField path="/create-sport-field" />
5354
<OwnerSportField path="/owner-sport-field/:id" />
5455
<Favorites path="/favorites" />
56+
<Clubs path="/clubs/:id" />
5557
</Router>
5658
</main>
5759
</>

client/src/services/club.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,13 @@ async function unfavorite(clubId) {
5757
return response.json();
5858
}
5959

60-
export { getClubs, postClub, favorite, unfavorite, getFavoriteClubs };
60+
async function clubData(id) {
61+
const response = await fetch(`${apiUrl}/clubs/${id}`, {
62+
credentials: "include"
63+
});
64+
65+
if (!response.ok) throw new Error(response.statusText);
66+
return response.json();
67+
}
68+
69+
export { getClubs, postClub, favorite, unfavorite, getFavoriteClubs, clubData };

client/src/views/clubs.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/** @jsx jsx */
2+
import React from "react";
3+
import { jsx } from "@emotion/core";
4+
import { Title, Text, Card } from "../components/ui";
5+
import { clubData } from "../services/club";
6+
import SportfieldInfo from "../components/sportfield-info";
7+
8+
function Clubs({ id }) {
9+
const [club, setClub] = React.useState({ sport_fields: [] });
10+
11+
React.useEffect(() => {
12+
clubData(id).then(data => {
13+
setClub(data);
14+
});
15+
}, []);
16+
17+
const styleTitle = {
18+
fontSize: "0.8em"
19+
};
20+
21+
return (
22+
<div>
23+
<div
24+
css={{
25+
display: "flex",
26+
flexDirection: "column",
27+
"@media screen and (min-width: 768px)": {
28+
display: "flex",
29+
flexDirection: "row",
30+
justifyContent: "space-between"
31+
}
32+
}}
33+
>
34+
<div>
35+
<Title css={styleTitle}>Address</Title>
36+
<Text css={{ fontSize: "12px" }}>{club.address}</Text>
37+
</div>
38+
39+
<br />
40+
41+
<div>
42+
<Title css={styleTitle}>Schedule</Title>
43+
<div css={{ display: "flex", justifyContent: "space-between" }}>
44+
<Text htmlFor="monday-friday.init" css={{ fontSize: "12px" }}>
45+
Monday - Friday
46+
</Text>
47+
<Text css={{ fontSize: "12px" }}>
48+
{club.schedule && club.schedule["monday-friday"].start} -{" "}
49+
{club.schedule && club.schedule["monday-friday"].end}
50+
</Text>
51+
</div>
52+
53+
<div css={{ display: "flex", justifyContent: "space-between" }}>
54+
<Text htmlFor="schedule-saturdays-start" css={{ fontSize: "12px" }}>
55+
Saturday
56+
</Text>
57+
<Text css={{ fontSize: "12px" }}>
58+
{club.schedule && club.schedule["saturday"].start} -{" "}
59+
{club.schedule && club.schedule["saturday"].end}
60+
</Text>
61+
</div>
62+
63+
<div css={{ display: "flex", justifyContent: "space-between" }}>
64+
<Text htmlFor="schedule-sundays-start" css={{ fontSize: "12px" }}>
65+
Sunday
66+
</Text>
67+
<Text css={{ fontSize: "12px" }}>
68+
{club.schedule && club.schedule["sunday"].start} -{" "}
69+
{club.schedule && club.schedule["sunday"].end}
70+
</Text>
71+
</div>
72+
</div>
73+
</div>
74+
<br />
75+
<div
76+
css={{
77+
display: "flex",
78+
"@media screen and (max-width: 760px)": {
79+
display: "block"
80+
}
81+
}}
82+
>
83+
{club.sport_fields.map(sportField => {
84+
return <SportfieldInfo key={sportField.id} sportField={sportField} />;
85+
})}
86+
</div>
87+
</div>
88+
);
89+
}
90+
91+
export default Clubs;

0 commit comments

Comments
 (0)