*/
3 |
4 | .main-review-form-container {
5 | display: flex;
6 | justify-content: space-evenly;
7 | flex-direction: column;
8 | align-items: center;
9 | /* padding-left: 150px; */
10 | padding-right: 30px;
11 | }
12 |
13 | .review-form-container {
14 | border: 1px solid #cccccc;
15 | border-radius: 4px;
16 | width: 587px;
17 | height: 346px;
18 | padding: 18px;
19 | }
20 |
21 | .review-form-business-name {
22 | margin-bottom: 20px;
23 | }
24 |
25 | .review-form-business-name > a {
26 | color: #0073bb;
27 | font-size: 36px;
28 | font-family: "Helvetica Neue";
29 | font-weight: bold;
30 | text-decoration: none;
31 | }
32 |
33 | .review-form-business-name > a:hover {
34 | text-decoration: underline;
35 | cursor: pointer;
36 | }
37 |
38 | .contain-name-form {
39 | display: flex;
40 | flex-direction: column;
41 | /* justify-content: space-around; */
42 | /* align-items: flex-start; */
43 | }
44 |
45 | .review-form {
46 | height: 68%;
47 | }
48 | .one-star {
49 | background-color: #f2bc82;
50 | }
51 | .two-star {
52 | background-color: #fdc116;
53 | }
54 | .three-star {
55 | background-color: #ff9151;
56 | }
57 | .four-star {
58 | background-color: #f25a54;
59 | }
60 | .five-star {
61 | background-color: #d4202b;
62 | }
63 |
64 | .form-rating-list {
65 | display: flex;
66 | width: 181px;
67 | flex-direction: row-reverse;
68 | margin-bottom: 18px;
69 | }
70 | .form-body {
71 | display: block;
72 | width: 102%;
73 | border: 0;
74 | padding-top: 20px;
75 |
76 | height: 100%;
77 | font-size: 18px;
78 | resize: none;
79 | }
80 |
81 | .review-form-button {
82 | color: white;
83 | font-size: 14px;
84 | font-weight: 700;
85 | background-color: #d90007;
86 | background: linear-gradient(#d90007, #c91400);
87 | text-decoration: none;
88 | border-color: #8d0005;
89 | border-radius: 3px;
90 | min-width: 227px;
91 | min-height: 43px;
92 | align-items: center;
93 | padding: 10px 19px 10px 19px;
94 | margin: 18px 0;
95 | text-align: center;
96 | }
97 |
98 | .review-form-button:hover {
99 | color: red;
100 | }
101 |
102 | .fa-trash {
103 | display: inline-block;
104 | width: 25px;
105 | padding: 5px;
106 | border: 1px solid #ccc;
107 | border-radius: 3px;
108 | font-size: 18px;
109 | line-height: 1.5em;
110 | color: #999;
111 | background: transparent;
112 | box-shadow: none;
113 | white-space: nowrap;
114 | -webkit-transition: all 0.3s ease;
115 | transition: all 0.3s ease;
116 | text-align: center;
117 | position: absolute;
118 | bottom: 0px;
119 | right: 0px;
120 | }
121 |
122 | .fa-pencil {
123 | width: 18px;
124 | height: 18px;
125 | }
126 |
127 | .fa-trash:hover {
128 | background: #f8f8f8;
129 | background: -webkit-linear-gradient(#fff, #eee);
130 | background: linear-gradient(#fff, #eee);
131 | text-decoration: none;
132 | color: #333;
133 | border-color: #cdcdcd;
134 | border-color: rgba(0, 0, 0, 0.2);
135 | -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1),
136 | inset 0 1px 0 rgba(255, 255, 255, 0.5);
137 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1),
138 | inset 0 1px 0 rgba(255, 255, 255, 0.5);
139 | }
140 |
141 | .i {
142 | color: white;
143 | margin-left: 5px;
144 | background-color: #d3d3d3;
145 | border-radius: 3px;
146 | }
147 |
148 | .footer {
149 | padding-top: 100px;
150 | }
151 |
152 | .button-container {
153 | display: flex;
154 | align-items: flex-end;
155 | }
156 |
157 | .sub1-head-nav-bar {
158 | width: 80%;
159 | display: flex;
160 | align-items: center;
161 | }
162 | .ul-nav-bar-item {
163 | display: flex;
164 | justify-content: space-around;
165 | text-decoration: none;
166 | font-size: 15px;
167 | }
168 |
169 | .ul-nav-bar-item a {
170 | padding: 0 30px;
171 | text-decoration: none;
172 | border-left: 1px solid #e6e6e6;
173 | border-right: 1px solid #e6e6e6;
174 | font-family: "Helvetica Neue";
175 | color: #333;
176 |
177 | font-weight: 300px;
178 | min-height: 30px;
179 | padding-top: 10px;
180 | }
181 |
182 | .ul-nav-bar-item a:hover {
183 | color: #0073bb;
184 | cursor: pointer;
185 | }
186 | .sub2-head-nav-bar {
187 | width: 60%;
188 | display: flex;
189 | align-items: center;
190 | justify-content: space-evenly;
191 | }
192 | .contain-name-form-wrapper {
193 | width: 45%;
194 | padding-top: 30px;
195 | display: flex;
196 | flex-direction: column;
197 | margin: auto;
198 | justify-content: flex-start;
199 | align-items: flex-start;
200 | }
201 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/search/search.css:
--------------------------------------------------------------------------------
1 | .search-pic-sear-container {
2 | border-radius: 0 4px 4px 0;
3 | border: 0;
4 | background: #d32323;
5 | padding: 14px 20px 13px;
6 | -webkit-box-shadow: none;
7 | box-shadow: none;
8 | }
9 |
10 | .search-sear-container {
11 | height: 42px;
12 | border: none;
13 | width: 800px;
14 | color: rgb(200, 200, 200);
15 | font-size: 16px;
16 | color: black;
17 | }
18 | .location-sear-container {
19 | border: none;
20 | width: 65%;
21 | height: 44px;
22 | width: 800px;
23 | color: rgb(200, 200, 200);
24 | font-size: 16px;
25 | color: black;
26 | }
27 | .search-form-sear-container {
28 | display: flex;
29 | width: 100%;
30 | }
31 |
32 | .sear-ad-cont {
33 | display: flex;
34 | flex-direction: column;
35 | margin-bottom: 580px;
36 | }
37 |
38 | .drop-down-sear-container {
39 | background-color: white;
40 | width: 31%;
41 | position: absolute;
42 | margin-top: 42px;
43 | /* z-index: 1; */
44 | }
45 |
46 | .drop-down-list {
47 | text-decoration: none;
48 | list-style: none;
49 | font-family: Arial;
50 | color: black;
51 | font-size: 13px;
52 | font-weight: bold;
53 | }
54 |
55 | .drop-down-div {
56 | padding: 20px;
57 | }
58 | .drop-down-div:hover {
59 | background-color: #0073bb;
60 | }
61 |
62 | .find-sear-container {
63 | padding: 13px 13px 0;
64 | height: 70%;
65 | border-radius: 5px 0 0 5px;
66 | font-family: sans-serif;
67 | font-weight: bold;
68 | color: #666666;
69 | background-color: white;
70 | font-size: 18px;
71 | }
72 |
73 | .near-sear-container {
74 | padding: 13px 13px 0;
75 | height: 70%;
76 | font-family: sans-serif;
77 | font-weight: bold;
78 | color: #666666;
79 | background-color: white;
80 | font-size: 18px;
81 | }
82 |
83 | .search-bar-container {
84 | width: 65%;
85 | }
86 |
87 | .search-pic-nav-sear-container {
88 | border-radius: 0 4px 4px 0;
89 | border: 0;
90 | background: #d32323;
91 | /* padding: 14px 20px 13px; */
92 | -webkit-box-shadow: none;
93 | box-shadow: none;
94 | }
95 |
96 | .search-nav-sear-container {
97 | /* HEIGHT: 44px; */
98 | border: none;
99 | width: 300px;
100 | color: rgb(200, 200, 200);
101 | font-size: 14px;
102 | color: black;
103 | }
104 |
105 | .location-nav-sear-container {
106 | border: none;
107 | width: 65%;
108 | height: 34px;
109 | width: 300px;
110 | color: rgb(200, 200, 200);
111 | font-size: 14px;
112 | color: black;
113 | }
114 |
115 | .search-form-nav-sear-container {
116 | display: flex;
117 | width: 100%;
118 | max-height: 34px;
119 | }
120 |
121 | .drop-down-nav-sear-container {
122 | background-color: white;
123 | width: 25%;
124 | position: absolute;
125 | /* margin-top: 42px; */
126 | z-index: 2;
127 | }
128 |
129 | .find-nav-sear-container {
130 | padding: 11px 13px 0;
131 | border-radius: 5px 0 0 5px;
132 | font-family: sans-serif;
133 | font-weight: bold;
134 | color: #666666;
135 | background-color: white;
136 | font-size: 14px;
137 | }
138 |
139 | .near-nav-sear-container {
140 | padding: 11px 13px 0;
141 | font-family: sans-serif;
142 | font-weight: bold;
143 | color: #666666;
144 | background-color: white;
145 | font-size: 14px;
146 | }
147 |
148 | .hide {
149 | display: none;
150 | }
151 |
152 | .login-signup-nav {
153 | display: flex;
154 | width: 17%;
155 | justify-content: space-evenly;
156 | }
157 |
158 | .login-sear-nav {
159 | padding: 10px;
160 | border-radius: 4px;
161 | border: solid 1px #c41314;
162 | border: solid 1px #c41314;
163 | background: #d41314;
164 | color: white;
165 | font-size: 14px;
166 | cursor: pointer;
167 | margin: auto;
168 | }
169 |
170 | .signup-sear-nav {
171 | padding: 10px;
172 | border-radius: 4px;
173 | border: solid 1px #c41314;
174 | background: white;
175 | color: black;
176 | font-size: 14px;
177 | cursor: pointer;
178 | margin: auto;
179 | }
180 |
181 | .dropped-down-list1 {
182 | z-index: 2;
183 | position: absolute;
184 | left: 952px;
185 | top: 51px;
186 | min-height: 156px;
187 | max-width: 15%;
188 | margin-top: 20px;
189 | background: white;
190 | border: 1px solid #ccc;
191 | border-color: rgba(0, 0, 0, 0.2);
192 | border-radius: 3px;
193 | -webkit-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
194 | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
195 | font-family: sans-serif;
196 | }
197 | .three {
198 | top: 51px !important;
199 | right: 285px !important;
200 | font-size: 30px !important;
201 | position: absolute !important;
202 | color: white;
203 | }
204 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/session/log_in.css:
--------------------------------------------------------------------------------
1 | .login-header {
2 | width: 100%;
3 | height: 70px;
4 | border: 1px solid red;
5 | background-color: #d90007;
6 | }
7 |
8 | .login-head {
9 | display: flex;
10 | justify-content: center;
11 | margin-top: 20px;
12 | font-family: Helvetica;
13 | font-size: 28px;
14 | font-weight: bold;
15 | -webkit-text-stroke-color: black;
16 | }
17 |
18 | .formtype-header {
19 | color: red;
20 | display: flex;
21 | justify-content: center;
22 | margin: 10px;
23 | font-family: Helvetica;
24 | font-size: 20px;
25 | font-weight: bold;
26 | }
27 |
28 | .hr-line {
29 | border: none;
30 | border-top: 1px solid #ccc;
31 | border-bottom: 1px solid transparent;
32 | text-align: center;
33 | color: gray;
34 | }
35 |
36 | .hr-line legend {
37 | padding: 0 10px;
38 | }
39 |
40 | .formtype-form {
41 | display: block;
42 | margin-top: 120px;
43 | margin-left: 300px;
44 | margin-bottom: 150px;
45 | width: 300px;
46 | }
47 |
48 | .sign-up-link {
49 | display: flex;
50 | justify-content: center;
51 | text-decoration: none;
52 | font-family: Helvetica;
53 | font-size: 14px;
54 | font-weight: bold;
55 | }
56 |
57 | .sign-up-link a {
58 | text-decoration: none;
59 | color: #0073bb;
60 | padding-left: 5px;
61 | }
62 |
63 | .sign-up-link a:hover {
64 | text-decoration: underline;
65 | }
66 |
67 | .bottom-sign-up-link {
68 | margin: 5px;
69 | text-align: right;
70 | color: #999;
71 | font-size: 12px;
72 | font-family: Helvetica;
73 | }
74 |
75 | .bottom-sign-up-link a {
76 | text-decoration: none;
77 | }
78 |
79 | .bottom-sign-up-link a:hover {
80 | text-decoration: underline;
81 | }
82 |
83 | .email {
84 | width: 95%;
85 | padding: 6px;
86 | margin-top: 20px;
87 | margin-bottom: 8px;
88 | font-size: 14px;
89 | border: 1px solid gray;
90 |
91 | border-radius: 3px;
92 | }
93 |
94 | .password {
95 | width: 95%;
96 | padding: 6px;
97 | font-size: 14px;
98 | border: 1px solid gray;
99 |
100 | border-radius: 3px;
101 | }
102 |
103 | .submit {
104 | margin-top: 45px;
105 | width: 100%;
106 | background-color: #d90007;
107 | height: 45px;
108 | color: white;
109 | font-size: 17px;
110 | font-weight: bold;
111 | border: 1px solid black;
112 | box-shadow: 5px black;
113 |
114 | border-radius: 3px;
115 | }
116 |
117 | .login-submit {
118 | margin-top: 45px;
119 | width: 100%;
120 | border-color: #8d0005;
121 | background-color: #d90007;
122 |
123 | height: 45px;
124 | color: white;
125 | font-size: 17px;
126 | font-weight: bold;
127 | border: 1px solid rgb(141, 0, 5);
128 | box-shadow: 5px black;
129 |
130 | border-radius: 3px;
131 | }
132 |
133 | .login-submit:hover {
134 | background-color: #ed0008;
135 | background: linear-gradient(#ed0008, #dd1600);
136 | cursor: pointer;
137 | }
138 |
139 | .bottom-sign-up-link {
140 | justify-content: flex-end;
141 | color: #999;
142 | }
143 |
144 | .image {
145 | display: block;
146 | margin-top: 145px;
147 | margin-left: 750px;
148 | }
149 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/session/reset.css:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | div,
4 | span,
5 | applet,
6 | object,
7 | iframe,
8 | h1,
9 | h2,
10 | h3,
11 | h4,
12 | h5,
13 | h6,
14 | p,
15 | blockquote,
16 | pre,
17 | a,
18 | abbr,
19 | acronym,
20 | address,
21 | big,
22 | cite,
23 | code,
24 | del,
25 | dfn,
26 | em,
27 | img,
28 | ins,
29 | kbd,
30 | q,
31 | s,
32 | samp,
33 | small,
34 | strike,
35 | strong,
36 | sub,
37 | sup,
38 | tt,
39 | var,
40 | b,
41 | u,
42 | i,
43 | center,
44 | dl,
45 | dt,
46 | dd,
47 | ol,
48 | ul,
49 | li,
50 | fieldset,
51 | form,
52 | label,
53 | legend,
54 | table,
55 | caption,
56 | tbody,
57 | tfoot,
58 | thead,
59 | tr,
60 | th,
61 | td,
62 | article,
63 | aside,
64 | canvas,
65 | details,
66 | embed,
67 | figure,
68 | figcaption,
69 | footer,
70 | header,
71 | hgroup,
72 | menu,
73 | nav,
74 | output,
75 | ruby,
76 | section,
77 | summary,
78 | time,
79 | mark,
80 | audio,
81 | video {
82 | margin: 0;
83 | padding: 0;
84 | border: 0;
85 | font-size: 100%;
86 | font: inherit;
87 | vertical-align: baseline;
88 | }
89 | article,
90 | aside,
91 | details,
92 | figcaption,
93 | figure,
94 | footer,
95 | header,
96 | hgroup,
97 | menu,
98 | nav,
99 | section {
100 | display: block;
101 | }
102 | body {
103 | line-height: 1;
104 | }
105 | ol,
106 | ul {
107 | list-style: none;
108 | }
109 | blockquote,
110 | q {
111 | quotes: none;
112 | }
113 | blockquote:before,
114 | blockquote:after,
115 | q:before,
116 | q:after {
117 | content: "";
118 | content: none;
119 | }
120 | table {
121 | border-collapse: collapse;
122 | border-spacing: 0;
123 | }
124 |
125 | input:focus {
126 | outline: none;
127 | }
128 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/session/sign_up.css:
--------------------------------------------------------------------------------
1 | .comment {
2 | display: flex;
3 | justify-content: center;
4 | font-family: Helvetica;
5 | font-weight: bold;
6 | font-size: 14px;
7 | }
8 |
9 | .fname {
10 | padding: 6px;
11 | margin-right: 3px;
12 | border: 1px solid gray;
13 | font-size: 14px;
14 | width: 120px;
15 | border-radius: 3px;
16 | }
17 |
18 | .lname {
19 | padding: 6px;
20 | font-size: 14px;
21 |
22 | border: 1px solid gray;
23 |
24 | border-radius: 3px;
25 | }
26 |
27 | .zipcode {
28 | padding: 6px;
29 | font-size: 14px;
30 | width: 95%;
31 | margin-top: 20px;
32 |
33 | border: 1px solid gray;
34 | margin-bottom: 10px;
35 |
36 | border-radius: 3px;
37 | }
38 |
39 | .test {
40 | margin: 5px;
41 | text-align: right;
42 | color: #999;
43 | font-size: 12px;
44 | padding-top: 7px;
45 | font-family: Helvetica;
46 | }
47 |
48 | .bday {
49 | color: black;
50 | font-family: Helvetica;
51 | font-weight: bold;
52 | font-size: 14px;
53 | margin-top: 10px;
54 | margin-right: 4px;
55 | }
56 | .optional {
57 | color: #999;
58 | margin-top: 5px;
59 |
60 | font-family: Helvetica;
61 | font-size: 12px;
62 | }
63 |
64 | .submit {
65 | margin-top: 15px;
66 | width: 100%;
67 | background-color: #d5312d;
68 | height: 45px;
69 | color: white;
70 | font-size: 17px;
71 | font-weight: bold;
72 | border: 1px solid black;
73 | box-shadow: 5px black;
74 | border-radius: 3px;
75 | }
76 |
77 | .submit:hover {
78 | cursor: pointer;
79 | background-color: red;
80 | }
81 |
82 | .image {
83 | display: block;
84 | margin-top: 145px;
85 | margin-left: 750px;
86 | }
87 |
88 | .signup-birthday {
89 | font-size: 15px;
90 | font-family: Helvetica;
91 | font-weight: bold;
92 | padding-top: 5px;
93 | }
94 |
95 | .optional {
96 | padding-left: 6px;
97 | font-weight: normal;
98 | }
99 |
100 | .small-brand-name {
101 | height: 40px;
102 | padding-right: 15px;
103 | /* margin-bottom: 5px; */
104 | }
105 | .small-brand-name2 {
106 | height: 40px;
107 | padding-right: 15px;
108 | padding-left: 170px;
109 | }
110 | .birthday {
111 | display: flex;
112 | justify-content: space-between;
113 | padding-top: 10px;
114 | }
115 |
116 | .birthday select {
117 | border: 1px solid #999;
118 | font-size: 14px;
119 | background-color: white;
120 | color: gray;
121 | height: 30px;
122 | padding: 7px;
123 | align-items: space-around;
124 | width: 90px;
125 | }
126 |
127 | .guest-demo {
128 | margin-top: 15px;
129 | width: 100%;
130 | background-color: #3b5998;
131 | height: 40px;
132 | color: white;
133 | font-size: 15px;
134 | margin-bottom: 15px;
135 | font-weight: bold;
136 | border: 1px solid black;
137 | box-shadow: 5px black;
138 |
139 | border-radius: 3px;
140 | }
141 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/users/prof.css:
--------------------------------------------------------------------------------
1 | .user-prof-picture {
2 | width: 150px;
3 | height: 150px;
4 | position: absolute;
5 | border: 1px solid #cccccc;
6 | top: 150px;
7 | left: 305px;
8 | }
9 |
10 | .user-prof-wrapper {
11 | background: #f5f5f5;
12 | height: 160px;
13 | border-bottom: 1px solid #e6e6e6;
14 | display: flex;
15 | align-items: center;
16 | flex-direction: column;
17 | justify-content: space-around;
18 | }
19 |
20 | .user-prof-wrapper2 {
21 | display: flex;
22 | padding-right: 160px;
23 | flex-direction: column;
24 | width: 21%;
25 |
26 | padding-top: 20px;
27 | margin-top: auto;
28 | align-items: flex-start;
29 | }
30 |
31 | .user-prof-full-name {
32 | display: flex;
33 | justify-content: space-evenly;
34 | font-weight: 700;
35 | margin-bottom: 6px;
36 | font-size: 29px;
37 | line-height: 1.2em;
38 | font-family: sans-serif;
39 | margin-right: 50px;
40 | }
41 |
42 | .user-prof-fname {
43 | padding-right: 5px;
44 | }
45 |
46 | .user-prof-location {
47 | margin-bottom: 26px;
48 | font-size: 19px;
49 | width: 100%;
50 | margin-right: 250px;
51 | line-height: 1.2em;
52 | font-family: sans-serif;
53 | }
54 |
55 | .num-of-reviews {
56 | display: flex;
57 | margin: 50px 0;
58 | justify-content: center;
59 | font-weight: 700;
60 | font-size: 21px;
61 | line-height: 1.28571em;
62 | color: #d32323;
63 | font-family: sans-serif;
64 | }
65 |
66 | .user-prof-rev-pic {
67 | width: 60px;
68 | height: 60px;
69 | border-radius: 4px;
70 | object-fit: cover;
71 | }
72 | .user-reviews-wrapper {
73 | width: 31%;
74 | margin: auto;
75 | padding: 30px;
76 | border: 1px solid #e6e6e6;
77 | }
78 |
79 | .user-review-wrapper0 {
80 | margin-bottom: 20px;
81 | border-bottom: 1px solid #e6e6e6;
82 | padding-bottom: 20px;
83 | }
84 |
85 | .user-review-wrapper1 {
86 | display: flex;
87 | justify-content: space-between;
88 | }
89 | .rev-pic-ad {
90 | display: flex;
91 | }
92 |
93 | .rev-ad {
94 | display: flex;
95 | flex-direction: column;
96 | }
97 |
98 | .rev-bus-name {
99 | color: #0073bb;
100 | font-weight: 700;
101 | font-size: 15px;
102 | padding-bottom: 4px;
103 | }
104 |
105 | .rev-stars {
106 | padding: 5px 0 0 3px;
107 | }
108 |
109 | .rev-date {
110 | font-family: Arial;
111 | font-size: 13px;
112 | color: gray;
113 | padding-top: 3px;
114 | }
115 |
116 | .rev-ad {
117 | font-family: Arial;
118 | font-size: 13px;
119 | padding: 3px 0 0 10px;
120 | }
121 |
122 | .rev-body {
123 | font-family: Arial;
124 | font-size: 15px;
125 | padding: 5px 0 0 3px;
126 | }
127 |
128 | .rev-body-wrapper {
129 | display: flex;
130 | justify-content: space-between;
131 | }
132 |
133 | .rev-edi-del {
134 | display: flex;
135 | justify-content: space-between;
136 | padding-top: 15px;
137 | margin: auto;
138 | }
139 |
140 | .rev-edit-link {
141 | text-decoration: none;
142 | color: #0073bb;
143 | }
144 | .dub-edit {
145 | font-family: arial;
146 | padding: 5px;
147 | border: 1px solid #ccc;
148 | border: 1px solid;
149 | border-radius: 3px;
150 | font-size: 13px;
151 | line-height: 1.5em;
152 | color: #666;
153 | cursor: pointer;
154 | border-color: #ccc;
155 | background-color: #f7f7f7;
156 | background: linear-gradient(#fff, #f7f7f7);
157 | box-shadow: none;
158 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
159 | white-space: nowrap;
160 | -webkit-transition: all 0.3s ease;
161 | transition: all 0.3s ease;
162 | height: 20px;
163 | width: 108px;
164 | }
165 |
--------------------------------------------------------------------------------
/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Channel < ActionCable::Channel::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Connection < ActionCable::Connection::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/controllers/api/adjectives_controller.rb:
--------------------------------------------------------------------------------
1 |
2 | class Api::AdjectivesController < ApplicationController
3 |
4 | def create_like
5 | like_param = params[:like]
6 | user_id = like_param[:user_id].to_i
7 | @review_id = like_param[:review_id].to_i
8 | @like = Like.new(user_id: user_id, review_id: @review_id)
9 | @user_marked = 1
10 | if @like.save
11 | render 'api/adjectives/like'
12 | else
13 | render json: @like.errors.full_messages, status: 422
14 | end
15 | end
16 |
17 | def delete_like
18 | @review_id = params[:id].to_i
19 | user_id = params[:like][:user_id].to_i
20 | @like = Like.find_by(user_id: user_id, review_id: @review_id)
21 | @user_marked = 0
22 |
23 | @like.destroy
24 | render 'api/adjectives/like'
25 | end
26 |
27 | def show_like
28 | @review_id = params[:id].to_i
29 | @like = Like.where(review_id: @review_id, user_id: params[:like][:user_id])
30 | @user_marked = @like.where(review_id: @review_id, user_id: params[:like][:user_id]).length
31 | render 'api/adjectives/like'
32 | end
33 |
34 | def show_cool
35 | @review_id = params[:id].to_i
36 | @cools = Cool.where(review_id: @review_id)
37 | @user_marked = @cools.where(review_id: @review_id, user_id: params[:cool][:user_id])
38 | render 'api/adjectives/show_cool'
39 |
40 | end
41 | def show_funny
42 | @review_id = params[:id].to_i
43 | @funny = Funny.where(review_id: @review_id)
44 | @user_marked = @funny.where(review_id: @review_id, user_id: params[:funny][:user_id])
45 | render 'api/adjectives/show_funny'
46 | end
47 |
48 | def show_useful
49 | @review_id = params[:id].to_i
50 | @useful = Useful.where(review_id: @review_id)
51 | @user_marked = @useful.where(review_id: @review_id, user_id: params[:useful][:user_id])
52 | render 'api/adjectives/show_useful'
53 | end
54 |
55 | def update_cool
56 | cool_params = params[:cool]
57 | user_id = cool_params[:user_id].to_i
58 | @review_id = cool_params[:review_id].to_i
59 | if Cool.where(review_id: @review_id,user_id: user_id).length == 0
60 | @user_marked = Cool.where(review_id: @review_id,user_id: user_id)
61 | Cool.create!(user_id: user_id, review_id: @review_id)
62 | @cools = Cool.where(review_id: @review_id)
63 | else
64 | @user_marked = Cool.where(review_id: @review_id,user_id: user_id)
65 | cool = Cool.find_by(user_id: user_id, review_id: @review_id)
66 | cool.destroy
67 | @cools = Cool.where(review_id: @review_id)
68 | end
69 |
70 | render 'api/adjectives/update_cool'
71 | end
72 |
73 | def update_useful
74 | useful_params = params[:useful]
75 | user_id = useful_params[:user_id].to_i
76 | @review_id = useful_params[:review_id].to_i
77 | if Useful.where(review_id: @review_id,user_id: user_id).length == 0
78 | @user_marked = Useful.where(review_id: @review_id,user_id: user_id)
79 | Useful.create!(user_id: user_id, review_id: @review_id)
80 | @useful = Useful.where(review_id: @review_id)
81 | else
82 | @user_marked = Useful.where(review_id: @review_id,user_id: user_id)
83 | useful = Useful.find_by(user_id: user_id, review_id: @review_id)
84 | useful.destroy
85 | @useful = Useful.where(review_id: @review_id)
86 | end
87 |
88 | render 'api/adjectives/update_useful'
89 | end
90 |
91 | def update_funny
92 | funny_params = params[:funny]
93 | user_id = funny_params[:user_id].to_i
94 | @review_id = funny_params[:review_id].to_i
95 | if Funny.where(review_id: @review_id,user_id: user_id).length == 0
96 | @user_marked = Funny.where(review_id: @review_id,user_id: user_id)
97 | Funny.create!(user_id: user_id, review_id: @review_id)
98 | @funny = Funny.where(review_id: @review_id)
99 | else
100 | @user_marked = Funny.where(review_id: @review_id,user_id: user_id)
101 | funny = Funny.find_by(user_id: user_id, review_id: @review_id)
102 | funny.destroy
103 | @funny = Funny.where(review_id: @review_id)
104 | end
105 |
106 | render 'api/adjectives/update_funny'
107 | end
108 |
109 |
110 | private
111 | def adjective_params
112 | params.require(:adjective).permit(:review_id, :user_id)
113 | end
114 |
115 | end
116 |
--------------------------------------------------------------------------------
/app/controllers/api/business_categories_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::BusinessCategoriesController < ApplicationController
2 |
3 |
4 | def index
5 | # @businesses = BusinessCategory.find_by(id: params[:business_category_id]).businesses
6 | @businesses = BusinessCategory.all
7 | # render 'api/categories/index'
8 |
9 |
10 | end
11 |
12 | # def create
13 | # @business = BusinessCategory.new(business_category_params)
14 | #
15 | # if @business.save
16 | # render :index
17 | # else
18 | # render json: @business.errors.full_messages
19 | # end
20 | # end
21 |
22 |
23 |
24 |
25 | private
26 | def business_category_params
27 | params.require(:business_category).permit(:category)
28 | end
29 |
30 | end
31 |
--------------------------------------------------------------------------------
/app/controllers/api/businesses_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::BusinessesController < ApplicationController
2 |
3 | def show
4 | @business = Business.includes(:reviews).with_attached_photos.find(params[:id])
5 | @reviews = @business.reviews.includes(:user).includes(:business).order(created_at: :desc)
6 | end
7 |
8 | def index
9 | @businesses = params[:business_category_id] ? Business.includes(:reviews).with_attached_photos.where( business_category_id: params[:business_category_id]) : Business.includes(:reviews).with_attached_photos.all
10 | end
11 |
12 | def search
13 | if params[:dropdown]
14 | @businesses = Business.where('name ILIKE ?', "%#{params[:name]}%")
15 | else
16 | query_matches = ""
17 | param_queries = {price: params[:price], noise: params[:noise], delivery: params[:delivery],name: params[:name]}
18 | selected_queries = param_queries.select {|k,v| v.length > 2}
19 | selected_queries.keys.each_with_index do |query,idx|
20 | if idx != selected_queries.length - 1
21 | query_matches << "#{query} IN #{selected_queries[query]} AND "
22 | else
23 | query_matches << "#{query} IN #{selected_queries[query]} "
24 | end
25 | end
26 | # Business.where("price IN (3,4) AND noise IN (1)")
27 | @businesses = Business.where(query_matches)
28 | end
29 |
30 | render :index
31 | end
32 |
33 |
34 | def create
35 | @business = Business.new(business_params)
36 |
37 | if @business.save
38 | render 'api/businesses/show'
39 | else
40 | render json: @business.errors.full_messages, status: 404
41 | end
42 | end
43 |
44 |
45 |
46 | private
47 | def business_params
48 | params
49 | .require(:business)
50 | .permit(:owner_id, :name, :address, :hours, :phone_number,
51 | :website, :city, :state, :zip_code,
52 | :business_category_id, :latitude, :longitude, :price, :delivery, :noise)
53 | end
54 |
55 | end
56 |
--------------------------------------------------------------------------------
/app/controllers/api/reviews_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::ReviewsController < ApplicationController
2 |
3 |
4 | def show
5 | @review = Review.find(params[:id])
6 | end
7 |
8 | def index
9 | if params[:business_id]
10 | @reviews = Review.includes(:user).includes(:business).where( business_id: params[:business_id]).order(id: :desc)[0..8]
11 | else
12 | @reviews = Review.includes(:user).includes(:business).all.order(id: :desc)[0..8]
13 | end
14 | end
15 |
16 | def create
17 | @review = Review.new(review_params)
18 | @review.user_id = current_user.id
19 |
20 | if @review.save
21 | render "api/reviews/show"
22 | else
23 | render json: @review.errors.full_messages, status: 522
24 | end
25 | end
26 |
27 | def update
28 | @review = Review.find(params[:id])
29 |
30 | if @review.update(review_params)
31 | render 'api/reviews/show'
32 | else
33 | render json: @review.errors.full_messages, status: 522
34 | end
35 | end
36 |
37 |
38 | def destroy
39 | @review = Review.find(params[:id])
40 | @review.destroy
41 | render 'api/reviews/show'
42 | end
43 |
44 |
45 |
46 |
47 | private
48 | def review_params
49 | params.require(:review).permit(:business_id, :rating, :body)
50 | end
51 |
52 |
53 | end
54 |
--------------------------------------------------------------------------------
/app/controllers/api/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::SessionsController < ApplicationController
2 |
3 | def create
4 | @user = User.find_by_credentials(
5 | params[:user][:email],
6 | params[:user][:password]
7 | )
8 |
9 | if @user
10 | login(@user)
11 | render 'api/users/show'
12 | else
13 | render json: ['Invalid credentials'] , status: 404
14 | end
15 | end
16 |
17 |
18 | def destroy
19 | @user = current_user
20 | if @user
21 | logout!
22 | render json: {}
23 | else
24 | render json: ['No current user'], status: 404
25 | end
26 | end
27 |
28 |
29 | end
30 |
--------------------------------------------------------------------------------
/app/controllers/api/users_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::UsersController < ApplicationController
2 |
3 | def index
4 | @users = User.all
5 | end
6 |
7 | def create
8 | @user = User.new(user_params)
9 | unless user_params["birthday"]["month"].length == 0 || user_params["birthday"]["year"].length == 0|| user_params["birthday"]["day"].length == 0
10 | new_bday = User.convert_to_date(user_params["birthday"])
11 | @user.birthday = new_bday
12 | end
13 |
14 |
15 |
16 | if @user.save
17 | login(@user)
18 | render 'api/users/show'
19 | else
20 | render json: @user.errors.full_messages, status: 404
21 | end
22 | end
23 |
24 | def show
25 | @user = User.find(params[:id])
26 | render :show
27 | end
28 |
29 | private
30 | def user_params
31 | params.require(:user).permit(:password, :fname, :lname, :email, :zipcode, birthday: [:month, :day, :year])
32 | end
33 |
34 | end
35 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | protect_from_forgery with: :exception
3 |
4 |
5 | helper_method :current_user, :logged_in?
6 |
7 | private
8 | def current_user
9 | @current_user ||= User.find_by_session_token(session[:session_token])
10 | end
11 |
12 | def logged_in?
13 | !!current_user
14 | end
15 |
16 | def login(user)
17 | @current_user = user
18 | session[:session_token] = user.reset_token!
19 | end
20 |
21 | def logout!
22 | current_user.try(:reset_token!)
23 | session[:session_token] = nil
24 | end
25 |
26 | def require_signed_in!
27 | redirect_to new_session_url unless signed_in?
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/app/controllers/static_pages_controller.rb:
--------------------------------------------------------------------------------
1 | class StaticPagesController < ApplicationController
2 | def root; end
3 | end
4 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 |
3 | # have it in an array and call it in applicaiton.hmtl.erb, it will generate for you
4 | # ['bakery.jp']
5 |
6 | def generate_random_pic
7 |
8 | ["burgers.jpg","o.jpg", "splash.jpg", "cookie.jpg"].sample
9 | end
10 |
11 |
12 | end
13 |
--------------------------------------------------------------------------------
/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base
2 | end
3 |
--------------------------------------------------------------------------------
/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: 'from@example.com'
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/app/models/adjective.rb:
--------------------------------------------------------------------------------
1 | class Adjective < ActiveRecord::Base
2 |
3 |
4 | validates :user_id, :review_id, presence: true
5 |
6 | belongs_to :review
7 | belongs_to :user
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | self.abstract_class = true
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/business.rb:
--------------------------------------------------------------------------------
1 | class Business < ApplicationRecord
2 | validates :address, presence: true, uniqueness: true
3 | validates :name, :hours, :phone_number, :website, :city, :state, :zip_code, presence: true
4 | validates :latitude, :longitude, :business_category_id, presence: true
5 |
6 |
7 | belongs_to :business_category
8 | belongs_to :owner,
9 | foreign_key: :owner_id,
10 | class_name: :User,
11 | optional: true
12 |
13 | has_many :reviews
14 | has_many_attached :photos
15 |
16 | def self.in_bounds(bounds)
17 | self.where("latitude < ?", bounds[:northEast][:latitude])
18 | .where("latitude > ?", bounds[:southWest][:latitude])
19 | .where("longitude > ?", bounds[:southWest][:longitude])
20 | .where("longitude < ?", bounds[:northEast][:longitude])
21 | end
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/app/models/business_category.rb:
--------------------------------------------------------------------------------
1 | class BusinessCategory < ApplicationRecord
2 | validates :category, presence: true
3 |
4 | has_many :businesses
5 |
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/app/models/concerns/.keep
--------------------------------------------------------------------------------
/app/models/cool.rb:
--------------------------------------------------------------------------------
1 | class Cool < Adjective
2 |
3 |
4 | validates :user_id, :review_id, presence: true
5 |
6 | belongs_to :review
7 | belongs_to :user
8 |
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/app/models/funny.rb:
--------------------------------------------------------------------------------
1 | class Funny < Adjective
2 |
3 |
4 | validates :user_id, :review_id, presence: true
5 |
6 | belongs_to :review
7 | belongs_to :user
8 |
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/app/models/like.rb:
--------------------------------------------------------------------------------
1 | class Like < Adjective
2 |
3 |
4 | validates :user_id, :review_id, presence: true
5 |
6 | belongs_to :review
7 | belongs_to :user
8 |
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/app/models/photo.rb:
--------------------------------------------------------------------------------
1 | class Photo < ApplicationRecord
2 | validates :business_id, :image_url, presence: true
3 |
4 | belongs_to :business
5 |
6 | end
7 |
--------------------------------------------------------------------------------
/app/models/review.rb:
--------------------------------------------------------------------------------
1 | class Review < ApplicationRecord
2 | validates :rating, :body, presence: true
3 |
4 | belongs_to :user
5 | belongs_to :business
6 | has_many :adjectives
7 |
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/app/models/useful.rb:
--------------------------------------------------------------------------------
1 | class Useful < Adjective
2 |
3 |
4 | validates :user_id, :review_id, presence: true
5 |
6 | belongs_to :review
7 | belongs_to :user
8 |
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/app/models/user.rb:
--------------------------------------------------------------------------------
1 | class User < ApplicationRecord
2 | validates :email, :password_digest, :session_token, presence: true, uniqueness: true
3 | validates :fname, :lname, :zipcode, presence: true
4 | validates :password, length: { minimum: 6, allow_nil: true }
5 |
6 | has_many :businesses
7 | has_many :reviews
8 | has_many :adjectives
9 |
10 |
11 | attr_reader :password
12 |
13 | after_initialize :ensure_session_token
14 |
15 | def self.find_by_credentials(email, password)
16 | user = User.find_by(email: email)
17 | return nil unless user && user.valid_password?(password)
18 | user
19 | end
20 |
21 | def self.convert_to_date(object)
22 | year = object["year"].to_i
23 | month = object["month"].to_i
24 | day = object["day"].to_i
25 | Date.new(year,month,day)
26 | end
27 |
28 | def password=(password)
29 | @password = password
30 | self.password_digest = BCrypt::Password.create(password)
31 | end
32 |
33 |
34 | def valid_password?(password)
35 | bcryped_pw = BCrypt::Password.new(self.password_digest)
36 | bcryped_pw.is_password?(password)
37 | end
38 |
39 |
40 | def reset_token!
41 | self.session_token = SecureRandom.urlsafe_base64(16)
42 | self.save!
43 | self.session_token
44 | end
45 |
46 | private
47 | def ensure_session_token
48 | self.session_token ||= SecureRandom.urlsafe_base64(16)
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/app/views/api/adjectives/like.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.adjectives do
2 |
3 | json.likes do
4 | json.set! @review_id do
5 | json.like @like
6 | json.like_count @user_marked
7 | end
8 | end
9 |
10 | json.funny do
11 |
12 | end
13 |
14 | json.cool do
15 |
16 | end
17 |
18 | json.useful do
19 |
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/app/views/api/adjectives/show_cool.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.adjectives do
2 |
3 | json.cool do
4 | json.set! @review_id do
5 | json.cools @cools
6 | json.cool_count @user_marked.length
7 | end
8 | end
9 |
10 |
11 | json.funny do
12 | end
13 |
14 | json.useful do
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/app/views/api/adjectives/show_funny.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.adjectives do
2 |
3 | json.funny do
4 | json.set! @review_id do
5 | json.funny @funny
6 | json.funny_count @user_marked.length
7 | end
8 | end
9 |
10 | json.cool do
11 | end
12 |
13 | json.useful do
14 | end
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/app/views/api/adjectives/show_useful.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.adjectives do
2 |
3 | json.useful do
4 | json.set! @review_id do
5 | json.useful @useful
6 | json.useful_count @user_marked.length
7 | end
8 | end
9 |
10 | json.cool do
11 | end
12 |
13 | json.funny do
14 | end
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/app/views/api/adjectives/update_cool.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.adjectives do
2 |
3 | json.cool do
4 | json.set! @review_id do
5 | json.cools @cools
6 | json.cool_count @user_marked.length
7 | end
8 | end
9 |
10 | json.funny do
11 | end
12 |
13 | json.useful do
14 | end
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/app/views/api/adjectives/update_funny.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.adjectives do
2 |
3 | json.funny do
4 | json.set! @review_id do
5 | json.funny @funny
6 | json.funny_count @user_marked.length
7 | end
8 | end
9 |
10 | json.cool do
11 | end
12 |
13 | json.useful do
14 | end
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/app/views/api/adjectives/update_useful.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.adjectives do
2 |
3 | json.useful do
4 | json.set! @review_id do
5 | json.useful @useful
6 | json.useful_count @user_marked.length
7 | end
8 | end
9 |
10 | json.cool do
11 | end
12 |
13 | json.funny do
14 | end
15 |
16 |
17 | end
18 |
--------------------------------------------------------------------------------
/app/views/api/business_categories/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | @businesses.each do |business|
2 | json.set! business.id do
3 | json.extract! business, :id, :category
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/views/api/businesses/_business.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.extract! business, :id, :owner_id, :name, :address, :hours, :phone_number, :website, :city , :state, :zip_code, :business_category_id, :latitude, :longitude
2 |
--------------------------------------------------------------------------------
/app/views/api/businesses/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | @businesses.each do |business|
2 | json.set! business.id do
3 | json.extract!(
4 | business,
5 | :id,
6 | :owner_id,
7 | :name,
8 | :address,
9 | :hours,
10 | :price,
11 | :phone_number,
12 | :website,
13 | :city ,
14 | :state,
15 | :zip_code,
16 | :business_category_id,
17 | :latitude,
18 | :longitude,
19 | :reviews)
20 | json.photos do
21 | json.array! business.photos.each do |photo|
22 | json.photo_image_url url_for(photo)
23 | end
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/app/views/api/businesses/show.json.jbuilder:
--------------------------------------------------------------------------------
1 |
2 | json.extract!(
3 | @business,
4 | :id,
5 | :owner_id,
6 | :name,
7 | :address,
8 | :hours,
9 | :phone_number,
10 | :website,
11 | :city ,
12 | :state,
13 | :price,
14 | :zip_code,
15 | :price,
16 | :business_category_id,
17 | :latitude,
18 | :longitude)
19 |
20 | json.photos do
21 | json.array! @business.photos do |photo|
22 | json.photo_image_url url_for(photo)
23 | end
24 | end
25 |
26 |
27 | json.reviews do
28 | json.array! @reviews do |review|
29 | ## fix would be to set the review id here ???
30 | json.extract!(
31 | review,
32 | :id,
33 | :user_id,
34 | :business_id,
35 | :body,
36 | :rating,
37 | :created_at,
38 | )
39 | #fixed security issue, no pw
40 | json.user do
41 | json.extract! review.user, :fname, :lname
42 | end
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/app/views/api/categories/_category.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.extract! business_category, :id, :category
2 |
--------------------------------------------------------------------------------
/app/views/api/categories/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | @business_categories.each do |category|
2 | json.set! category.id do
3 | json.partial! 'api/shared/categories', business_category: @business_category
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/views/api/reviews/index.json.jbuilder:
--------------------------------------------------------------------------------
1 |
2 | @reviews.each do |review|
3 | json.set! review.id do
4 | json.extract! review, :id, :user_id, :business_id, :rating, :body, :user, :business
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/app/views/api/reviews/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.extract! @review, :id, :user_id, :business_id, :rating, :body, :created_at, :user, :business
2 |
--------------------------------------------------------------------------------
/app/views/api/users/_user.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.extract! user, :id, :fname, :lname
2 |
--------------------------------------------------------------------------------
/app/views/api/users/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | @users.each do |user|
2 | json.set! user.id do
3 | json.extract! user, :id, :fname, :lname, :reviews
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/views/api/users/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.extract! @user, :id, :fname, :lname, :reviews
2 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
BetterHelp
6 | <%= csrf_meta_tags %>
7 | <%= csp_meta_tag %>
8 |
9 | <%= javascript_include_tag "https://maps.googleapis.com/maps/api/js?key=AIzaSyCeLxEq2Ga-eCm60KrJT68p_EtjMEvkERc" %>
10 | <%= stylesheet_link_tag 'application', media: 'all' %>
11 | <%= javascript_include_tag 'application' %>
12 | <%= favicon_link_tag asset_path('better_help_splash_thicc.jpg'), :rel => 'icon', :type => 'image/jpg' %>
13 |
14 |
15 |
16 |
17 |
18 |
19 |
34 |
35 |
36 | <%= yield %>
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.text.erb:
--------------------------------------------------------------------------------
1 | <%= yield %>
2 |
--------------------------------------------------------------------------------
/app/views/static_pages/root.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <% if logged_in? %>
6 |
9 | <% end %>
10 |
--------------------------------------------------------------------------------
/betterhelp.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/betterhelp.gif
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | APP_PATH = File.expand_path('../config/application', __dir__)
8 | require_relative '../config/boot'
9 | require 'rails/commands'
10 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | require_relative '../config/boot'
8 | require 'rake'
9 | Rake.application.run
10 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'fileutils'
3 | include FileUtils
4 |
5 | # path to your application root.
6 | APP_ROOT = File.expand_path('..', __dir__)
7 |
8 | def system!(*args)
9 | system(*args) || abort("\n== Command #{args} failed ==")
10 | end
11 |
12 | chdir APP_ROOT do
13 | # This script is a starting point to setup your application.
14 | # Add necessary setup steps to this file.
15 |
16 | puts '== Installing dependencies =='
17 | system! 'gem install bundler --conservative'
18 | system('bundle check') || system!('bundle install')
19 |
20 | # Install JavaScript dependencies if using Yarn
21 | # system('bin/yarn')
22 |
23 | # puts "\n== Copying sample files =="
24 | # unless File.exist?('config/database.yml')
25 | # cp 'config/database.yml.sample', 'config/database.yml'
26 | # end
27 |
28 | puts "\n== Preparing database =="
29 | system! 'bin/rails db:setup'
30 |
31 | puts "\n== Removing old logs and tempfiles =="
32 | system! 'bin/rails log:clear tmp:clear'
33 |
34 | puts "\n== Restarting application server =="
35 | system! 'bin/rails restart'
36 | end
37 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads spring without using Bundler, in order to be fast.
4 | # It gets overwritten when you run the `spring binstub` command.
5 |
6 | unless defined?(Spring)
7 | require 'rubygems'
8 | require 'bundler'
9 |
10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
11 | spring = lockfile.specs.detect { |spec| spec.name == "spring" }
12 | if spring
13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
14 | gem 'spring', spring.version
15 | require 'spring/binstub'
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/bin/update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'fileutils'
3 | include FileUtils
4 |
5 | # path to your application root.
6 | APP_ROOT = File.expand_path('..', __dir__)
7 |
8 | def system!(*args)
9 | system(*args) || abort("\n== Command #{args} failed ==")
10 | end
11 |
12 | chdir APP_ROOT do
13 | # This script is a way to update your development environment automatically.
14 | # Add necessary update steps to this file.
15 |
16 | puts '== Installing dependencies =='
17 | system! 'gem install bundler --conservative'
18 | system('bundle check') || system!('bundle install')
19 |
20 | # Install JavaScript dependencies if using Yarn
21 | # system('bin/yarn')
22 |
23 | puts "\n== Updating database =="
24 | system! 'bin/rails db:migrate'
25 |
26 | puts "\n== Removing old logs and tempfiles =="
27 | system! 'bin/rails log:clear tmp:clear'
28 |
29 | puts "\n== Restarting application server =="
30 | system! 'bin/rails restart'
31 | end
32 |
--------------------------------------------------------------------------------
/bin/yarn:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_ROOT = File.expand_path('..', __dir__)
3 | Dir.chdir(APP_ROOT) do
4 | begin
5 | exec "yarnpkg", *ARGV
6 | rescue Errno::ENOENT
7 | $stderr.puts "Yarn executable was not detected in the system."
8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
9 | exit 1
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require_relative 'config/environment'
4 |
5 | run Rails.application
6 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require_relative 'boot'
2 |
3 | require 'rails/all'
4 |
5 | # Require the gems listed in Gemfile, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(*Rails.groups)
8 |
9 | module FullStackProject
10 | class Application < Rails::Application
11 | # Initialize configuration defaults for originally generated Rails version.
12 | config.load_defaults 5.2
13 |
14 | # Settings in config/environments/* take precedence over those specified here.
15 | # Application configuration can go into files in config/initializers
16 | # -- all .rb files in that directory are automatically loaded after loading
17 | # the framework and any gems in your application.
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
5 |
--------------------------------------------------------------------------------
/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: async
6 |
7 | production:
8 | adapter: redis
9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
10 | channel_prefix: full_stack_project_production
11 |
--------------------------------------------------------------------------------
/config/credentials.yml.enc:
--------------------------------------------------------------------------------
1 | THFuwhaEzIV/dX2L3KoP5GOT7+Ed2weMUG12jOqkezeSyjm77km0KQMp/CzEdxxv826tp+AbSmYoFn2t43oq48F5ZJBkQb3yzCdMAFxtuN2RTvzvBv/FPjYq/gLCLKIUrDhnOzcdSyL1LipjV/HSrA/X1aPTSDDgsML4XyD0/Cvfg7HlVTpZ2KRBYxIlbU9q8nFg3zKtglqvkWhbfJXm+M3wTlmvKuIae5CuCLOfnafpQbxmwsgGB/KMrB1M3WS5UaRLPoH5QCkRcFJJKz6HMYQDIyfAsNk6vyF7AJgm9/ZmfNO0S3WUJsb7WoWiVT5T7Buuv5KKS5SxS3JGAU3CG2xrSa5aQHyIKikdOpTTS+/VfZhcn/ryLBh0cQU7Lj9B9c2FBNCxjCa6EOgKZRpGhT1RzWvxW01KFzpTodSbhSlGJnlPNClHK2LYtlig3wjiYQYDXfgfeSYmSqU67YO4IfiwJOrIWm0yPf3QulJzaFkDqPnnPJeFvc8V+b07kVl/RVhoQzgxWxXiMp/YkjFhbTt8UPmx14zcffzVZhhKpamdOgmlC4YaaCkkHSAEvpDv3oIrQs3ay0QodiwrGd0iTY6hCsO4Tibr--lBAG97QL4mMfUeNq--Xd6lxxI6fGq9c1x5zWSQhQ==
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # PostgreSQL. Versions 9.1 and up are supported.
2 | #
3 | # Install the pg driver:
4 | # gem install pg
5 | # On OS X with Homebrew:
6 | # gem install pg -- --with-pg-config=/usr/local/bin/pg_config
7 | # On OS X with MacPorts:
8 | # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
9 | # On Windows:
10 | # gem install pg
11 | # Choose the win32 build.
12 | # Install PostgreSQL and put its /bin directory on your path.
13 | #
14 | # Configure Using Gemfile
15 | # gem 'pg'
16 | #
17 | default: &default
18 | adapter: postgresql
19 | encoding: unicode
20 | # For details on connection pooling, see Rails configuration guide
21 | # http://guides.rubyonrails.org/configuring.html#database-pooling
22 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
23 |
24 | development:
25 | <<: *default
26 | database: full_stack_project_development
27 |
28 | # The specified database role being used to connect to postgres.
29 | # To create additional roles in postgres see `$ createuser --help`.
30 | # When left blank, postgres will use the default role. This is
31 | # the same name as the operating system user that initialized the database.
32 | #username: full_stack_project
33 |
34 | # The password associated with the postgres role (username).
35 | #password:
36 |
37 | # Connect on a TCP socket. Omitted by default since the client uses a
38 | # domain socket that doesn't need configuration. Windows does not have
39 | # domain sockets, so uncomment these lines.
40 | #host: localhost
41 |
42 | # The TCP port the server listens on. Defaults to 5432.
43 | # If your server runs on a different port number, change accordingly.
44 | #port: 5432
45 |
46 | # Schema search path. The server defaults to $user,public
47 | #schema_search_path: myapp,sharedapp,public
48 |
49 | # Minimum log levels, in increasing order:
50 | # debug5, debug4, debug3, debug2, debug1,
51 | # log, notice, warning, error, fatal, and panic
52 | # Defaults to warning.
53 | #min_messages: notice
54 |
55 | # Warning: The database defined as "test" will be erased and
56 | # re-generated from your development database when you run "rake".
57 | # Do not set this db to the same as development or production.
58 | test:
59 | <<: *default
60 | database: full_stack_project_test
61 |
62 | # As with config/secrets.yml, you never want to store sensitive information,
63 | # like your database password, in your source code. If your source code is
64 | # ever seen by anyone, they now have access to your database.
65 | #
66 | # Instead, provide the password as a unix environment variable when you boot
67 | # the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
68 | # for a full rundown on how to provide these environment variables in a
69 | # production deployment.
70 | #
71 | # On Heroku and other platform providers, you may have a full connection URL
72 | # available as an environment variable. For example:
73 | #
74 | # DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
75 | #
76 | # You can use this database configuration with:
77 | #
78 | # production:
79 | # url: <%= ENV['DATABASE_URL'] %>
80 | #
81 | production:
82 | <<: *default
83 | database: full_stack_project_production
84 | username: full_stack_project
85 | password: <%= ENV['FULL_STACK_PROJECT_DATABASE_PASSWORD'] %>
86 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require_relative 'application'
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports.
13 | config.consider_all_requests_local = true
14 |
15 | # Enable/disable caching. By default caching is disabled.
16 | # Run rails dev:cache to toggle caching.
17 | if Rails.root.join('tmp', 'caching-dev.txt').exist?
18 | config.action_controller.perform_caching = true
19 |
20 | config.cache_store = :memory_store
21 | config.public_file_server.headers = {
22 | 'Cache-Control' => "public, max-age=#{2.days.to_i}"
23 | }
24 | else
25 | config.action_controller.perform_caching = false
26 |
27 | config.cache_store = :null_store
28 | end
29 |
30 | # Store uploaded files on the local file system (see config/storage.yml for options)
31 | config.active_storage.service = :amazon_dev
32 |
33 | # Don't care if the mailer can't send.
34 | config.action_mailer.raise_delivery_errors = false
35 |
36 | config.action_mailer.perform_caching = false
37 |
38 | # Print deprecation notices to the Rails logger.
39 | config.active_support.deprecation = :log
40 |
41 | # Raise an error on page load if there are pending migrations.
42 | config.active_record.migration_error = :page_load
43 |
44 | # Highlight code that triggered database queries in logs.
45 | config.active_record.verbose_query_logs = true
46 |
47 | # Debug mode disables concatenation and preprocessing of assets.
48 | # This option may cause significant delays in view rendering with a large
49 | # number of complex assets.
50 | config.assets.debug = true
51 |
52 | # Suppress logger output for asset requests.
53 | config.assets.quiet = true
54 |
55 | # Raises error for missing translations
56 | # config.action_view.raise_on_missing_translations = true
57 |
58 | # Use an evented file watcher to asynchronously detect changes in source code,
59 | # routes, locales, etc. This feature depends on the listen gem.
60 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker
61 | end
62 |
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Code is not reloaded between requests.
5 | config.cache_classes = true
6 |
7 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
18 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
19 | # config.require_master_key = true
20 |
21 | # Disable serving static files from the `/public` folder by default since
22 | # Apache or NGINX already handles this.
23 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
24 |
25 | # Compress JavaScripts and CSS.
26 | config.assets.js_compressor = :uglifier
27 | # config.assets.css_compressor = :sass
28 |
29 | # Do not fallback to assets pipeline if a precompiled asset is missed.
30 | config.assets.compile = false
31 |
32 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
33 |
34 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
35 | # config.action_controller.asset_host = 'http://assets.example.com'
36 |
37 | # Specifies the header that your server uses for sending files.
38 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
39 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
40 |
41 | # Store uploaded files on the local file system (see config/storage.yml for options)
42 | config.active_storage.service = :amazon_prod
43 |
44 | # Mount Action Cable outside main process or domain
45 | # config.action_cable.mount_path = nil
46 | # config.action_cable.url = 'wss://example.com/cable'
47 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
48 |
49 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
50 | # config.force_ssl = true
51 |
52 | # Use the lowest log level to ensure availability of diagnostic information
53 | # when problems arise.
54 | config.log_level = :debug
55 |
56 | # Prepend all log lines with the following tags.
57 | config.log_tags = [ :request_id ]
58 |
59 | # Use a different cache store in production.
60 | # config.cache_store = :mem_cache_store
61 |
62 | # Use a real queuing backend for Active Job (and separate queues per environment)
63 | # config.active_job.queue_adapter = :resque
64 | # config.active_job.queue_name_prefix = "full_stack_project_#{Rails.env}"
65 |
66 | config.action_mailer.perform_caching = false
67 |
68 | # Ignore bad email addresses and do not raise email delivery errors.
69 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
70 | # config.action_mailer.raise_delivery_errors = false
71 |
72 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
73 | # the I18n.default_locale when a translation cannot be found).
74 | config.i18n.fallbacks = true
75 |
76 | # Send deprecation notices to registered listeners.
77 | config.active_support.deprecation = :notify
78 |
79 | # Use default logging formatter so that PID and timestamp are not suppressed.
80 | config.log_formatter = ::Logger::Formatter.new
81 |
82 | # Use a different logger for distributed setups.
83 | # require 'syslog/logger'
84 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
85 |
86 | if ENV["RAILS_LOG_TO_STDOUT"].present?
87 | logger = ActiveSupport::Logger.new(STDOUT)
88 | logger.formatter = config.log_formatter
89 | config.logger = ActiveSupport::TaggedLogging.new(logger)
90 | end
91 |
92 | # Do not dump schema after migrations.
93 | config.active_record.dump_schema_after_migration = false
94 | end
95 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure public file server for tests with Cache-Control for performance.
16 | config.public_file_server.enabled = true
17 | config.public_file_server.headers = {
18 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}"
19 | }
20 |
21 | # Show full error reports and disable caching.
22 | config.consider_all_requests_local = true
23 | config.action_controller.perform_caching = false
24 |
25 | # Raise exceptions instead of rendering exception templates.
26 | config.action_dispatch.show_exceptions = false
27 |
28 | # Disable request forgery protection in test environment.
29 | config.action_controller.allow_forgery_protection = false
30 |
31 | # Store uploaded files on the local file system in a temporary directory
32 | config.active_storage.service = :test
33 |
34 | config.action_mailer.perform_caching = false
35 |
36 | # Tell Action Mailer not to deliver emails to the real world.
37 | # The :test delivery method accumulates sent emails in the
38 | # ActionMailer::Base.deliveries array.
39 | config.action_mailer.delivery_method = :test
40 |
41 | # Print deprecation notices to the stderr.
42 | config.active_support.deprecation = :stderr
43 |
44 | # Raises error for missing translations
45 | # config.action_view.raise_on_missing_translations = true
46 | end
47 |
--------------------------------------------------------------------------------
/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # ActiveSupport::Reloader.to_prepare do
4 | # ApplicationController.renderer.defaults.merge!(
5 | # http_host: 'example.org',
6 | # https: false
7 | # )
8 | # end
9 |
--------------------------------------------------------------------------------
/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = '1.0'
5 |
6 | # Add additional assets to the asset load path.
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 | # Add Yarn node_modules folder to the asset load path.
9 | Rails.application.config.assets.paths << Rails.root.join('node_modules')
10 |
11 | # Precompile additional assets.
12 | # application.js, application.css, and all non-JS/CSS in the app/assets
13 | # folder are already added.
14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css )
15 |
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/config/initializers/content_security_policy.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Define an application-wide content security policy
4 | # For further information see the following documentation
5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
6 |
7 | # Rails.application.config.content_security_policy do |policy|
8 | # policy.default_src :self, :https
9 | # policy.font_src :self, :https, :data
10 | # policy.img_src :self, :https, :data
11 | # policy.object_src :none
12 | # policy.script_src :self, :https
13 | # policy.style_src :self, :https
14 |
15 | # # Specify URI for violation reports
16 | # # policy.report_uri "/csp-violation-report-endpoint"
17 | # end
18 |
19 | # If you are using UJS then enable automatic nonce generation
20 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
21 |
22 | # Report CSP violations to a specified URI
23 | # For further information see the following documentation:
24 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
25 | # Rails.application.config.content_security_policy_report_only = true
26 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Specify a serializer for the signed and encrypted cookie jars.
4 | # Valid options are :json, :marshal, and :hybrid.
5 | Rails.application.config.action_dispatch.cookies_serializer = :json
6 |
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json]
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # The following keys must be escaped otherwise they will not be retrieved by
20 | # the default I18n backend:
21 | #
22 | # true, false, on, off, yes, no
23 | #
24 | # Instead, surround them with single quotes.
25 | #
26 | # en:
27 | # 'true': 'foo'
28 | #
29 | # To learn more, please read the Rails Internationalization guide
30 | # available at http://guides.rubyonrails.org/i18n.html.
31 |
32 | en:
33 | hello: "Hello world"
34 |
--------------------------------------------------------------------------------
/config/puma.rb:
--------------------------------------------------------------------------------
1 | # Puma can serve each request in a thread from an internal thread pool.
2 | # The `threads` method setting takes two numbers: a minimum and maximum.
3 | # Any libraries that use thread pools should be configured to match
4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
5 | # and maximum; this matches the default thread size of Active Record.
6 | #
7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8 | threads threads_count, threads_count
9 |
10 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
11 | #
12 | port ENV.fetch("PORT") { 3000 }
13 |
14 | # Specifies the `environment` that Puma will run in.
15 | #
16 | environment ENV.fetch("RAILS_ENV") { "development" }
17 |
18 | # Specifies the number of `workers` to boot in clustered mode.
19 | # Workers are forked webserver processes. If using threads and workers together
20 | # the concurrency of the application would be max `threads` * `workers`.
21 | # Workers do not work on JRuby or Windows (both of which do not support
22 | # processes).
23 | #
24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
25 |
26 | # Use the `preload_app!` method when specifying a `workers` number.
27 | # This directive tells Puma to first boot the application and load code
28 | # before forking the application. This takes advantage of Copy On Write
29 | # process behavior so workers use less memory.
30 | #
31 | # preload_app!
32 |
33 | # Allow puma to be restarted by `rails restart` command.
34 | plugin :tmp_restart
35 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
3 | root to: 'static_pages#root'
4 |
5 | namespace :api, defaults: { format: 'json' } do
6 | get 'businesses/search', to: 'businesses#search'
7 | # get 'adjectives/adjective', to: 'adjectives#find_adjective'
8 |
9 | post 'adjectives/likes', to: 'adjectives#create_like'
10 | delete 'adjectives/likes/:id', to: 'adjectives#delete_like'
11 | patch 'adjectives/cool', to: 'adjectives#update_cool'
12 | patch 'adjectives/useful', to: 'adjectives#update_useful'
13 | patch 'adjectives/funny', to: 'adjectives#update_funny'
14 | get 'adjectives/cool/:id', to: 'adjectives#show_cool'
15 | get 'adjectives/like/:id', to: 'adjectives#show_like'
16 | get 'adjectives/funny/:id', to: 'adjectives#show_funny'
17 | get 'adjectives/useful/:id', to: 'adjectives#show_useful'
18 |
19 | resources :users, only: [:create, :show, :index]
20 | resource :session, only: [:create, :destroy]
21 | resources :businesses, only: [:index, :create, :show] do
22 | resources :reviews, only: [:create, :index]
23 | end
24 | resources :business_categories, only: [:index, :create, :show] do
25 | resources :businesses, only: [:index]
26 | end
27 | resources :reviews, only: [:show, :destroy, :update, :index]
28 |
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/config/spring.rb:
--------------------------------------------------------------------------------
1 | %w[
2 | .ruby-version
3 | .rbenv-vars
4 | tmp/restart.txt
5 | tmp/caching-dev.txt
6 | ].each { |path| Spring.watch(path) }
7 |
--------------------------------------------------------------------------------
/config/storage.yml:
--------------------------------------------------------------------------------
1 | amazon_dev:
2 | service: S3
3 | access_key_id: <%= Rails.application.credentials.aws[:access_key_id] %>
4 | secret_access_key: <%= Rails.application.credentials.aws[:secret_access_key] %>
5 | region: <%= Rails.application.credentials.aws[:region] %>
6 | bucket: <%= Rails.application.credentials.aws[:dev][:bucket] %>
7 |
8 | amazon_prod:
9 | service: S3
10 | access_key_id: <%= Rails.application.credentials.aws[:access_key_id] %>
11 | secret_access_key: <%= Rails.application.credentials.aws[:secret_access_key] %>
12 | region: <%= Rails.application.credentials.aws[:region] %>
13 | bucket: <%= Rails.application.credentials.aws[:prod][:bucket] %>
14 |
--------------------------------------------------------------------------------
/db/migrate/20180911155746_create_users.rb:
--------------------------------------------------------------------------------
1 | class CreateUsers < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :users do |t|
4 | t.string :fname, null: false
5 | t.string :lname, null: false
6 | t.string :email, null: false
7 | t.integer :zipcode, null: false
8 | t.date :birthday
9 | t.string :password_digest, null: false
10 | t.string :session_token, null: false
11 | t.timestamps
12 | end
13 | add_index :users, :session_token, unique: true
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20180911160222_create_businesses.rb:
--------------------------------------------------------------------------------
1 | class CreateBusinesses < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :businesses do |t|
4 | t.integer :owner_id
5 | t.string :name, null: false
6 | t.string :address, null: false
7 | t.string :hours, null: false
8 | t.string :phone_number, null: false
9 | t.string :website, null: false
10 | t.string :city, null: false
11 | t.string :state, null: false
12 | t.integer :zip_code, null: false
13 | t.integer :business_category_id, null: false
14 | t.integer :latitude, null: false
15 | t.integer :longitude, null: false
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/db/migrate/20180911160820_drop_business_table.rb:
--------------------------------------------------------------------------------
1 | class DropBusinessTable < ActiveRecord::Migration[5.2]
2 | def change
3 | drop_table :businesses
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20180913175102_createbusinesses.rb:
--------------------------------------------------------------------------------
1 | class Createbusinesses < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :businesses do |t|
4 | t.integer :owner_id
5 | t.string :name, null: false
6 | t.string :address, null: false
7 | t.string :hours, null: false
8 | t.string :phone_number, null: false
9 | t.string :website, null: false
10 | t.string :city, null: false
11 | t.string :state, null: false
12 | t.integer :zip_code, null: false
13 | t.integer :business_category_id, null: false
14 | t.float :latitude, null: false
15 | t.float :longitude, null: false
16 | t.timestamps
17 | end
18 | add_index :businesses, :address, unique: true
19 | add_index :businesses, :state
20 | add_index :businesses, :zip_code
21 | add_index :businesses, :business_category_id
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/db/migrate/20180913190607_create_business_categories.rb:
--------------------------------------------------------------------------------
1 | class CreateBusinessCategories < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :business_categories do |t|
4 | t.string :category, null: false
5 | t.timestamps
6 | end
7 | add_index :business_categories, :category
8 |
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20180914191711_create_reviews.rb:
--------------------------------------------------------------------------------
1 | class CreateReviews < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :reviews do |t|
4 | t.integer :user_id, null: false
5 | t.integer :business_id, null: false
6 | t.integer :rating, null: false
7 | t.text :body, null: false
8 | t.timestamps
9 | end
10 | add_index :reviews, :user_id
11 | add_index :reviews, [:business_id, :user_id]
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20180915225629_change_col_for_hours_to_allow_array.rb:
--------------------------------------------------------------------------------
1 | class ChangeColForHoursToAllowArray < ActiveRecord::Migration[5.2]
2 | def change
3 | remove_column :businesses, :hours
4 | add_column :businesses, :hours, :string, array:true, default: []
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20180917155120_create_photos.rb:
--------------------------------------------------------------------------------
1 | class CreatePhotos < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :photos do |t|
4 | t.integer :business_id, null: false
5 | t.string :image_url, null: false
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20180918141232_create_active_storage_tables.active_storage.rb:
--------------------------------------------------------------------------------
1 | # This migration comes from active_storage (originally 20170806125915)
2 | class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
3 | def change
4 | create_table :active_storage_blobs do |t|
5 | t.string :key, null: false
6 | t.string :filename, null: false
7 | t.string :content_type
8 | t.text :metadata
9 | t.bigint :byte_size, null: false
10 | t.string :checksum, null: false
11 | t.datetime :created_at, null: false
12 |
13 | t.index [ :key ], unique: true
14 | end
15 |
16 | create_table :active_storage_attachments do |t|
17 | t.string :name, null: false
18 | t.references :record, null: false, polymorphic: true, index: false
19 | t.references :blob, null: false
20 |
21 | t.datetime :created_at, null: false
22 |
23 | t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/db/migrate/20181023223516_add_col_to_businesses.rb:
--------------------------------------------------------------------------------
1 | class AddColToBusinesses < ActiveRecord::Migration[5.2]
2 | def change
3 | add_column :businesses, :price, :integer
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20181026180211_add_col_bus.rb:
--------------------------------------------------------------------------------
1 | class AddColBus < ActiveRecord::Migration[5.2]
2 | def change
3 | add_column :businesses, :delivery, :boolean
4 | add_column :businesses, :noise, :string
5 |
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20181026183252_changecolinbusiniess.rb:
--------------------------------------------------------------------------------
1 | class Changecolinbusiniess < ActiveRecord::Migration[5.2]
2 | def change
3 | remove_column :businesses, :delivery
4 | add_column :businesses, :delivery, :string
5 |
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20181027205347_add_col_to_reviews.rb:
--------------------------------------------------------------------------------
1 | class AddColToReviews < ActiveRecord::Migration[5.2]
2 | def change
3 | add_column :reviews, :like, :integer
4 | add_column :reviews, :funny, :integer
5 | add_column :reviews, :useful, :integer
6 | add_column :reviews, :cool, :integer
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20181102230142_changecoltobusiness.rb:
--------------------------------------------------------------------------------
1 | class Changecoltobusiness < ActiveRecord::Migration[5.2]
2 | def change
3 | remove_column :businesses, :delivery
4 | remove_column :businesses, :noise
5 | add_column :businesses, :noise, :integer
6 | add_column :businesses, :delivery, :integer
7 |
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20181105213012_removecolfromreviews.rb:
--------------------------------------------------------------------------------
1 | class Removecolfromreviews < ActiveRecord::Migration[5.2]
2 | def change
3 | remove_column :reviews, :cool
4 | remove_column :reviews, :useful
5 | remove_column :reviews, :funny
6 | remove_column :reviews, :like
7 |
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20181106173245_createattributestable.rb:
--------------------------------------------------------------------------------
1 | class Createattributestable < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :attribute do |t|
4 | t.string :type
5 | t.integer :user_id, null: false
6 | t.integer :review_id, null: false
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20181106191932_change_attribute_to_attributes.rb:
--------------------------------------------------------------------------------
1 | class ChangeAttributeToAttributes < ActiveRecord::Migration[5.2]
2 | def change
3 | rename_table :attribute, :attributes
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20181106194509_change_attributes_to_adjectives.rb:
--------------------------------------------------------------------------------
1 | class ChangeAttributesToAdjectives < ActiveRecord::Migration[5.2]
2 | def change
3 | rename_table :attributes, :adjectives
4 |
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/frontend/actions/adjective_actions.js:
--------------------------------------------------------------------------------
1 | import * as AdjectivesApiUtil from "./../util/adjective_util";
2 |
3 | export const RECEIVE_LIKE = "RECEIVE_LIKE";
4 | export const REMOVE_LIKE = "REMOVE_LIKE";
5 | export const RECEIVE_COOL = "RECEIVE_COOL";
6 | export const UPDATE_COOL = "UPDATE_COOL";
7 | export const RECEIVE_FUNNY = "RECEIVE_FUNNY";
8 | export const UPDATE_FUNNY = "UPDATE_FUNNY";
9 | export const RECEIVE_USEFUL = "RECEIVE_USEFUL";
10 | export const UPDATE_USEFUL = "UPDATE_USEFUL";
11 |
12 | export const receiveLike = payload => {
13 | return {
14 | type: RECEIVE_LIKE,
15 | payload
16 | };
17 | };
18 |
19 | export const removeLike = payload => {
20 | return {
21 | type: REMOVE_LIKE,
22 | payload
23 | };
24 | };
25 | export const receiveCool = payload => {
26 | return {
27 | type: RECEIVE_COOL,
28 | payload
29 | };
30 | };
31 |
32 | export const editCool = payload => {
33 | return {
34 | type: UPDATE_COOL,
35 | payload
36 | };
37 | };
38 |
39 | export const receiveFunny = payload => {
40 | return {
41 | type: RECEIVE_FUNNY,
42 | payload
43 | };
44 | };
45 |
46 | export const editFunny = payload => {
47 | return {
48 | type: UPDATE_FUNNY,
49 | payload
50 | };
51 | };
52 |
53 | export const receiveUseful = payload => {
54 | return {
55 | type: RECEIVE_USEFUL,
56 | payload
57 | };
58 | };
59 |
60 | export const editUseful = payload => {
61 | return {
62 | type: UPDATE_USEFUL,
63 | payload
64 | };
65 | };
66 |
67 | export const fetchLike = like => dispatch => {
68 | return AdjectivesApiUtil.fetchLike(like).then(like => {
69 | return dispatch(receiveLike(like));
70 | });
71 | };
72 | export const fetchCool = cool => dispatch => {
73 | return AdjectivesApiUtil.fetchCool(cool).then(cool => {
74 | return dispatch(receiveCool(cool));
75 | });
76 | };
77 |
78 | export const fetchFunny = funny => dispatch => {
79 | return AdjectivesApiUtil.fetchFunny(funny).then(funny => {
80 | return dispatch(receiveFunny(funny));
81 | });
82 | };
83 |
84 | export const fetchUseful = useful => dispatch => {
85 | return AdjectivesApiUtil.fetchUseful(useful).then(useful => {
86 | return dispatch(receiveUseful(useful));
87 | });
88 | };
89 |
90 | export const deleteLike = like => dispatch => {
91 | return AdjectivesApiUtil.deleteLike(like).then(like => {
92 | return dispatch(removeLike(like));
93 | });
94 | };
95 |
96 | export const createLike = like => dispatch => {
97 | return AdjectivesApiUtil.createLike(like).then(like => {
98 | return dispatch(receiveLike(like));
99 | });
100 | };
101 |
102 | export const updateCool = cool => dispatch => {
103 | return AdjectivesApiUtil.updateCool(cool).then(cool => {
104 | return dispatch(editCool(cool));
105 | });
106 | };
107 |
108 | export const updateUseful = useful => dispatch => {
109 | return AdjectivesApiUtil.updateUseful(useful).then(useful => {
110 | return dispatch(editUseful(useful));
111 | });
112 | };
113 |
114 | export const updateFunny = funny => dispatch => {
115 | return AdjectivesApiUtil.updateFunny(funny).then(funny => {
116 | return dispatch(editFunny(funny));
117 | });
118 | };
119 |
--------------------------------------------------------------------------------
/frontend/actions/business_category_actions.js:
--------------------------------------------------------------------------------
1 | import * as BusinessCategoryAPIUtil from './../util/business_categories_util';
2 |
3 | export const RECEIVE_ALL_BUSINESS_CATEGORIES = 'RECEIVE_ALL_BUSINESS_CATEGORIES';
4 | export const RECEIVE_SELECTED_BUSINESS_CATEGORIES = 'RECEIVE_SELECTED_BUSINESS_CATEGORIES';
5 |
6 |
7 | export const receiveAllBusinessCategories = businessCategories => {
8 | return {
9 | type: RECEIVE_ALL_BUSINESS_CATEGORIES,
10 | businessCategories
11 | };
12 | };
13 |
14 | export const requestAllBusinessCategories = () => {
15 | return dispatch => {
16 | return BusinessCategoryAPIUtil.fetchBusinessCategories().then( businessCategories => {
17 | return dispatch(receiveAllBusinessCategories(businessCategories));
18 | });
19 | };
20 | };
21 |
22 | export const receiveSelectedBusinessCategories = selectedBusinessCategories => {
23 | return {
24 | type: RECEIVE_SELECTED_BUSINESS_CATEGORIES,
25 | selectedBusinessCategories
26 | };
27 | };
28 |
--------------------------------------------------------------------------------
/frontend/actions/businesses_actions.js:
--------------------------------------------------------------------------------
1 | import * as BusinessesApiUtil from "./../util/businesses_util";
2 | import * as BusinessCategoriesUtil from "./../util/business_categories_util";
3 |
4 | export const RECEIVE_BUSINESSES = "RECEIVE_BUSINESSES";
5 | export const RECEIVE_SELECTED_BUSINESS_CATEGORIES =
6 | "RECEIVE_SELECTED_BUSINESS_CATEGORIES";
7 | export const RECEIVE_BUSINESS = "RECEIVE_BUSINESS";
8 |
9 | export const receiveBusinesses = selectedBusinessCategories => {
10 | return {
11 | type: RECEIVE_BUSINESSES,
12 | selectedBusinessCategories
13 | };
14 | };
15 |
16 | export const receiveSelectedBusinesses = businesses => {
17 | return {
18 | type: RECEIVE_SELECTED_BUSINESS_CATEGORIES,
19 | businesses
20 | };
21 | };
22 |
23 | export const receiveBusiness = business => {
24 | return {
25 | type: RECEIVE_BUSINESS,
26 | business
27 | };
28 | };
29 |
30 | export const receiveAllBusinesses = businesses => {
31 | return {
32 | type: RECEIVE_BUSINESSES,
33 | businesses
34 | };
35 | };
36 |
37 | export const requestAllBusinesses = () => {
38 | return dispatch => {
39 | return BusinessesApiUtil.fetchBusinesses().then(businesses => {
40 | return dispatch(receiveAllBusinesses(businesses));
41 | });
42 | };
43 | };
44 |
45 | export const requestSelectedBusinessCategories = selectedCategory => {
46 | return dispatch => {
47 | return BusinessCategoriesUtil.fetchSelectedBusinessCategories(
48 | selectedCategory
49 | ).then(selectedBusinessCategories => {
50 | return dispatch(receiveSelectedBusinesses(selectedBusinessCategories));
51 | });
52 | };
53 | };
54 |
55 | export const requestSingleBusiness = id => {
56 | return dispatch => {
57 | return BusinessesApiUtil.fetchBusiness(id).then(business => {
58 | return dispatch(receiveBusiness(business));
59 | });
60 | };
61 | };
62 |
--------------------------------------------------------------------------------
/frontend/actions/filter_actions.js:
--------------------------------------------------------------------------------
1 | export const UPDATE_BOUNDS = 'UPDATE_BOUNDS';
2 |
3 |
4 | export const updateFilter = (filter , value) => ({
5 | type: UPDATE_FILTER,
6 | filter,
7 | value
8 | });
9 |
--------------------------------------------------------------------------------
/frontend/actions/reviews_actions.js:
--------------------------------------------------------------------------------
1 | import * as ReviewApiUtil from "./../util/reviews_util";
2 |
3 | export const RECEIVE_ALL_REVIEWS = "RECEIVE_ALL_REVIEWS";
4 | export const RECEIVE_REVIEW = "RECEIVE_REVIEW";
5 | export const REMOVE_REVIEW = "REMOVE_REVIEW";
6 | export const RECEIVE_REVIEW_ERRORS = "RECEIVE_REVIEW_ERRORS";
7 |
8 | export const receiveReview = review => {
9 | return {
10 | type: RECEIVE_REVIEW,
11 | review
12 | };
13 | };
14 |
15 | export const receiveAllReviews = reviews => {
16 | return {
17 | type: RECEIVE_ALL_REVIEWS,
18 | reviews
19 | };
20 | };
21 |
22 | export const receiveReviewErrors = errors => {
23 | return {
24 | type: RECEIVE_REVIEW_ERRORS,
25 | errors
26 | };
27 | };
28 |
29 | export const removeReview = review => {
30 | return {
31 | type: REMOVE_REVIEW,
32 | review
33 | };
34 | };
35 |
36 | export const fetchAllReviews = businessId => {
37 | return dispatch => {
38 | return ReviewApiUtil.fetchAllReviews(businessId).then(reviews => {
39 | return dispatch(receiveAllReviews(reviews));
40 | });
41 | };
42 | };
43 |
44 | export const fetchAllUnrelatedReviews = () => {
45 | return dispatch => {
46 | return ReviewApiUtil.fetchAllUnrelatedReviews().then(reviews => {
47 | return dispatch(receiveAllReviews(reviews));
48 | });
49 | };
50 | };
51 |
52 | export const fetchReview = id => {
53 | return dispatch => {
54 | return ReviewApiUtil.fetchReview(id).then(review => {
55 | return dispatch(receiveReview(review));
56 | });
57 | };
58 | };
59 |
60 | export const createReview = business => {
61 | return dispatch => {
62 | return ReviewApiUtil.createReview(business).then(
63 | review => {
64 | return dispatch(receiveReview(review));
65 | },
66 | errors => {
67 | return dispatch(receiveReviewErrors(errors.responseJSON));
68 | }
69 | );
70 | };
71 | };
72 |
73 | export const updateReview = review => {
74 | return dispatch => {
75 | return ReviewApiUtil.updateReview(review).then(
76 | review => {
77 | return dispatch(receiveReview(review));
78 | },
79 | errors => {
80 | return dispatch(receiveReviewErrors(errors.responseJSON));
81 | }
82 | );
83 | };
84 | };
85 |
86 | export const deleteReview = review => {
87 | return dispatch => {
88 | return ReviewApiUtil.deleteReview(review).then(review => {
89 | return dispatch(removeReview(review));
90 | });
91 | };
92 | };
93 |
--------------------------------------------------------------------------------
/frontend/actions/search_actions.js:
--------------------------------------------------------------------------------
1 | import * as SearchApiUtil from "../util/search_api_util";
2 | export const CLEAR_SEARCH = "CLEAR_SEARCH";
3 |
4 | export const RECEIVE_SEARCH_RESULTS = "RECEIVE_SEARCH_RESULTS";
5 | export const RECEIVE_DROPDOWN_BUSINESSES = "RECEIVE_DROPDOWN_BUSINESSES";
6 |
7 | const receiveSearchResults = results => {
8 | return {
9 | type: RECEIVE_SEARCH_RESULTS,
10 | results
11 | };
12 | };
13 |
14 | export const receiveDropdownBusinesses = businesses => {
15 | return {
16 | type: RECEIVE_DROPDOWN_BUSINESSES,
17 | businesses
18 | };
19 | };
20 |
21 | export const requestDropdownBusinesses = searchData => dispatch => {
22 | return SearchApiUtil.searchBusinesses(searchData).then(results => {
23 | return dispatch(receiveDropdownBusinesses(results));
24 | });
25 | };
26 | export const searchBusinesses = searchData => dispatch => {
27 | return SearchApiUtil.searchBusinesses(searchData).then(results => {
28 | return dispatch(receiveSearchResults(results));
29 | });
30 | };
31 |
32 | export const clearSearch = () => {
33 | return {
34 | type: CLEAR_SEARCH
35 | };
36 | };
37 |
--------------------------------------------------------------------------------
/frontend/actions/sessions_actions.js:
--------------------------------------------------------------------------------
1 | import * as SessionAPIUtil from "./../util/session_api_util";
2 | export const RECEIVE_CURRENT_USER = "RECEIVE_CURRENT_USER";
3 | export const LOGOUT_CURRENT_USER = "LOGOUT_CURRENT_USER";
4 | export const RECEIVE_SESSION_ERRORS = "RECEIVE_SESSION_ERRORS";
5 | export const CLEAR_ERRORS = "CLEAR_ERRORS";
6 | export const RECEIVE_LOGIN_ERRORS = "RECEIVE_LOGIN_ERRORS";
7 | export const RECEIVE_SIGNUP_ERRORS = "RECEIVE_SIGNUP_ERRORS";
8 | export const RECEIVE_ALL_USERS = "RECEIVE_ALL_USERS";
9 |
10 | const receiveCurrentUser = user => {
11 | return {
12 | type: RECEIVE_CURRENT_USER,
13 | user
14 | };
15 | };
16 | const receiveAllUsers = users => {
17 | return {
18 | type: RECEIVE_ALL_USERS,
19 | users
20 | };
21 | };
22 |
23 | const logoutCurrentUser = () => {
24 | return {
25 | type: LOGOUT_CURRENT_USER
26 | };
27 | };
28 |
29 | export const receiveErrors = errors => {
30 | return {
31 | type: RECEIVE_SESSION_ERRORS,
32 | errors
33 | };
34 | };
35 |
36 | function receiveLoginErrors(errors) {
37 | return {
38 | type: RECEIVE_LOGIN_ERRORS,
39 | errors
40 | };
41 | }
42 |
43 | function receiveSignupErrors(errors) {
44 | return {
45 | type: RECEIVE_SIGNUP_ERRORS,
46 | errors
47 | };
48 | }
49 |
50 | export const clearErrors = () => {
51 | return {
52 | type: CLEAR_ERRORS
53 | };
54 | };
55 |
56 | export const fetchCurrentUser = user => dispatch => {
57 | return SessionAPIUtil.currentUser(user).then(user => {
58 | return dispatch(receiveCurrentUser(user));
59 | });
60 | };
61 | export const fetchAllUsers = () => dispatch => {
62 | return SessionAPIUtil.fetchAllUsers().then(users => {
63 | return dispatch(receiveAllUsers(users));
64 | });
65 | };
66 |
67 | export const signup = user => dispatch =>
68 | SessionAPIUtil.signup(user).then(
69 | user => dispatch(receiveCurrentUser(user)),
70 | errors => dispatch(receiveErrors(errors.responseJSON))
71 | );
72 |
73 | export const login = user => dispatch =>
74 | SessionAPIUtil.login(user).then(
75 | user => dispatch(receiveCurrentUser(user)),
76 | errors => dispatch(receiveErrors(errors.responseJSON))
77 | );
78 |
79 | export const logout = () => dispatch =>
80 | SessionAPIUtil.logout().then(() => dispatch(logoutCurrentUser()));
81 |
--------------------------------------------------------------------------------
/frontend/better_help.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import Root from './components/root';
4 | import configureStore from './store/store';
5 | import { requestSelectedBusinessCategories } from './actions/business_category_actions';
6 | import { requestSingleBusiness } from './actions/businesses_actions';
7 |
8 | document.addEventListener("DOMContentLoaded", () => {
9 | let preloadedState;
10 | if (window.currentUser) {
11 | preloadedState = {
12 | session: {
13 | id: window.currentUser.id
14 | },
15 | entities: {
16 | users: {
17 | [window.currentUser.id]: window.currentUser
18 | }
19 | }
20 | };
21 | } else {
22 | preloadedState = {};
23 | }
24 | delete(window.currentUser);
25 |
26 | const store = configureStore(preloadedState);
27 | window.dispatch = store.dispatch;
28 | window.requestSingleBusiness = requestSingleBusiness;
29 | const root = document.getElementById('root');
30 | ReactDOM.render(
, root)
31 | });
32 |
--------------------------------------------------------------------------------
/frontend/components/App.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SignUpFormContainer from './session/sign_up_container';
3 | import SplashContainer from './splash/splash_container';
4 | import LoginFormContainer from './session/login_form_container';
5 | import { AuthRoute, ProtectedRoute } from '../util/route_util';
6 | import { Route } from 'react-router-dom';
7 | import BusinessCategoryIndexContainer from './business_category/business_category_index_container';
8 | import BusinessesContainer from './businesses/businesses_container';
9 | import BusinessShowContainer from './businesses/business_show_container';
10 | import CreateReviewFormContainer from './reviews/create_review_form_container';
11 | import EditReviewFormContainer from './reviews/edit_review_form_container';
12 | import BusinessIndexContainer from './businesses/business_index_container';
13 | import SearchBusinessPageContainer from './search/search_business_page_container';
14 | import SearchContainer from './search/search_container';
15 | import SearchDropDownContainer from './search/search_drop_down_container';
16 | import ProfileContainer from './user/profile_container';
17 |
18 | const App = () => (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
54 |
55 |

56 |
57 |
58 |
59 |
60 | )
61 |
62 | export default App;
63 |
--------------------------------------------------------------------------------
/frontend/components/business_category/business_category.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { withRouter } from "react-router-dom";
3 | import { Link } from "react-router-dom";
4 |
5 | class BusinessCategory extends React.Component {
6 | render() {
7 | return (
8 |
9 |
10 |
11 |
12 | {this.props.category.category}
13 |
14 |
15 |
16 | );
17 | }
18 | }
19 |
20 | export default withRouter(BusinessCategory);
21 |
--------------------------------------------------------------------------------
/frontend/components/business_category/business_category_index.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { withRouter } from "react-router-dom";
3 | import { Link } from "react-router-dom";
4 | import BusinessCategory from "./business_category";
5 |
6 | class BusinessCategoryIndex extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | }
10 |
11 | componentDidMount() {
12 | this.props.requestAllBusinessCategories();
13 | }
14 |
15 | toggleIcons(category) {
16 | switch (category.category) {
17 | case "Cafes":
18 | return "fas fa-coffee one";
19 | case "Restaurants":
20 | return "fal fa-utentils one";
21 | case "Home Services":
22 | return "fas fa-home one";
23 | case "Bootcamps":
24 | return "fas fa-keyboard one";
25 | default:
26 | return "fa fa-utensils one";
27 | }
28 | }
29 |
30 | render() {
31 | const businessCategories = this.props.businessCategories.map(
32 | (category, idx) => (
33 |
39 | )
40 | );
41 |
42 | return (
43 |
44 |
{businessCategories}
45 |
46 | );
47 | }
48 | }
49 |
50 | export default withRouter(BusinessCategoryIndex);
51 |
--------------------------------------------------------------------------------
/frontend/components/business_category/business_category_index_container.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import BusinessCategoryIndex from './business_category_index';
4 | import { requestAllBusinessCategories } from '../../actions/business_category_actions';
5 | import { requestSelectedBusinessCategories } from '../../actions/businesses_actions';
6 |
7 | const msp = state => {
8 | return {
9 | businessCategories: Object.values(state.entities.businessCategories),
10 | };
11 | };
12 |
13 |
14 | const mdp = dispatch => {
15 | return {
16 | requestAllBusinessCategories: () => dispatch(requestAllBusinessCategories()),
17 | requestSelectedBusinessCategories: () => dispatch(requestSelectedBusinessCategories())
18 | };
19 | };
20 |
21 |
22 | export default connect(msp,mdp)(BusinessCategoryIndex);
23 |
--------------------------------------------------------------------------------
/frontend/components/businesses/business.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { withRouter } from "react-router-dom";
3 | import { Link } from "react-router-dom";
4 | import ReactStars from "react-stars";
5 |
6 | class Business extends React.Component {
7 | render() {
8 | const review = this.props.business.reviews;
9 | const reviewCount = review ? review.length : 0;
10 | const reviewBody = reviewCount > 0 && review ? review[0].body : "";
11 |
12 | let reviewScore = [0];
13 | review.forEach(review => {
14 | reviewScore.push(review.rating);
15 | });
16 |
17 | reviewScore =
18 | reviewScore.reduce((acc, el) => {
19 | return acc + el;
20 | }) / review.length;
21 |
22 | return (
23 |
24 |
25 |
29 |

33 |
34 |
35 |
36 |
37 |
38 |
39 |
{this.props.idx + 1}.
40 |
41 | {this.props.business.name}
42 |
43 |
44 |
45 |
54 |
{reviewCount} reviews
55 |
56 |
57 |
58 |
59 |
{this.props.business.phone_number}
60 |
61 | {this.props.business.address}
62 |
63 | {this.props.business.city}
64 | {reviewBody}
65 |
66 |
67 |
68 |
69 |
70 | );
71 | }
72 | }
73 |
74 | export default withRouter(Business);
75 |
76 | // {})
77 |
--------------------------------------------------------------------------------
/frontend/components/businesses/business_index_container.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import BusinessIndex from './business_index';
4 | import { requestAllBusinesses } from '../../actions/businesses_actions';
5 | import { requestAllBusinessCategories } from '../../actions/business_category_actions';
6 |
7 |
8 |
9 | const msp = (state,ownProps) => {
10 |
11 | return {
12 | currentUser: state.entities.users[state.session.id],
13 | businesses: Object.values(state.entities.businesses),
14 | businessCategories: Object.values(state.entities.businessCategories)
15 | };
16 | };
17 |
18 |
19 | const mdp = dispatch => {
20 | return {
21 | requestAllBusinesses: () => dispatch(requestAllBusinesses()),
22 | requestAllBusinessCategories: () => dispatch(requestAllBusinessCategories())
23 | };
24 | };
25 |
26 |
27 | export default connect(msp,mdp)(BusinessIndex);
28 |
--------------------------------------------------------------------------------
/frontend/components/businesses/business_map_container.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import BusinessMap from '../map/business_map';
4 | import { requestAllBusinesses } from '../../actions/businesses_actions';
5 |
6 |
7 | const msp = (state,ownProps) => {
8 | let businesses;
9 | if (state.entities.business){
10 | businesses = Object.values(state.entities.businesses);
11 | } else {
12 | businesses = [];
13 | }
14 | return {
15 | businesses: businesses,
16 | };
17 | };
18 |
19 |
20 | const mdp = dispatch => {
21 | return {
22 | requestAllBusinesses: () => dispatch(requestAllBusinesses())
23 | };
24 | };
25 |
26 |
27 | export default connect(msp,mdp)(BusinessMap);
28 |
--------------------------------------------------------------------------------
/frontend/components/businesses/business_show_container.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { connect } from "react-redux";
3 | import BusinessShow from "./business_show";
4 | import { requestSingleBusiness } from "../../actions/businesses_actions";
5 | import { deleteReview, updateReview } from "../../actions/reviews_actions";
6 | import { requestAllBusinessCategories } from "../../actions/business_category_actions";
7 | import { fetchAllUsers } from "../../actions/sessions_actions";
8 |
9 | const msp = (state, ownProps) => {
10 | const fetchedBusiness =
11 | state.entities.businesses[ownProps.match.params.businessId];
12 | let reviews = [];
13 | if (fetchedBusiness) {
14 | reviews = fetchedBusiness.reviews;
15 | }
16 | return {
17 | users: state.entities.users,
18 | business: fetchedBusiness,
19 | reviews: reviews,
20 | currentUser: state.entities.users[state.session.id],
21 | session: state.session.id,
22 | businessCategories: Object.values(state.entities.businessCategories)
23 | };
24 | };
25 |
26 | const mdp = dispatch => {
27 | return {
28 | requestSingleBusiness: id => dispatch(requestSingleBusiness(id)),
29 | updateReview: review => dispatch(updateReview(review)),
30 | deleteReview: id => dispatch(deleteReview(id)),
31 | requestAllBusinessCategories: () =>
32 | dispatch(requestAllBusinessCategories()),
33 | fetchAllUsers: userId => dispatch(fetchAllUsers(userId))
34 | };
35 | };
36 |
37 | export default connect(
38 | msp,
39 | mdp
40 | )(BusinessShow);
41 |
--------------------------------------------------------------------------------
/frontend/components/businesses/business_to_write_review.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { withRouter } from "react-router-dom";
3 | import { Link } from "react-router-dom";
4 | import ReactStars from "react-stars";
5 |
6 | class BusinessToWriteReview extends React.Component {
7 | componentWillReceiveProps(nextProps) {
8 | if (
9 | this.props.match.params.businessId !== nextProps.match.params.businessId
10 | ) {
11 | this.props.requestSingleBusiness(nextProps.match.params.businessId);
12 | }
13 | }
14 |
15 | render() {
16 | const review = this.props.business.reviews;
17 |
18 | let reviewScore = [0];
19 | review.forEach(review => {
20 | reviewScore.push(review.rating);
21 | });
22 |
23 | if (reviewScore.length > 0) {
24 | reviewScore =
25 | reviewScore.reduce((acc, el) => {
26 | return acc + el;
27 | }) / review.length;
28 | }
29 |
30 | return (
31 |
32 |
33 |
37 |

41 |
42 |
43 |
44 |
45 |
46 |
50 | {this.props.business.name}
51 |
52 |
53 |
54 |
55 |
56 |
57 | {this.props.business.address}
58 |
59 |
60 | {this.props.business.city}
61 |
62 |
63 |
64 |
73 |
74 |
75 |
76 |
77 | );
78 | }
79 | }
80 |
81 | export default withRouter(BusinessToWriteReview);
82 |
83 | // {})
84 |
--------------------------------------------------------------------------------
/frontend/components/businesses/businesses_container.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import Businesses from './businesses';
4 | import { requestSelectedBusinessCategories } from '../../actions/businesses_actions';
5 | import { requestAllBusinessCategories } from '../../actions/business_category_actions';
6 | import { searchBusinesses } from '../../actions/search_actions';
7 |
8 |
9 | const msp = (state,ownProps) => {
10 |
11 | let businessCategoryName;
12 | if (state.entities.businessCategories){
13 | Object.values(state.entities.businessCategories).forEach( category => {
14 | if (category.id.toString() === ownProps.match.params.id){
15 | businessCategoryName = category.category;
16 | }
17 | });
18 | }
19 |
20 | return {
21 | currentUser: state.entities.users[state.session.id],
22 | businesses: Object.values(state.entities.businesses),
23 | category: ownProps.match.params.id,
24 | businessCategories: Object.values(state.entities.businessCategories),
25 | businessCategoryName
26 | };
27 | };
28 |
29 |
30 | const mdp = dispatch => {
31 | return {
32 | searchBusinesses: (searchData) => dispatch(searchBusinesses(searchData)),
33 | requestSelectedBusinessCategories: (businessCategory) => dispatch(requestSelectedBusinessCategories(businessCategory)),
34 | requestAllBusinessCategories: () => dispatch(requestAllBusinessCategories())
35 |
36 | };
37 | };
38 |
39 |
40 | export default connect(msp,mdp)(Businesses);
41 |
--------------------------------------------------------------------------------
/frontend/components/businesses/filter_nav.jsx:
--------------------------------------------------------------------------------
1 | // import React from 'react';
2 | // import ReactDOM from 'react-dom';
3 | //
4 | // class FilterForm extends React.Component {
5 | //
6 | // render() {
7 | // return (
8 | //
9 | //
10 | //
Browsing Restaurants in Manhattan, NY
11 | //
53 | //
54 | //
55 | // );
56 | // }
57 | // }
58 |
--------------------------------------------------------------------------------
/frontend/components/map/business_map.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withRouter } from 'react-router-dom';
3 | import { Link } from 'react-router-dom';
4 | import MarkerManager from '../../util/marker_manager';
5 |
6 |
7 | /// ayellapragada@gmail.com
8 | const mapOptions = {
9 | center: {
10 | lat: 40.915494,
11 | lng: -74.002209
12 | },
13 | zoom: 7
14 | };
15 |
16 |
17 | const getCoordsObj = latlng => ({
18 | lat: latLng.lat(),
19 | lng: latLng.lng()
20 | });
21 |
22 | class BusinessMap extends React.Component {
23 |
24 | componentDidMount() {
25 | const map = this.refs.map;
26 | this.map = new google.maps.Map(this.mapNode, mapOptions);
27 | this.MarkerManager = new MarkerManager(this.map, this.handleMarkerClick.bind(this));
28 | if (this.props.single) {
29 | this.MarkerManager.createMarkerFromBusiness(this.props.business);
30 | } else {
31 | this.MarkerManager.updateMarkers(this.props.businesses);
32 | }
33 | }
34 |
35 | componentDidUpdate() {
36 | if (this.props.single) {
37 | this.MarkerManager.createMarkerFromBusiness(this.props.business);
38 | const business = this.props.business;
39 | this.MarkerManager.createMarkerFromBusiness(this.props.business);
40 | this.MarkerManager.updateMarkers([business]);
41 | } else {
42 | this.MarkerManager.updateMarkers(this.props.businesses);
43 | }
44 | }
45 |
46 | handleMarkerClick(business) {
47 | const url = `https://www.google.com/maps/place/${business.address}`;
48 | window.open(url);
49 | }
50 |
51 | render() {
52 | return (
53 | this.mapNode = map }>
54 |
55 | )
56 |
57 | }
58 | }
59 |
60 | export default withRouter(BusinessMap);
61 |
--------------------------------------------------------------------------------
/frontend/components/reviews/create_review_form_container.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import ReviewForm from './review_form';
4 | import { createReview } from '../../actions/reviews_actions';
5 | import { requestSingleBusiness } from '../../actions/businesses_actions';
6 | import { clearErrors } from '../../actions/sessions_actions';
7 |
8 | const msp = (state ,ownProps) => {
9 | const errors = state.errors.review;
10 | const business_id = ownProps.match.params.businessId;
11 | const business = state.entities.businesses[ownProps.match.params.businessId] || {};
12 | const review = {
13 | rating: '',
14 | body: '',
15 | business_id: business_id,
16 | };
17 | const formType = 'Write a Review';
18 | return {
19 | errors,
20 | review,
21 | formType,
22 | business
23 | };
24 | };
25 |
26 | const mdp = dispatch =>{
27 | return {
28 | action: (review) => dispatch(createReview(review)),
29 | requestSingleBusiness: id => dispatch(requestSingleBusiness(id)),
30 | clearErrors: () => dispatch(clearErrors())
31 |
32 | };
33 | };
34 |
35 | export default connect(msp,mdp)(ReviewForm);
36 |
--------------------------------------------------------------------------------
/frontend/components/reviews/edit_review_form_container.jsx:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import ReviewForm from './review_form';
3 | import { updateReview, fetchReview } from '../../actions/reviews_actions';
4 | import { clearErrors } from '../../actions/sessions_actions';
5 | import { requestSingleBusiness } from '../../actions/businesses_actions';
6 |
7 |
8 | const msp = (state, ownProps) => {
9 | // only way to get to this props should be thorugh the business show page
10 |
11 | const businessId = ownProps.match.params.businessId;
12 | const reviewId = ownProps.match.params.id;
13 | const business = state.entities.businesses[ownProps.match.params.businessId] || {};
14 | // const review = (state.entities.businesses[businessId] && state.entities.businesses[businessId].reviews[reviewId]) || {};
15 | const review = state.entities.businesses[businessId].reviews.find(rev => rev.id === parseInt(reviewId));
16 |
17 | const errors = state.errors.review;
18 | const formType = "Update Review";
19 | return { review, errors, formType, business };
20 | };
21 |
22 | const mdp = (dispatch) => {
23 | return {
24 | action: review => dispatch(updateReview(review)),
25 | fetchReview: id => dispatch(fetchReview(id)),
26 | clearErrors: () => dispatch(clearErrors()),
27 | requestSingleBusiness: id => dispatch(requestSingleBusiness(id)),
28 |
29 | };
30 | };
31 |
32 | export default connect(msp, mdp)(ReviewForm);
33 |
--------------------------------------------------------------------------------
/frontend/components/root.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Provider } from 'react-redux';
3 | import App from './App';
4 | import { HashRouter } from 'react-router-dom';
5 |
6 | const Root = ({ store }) => (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | );
15 |
16 | export default Root;
17 |
--------------------------------------------------------------------------------
/frontend/components/search/search.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withRouter } from 'react-router-dom';
3 | import { Link } from 'react-router-dom';
4 | import Business from '../businesses/business';
5 | import BusinessMap from '../map/business_map';
6 | import BusinessIndexContainer from '../businesses/business_index_container';
7 |
8 | class Search extends React.Component {
9 |
10 |
11 | render() {
12 |
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
20 | )
21 | }
22 | }
23 |
24 | export default withRouter(Search);
25 |
26 | // {})
27 |
--------------------------------------------------------------------------------
/frontend/components/search/search_business_page_container.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import SearchBusinessPage from './search_business_page';
4 | import { searchBusinesses } from '../../actions/search_actions';
5 | import { selectSearchBusinesses } from '../../reducers/selectors';
6 | import { requestAllBusinessCategories } from '../../actions/business_category_actions';
7 |
8 | const msp = (state,ownProps) => {
9 |
10 | let searchedBusIds = state.session.searchR;
11 | let businesses = Object.values(state.entities.businesses);
12 | return {
13 | currentUser: state.entities.users[state.session.id],
14 | searchedBusinesses: selectSearchBusinesses(businesses,searchedBusIds),
15 | businessCategories: Object.values(state.entities.businessCategories),
16 | };
17 | };
18 |
19 |
20 | const mdp = dispatch => {
21 |
22 | return {
23 | searchBusinesses: (searchData) => dispatch(searchBusinesses(searchData)),
24 | requestAllBusinessCategories: () => dispatch(requestAllBusinessCategories())
25 | };
26 | };
27 |
28 |
29 | export default connect(msp,mdp)(SearchBusinessPage);
30 |
--------------------------------------------------------------------------------
/frontend/components/search/search_container.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import Search from './search';
4 | import { requestAllBusinesses } from '../../actions/businesses_actions';
5 |
6 |
7 | const msp = (state,ownProps) => {
8 | return {
9 | businesses: Object.values(state.entities.businesses)
10 | };
11 | };
12 |
13 |
14 | const mdp = dispatch => {
15 | return {
16 | requestAllBusinesses: () => dispatch(requestAllBusinesses())
17 | };
18 | };
19 |
20 |
21 | export default connect(msp,mdp)(Search);
22 |
--------------------------------------------------------------------------------
/frontend/components/search/search_drop_down.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withRouter } from 'react-router-dom';
3 | import { Link } from 'react-router-dom';
4 |
5 | class SearchDropDown extends React.Component {
6 |
7 | componentWillUnmount(){
8 | // this.props.clearSearch()
9 | }
10 |
11 | render() {
12 |
13 | if (this.props.name.length === 0){
14 | return (
15 | null
16 | )
17 | } else {
18 | return (
19 |
20 |
{this.props.business.name}
21 |
22 | )
23 | }
24 | }
25 | }
26 |
27 | export default withRouter(SearchDropDown);
28 |
--------------------------------------------------------------------------------
/frontend/components/search/search_drop_down_container.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { selectSearchBusinesses } from '../../reducers/selectors';
4 | import { searchBusinesses, clearSearch } from '../../actions/search_actions';
5 | import SearchDropDown from './search_drop_down';
6 |
7 |
8 | const msp = (state,ownProps) => {
9 |
10 | let searchedBusIds = state.session.searchR;
11 | let businesses = Object.values(state.entities.businesses);
12 | return {
13 | searchedBusinesses: selectSearchBusinesses(businesses,searchedBusIds)
14 | };
15 | };
16 |
17 |
18 | const mdp = dispatch => {
19 |
20 | return {
21 | clearSearch: () => dispatch(clearSearch()),
22 | searchBusinesses: (searchData) => dispatch(searchBusinesses(searchData))
23 | };
24 | };
25 |
26 |
27 | // export default connect(msp,mdp)(SearchDropDown);
28 |
--------------------------------------------------------------------------------
/frontend/components/search/search_form_container.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { connect } from "react-redux";
3 | import {
4 | requestDropdownBusinesses,
5 | clearSearch
6 | } from "../../actions/search_actions";
7 | import { clearErrors } from "../../actions/sessions_actions";
8 | import SearchForm from "./search_form";
9 | import { logout } from "../../actions/sessions_actions";
10 | import errorsReducer from "../../reducers/errors_reducer";
11 | import { Link } from "react-router-dom";
12 | import { selectSearchBusinesses } from "../../reducers/selectors";
13 | import { requestAllBusinessCategories } from "../../actions/business_category_actions";
14 |
15 | const msp = (state, ownProps) => {
16 | let userProf = "nav-sear-container-false";
17 | if (state.session.id) {
18 | userProf = "nav-sear-container-true";
19 | }
20 |
21 | let searchedBusIds = state.session.searchR;
22 | let businesses = Object.values(state.entities.searches);
23 |
24 | return {
25 | currentUser: state.entities.users[state.session.id],
26 | userLoggedIn: userProf,
27 | businessCategories: Object.values(state.entities.businessCategories),
28 | searchedBusinesses: businesses
29 | };
30 | };
31 |
32 | const mapDispatchToProps = dispatch => {
33 | return {
34 | clearSearch: () => dispatch(clearSearch()),
35 | logout: () => dispatch(logout()),
36 | requestAllBusinessCategories: () =>
37 | dispatch(requestAllBusinessCategories()),
38 | requestDropdownBusinesses: searchData =>
39 | dispatch(requestDropdownBusinesses(searchData)),
40 | clearErrors: () => dispatch(clearErrors())
41 | };
42 | };
43 |
44 | export default connect(
45 | msp,
46 | mapDispatchToProps
47 | )(SearchForm);
48 |
49 | // create selector and iterate ver search results and match the ones in business lsice of state
50 | // state.session.search
51 |
--------------------------------------------------------------------------------
/frontend/components/session/login_form.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withRouter } from 'react-router-dom';
3 | import { Link } from 'react-router-dom';
4 |
5 | class LogInForm extends React.Component {
6 |
7 | constructor(props) {
8 | super(props);
9 | this.state = {
10 | email: "",
11 | password: ""
12 | };
13 | this.handleSubmit = this.handleSubmit.bind(this);
14 | this.guestSignin = this.guestSignin.bind(this);
15 |
16 | }
17 |
18 | componentWillMount() {
19 | this.props.clearErrors();
20 | }
21 |
22 | handleSubmit(e){
23 | e.preventDefault();
24 | const user = Object.assign({}, this.state);
25 | // this.props.clearErrors();
26 | this.props.processForm(user);
27 | }
28 |
29 | update(field){
30 | return (e) => {
31 | this.setState({
32 | [field]: e.currentTarget.value
33 | });
34 | };
35 | }
36 |
37 | guestSignin(e) {
38 | e.preventDefault();
39 | const user = {
40 | email: "guest@demo.org",
41 | password: "123123",
42 | fname: "Guest",
43 | lname: "Demo",
44 | zipcode: "11364",
45 | birthday: {
46 | month: "Dec",
47 | day: 8,
48 | year: 1985
49 | }
50 | };
51 | this.props.processForm(user);
52 | }
53 |
54 |
55 | renderErrors() {
56 | return(
57 |
58 | {this.props.errors.map((error, i) => (
59 | -
60 | {error}
61 |
62 | ))}
63 |
64 | );
65 | }
66 |
67 | render(){
68 | const header = this.props.formType;
69 |
70 | return (
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
112 |
113 |
114 | )
115 | }
116 | }
117 |
118 |
119 |
120 | export default withRouter(LogInForm);
121 |
--------------------------------------------------------------------------------
/frontend/components/session/login_form_container.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { login, clearErrors } from '../../actions/sessions_actions';
4 | import LoginForm from './login_form';
5 | import errorsReducer from '../../reducers/errors_reducer';
6 | import { Link } from 'react-router-dom';
7 |
8 |
9 | const msp = (state, ownProps) => {
10 | return {
11 | errors: state.errors.session,
12 | formType: 'Login',
13 | link: Sign Up
14 | };
15 | };
16 |
17 | const mapDispatchToProps = dispatch => {
18 | return {
19 | processForm: (user) => dispatch(login(user)),
20 | clearErrors: () => dispatch(clearErrors())
21 | };
22 | };
23 |
24 |
25 | export default connect(msp,mapDispatchToProps)(LoginForm);
26 |
--------------------------------------------------------------------------------
/frontend/components/session/sign_up_container.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { signup, clearErrors, login} from '../../actions/sessions_actions';
4 | import SignUpForm from './sign_up_form';
5 | import errorsReducer from '../../reducers/errors_reducer';
6 | import { Link } from 'react-router-dom';
7 |
8 |
9 | const msp = (state, ownProps) => {
10 | return {
11 | errors: state.errors.session,
12 | formType: 'Signup',
13 | link: Login
14 | };
15 | };
16 |
17 | const mapDispatchToProps = dispatch => {
18 | return {
19 | login: (user) => dispatch(login(user)),
20 | processForm: (user) => dispatch(signup(user)),
21 | clearErrors: () => dispatch(clearErrors())
22 | };
23 | };
24 |
25 | export default connect(msp,mapDispatchToProps)(SignUpForm);
26 |
--------------------------------------------------------------------------------
/frontend/components/splash/splash_business_categories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withRouter } from 'react-router-dom';
3 | import { Link } from 'react-router-dom';
4 | import ReactStars from 'react-stars';
5 |
6 |
7 | class SplashBusinessCategories extends React.Component {
8 |
9 |
10 | toggleIcons(category){
11 | switch (category.category) {
12 | case "Cafes":
13 | return "https://s3.amazonaws.com/betterhelp-dev/coff.png";
14 | case "Restaurant":
15 | return "https://s3.amazonaws.com/betterhelp-dev/rest.png";
16 | case "Home Services":
17 | return "https://s3.amazonaws.com/betterhelp-dev/wrench.png";
18 | case "Bootcamps":
19 | return "https://s3.amazonaws.com/betterhelp-dev/lap.png";
20 | default:
21 | return "https://s3.amazonaws.com/betterhelp-dev/coff.png";
22 | }
23 | }
24 |
25 | render() {
26 | const category = this.props.category;
27 | return (
28 |
29 |
30 |
31 |
})
32 |
33 |
34 |
35 | {category.category}
36 |
37 |
38 |
39 | )
40 | }
41 |
42 | }
43 |
44 | export default withRouter(SplashBusinessCategories);
45 |
46 | // {})
47 |
--------------------------------------------------------------------------------
/frontend/components/splash/splash_businesses.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { withRouter } from "react-router-dom";
3 | import { Link } from "react-router-dom";
4 | import ReactStars from "react-stars";
5 |
6 | class SplashBusinesses extends React.Component {
7 | render() {
8 | let business = this.props.business;
9 | let numReviews = this.props.business.reviews.length;
10 | let reviewScore = [0];
11 | let reviewCount = this.props.business.reviews.forEach(review => {
12 | reviewScore.push(review.rating);
13 | });
14 |
15 | reviewScore =
16 | reviewScore.reduce((acc, el) => {
17 | return acc + el;
18 | }) / numReviews;
19 |
20 | return (
21 |
22 |
23 |

27 |
28 |
29 |
{business.name}
30 |
31 |
32 |
33 |
40 |
41 | {numReviews} reviews
42 |
43 |
44 |
{business.city}
45 |
46 | {" "}
47 | Opened 6 weeks ago{" "}
48 |
49 |
50 | );
51 | }
52 | }
53 |
54 | export default withRouter(SplashBusinesses);
55 |
56 | // {})
57 |
--------------------------------------------------------------------------------
/frontend/components/splash/splash_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from "react-redux";
2 | import { logout } from "../../actions/sessions_actions";
3 | import { requestAllBusinesses } from "../../actions/businesses_actions";
4 | import { fetchAllUnrelatedReviews } from "../../actions/reviews_actions";
5 | import { requestAllBusinessCategories } from "../../actions/business_category_actions";
6 | import Splash from "./splash";
7 |
8 | const mapStateToProps = state => {
9 | return {
10 | currentUser: state.entities.users[state.session.id],
11 | businesses: Object.values(state.entities.businesses),
12 | reviews: Object.values(state.entities.reviews),
13 | businessCategories: Object.values(state.entities.businessCategories)
14 | };
15 | };
16 |
17 | const mapDispatchToPros = dispatch => {
18 | return {
19 | logout: () => dispatch(logout()),
20 | fetchAllUnrelatedReviews: () => dispatch(fetchAllUnrelatedReviews()),
21 | requestAllBusinesses: () => dispatch(requestAllBusinesses()),
22 | requestAllBusinessCategories: () => dispatch(requestAllBusinessCategories())
23 | };
24 | };
25 |
26 | export default connect(
27 | mapStateToProps,
28 | mapDispatchToPros
29 | )(Splash);
30 |
--------------------------------------------------------------------------------
/frontend/components/splash/splash_reviews.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { withRouter } from "react-router-dom";
3 | import { connect } from "react-redux";
4 | import { Link } from "react-router-dom";
5 | import ReactStars from "react-stars";
6 | import {
7 | requestSingleBusiness,
8 | requestAllBusinesses
9 | } from "../../actions/businesses_actions";
10 | import AdjectiveShow from "../adjective/adjective_show.jsx";
11 |
12 | class SplashReviews extends React.Component {
13 | componentDidMount() {
14 | // this.props.requestSingleBusiness(this.props.review.business_id);
15 | this.props.requestAllBusinesses();
16 | }
17 |
18 | asd() {
19 | let a = [this.props.review].map(review => {
20 | return (
21 |
28 | );
29 | });
30 | return a;
31 | }
32 |
33 | render() {
34 | const review = this.props.review;
35 | const b = this.asd();
36 | const user = this.props.review.user;
37 | const business = this.props.business;
38 | const businessLength = Object.values(this.props.business).length;
39 | let matchedBusiness = business[review.business_id];
40 | let photo;
41 | if (matchedBusiness) {
42 | photo = matchedBusiness.photos[0].photo_image_url;
43 | } else {
44 | matchedBusiness = "";
45 | }
46 |
47 | return (
48 |
49 |
50 |
51 |
52 |

53 |
54 |
55 |
56 | {user.fname} {user.lname}
57 |
58 |
Wrote a review
59 |
60 |
61 |
62 |
63 |

64 |
65 |
66 |
67 |
71 | {matchedBusiness.name}
72 |
73 |
74 |
75 |
76 |
84 |
85 |
{review.body}
86 |
87 | {b}
88 |
89 |
90 | );
91 | }
92 | }
93 |
94 | const mapStateToProps = state => {
95 | return {
96 | business: state.entities.businesses
97 | };
98 | };
99 |
100 | const mapDispatchToProps = dispatch => {
101 | return {
102 | deleteReview: id => dispatch(deleteReview(id)),
103 | updateReview: review => dispatch(updateReview(review)),
104 | requestSingleBusiness: id => dispatch(requestSingleBusiness(id)),
105 | requestAllBusinesses: () => dispatch(requestAllBusinesses())
106 | };
107 | };
108 | // export default withRouter(SplashReviews);
109 | export default connect(
110 | mapStateToProps,
111 | mapDispatchToProps
112 | )(SplashReviews);
113 |
114 | // {})
115 |
--------------------------------------------------------------------------------
/frontend/components/user/profile.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import BusinessCategoryIndexContainer from "../business_category/business_category_index_container";
4 | import SearchFormContainer from "../search/search_form_container";
5 | import BusinessIndexContainer from "../businesses/business_index_container";
6 | import Business from "../businesses/business_index_container";
7 | import UserReview from "./user_reviews";
8 |
9 | class Profile extends React.Component {
10 | constructor(props) {
11 | super(props);
12 | }
13 |
14 | componentDidMount() {
15 | this.props.fetchCurrentUser(this.props.currentUser.id);
16 | this.props.requestAllBusinessCategories();
17 | }
18 |
19 | userReviews() {
20 | let userReviews;
21 | if (this.props.reviews) {
22 | userReviews = this.props.reviews.map(review => {
23 | return ;
24 | });
25 | }
26 | return userReviews;
27 | }
28 |
29 | render() {
30 | let res, home, cafe, boot;
31 | if (this.props.businessCategories.length > 0) {
32 | res = this.props.businessCategories[0].id;
33 | home = this.props.businessCategories[1].id;
34 | cafe = this.props.businessCategories[2].id;
35 | boot = this.props.businessCategories[3].id;
36 | }
37 |
38 | let reviewLength;
39 | if (this.props.reviews) {
40 | reviewLength = (
41 |
42 | You have {this.props.reviews.length} written reviews
43 |
44 | );
45 | }
46 |
47 | let brandName;
48 | if (this.props.currentUser) {
49 | brandName = "small-brand-name2";
50 | } else {
51 | brandName = "small-brand-name";
52 | }
53 |
54 | return (
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
71 |
72 |
Restaurant
73 |
74 |
78 |
79 |
Home Services
80 |
81 |
85 |
86 |
Cafes
87 |
88 |
92 |
93 |
Bootcamps
94 |
95 |
96 |
97 |
98 |
99 |
Write a Review
100 |
101 |
102 |
103 |
104 |
105 |
106 |

110 |
111 |
112 |
113 | {this.props.currentUser.fname}
114 |
115 |
{this.props.currentUser.lname}
116 |
117 |
Manhattan, NY
118 |
119 |
120 |
121 | {reviewLength}
122 |
123 |
{this.userReviews()}
124 |
125 | );
126 | }
127 | }
128 |
129 | export default Profile;
130 |
--------------------------------------------------------------------------------
/frontend/components/user/profile_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from "react-redux";
2 | import Profile from "./profile";
3 | import { fetchAllUnrelatedReviews } from "../../actions/reviews_actions";
4 | import { fetchCurrentUser } from "../../actions/sessions_actions";
5 | import { requestAllBusinessCategories } from "../../actions/business_category_actions";
6 | import { requestAllBusinesses } from "../../actions/businesses_actions";
7 |
8 | const mapStateToProps = state => {
9 | return {
10 | businesses: state.entities.businesses,
11 | reviews: state.entities.users[state.session.id].reviews,
12 | currentUser: state.entities.users[state.session.id],
13 | businessCategories: Object.values(state.entities.businessCategories)
14 | };
15 | };
16 |
17 | const mapDispatchToProps = dispatch => {
18 | return {
19 | requestAllBusinessCategories: () =>
20 | dispatch(requestAllBusinessCategories()),
21 | fetchCurrentUser: user => dispatch(fetchCurrentUser(user)),
22 | fetchAllUnrelatedReviews: () => dispatch(fetchAllUnrelatedReviews()),
23 | requestAllBusinesses: () => dispatch(requestAllBusinesses())
24 | };
25 | };
26 | export default connect(
27 | mapStateToProps,
28 | mapDispatchToProps
29 | )(Profile);
30 |
--------------------------------------------------------------------------------
/frontend/components/user/user_reviews.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { requestSingleBusiness } from '../../actions/businesses_actions';
4 | import ReactStars from 'react-stars';
5 | import { Link } from 'react-router-dom';
6 | import { deleteReview, updateReview } from '../../actions/reviews_actions';
7 |
8 | class UserReview extends React.Component {
9 | constructor(props){
10 | super(props);
11 | }
12 |
13 | componentDidMount() {
14 | this.props.requestSingleBusiness(this.props.review.business_id);
15 | }
16 |
17 | render() {
18 | const review = this.props.review;
19 | const reviewBus = review.business_id;
20 | const matchedBus = this.props.business[review.business_id];
21 | let busName;
22 | let bus;
23 | let photo;
24 | if (matchedBus && matchedBus.id === reviewBus){
25 | busName = matchedBus.name;
26 | bus = matchedBus;
27 | photo = matchedBus.photos[0].photo_image_url;
28 | } else {
29 | busName = '';
30 | photo = '';
31 | bus = '';
32 | }
33 | return (
34 |
35 |
36 |
37 |
38 |

39 |
40 |
41 |
42 | {busName}
43 |
44 |
45 | {bus.address}
46 |
47 |
48 |
49 |
50 |
51 | Wrote review on {review.created_at.slice(0,10)}
52 |
53 |
54 |
55 |
62 |
63 |
64 | {review.body.slice(0,180)}
65 |
66 |
67 |
68 |
Update My Review
69 |
![]()
this.props.deleteReview(review.id)} className="dub" src={window.trashBin}>
70 |
71 |
72 |
73 | )
74 | }
75 | }
76 |
77 |
78 | const mapStateToProps = (state) => {
79 | return {
80 | business: state.entities.businesses
81 | }
82 | }
83 |
84 | const mapDispatchToProps = (dispatch) => {
85 | return {
86 | deleteReview: (id) => dispatch(deleteReview(id)),
87 | updateReview: review => dispatch(updateReview(review)),
88 | requestSingleBusiness: (id) => dispatch(requestSingleBusiness(id)),
89 | }
90 | }
91 |
92 | export default connect(mapStateToProps, mapDispatchToProps)(UserReview);
93 |
--------------------------------------------------------------------------------
/frontend/reducers/adjectives_reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | RECEIVE_LIKE,
3 | REMOVE_LIKE,
4 | RECEIVE_COOL,
5 | UPDATE_COOL,
6 | RECEIVE_FUNNY,
7 | UPDATE_FUNNY,
8 | RECEIVE_USEFUL,
9 | UPDATE_USEFUL
10 | } from "../actions/adjective_actions";
11 | import { merge } from "lodash";
12 |
13 | export default (state = {}, action) => {
14 | let newState;
15 | let reviewId;
16 | let reviews;
17 | Object.freeze(state);
18 | switch (action.type) {
19 | case RECEIVE_LIKE:
20 | return merge({}, state, action.payload.adjectives);
21 | case REMOVE_LIKE:
22 | newState = merge({}, state);
23 | reviewId = Object.keys(action.payload.adjectives.likes);
24 | delete newState.likes[reviewId];
25 | return newState;
26 | case RECEIVE_COOL:
27 | return merge({}, state, action.payload.adjectives);
28 | case UPDATE_COOL:
29 | newState = merge({}, state);
30 | reviewId = Object.keys(action.payload.adjectives.cool);
31 | delete newState.cool[reviewId];
32 | return merge({}, newState, action.payload.adjectives);
33 | case RECEIVE_FUNNY:
34 | return merge({}, state, action.payload.adjectives);
35 | case UPDATE_FUNNY:
36 | newState = merge({}, state);
37 | reviewId = Object.keys(action.payload.adjectives.funny);
38 | delete newState.funny[reviewId];
39 | return merge({}, newState, action.payload.adjectives);
40 | case RECEIVE_USEFUL:
41 | return merge({}, state, action.payload.adjectives);
42 | case UPDATE_USEFUL:
43 | newState = merge({}, state);
44 | reviewId = Object.keys(action.payload.adjectives.useful);
45 | delete newState.useful[reviewId];
46 | return merge({}, newState, action.payload.adjectives);
47 | default:
48 | return state;
49 | }
50 | };
51 |
--------------------------------------------------------------------------------
/frontend/reducers/business_categories_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_ALL_BUSINESS_CATEGORIES, RECEIVE_SELECTED_BUSINESS_CATEGORIES } from '../actions/business_category_actions';
2 |
3 |
4 | export default (state = {}, action) => {
5 | Object.freeze(state);
6 | switch (action.type) {
7 | case RECEIVE_ALL_BUSINESS_CATEGORIES:
8 | return action.businessCategories;
9 |
10 | default:
11 | return state;
12 | }
13 |
14 | };
15 |
--------------------------------------------------------------------------------
/frontend/reducers/businesses_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_SELECTED_BUSINESS_CATEGORIES } from "../actions/business_category_actions";
2 | import {
3 | RECEIVE_BUSINESS,
4 | RECEIVE_BUSINESSES
5 | } from "../actions/businesses_actions";
6 | import { RECEIVE_REVIEW, REMOVE_REVIEW } from "../actions/reviews_actions";
7 | import { RECEIVE_SEARCH_RESULTS } from "../actions/search_actions";
8 | import { merge } from "lodash";
9 |
10 | export default (state = {}, action) => {
11 | let businessId;
12 | let reviewId;
13 | let newState;
14 | let reviews;
15 | let a;
16 |
17 | Object.freeze(state);
18 | switch (action.type) {
19 | case RECEIVE_SELECTED_BUSINESS_CATEGORIES:
20 | return action.businesses;
21 | case RECEIVE_BUSINESSES:
22 | return action.businesses;
23 | case RECEIVE_BUSINESS:
24 | a = merge({}, state, { [action.business.id]: action.business });
25 |
26 | return merge({}, state, { [action.business.id]: action.business });
27 | case RECEIVE_REVIEW:
28 | newState = merge({}, state);
29 | // returns from backend as snake case
30 | businessId = action.review.business_id;
31 | reviewId = action.review.id;
32 |
33 | reviews = [];
34 | newState[businessId].reviews.forEach(review => {
35 | if (review.id !== action.review.id) {
36 | reviews.push(review);
37 | } else {
38 | reviews.push(action.review);
39 | }
40 | });
41 | newState[businessId].reviews = reviews;
42 | return newState;
43 | case REMOVE_REVIEW:
44 | newState = merge({}, state);
45 | // returns from backend as snake case
46 | businessId = action.review.business_id;
47 | reviewId = action.review.id;
48 | reviews = [];
49 | newState[businessId].reviews.forEach(review => {
50 | if (review.id !== action.review.id) {
51 | reviews.push(review);
52 | }
53 | });
54 |
55 | newState[businessId].reviews = reviews;
56 | return newState;
57 | case RECEIVE_SEARCH_RESULTS:
58 | return action.results;
59 | default:
60 | return state;
61 | }
62 | };
63 |
--------------------------------------------------------------------------------
/frontend/reducers/entities_reducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 |
3 | import usersReducer from './users_reducer';
4 | import businessCategoriesReducer from './business_categories_reducer';
5 | import businessesReducer from './businesses_reducer';
6 | import reviewsReducer from './reviews_reducer';
7 | import searchReducer from './search_reducer';
8 | import adjectivesReducer from './adjectives_reducer';
9 |
10 |
11 |
12 | const entitiesReducer = combineReducers({
13 | users: usersReducer,
14 | businessCategories: businessCategoriesReducer,
15 | businesses: businessesReducer,
16 | reviews: reviewsReducer,
17 | searches: searchReducer,
18 | adjectives: adjectivesReducer
19 | });
20 |
21 | export default entitiesReducer;
22 |
--------------------------------------------------------------------------------
/frontend/reducers/errors_reducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers} from 'redux';
2 | import LoginErrorsReducer from './login_errors_reducer';
3 | import SignUpErrorsReducer from './signup_errors_reducer';
4 | import session from './session_errors_reducer';
5 | import reviewErrorsReducer from './reviews_errors_reducer';
6 |
7 | const errorsReducer = combineReducers({
8 | session,
9 | review: reviewErrorsReducer
10 | });
11 |
12 |
13 | export default errorsReducer;
14 |
15 |
16 | // loginErrors: LoginErrorsReducer,
17 | // signupErrors: SignUpErrorsReducer
18 |
--------------------------------------------------------------------------------
/frontend/reducers/login_errors_reducer.js:
--------------------------------------------------------------------------------
1 | import { CLEAR_ERRORS, RECEIVE_LOGIN_ERRORS, RECEIVE_CURRENT_USER } from '../actions/sessions_actions';
2 |
3 |
4 | export default (state = [], action) => {
5 | Object.freeze(state);
6 | switch (action.type) {
7 | case RECEIVE_CURRENT_USER:
8 | return [];
9 | case RECEIVE_LOGIN_ERRORS:
10 | return action.errors;
11 | case CLEAR_ERRORS:
12 | return [];
13 | default:
14 | return state;
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/frontend/reducers/reviews_errors_reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | RECEIVE_REVIEW_ERRORS,
3 | RECEIVE_REVIEW
4 | } from "../actions/reviews_actions";
5 | import { CLEAR_ERRORS } from "../actions/sessions_actions";
6 |
7 | const reviewErrorsReducer = (state = [], action) => {
8 | Object.freeze(state);
9 |
10 | switch (action.type) {
11 | case RECEIVE_REVIEW_ERRORS:
12 | return action.errors;
13 | case CLEAR_ERRORS:
14 | return [];
15 | default:
16 | return state;
17 | }
18 | };
19 |
20 | export default reviewErrorsReducer;
21 |
--------------------------------------------------------------------------------
/frontend/reducers/reviews_reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | REMOVE_REVIEW,
3 | RECEIVE_REVIEW,
4 | RECEIVE_ALL_REVIEWS
5 | } from "../actions/reviews_actions";
6 | import { merge } from "lodash";
7 |
8 | export default (state = {}, action) => {
9 | Object.freeze(state);
10 | switch (action.type) {
11 | case RECEIVE_ALL_REVIEWS:
12 | return action.reviews;
13 | default:
14 | return state;
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/frontend/reducers/root_reducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import session from './session_reducer';
3 | import errorsReducer from './errors_reducer';
4 | import entitiesReducer from './entities_reducer';
5 |
6 | export const rootReducer = combineReducers({
7 | session,
8 | errors: errorsReducer,
9 | entities: entitiesReducer
10 | });
11 |
--------------------------------------------------------------------------------
/frontend/reducers/search_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_SEARCH_RESULTS, RECEIVE_DROPDOWN_BUSINESSES } from '../actions/search_actions';
2 | import { merge } from 'lodash';
3 | import {CLEAR_SEARCH} from '../actions/search_actions';
4 |
5 | export default (state = {}, action) => {
6 |
7 | Object.freeze(state);
8 | switch (action.type) {
9 | case CLEAR_SEARCH:
10 | return [];
11 | case RECEIVE_DROPDOWN_BUSINESSES:
12 | return action.businesses;
13 | default:
14 | return state;
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/frontend/reducers/selectors.js:
--------------------------------------------------------------------------------
1 | export const selectSearchedBusinessIds = results => {
2 | let resultArr = [];
3 | results.forEach( result => {
4 | resultArr.push(result.id);
5 | });
6 | return resultArr;
7 | };
8 |
9 |
10 | export const selectSearchBusinesses = (businesses, selectSearchedBusinessIds) => {
11 |
12 | let results = [];
13 |
14 | businesses.forEach( business => {
15 | if (selectSearchedBusinessIds && business.id && selectSearchedBusinessIds.includes(business.id.toString())){
16 | results.push(business);
17 | }
18 | });
19 |
20 |
21 | return results;
22 | };
23 |
--------------------------------------------------------------------------------
/frontend/reducers/session_errors_reducer.js:
--------------------------------------------------------------------------------
1 | import { CLEAR_ERRORS, RECEIVE_SESSION_ERRORS, RECEIVE_CURRENT_USER } from '../actions/sessions_actions';
2 |
3 |
4 | export default (state = [], action) => {
5 | Object.freeze(state);
6 | switch (action.type) {
7 | case RECEIVE_CURRENT_USER:
8 | case CLEAR_ERRORS:
9 | return [];
10 | case RECEIVE_SESSION_ERRORS:
11 | return action.errors;
12 | default:
13 | return state;
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/frontend/reducers/session_reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | RECEIVE_CURRENT_USER,
3 | LOGOUT_CURRENT_USER
4 | } from "../actions/sessions_actions";
5 | import { RECEIVE_SEARCH_RESULTS } from "../actions/search_actions";
6 | import { selectSearchedBusinessIds } from "./selectors.js";
7 | import { merge } from "lodash";
8 |
9 | const defaultState = {
10 | id: null,
11 | searcR: []
12 | };
13 |
14 | const sessionReducer = (state = defaultState, action) => {
15 | switch (action.type) {
16 | case RECEIVE_CURRENT_USER: {
17 | return {
18 | id: action.user.id,
19 | searchR: []
20 | };
21 | }
22 | case LOGOUT_CURRENT_USER: {
23 | return defaultState;
24 | }
25 | case RECEIVE_SEARCH_RESULTS:
26 | return {
27 | id: state.id,
28 | searchR: Object.keys(action.results)
29 | };
30 | default: {
31 | return state;
32 | }
33 | }
34 | };
35 |
36 | export default sessionReducer;
37 |
--------------------------------------------------------------------------------
/frontend/reducers/signup_errors_reducer.js:
--------------------------------------------------------------------------------
1 | import { CLEAR_ERRORS, RECEIVE_SIGNUP_ERRORS, RECEIVE_CURRENT_USER } from '../actions/sessions_actions';
2 |
3 |
4 | export default (state = [], action) => {
5 | Object.freeze(state);
6 | switch (action.type) {
7 | case RECEIVE_CURRENT_USER:
8 | return [];
9 | case RECEIVE_SIGNUP_ERRORS:
10 | return action.errors;
11 | case CLEAR_ERRORS:
12 | return [];
13 | default:
14 | return state;
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/frontend/reducers/users_reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | RECEIVE_CURRENT_USER,
3 | RECEIVE_ALL_USERS
4 | } from "../actions/sessions_actions";
5 | import { REMOVE_REVIEW } from "../actions/reviews_actions";
6 | import { merge } from "lodash";
7 |
8 | export default (state = {}, action) => {
9 | let newState;
10 | let userId;
11 | let reviewId;
12 | let businessId;
13 | let reviews;
14 | Object.freeze(state);
15 | switch (action.type) {
16 | case RECEIVE_ALL_USERS:
17 | return action.users;
18 | case RECEIVE_CURRENT_USER:
19 | newState = Object.assign({}, state);
20 | newState[action.user.id] = action.user;
21 | return newState;
22 | case REMOVE_REVIEW:
23 | newState = merge({}, state);
24 | // returns from backend as snake case
25 | businessId = action.review.business_id;
26 | reviewId = action.review.id;
27 | userId = action.review.user_id;
28 | reviews = [];
29 | newState[userId].reviews.forEach(review => {
30 | if (review.id !== action.review.id) {
31 | reviews.push(review);
32 | }
33 | });
34 | newState[userId].reviews = reviews;
35 | return newState;
36 | default:
37 | return state;
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/frontend/store/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware } from 'redux';
2 | import logger from 'redux-logger';
3 | import thunk from 'redux-thunk';
4 | import { rootReducer } from '../reducers/root_reducer';
5 |
6 | const configureStore = (preloadedState = {}) => (
7 | createStore(
8 | rootReducer,
9 | preloadedState,
10 | applyMiddleware(thunk, logger)
11 | )
12 | );
13 |
14 | export default configureStore;
15 |
--------------------------------------------------------------------------------
/frontend/util/adjective_util.js:
--------------------------------------------------------------------------------
1 | export const fetchLike = like => {
2 | return $.ajax({
3 | method: "GET",
4 | url: `api/adjectives/like/${like.review_id}`,
5 | data: { like }
6 | });
7 | };
8 | export const fetchCool = cool => {
9 | return $.ajax({
10 | method: "GET",
11 | url: `api/adjectives/cool/${cool.review_id}`,
12 | data: { cool }
13 | });
14 | };
15 | export const fetchFunny = funny => {
16 | return $.ajax({
17 | method: "GET",
18 | url: `api/adjectives/funny/${funny.review_id}`,
19 | data: { funny }
20 | });
21 | };
22 | export const fetchUseful = useful => {
23 | return $.ajax({
24 | method: "GET",
25 | url: `api/adjectives/useful/${useful.review_id}`,
26 | data: { useful }
27 | });
28 | };
29 | export const createLike = like => {
30 | return $.ajax({
31 | method: "POST",
32 | url: `api/adjectives/likes/`,
33 | data: { like }
34 | });
35 | };
36 | export const deleteLike = like => {
37 | return $.ajax({
38 | method: "DELETE",
39 | url: `api/adjectives/likes/${like.review_id}`,
40 | data: { like }
41 | });
42 | };
43 | export const updateCool = cool => {
44 | return $.ajax({
45 | method: "PATCH",
46 | url: `api/adjectives/cool/`,
47 | data: { cool }
48 | });
49 | };
50 | export const updateUseful = useful => {
51 | return $.ajax({
52 | method: "PATCH",
53 | url: `api/adjectives/useful/`,
54 | data: { useful }
55 | });
56 | };
57 | export const updateFunny = funny => {
58 | return $.ajax({
59 | method: "PATCH",
60 | url: `api/adjectives/funny/`,
61 | data: { funny }
62 | });
63 | };
64 |
--------------------------------------------------------------------------------
/frontend/util/business_categories_util.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | export const fetchBusinessCategories = () => {
4 | return $.ajax({
5 | method: 'GET',
6 | url: "api/business_categories",
7 | });
8 | };
9 |
10 |
11 | export const fetchSelectedBusinessCategories = (businessCategory) => {
12 | return $.ajax({
13 | method: 'GET',
14 | url: `api/business_categories/${businessCategory}/businesses`,
15 |
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/frontend/util/businesses_util.jsx:
--------------------------------------------------------------------------------
1 |
2 |
3 | export const fetchBusinesses = (businesses) => {
4 |
5 | return $.ajax({
6 | method: 'GET',
7 | url: "api/businesses",
8 | data: { businesses }
9 | });
10 | };
11 |
12 |
13 | export const fetchBusiness = (id) => {
14 | return $.ajax({
15 | method: 'GET',
16 | url: `api/businesses/${id}`
17 | });
18 | };
19 |
--------------------------------------------------------------------------------
/frontend/util/marker_manager.js:
--------------------------------------------------------------------------------
1 | export default class MarkerManager {
2 | constructor(map, handleClick) {
3 | this.map = map;
4 | this.handleClick = handleClick;
5 | this.markers = {};
6 | }
7 | updateMarkers(businesses) {
8 | const businessesObj = {};
9 |
10 | businesses.forEach(business => businessesObj[business.id] = business);
11 |
12 | businesses.filter(business => !this.markers[business.id]).forEach(newBusiness => this.createMarkerFromBusiness(newBusiness));
13 |
14 | Object.keys(this.markers)
15 | .filter(businessId => !businessesObj[businessId])
16 | .forEach((businessId) => this.removeMarker(this.markers[businessId]));
17 | }
18 |
19 | createMarkerFromBusiness(business) {
20 | const position = new google.maps.LatLng(business.latitude, business.longitude);
21 |
22 | const marker = new google.maps.Marker({
23 | position,
24 | map: this.map,
25 | businessId: business.id
26 | });
27 |
28 | marker.addListener('click', () => this.handleClick(business));
29 | this.markers[marker.businessId] = marker;
30 | }
31 |
32 | removeMarker(marker) {
33 | this.markers[marker.businessId].setMap(null);
34 | delete this.markers[marker.businessId];
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/frontend/util/reviews_util.jsx:
--------------------------------------------------------------------------------
1 | export const fetchAllReviews = (businessId) => {
2 | return $.ajax({
3 | method: 'GET',
4 | url: `api/businesses/${businessId}/reviews`
5 | });
6 | };
7 |
8 | export const fetchAllUnrelatedReviews = () => {
9 | return $.ajax({
10 | method: 'GET',
11 | url: `api/reviews`
12 | });
13 | };
14 |
15 | export const fetchReview = id => {
16 | return $.ajax({
17 | method: 'GET',
18 | url: `api/reviews/${id}`
19 | });
20 | };
21 |
22 | export const createReview = review => {
23 | return $.ajax({
24 | method: 'POST',
25 | url: `api/businesses/${review.businessId}/reviews`,
26 | data: { review }
27 | });
28 | };
29 |
30 | export const updateReview = review => {
31 | return $.ajax({
32 | method: 'PATCH',
33 | url: `api/reviews/${review.id}`,
34 | data: { review }
35 | });
36 | };
37 |
38 | export const deleteReview = id => {
39 | return $.ajax({
40 | method: 'DELETE',
41 | url: `api/reviews/${id}`
42 | });
43 | };
44 |
--------------------------------------------------------------------------------
/frontend/util/route_util.jsx:
--------------------------------------------------------------------------------
1 | import { withRouter } from 'react-router-dom';
2 | import { connect } from 'react-redux';
3 | import React from 'react';
4 | import { Route, Redirect } from 'react-router-dom';
5 |
6 | const Auth = ({component: Component, path, loggedIn, exact}) => (
7 | (
8 | !loggedIn ? (
9 |
10 | ) : (
11 |
12 | )
13 | )}/>
14 | );
15 |
16 | const Protected = ({ component: Component, path, loggedIn }) => (
17 | (
18 | loggedIn ? (
19 |
20 | ) : (
21 |
22 | )
23 | )} />
24 | );
25 |
26 | const mapStateToProps = state => {
27 | return {loggedIn: Boolean(state.session.id)};
28 | };
29 |
30 | export const AuthRoute = withRouter(connect(mapStateToProps, null)(Auth));
31 |
32 | export const ProtectedRoute = withRouter(connect(mapStateToProps)(Protected));
33 |
--------------------------------------------------------------------------------
/frontend/util/search_api_util.js:
--------------------------------------------------------------------------------
1 | export const searchBusinesses = (query) => {
2 | return $.ajax({
3 | method: 'GET',
4 | url: `api/businesses/search/?${query}`
5 | });
6 | };
7 |
--------------------------------------------------------------------------------
/frontend/util/session_api_util.js:
--------------------------------------------------------------------------------
1 | export const signup = user => {
2 | return $.ajax({
3 | method: "POST",
4 | url: "api/users",
5 | data: {
6 | user
7 | }
8 | });
9 | };
10 |
11 | export const login = user => {
12 | return $.ajax({
13 | method: "POST",
14 | url: "api/session",
15 | data: {
16 | user
17 | }
18 | });
19 | };
20 |
21 | export const logout = () => {
22 | return $.ajax({
23 | method: "DELETE",
24 | url: "api/session"
25 | });
26 | };
27 |
28 | export const currentUser = id => {
29 | return $.ajax({
30 | method: "GET",
31 | url: `api/users/${id}`
32 | });
33 | };
34 |
35 | export const fetchAllUsers = () => {
36 | return $.ajax({
37 | method: "GET",
38 | url: `api/users/`
39 | });
40 | };
41 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/lib/tasks/.keep
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/log/.keep
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "BetterHelp",
3 | "private": true,
4 | "dependencies": {
5 | "@babel/core": "^7.0.0",
6 | "@babel/preset-env": "^7.0.0",
7 | "@babel/preset-react": "^7.0.0",
8 | "babel-loader": "^8.0.2",
9 | "lodash": "^4.17.10",
10 | "react": "^16.6.0",
11 | "react-debounce-input": "^3.2.0",
12 | "react-dom": "^16.5.0",
13 | "react-google-maps": "^9.4.5",
14 | "react-redux": "^5.0.7",
15 | "react-router-dom": "^4.3.1",
16 | "react-stars": "^2.2.5",
17 | "recompose": "^0.30.0",
18 | "redux": "^4.0.0",
19 | "redux-logger": "^3.0.6",
20 | "redux-thunk": "^2.3.0",
21 | "webpack": "^4.17.2",
22 | "webpack-cli": "^3.1.0"
23 | },
24 | "description": "This README would normally document whatever steps are necessary to get the application up and running.",
25 | "version": "1.0.0",
26 | "main": "index.js",
27 | "directories": {
28 | "lib": "lib",
29 | "test": "test"
30 | },
31 | "scripts": {
32 | "test": "echo \"Error: no test specified\" && exit 1",
33 | "webpack": "webpack --watch --mode=development",
34 | "postinstall": "webpack"
35 | },
36 | "engines": {
37 | "node": "8.4.0",
38 | "npm": "6.1.0"
39 | },
40 | "keywords": [],
41 | "author": "",
42 | "license": "ISC"
43 | }
44 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/public/favicon.ico
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 |
--------------------------------------------------------------------------------
/storage/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/storage/.keep
--------------------------------------------------------------------------------
/test/application_system_test_case.rb:
--------------------------------------------------------------------------------
1 | require "test_helper"
2 |
3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
4 | driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
5 | end
6 |
--------------------------------------------------------------------------------
/test/controllers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/test/controllers/.keep
--------------------------------------------------------------------------------
/test/fixtures/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/test/fixtures/.keep
--------------------------------------------------------------------------------
/test/fixtures/files/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/test/fixtures/files/.keep
--------------------------------------------------------------------------------
/test/helpers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/test/helpers/.keep
--------------------------------------------------------------------------------
/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/test/integration/.keep
--------------------------------------------------------------------------------
/test/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/test/mailers/.keep
--------------------------------------------------------------------------------
/test/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/test/models/.keep
--------------------------------------------------------------------------------
/test/system/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/test/system/.keep
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV['RAILS_ENV'] ||= 'test'
2 | require_relative '../config/environment'
3 | require 'rails/test_help'
4 |
5 | class ActiveSupport::TestCase
6 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
7 | fixtures :all
8 |
9 | # Add more helper methods to be used by all tests here...
10 | end
11 |
--------------------------------------------------------------------------------
/tmp/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/tmp/.keep
--------------------------------------------------------------------------------
/vendor/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanahn95/BetterHelp/63e5d757b08268284fff63040fff130d130e41a4/vendor/.keep
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | module.exports = {
4 | entry: "./frontend/better_help.jsx",
5 | output: {
6 | path: path.join(__dirname, "app", "assets", "javascripts"),
7 | filename: "bundle.js"
8 | },
9 | resolve: {
10 | extensions: [".js", ".jsx", "*"]
11 | },
12 | devtool: "source-map",
13 | module: {
14 | rules: [
15 | {
16 | test: /\.(js|jsx)$/,
17 | use: {
18 | loader: 'babel-loader',
19 | query: {
20 | presets: ['@babel/preset-env', '@babel/preset-react']
21 | }
22 | },
23 | exclude: /node_modules/
24 | }
25 | ]
26 | }
27 | };
28 |
--------------------------------------------------------------------------------