├── .gitignore
├── README.md
├── custom.d.ts
├── dist
├── 269d1e109e9c172ffe2f91a4fd0e77cf.png
├── bundle.js
├── bundle.js.LICENSE.txt
└── index.html
├── package-lock.json
├── package.json
├── sampleWeatherData.json
├── server
├── configurePath.js
├── controllers
│ └── weatherController.js
├── routes
│ └── api.js
└── server.js
├── src
├── App.js.bak
├── App.tsx
├── assets
│ └── images
│ │ └── logo.png
├── components
│ ├── Cards.js
│ ├── Modal.js
│ └── TextBox.js
├── containers
│ └── MainContainer.js
├── index.html
├── index.js.bak
├── index.tsx
└── styles.scss
├── tsconfig.json
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Travel Cast
--------------------------------------------------------------------------------
/custom.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.png' {
2 | const value: string;
3 | export default value
4 | }
--------------------------------------------------------------------------------
/dist/269d1e109e9c172ffe2f91a4fd0e77cf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/howardsun-dev/soloProject/6f40fc0c47d5ee7d64c0619d8ff635453314e6e3/dist/269d1e109e9c172ffe2f91a4fd0e77cf.png
--------------------------------------------------------------------------------
/dist/bundle.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*!
2 | * @kurkle/color v0.3.2
3 | * https://github.com/kurkle/color#readme
4 | * (c) 2023 Jukka Kurkela
5 | * Released under the MIT License
6 | */
7 |
8 | /*!
9 | * Chart.js v4.4.2
10 | * https://www.chartjs.org
11 | * (c) 2024 Chart.js Contributors
12 | * Released under the MIT License
13 | */
14 |
15 | /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
16 |
17 | /**
18 | * @license React
19 | * react-dom.production.min.js
20 | *
21 | * Copyright (c) Facebook, Inc. and its affiliates.
22 | *
23 | * This source code is licensed under the MIT license found in the
24 | * LICENSE file in the root directory of this source tree.
25 | */
26 |
27 | /**
28 | * @license React
29 | * react.production.min.js
30 | *
31 | * Copyright (c) Facebook, Inc. and its affiliates.
32 | *
33 | * This source code is licensed under the MIT license found in the
34 | * LICENSE file in the root directory of this source tree.
35 | */
36 |
37 | /**
38 | * @license React
39 | * scheduler.production.min.js
40 | *
41 | * Copyright (c) Facebook, Inc. and its affiliates.
42 | *
43 | * This source code is licensed under the MIT license found in the
44 | * LICENSE file in the root directory of this source tree.
45 | */
46 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
Convenient Little Travel App
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "soloproject",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "NODE_ENV=production nodemon server/server.js",
8 | "build": "webpack",
9 | "dev": "concurrently \"NODE_ENV=development nodemon server/server.js\" \"NODE_ENV=development webpack serve --open --hot\""
10 | },
11 | "nodemonConfig": {
12 | "ignore": [
13 | "build",
14 | "client"
15 | ]
16 | },
17 | "keywords": [],
18 | "author": "Howard Sun",
19 | "license": "ISC",
20 | "dependencies": {
21 | "@types/jest": "^29.5.12",
22 | "@types/node": "^20.11.30",
23 | "@types/react": "^18.2.69",
24 | "@types/react-dom": "^18.2.22",
25 | "axios": "^1.6.7",
26 | "chart.js": "^4.4.2",
27 | "express": "^4.18.3",
28 | "react": "^18.2.0",
29 | "react-chartjs-2": "^5.2.0",
30 | "react-dom": "^18.2.0",
31 | "typescript": "^5.4.3"
32 | },
33 | "devDependencies": {
34 | "@babel/core": "^7.24.0",
35 | "@babel/preset-env": "^7.24.0",
36 | "@babel/preset-react": "^7.23.3",
37 | "babel-loader": "^9.1.3",
38 | "concurrently": "^8.2.2",
39 | "css-loader": "^6.10.0",
40 | "file-loader": "^6.2.0",
41 | "html-webpack-plugin": "^5.6.0",
42 | "nodemon": "^3.1.0",
43 | "sass": "^1.71.1",
44 | "sass-loader": "^14.1.1",
45 | "style-loader": "^3.3.4",
46 | "webpack": "^5.90.3",
47 | "webpack-cli": "^5.1.4",
48 | "webpack-dev-server": "^5.0.2"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/sampleWeatherData.json:
--------------------------------------------------------------------------------
1 | {
2 | "latitude": 41.875,
3 | "longitude": 72.875,
4 | "generationtime_ms": 0.08594989776611328,
5 | "utc_offset_seconds": 0,
6 | "timezone": "GMT",
7 | "timezone_abbreviation": "GMT",
8 | "elevation": 879,
9 | "current_units": {
10 | "time": "iso8601",
11 | "interval": "seconds",
12 | "temperature_2m": "°F",
13 | "wind_speed_10m": "mp/h"
14 | },
15 | "current": {
16 | "time": "2024-03-07T04:45",
17 | "interval": 900,
18 | "temperature_2m": 43,
19 | "wind_speed_10m": 1.8
20 | },
21 | "hourly_units": {
22 | "time": "iso8601",
23 | "temperature_2m": "°F",
24 | "precipitation": "inch",
25 | "wind_speed_10m": "mp/h",
26 | "wind_direction_10m": "°",
27 | "temperature_80m": "°F"
28 | },
29 | "hourly": {
30 | "time": [
31 | "2024-03-07T00:00",
32 | "2024-03-07T01:00",
33 | "2024-03-07T02:00",
34 | "2024-03-07T03:00",
35 | "2024-03-07T04:00",
36 | "2024-03-07T05:00",
37 | "2024-03-07T06:00",
38 | "2024-03-07T07:00",
39 | "2024-03-07T08:00",
40 | "2024-03-07T09:00",
41 | "2024-03-07T10:00",
42 | "2024-03-07T11:00",
43 | "2024-03-07T12:00",
44 | "2024-03-07T13:00",
45 | "2024-03-07T14:00",
46 | "2024-03-07T15:00",
47 | "2024-03-07T16:00",
48 | "2024-03-07T17:00",
49 | "2024-03-07T18:00",
50 | "2024-03-07T19:00",
51 | "2024-03-07T20:00",
52 | "2024-03-07T21:00",
53 | "2024-03-07T22:00",
54 | "2024-03-07T23:00",
55 | "2024-03-08T00:00",
56 | "2024-03-08T01:00",
57 | "2024-03-08T02:00",
58 | "2024-03-08T03:00",
59 | "2024-03-08T04:00",
60 | "2024-03-08T05:00",
61 | "2024-03-08T06:00",
62 | "2024-03-08T07:00",
63 | "2024-03-08T08:00",
64 | "2024-03-08T09:00",
65 | "2024-03-08T10:00",
66 | "2024-03-08T11:00",
67 | "2024-03-08T12:00",
68 | "2024-03-08T13:00",
69 | "2024-03-08T14:00",
70 | "2024-03-08T15:00",
71 | "2024-03-08T16:00",
72 | "2024-03-08T17:00",
73 | "2024-03-08T18:00",
74 | "2024-03-08T19:00",
75 | "2024-03-08T20:00",
76 | "2024-03-08T21:00",
77 | "2024-03-08T22:00",
78 | "2024-03-08T23:00",
79 | "2024-03-09T00:00",
80 | "2024-03-09T01:00",
81 | "2024-03-09T02:00",
82 | "2024-03-09T03:00",
83 | "2024-03-09T04:00",
84 | "2024-03-09T05:00",
85 | "2024-03-09T06:00",
86 | "2024-03-09T07:00",
87 | "2024-03-09T08:00",
88 | "2024-03-09T09:00",
89 | "2024-03-09T10:00",
90 | "2024-03-09T11:00",
91 | "2024-03-09T12:00",
92 | "2024-03-09T13:00",
93 | "2024-03-09T14:00",
94 | "2024-03-09T15:00",
95 | "2024-03-09T16:00",
96 | "2024-03-09T17:00",
97 | "2024-03-09T18:00",
98 | "2024-03-09T19:00",
99 | "2024-03-09T20:00",
100 | "2024-03-09T21:00",
101 | "2024-03-09T22:00",
102 | "2024-03-09T23:00",
103 | "2024-03-10T00:00",
104 | "2024-03-10T01:00",
105 | "2024-03-10T02:00",
106 | "2024-03-10T03:00",
107 | "2024-03-10T04:00",
108 | "2024-03-10T05:00",
109 | "2024-03-10T06:00",
110 | "2024-03-10T07:00",
111 | "2024-03-10T08:00",
112 | "2024-03-10T09:00",
113 | "2024-03-10T10:00",
114 | "2024-03-10T11:00",
115 | "2024-03-10T12:00",
116 | "2024-03-10T13:00",
117 | "2024-03-10T14:00",
118 | "2024-03-10T15:00",
119 | "2024-03-10T16:00",
120 | "2024-03-10T17:00",
121 | "2024-03-10T18:00",
122 | "2024-03-10T19:00",
123 | "2024-03-10T20:00",
124 | "2024-03-10T21:00",
125 | "2024-03-10T22:00",
126 | "2024-03-10T23:00",
127 | "2024-03-11T00:00",
128 | "2024-03-11T01:00",
129 | "2024-03-11T02:00",
130 | "2024-03-11T03:00",
131 | "2024-03-11T04:00",
132 | "2024-03-11T05:00",
133 | "2024-03-11T06:00",
134 | "2024-03-11T07:00",
135 | "2024-03-11T08:00",
136 | "2024-03-11T09:00",
137 | "2024-03-11T10:00",
138 | "2024-03-11T11:00",
139 | "2024-03-11T12:00",
140 | "2024-03-11T13:00",
141 | "2024-03-11T14:00",
142 | "2024-03-11T15:00",
143 | "2024-03-11T16:00",
144 | "2024-03-11T17:00",
145 | "2024-03-11T18:00",
146 | "2024-03-11T19:00",
147 | "2024-03-11T20:00",
148 | "2024-03-11T21:00",
149 | "2024-03-11T22:00",
150 | "2024-03-11T23:00",
151 | "2024-03-12T00:00",
152 | "2024-03-12T01:00",
153 | "2024-03-12T02:00",
154 | "2024-03-12T03:00",
155 | "2024-03-12T04:00",
156 | "2024-03-12T05:00",
157 | "2024-03-12T06:00",
158 | "2024-03-12T07:00",
159 | "2024-03-12T08:00",
160 | "2024-03-12T09:00",
161 | "2024-03-12T10:00",
162 | "2024-03-12T11:00",
163 | "2024-03-12T12:00",
164 | "2024-03-12T13:00",
165 | "2024-03-12T14:00",
166 | "2024-03-12T15:00",
167 | "2024-03-12T16:00",
168 | "2024-03-12T17:00",
169 | "2024-03-12T18:00",
170 | "2024-03-12T19:00",
171 | "2024-03-12T20:00",
172 | "2024-03-12T21:00",
173 | "2024-03-12T22:00",
174 | "2024-03-12T23:00",
175 | "2024-03-13T00:00",
176 | "2024-03-13T01:00",
177 | "2024-03-13T02:00",
178 | "2024-03-13T03:00",
179 | "2024-03-13T04:00",
180 | "2024-03-13T05:00",
181 | "2024-03-13T06:00",
182 | "2024-03-13T07:00",
183 | "2024-03-13T08:00",
184 | "2024-03-13T09:00",
185 | "2024-03-13T10:00",
186 | "2024-03-13T11:00",
187 | "2024-03-13T12:00",
188 | "2024-03-13T13:00",
189 | "2024-03-13T14:00",
190 | "2024-03-13T15:00",
191 | "2024-03-13T16:00",
192 | "2024-03-13T17:00",
193 | "2024-03-13T18:00",
194 | "2024-03-13T19:00",
195 | "2024-03-13T20:00",
196 | "2024-03-13T21:00",
197 | "2024-03-13T22:00",
198 | "2024-03-13T23:00"
199 | ],
200 | "temperature_2m": [
201 | 36,
202 | 35.8,
203 | 36.3,
204 | 37.1,
205 | 40.6,
206 | 43.4,
207 | 45.3,
208 | 46.5,
209 | 46.9,
210 | 47.2,
211 | 47.3,
212 | 46.9,
213 | 46.2,
214 | 44.6,
215 | 42,
216 | 39.3,
217 | 37.5,
218 | 36.3,
219 | 35.8,
220 | 35.7,
221 | 35.6,
222 | 35.8,
223 | 36.1,
224 | 36.3,
225 | 36.5,
226 | 36.3,
227 | 35.9,
228 | 36.9,
229 | 39.7,
230 | 43.6,
231 | 45.6,
232 | 46.8,
233 | 47.9,
234 | 48.9,
235 | 49.5,
236 | 49.6,
237 | 49.1,
238 | 47.3,
239 | 44.2,
240 | 41.2,
241 | 39.1,
242 | 37.6,
243 | 36.7,
244 | 36.4,
245 | 36.4,
246 | 36.8,
247 | 37.5,
248 | 37.7,
249 | 37.6,
250 | 36.6,
251 | 35.8,
252 | 36.6,
253 | 40.5,
254 | 43,
255 | 45.6,
256 | 47.8,
257 | 49.8,
258 | 51.1,
259 | 51.8,
260 | 52.3,
261 | 52.3,
262 | 49.9,
263 | 46.7,
264 | 44,
265 | 41.3,
266 | 40.2,
267 | 40.4,
268 | 40.6,
269 | 40.6,
270 | 40.9,
271 | 41.6,
272 | 41.3,
273 | 41.2,
274 | 40.8,
275 | 41,
276 | 42.1,
277 | 44.2,
278 | 46.3,
279 | 47.8,
280 | 48.8,
281 | 49.5,
282 | 49.6,
283 | 48.8,
284 | 47.6,
285 | 46.4,
286 | 45.6,
287 | 44.9,
288 | 44.3,
289 | 43.9,
290 | 43.6,
291 | 43.3,
292 | 43,
293 | 42.7,
294 | 42.3,
295 | 41.6,
296 | 40.9,
297 | 40.6,
298 | 40.5,
299 | 40.6,
300 | 41.5,
301 | 43.7,
302 | 46.6,
303 | 49.2,
304 | 51.4,
305 | 53.2,
306 | 54.7,
307 | 55.7,
308 | 56.1,
309 | 55.5,
310 | 53.2,
311 | 49.9,
312 | 47,
313 | 45,
314 | 43.2,
315 | 41.8,
316 | 40.9,
317 | 40.3,
318 | 39.9,
319 | 39.7,
320 | 39.6,
321 | 39.6,
322 | 39.3,
323 | 39.1,
324 | 40.2,
325 | 43.6,
326 | 48.4,
327 | 52.4,
328 | 55.2,
329 | 57.3,
330 | 58.6,
331 | 59.4,
332 | 59.3,
333 | 58.3,
334 | 55.9,
335 | 52.4,
336 | 49.6,
337 | 47.7,
338 | 46.2,
339 | 45.2,
340 | 44.9,
341 | 45,
342 | 45.1,
343 | 45,
344 | 45,
345 | 44.7,
346 | 44.2,
347 | 43.7,
348 | 43,
349 | 41.9,
350 | 40.6,
351 | 40.3,
352 | 41.5,
353 | 43.6,
354 | 45.1,
355 | 45.1,
356 | 44.6,
357 | 43.8,
358 | 42.5,
359 | 41.1,
360 | 39.8,
361 | 39.2,
362 | 38.9,
363 | 38.5,
364 | 37.8,
365 | 36.9,
366 | 36,
367 | 35.1,
368 | 34.3
369 | ],
370 | "precipitation": [
371 | 0,
372 | 0,
373 | 0,
374 | 0,
375 | 0,
376 | 0,
377 | 0,
378 | 0,
379 | 0,
380 | 0,
381 | 0,
382 | 0.004,
383 | 0,
384 | 0,
385 | 0,
386 | 0,
387 | 0,
388 | 0,
389 | 0,
390 | 0,
391 | 0,
392 | 0,
393 | 0,
394 | 0,
395 | 0,
396 | 0,
397 | 0,
398 | 0,
399 | 0,
400 | 0,
401 | 0,
402 | 0,
403 | 0,
404 | 0,
405 | 0,
406 | 0,
407 | 0,
408 | 0,
409 | 0,
410 | 0,
411 | 0,
412 | 0,
413 | 0,
414 | 0,
415 | 0,
416 | 0,
417 | 0,
418 | 0,
419 | 0,
420 | 0,
421 | 0,
422 | 0,
423 | 0,
424 | 0,
425 | 0,
426 | 0,
427 | 0,
428 | 0,
429 | 0,
430 | 0,
431 | 0,
432 | 0,
433 | 0,
434 | 0,
435 | 0,
436 | 0,
437 | 0,
438 | 0,
439 | 0,
440 | 0.004,
441 | 0.004,
442 | 0,
443 | 0,
444 | 0,
445 | 0,
446 | 0,
447 | 0,
448 | 0,
449 | 0,
450 | 0,
451 | 0,
452 | 0,
453 | 0.024,
454 | 0.024,
455 | 0.024,
456 | 0.008,
457 | 0.008,
458 | 0.008,
459 | 0,
460 | 0,
461 | 0,
462 | 0,
463 | 0,
464 | 0,
465 | 0,
466 | 0,
467 | 0,
468 | 0,
469 | 0,
470 | 0,
471 | 0,
472 | 0,
473 | 0,
474 | 0,
475 | 0,
476 | 0,
477 | 0,
478 | 0,
479 | 0,
480 | 0,
481 | 0,
482 | 0,
483 | 0,
484 | 0,
485 | 0,
486 | 0,
487 | 0,
488 | 0,
489 | 0,
490 | 0,
491 | 0,
492 | 0,
493 | 0,
494 | 0,
495 | 0,
496 | 0,
497 | 0,
498 | 0,
499 | 0,
500 | 0,
501 | 0,
502 | 0,
503 | 0,
504 | 0,
505 | 0,
506 | 0,
507 | 0,
508 | 0,
509 | 0,
510 | 0,
511 | 0,
512 | 0,
513 | 0.031,
514 | 0.031,
515 | 0.031,
516 | 0.106,
517 | 0.106,
518 | 0.106,
519 | 0.028,
520 | 0.028,
521 | 0.028,
522 | 0,
523 | 0,
524 | 0,
525 | 0,
526 | 0,
527 | 0,
528 | 0,
529 | 0,
530 | 0,
531 | 0,
532 | 0,
533 | 0,
534 | 0.004,
535 | 0.004,
536 | 0.004,
537 | 0.02,
538 | 0.02
539 | ],
540 | "wind_speed_10m": [
541 | 2,
542 | 1.3,
543 | 1.4,
544 | 3.1,
545 | 2.7,
546 | 1.6,
547 | 0.5,
548 | 1.6,
549 | 1.9,
550 | 1.6,
551 | 1.6,
552 | 2.2,
553 | 1.9,
554 | 1.7,
555 | 2.1,
556 | 2.7,
557 | 3.4,
558 | 2.8,
559 | 2.5,
560 | 2.2,
561 | 2.5,
562 | 2.7,
563 | 2.7,
564 | 2.4,
565 | 2.7,
566 | 2.3,
567 | 2.5,
568 | 1.8,
569 | 1,
570 | 0.4,
571 | 0.2,
572 | 1.3,
573 | 1.8,
574 | 1.7,
575 | 2.5,
576 | 2.8,
577 | 2.5,
578 | 2,
579 | 2.7,
580 | 2.9,
581 | 2.3,
582 | 2.1,
583 | 2.5,
584 | 2.2,
585 | 1.6,
586 | 0.9,
587 | 0.3,
588 | 0.6,
589 | 0.5,
590 | 1.8,
591 | 1.5,
592 | 1.2,
593 | 2.4,
594 | 2.8,
595 | 1.6,
596 | 4.3,
597 | 2.5,
598 | 3.9,
599 | 2.1,
600 | 2.9,
601 | 2.4,
602 | 0.9,
603 | 3.1,
604 | 1.9,
605 | 3,
606 | 2.8,
607 | 3.9,
608 | 1.4,
609 | 3.2,
610 | 3.4,
611 | 1.6,
612 | 3.1,
613 | 3.1,
614 | 1.7,
615 | 0.3,
616 | 0.7,
617 | 1.8,
618 | 1.8,
619 | 2.9,
620 | 3.2,
621 | 3.6,
622 | 3.6,
623 | 2.8,
624 | 1.9,
625 | 1.8,
626 | 2.2,
627 | 2.7,
628 | 2.9,
629 | 2.9,
630 | 2.7,
631 | 2.2,
632 | 1.8,
633 | 1.4,
634 | 0.9,
635 | 1.1,
636 | 1.4,
637 | 1.4,
638 | 0.7,
639 | 0.5,
640 | 1.1,
641 | 0.7,
642 | 0.5,
643 | 0.9,
644 | 1.1,
645 | 1.2,
646 | 1.3,
647 | 0.9,
648 | 0.4,
649 | 0.4,
650 | 1,
651 | 2.1,
652 | 2.7,
653 | 2.7,
654 | 2.5,
655 | 2.3,
656 | 2.2,
657 | 2.1,
658 | 2.4,
659 | 2.4,
660 | 2.1,
661 | 2.1,
662 | 2.4,
663 | 3.1,
664 | 3.5,
665 | 2.7,
666 | 1.8,
667 | 1,
668 | 0.8,
669 | 0.7,
670 | 0.7,
671 | 1.2,
672 | 2.5,
673 | 3.1,
674 | 2.7,
675 | 1.9,
676 | 1.6,
677 | 2.2,
678 | 3.6,
679 | 4.3,
680 | 4.3,
681 | 3.9,
682 | 3.2,
683 | 2.4,
684 | 3,
685 | 4.3,
686 | 5.4,
687 | 6,
688 | 6.1,
689 | 5.1,
690 | 4.9,
691 | 5.7,
692 | 5.7,
693 | 5.1,
694 | 4.8,
695 | 5.2,
696 | 5.9,
697 | 6.3,
698 | 6.3,
699 | 6,
700 | 5.7,
701 | 5.3,
702 | 5.1,
703 | 4.7,
704 | 4.6,
705 | 4.5,
706 | 4.3,
707 | 4.3,
708 | 4.7
709 | ],
710 | "wind_direction_10m": [
711 | 360,
712 | 360,
713 | 51,
714 | 30,
715 | 24,
716 | 8,
717 | 333,
718 | 196,
719 | 216,
720 | 196,
721 | 225,
722 | 264,
723 | 291,
724 | 293,
725 | 342,
726 | 355,
727 | 352,
728 | 346,
729 | 360,
730 | 354,
731 | 360,
732 | 355,
733 | 360,
734 | 34,
735 | 24,
736 | 11,
737 | 355,
738 | 360,
739 | 27,
740 | 360,
741 | 270,
742 | 270,
743 | 300,
744 | 310,
745 | 333,
746 | 346,
747 | 355,
748 | 360,
749 | 9,
750 | 4,
751 | 349,
752 | 347,
753 | 360,
754 | 6,
755 | 16,
756 | 14,
757 | 45,
758 | 315,
759 | 297,
760 | 300,
761 | 243,
762 | 248,
763 | 202,
764 | 209,
765 | 262,
766 | 267,
767 | 27,
768 | 204,
769 | 257,
770 | 309,
771 | 236,
772 | 346,
773 | 356,
774 | 324,
775 | 287,
776 | 346,
777 | 10,
778 | 342,
779 | 315,
780 | 323,
781 | 326,
782 | 270,
783 | 274,
784 | 293,
785 | 45,
786 | 108,
787 | 256,
788 | 256,
789 | 231,
790 | 245,
791 | 263,
792 | 274,
793 | 288,
794 | 315,
795 | 353,
796 | 6,
797 | 9,
798 | 9,
799 | 9,
800 | 5,
801 | 6,
802 | 7,
803 | 9,
804 | 14,
805 | 360,
806 | 351,
807 | 342,
808 | 360,
809 | 117,
810 | 143,
811 | 162,
812 | 243,
813 | 270,
814 | 259,
815 | 248,
816 | 239,
817 | 225,
818 | 180,
819 | 90,
820 | 27,
821 | 13,
822 | 5,
823 | 360,
824 | 350,
825 | 349,
826 | 360,
827 | 18,
828 | 34,
829 | 41,
830 | 49,
831 | 49,
832 | 34,
833 | 21,
834 | 15,
835 | 9,
836 | 360,
837 | 333,
838 | 326,
839 | 342,
840 | 342,
841 | 292,
842 | 270,
843 | 270,
844 | 275,
845 | 291,
846 | 326,
847 | 354,
848 | 4,
849 | 9,
850 | 12,
851 | 13,
852 | 8,
853 | 338,
854 | 297,
855 | 279,
856 | 272,
857 | 270,
858 | 274,
859 | 293,
860 | 330,
861 | 349,
862 | 349,
863 | 337,
864 | 326,
865 | 320,
866 | 317,
867 | 315,
868 | 315,
869 | 318,
870 | 321,
871 | 324,
872 | 326,
873 | 329,
874 | 331,
875 | 333,
876 | 339,
877 | 351,
878 | 8
879 | ],
880 | "temperature_80m": [
881 | 40.7,
882 | 40.4,
883 | 39.7,
884 | 39.1,
885 | 39.3,
886 | 40.7,
887 | 42.4,
888 | 43.4,
889 | 44.2,
890 | 44.7,
891 | 44.9,
892 | 44.7,
893 | 44.3,
894 | 44,
895 | 43.8,
896 | 43.6,
897 | 43.4,
898 | 43.1,
899 | 42.5,
900 | 41.8,
901 | 41.3,
902 | 40.9,
903 | 40.9,
904 | 40.7,
905 | 40.9,
906 | 40.7,
907 | 40.4,
908 | 40.2,
909 | 40.4,
910 | 41.1,
911 | 42.7,
912 | 43.8,
913 | 44.7,
914 | 46,
915 | 46.7,
916 | 47.2,
917 | 47.2,
918 | 47,
919 | 47,
920 | 46.7,
921 | 45.8,
922 | 44.5,
923 | 43.3,
924 | 42.4,
925 | 42,
926 | 41.6,
927 | 41.3,
928 | 41.1,
929 | 40.9,
930 | 40.6,
931 | 40.4,
932 | 39.5,
933 | 39.3,
934 | 40,
935 | 42.4,
936 | 44.7,
937 | 47,
938 | 47.9,
939 | 49,
940 | 50.3,
941 | 50.8,
942 | 50.5,
943 | 50.6,
944 | 50.6,
945 | 49.6,
946 | 48.1,
947 | 47.6,
948 | 47.2,
949 | 46.1,
950 | 45.8,
951 | 45.8,
952 | 44.9,
953 | 43.8,
954 | 43.6,
955 | 43.4,
956 | 43.6,
957 | 43.4,
958 | 43.8,
959 | 45.1,
960 | 45.8,
961 | 46.7,
962 | 47,
963 | 46.5,
964 | 45.6,
965 | 44.7,
966 | 44.3,
967 | 44.2,
968 | 44,
969 | 44,
970 | 44.2,
971 | 44.3,
972 | 44.3,
973 | 44.3,
974 | 44.3,
975 | 44.3,
976 | 44.2,
977 | 44,
978 | 43.3,
979 | 42.4,
980 | 42.2,
981 | 43.1,
982 | 44.7,
983 | 46.3,
984 | 48.1,
985 | 49.9,
986 | 51.5,
987 | 52.6,
988 | 53.3,
989 | 53.9,
990 | 54.2,
991 | 54.2,
992 | 53.7,
993 | 52.4,
994 | 50.8,
995 | 49.4,
996 | 48.5,
997 | 47.9,
998 | 47.4,
999 | 46.9,
1000 | 46.3,
1001 | 45.8,
1002 | 45.2,
1003 | 44.7,
1004 | 44.9,
1005 | 46,
1006 | 47.6,
1007 | 49.4,
1008 | 51.5,
1009 | 53.9,
1010 | 55.7,
1011 | 56.6,
1012 | 56.9,
1013 | 56.9,
1014 | 56.6,
1015 | 55.7,
1016 | 55,
1017 | 54.4,
1018 | 53.7,
1019 | 53,
1020 | 52.1,
1021 | 51.2,
1022 | 50.1,
1023 | 49.2,
1024 | 48.1,
1025 | 46.9,
1026 | 45.1,
1027 | 43.1,
1028 | 41.3,
1029 | 39.7,
1030 | 38.2,
1031 | 37.7,
1032 | 38.6,
1033 | 40.6,
1034 | 41.8,
1035 | 42.2,
1036 | 42,
1037 | 41.6,
1038 | 40.9,
1039 | 40,
1040 | 39.3,
1041 | 38.9,
1042 | 38.6,
1043 | 38,
1044 | 36.8,
1045 | 35.3,
1046 | 34.1,
1047 | 33,
1048 | 32.1
1049 | ]
1050 | }
1051 | }
--------------------------------------------------------------------------------
/server/configurePath.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | console.log(path.join(__dirname, '../dist'));
4 |
--------------------------------------------------------------------------------
/server/controllers/weatherController.js:
--------------------------------------------------------------------------------
1 | const axios = require('axios');
2 |
3 | const weatherController = {};
4 |
5 | weatherController.getWeather = async (req, res, next) => {
6 | try {
7 | const { latitude, longitude } = req.query;
8 | console.log(req.body);
9 |
10 | console.log('This is the Location 📍', latitude, longitude);
11 | /* axios as structure of
12 | data
13 | status (http code)
14 | statusText (OK/NotFound)
15 | headers
16 | config
17 | request
18 | */
19 |
20 | if (!latitude || !longitude) {
21 | return res.status(400).json({ error: 'Coordinates required' });
22 | }
23 | // https://api.open-meteo.com/v1/forecast?latitude=41.875&longitude=72.875¤t=temperature_2m,wind_speed_10m&hourly=temperature_2m,precipitation,wind_speed_10m,wind_direction_10m,temperature_80m&temperature_unit=fahrenheit&wind_speed_unit=mph&precipitation_unit=inch
24 | const response = await axios.get(
25 | `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,wind_speed_10m&hourly=temperature_2m,precipitation,wind_speed_10m,wind_direction_10m,temperature_80m&temperature_unit=fahrenheit&wind_speed_unit=mph&precipitation_unit=inch`
26 | );
27 |
28 | res.locals.weatherData = response.data;
29 |
30 | return next();
31 | } catch (error) {
32 | return next({
33 | log: `weatherController.getWeather had an error occur: ${error}`,
34 | status: 500,
35 | message: {
36 | err: 'An error occured getting weather, check logs for details',
37 | },
38 | });
39 | }
40 | };
41 |
42 | module.exports = weatherController;
43 |
--------------------------------------------------------------------------------
/server/routes/api.js:
--------------------------------------------------------------------------------
1 | // const { Router } = require('express');
2 | const express = require('express');
3 | const weatherController = require('../controllers/weatherController');
4 | const router = express.Router();
5 |
6 | router.get('/', (req, res) => {
7 | return res.send('Hello world from express Router!');
8 | });
9 |
10 | router.get('/weather', weatherController.getWeather, async (req, res) => {
11 | res.status(200).json(res.locals.weatherData);
12 | });
13 |
14 | module.exports = router;
15 |
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | const path = require('path');
4 |
5 | const PORT = 3000;
6 |
7 | const apiRouter = require('./routes/api');
8 |
9 | console.log(path.join(__dirname, '../index.html'));
10 |
11 | /**
12 | * handle parsing request body
13 | */
14 | app.use(express.json());
15 | app.use(express.urlencoded({ extended: true }));
16 |
17 | // statically serve everything in the build folder on the route '/build'
18 | app.use('/dist', express.static(path.join(__dirname, '../dist')));
19 | // serve index.html on the route '/'
20 | app.get('/', (req, res) => {
21 | return res.status(200).sendFile(path.join(__dirname, '../dist/index.html'));
22 | });
23 |
24 | // Router handlers
25 | app.use('/api', apiRouter);
26 |
27 |
28 | // Unknown route handler
29 | app.use((req, res) => res.sendStatus(404));
30 |
31 | /**
32 | * express error handler
33 | * @see https://expressjs.com/en/guide/error-handling.html#writing-error-handlers
34 | */
35 |
36 | app.use((err, req, res, next) => {
37 | const defaultErr = {
38 | log: 'Express error handler caught unknown middleware error',
39 | status: 500,
40 | message: { err: 'An error occurred' },
41 | };
42 | const errorObj = Object.assign({}, defaultErr, err);
43 | console.log(errorObj.log);
44 | return res.status(errorObj.status).json(errorObj.message);
45 | });
46 |
47 | /**
48 | * start server
49 | */
50 | app.listen(PORT, () => {
51 | console.log(`Server listening on port: ${PORT}...`);
52 | });
53 |
54 | module.exports = app;
55 |
--------------------------------------------------------------------------------
/src/App.js.bak:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import MainContainer from './containers/MainContainer';
4 | import logo from './assets/images/logo.png';
5 | import './styles.scss';
6 |
7 | // const logo = lazy(() => import('./assets/images/logo.png'))
8 |
9 | const App = () => {
10 | const [fadeIn, setFadeIn] = useState(false);
11 |
12 | useEffect(() => {
13 | setFadeIn(true); // Triggers the fade-in effect on component mount
14 | }, []);
15 |
16 | return (
17 |
18 |
19 |
20 |
28 |
29 |
30 |
31 |
32 | );
33 | };
34 |
35 | export default App;
36 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState, lazy, Suspense } from 'react';
2 | import MainContainer from './containers/MainContainer';
3 | import logo from './assets/images/logo.png';
4 | import './styles.scss';
5 |
6 | const App = () => {
7 | const [fadeIn, setFadeIn] = useState(false);
8 |
9 | useEffect(() => {
10 | setFadeIn(true);
11 | }, []);
12 |
13 | return (
14 |
15 |
}>
17 |
25 |
26 |
27 |
28 |
29 | );
30 | };
31 |
32 | //test commit
33 |
34 | export default App;
35 |
--------------------------------------------------------------------------------
/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/howardsun-dev/soloProject/6f40fc0c47d5ee7d64c0619d8ff635453314e6e3/src/assets/images/logo.png
--------------------------------------------------------------------------------
/src/components/Cards.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import {
3 | Chart as ChartJS,
4 | CategoryScale,
5 | LinearScale,
6 | BarElement,
7 | PointElement,
8 | LineElement,
9 | Title,
10 | Tooltip,
11 | Legend,
12 | Filler,
13 | } from 'chart.js';
14 | import { Chart } from 'react-chartjs-2';
15 |
16 | ChartJS.register(
17 | CategoryScale,
18 | LinearScale,
19 | BarElement,
20 | PointElement,
21 | LineElement,
22 | Title,
23 | Tooltip,
24 | Legend,
25 | Filler
26 | );
27 |
28 | const Cards = ({ weatherData }) => {
29 | if (!weatherData || !weatherData.current) {
30 | // If weatherData or weatherData.current is null, you can return a loading message or null
31 | return null; // Or return null to render nothing
32 | }
33 | // State to check of Modal is open or not
34 | const [isModalOpen, setModalOpen] = useState(false);
35 |
36 | const { current, hourly } = weatherData;
37 | const { time, temperature_2m, wind_speed_10m } = current;
38 | const timeGMT = time.concat('Z');
39 | const labels = hourly.time.map((element) => {
40 | const date = new Date(element + 'Z');
41 | return date.toLocaleString();
42 | });
43 |
44 | const toggleModal = () => setModalOpen(!isModalOpen);
45 |
46 | const data = {
47 | labels,
48 | datasets: [
49 | {
50 | type: 'line',
51 | label: 'Temperature 2m (°F)',
52 | data: hourly.temperature_2m,
53 | borderColor: 'rgb(255, 99, 132)',
54 | backgroundColor: 'rgba(255, 99, 132, 0.5)',
55 | yAxisID: 'y',
56 | },
57 | {
58 | type: 'line',
59 | label: 'Wind Speed 10m (mp/h)',
60 | data: hourly.wind_speed_10m,
61 | borderColor: 'rgb(54, 162, 235)',
62 | backgroundColor: 'rgba(54, 162, 235, 0.5)',
63 | yAxisID: 'y1',
64 | },
65 | {
66 | type: 'line',
67 | label: 'Temperature 80m (°F)',
68 | data: hourly.temperature_80m,
69 | borderColor: 'rgb(75, 192, 192)',
70 | backgroundColor: 'rgba(75, 192, 192, 0.5)',
71 | yAxisID: 'y',
72 | },
73 | {
74 | type: 'bar',
75 | label: 'Precipitation (inch)',
76 | data: hourly.precipitation,
77 | backgroundColor: 'rgba(153, 102, 255, 0.5)',
78 | yAxisID: 'y2',
79 | },
80 | ],
81 | };
82 |
83 | const options = {
84 | scales: {
85 | y: {
86 | type: 'linear',
87 | display: true,
88 | position: 'left',
89 | },
90 | y1: {
91 | type: 'linear',
92 | display: true,
93 | position: 'right',
94 | grid: {
95 | drawOnChartArea: false,
96 | },
97 | },
98 | y2: {
99 | type: 'linear',
100 | display: false,
101 | },
102 | },
103 | plugins: {
104 | legend: {
105 | position: 'top',
106 | },
107 | },
108 | };
109 |
110 | const readableTime = new Date(timeGMT).toLocaleString('en-US', {
111 | timeZone: 'America/New_York', // This will use Eastern Time, accounting for EST and EDT
112 | year: 'numeric',
113 | month: 'numeric',
114 | day: 'numeric',
115 | hour: '2-digit',
116 | minute: '2-digit',
117 | second: '2-digit',
118 | timeZoneName: 'short',
119 | });
120 |
121 | console.log(labels);
122 |
123 | return (
124 |
125 |
126 |
127 |
Last Update: {readableTime}
128 |
Temperature (2m): {temperature_2m} °F
129 |
Wind Speed: {wind_speed_10m} mp/h
130 |
131 | View Hourly Chart
132 |
133 |
134 | {isModalOpen &&
}
135 |
136 |
137 | );
138 | };
139 |
140 | export default Cards;
141 |
--------------------------------------------------------------------------------
/src/components/Modal.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Modal = ({ isOpen, children, onClose }) => {
4 | if (!isOpen) return null;
5 |
6 | return (
7 |
8 |
9 |
12 | {children}
13 |
14 |
15 | );
16 | };
17 |
18 | export default Modal;
19 |
--------------------------------------------------------------------------------
/src/components/TextBox.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const TextBox = ({
4 | handleSubmit,
5 | longitude,
6 | setLongitude,
7 | latitude,
8 | setLatitude,
9 | }) => {
10 | return (
11 |
12 |
34 |
35 | );
36 | };
37 |
38 | export default TextBox;
39 |
--------------------------------------------------------------------------------
/src/containers/MainContainer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * ************************************
3 | *
4 | * @module MainContainer
5 | * @author
6 | * @date
7 | * @description
8 | *
9 | * ************************************
10 | */
11 |
12 | import React, { useState, useEffect } from 'react';
13 | import Cards from '../components/Cards';
14 | import TextBox from '../components/TextBox';
15 | import axios from 'axios';
16 |
17 | const MainContainer = () => {
18 | const [latitude, setLatitude] = useState('');
19 | const [longitude, setLongitude] = useState('');
20 | const [error, setError] = useState(null);
21 | const [weatherData, setWeatherData] = useState(null);
22 |
23 | // const handleInput = (e) => {
24 | // const { name, value } = e.target;
25 | // if (name === latitude) {
26 | // setLatitude(value);
27 | // } else if (name === longitude) {
28 | // setLongitude(value);
29 | // }
30 | // };
31 |
32 | const fetchWeather = async () => {
33 | try {
34 | const response = await axios.get(
35 | `/api/weather?latitude=${latitude}&longitude=${longitude}`
36 | );
37 | setWeatherData(response.data);
38 | } catch (error) {
39 | console.error('Error fetching weather data: ', error);
40 | setError('Error fetching weather data. Please try again later.');
41 | }
42 | };
43 |
44 | const handleSubmit = (e) => {
45 | e.preventDefault();
46 |
47 | if (!latitude || !longitude) {
48 | setError('Please enter both latitude and longitude');
49 | return;
50 | }
51 |
52 | fetchWeather();
53 | };
54 |
55 | return (
56 |
57 | {error &&
{error}
}
58 | {/* Conditionally display an error message */}
59 |
66 |
67 |
68 | );
69 | };
70 |
71 | export default MainContainer;
72 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | TravelCast
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/index.js.bak:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { createRoot } from 'react-dom/client';
4 | import App from './App';
5 |
6 | const root = createRoot(document.getElementById('root'));
7 | root.render();
8 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { StrictMode } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import App from './App';
4 |
5 | const rootElement = document.getElementById('root');
6 |
7 | if (rootElement) {
8 | const root = createRoot(rootElement);
9 | root.render(
10 |
11 |
12 |
13 | );
14 | } else {
15 | console.error('Root element not found');
16 | }
17 |
--------------------------------------------------------------------------------
/src/styles.scss:
--------------------------------------------------------------------------------
1 | // Variables
2 | $background-color: #ec8f4c;
3 | $card-color: #aeebff;
4 | $border-radius: 10px;
5 |
6 | // Styles
7 | .fade-in {
8 | opacity: 0;
9 | animation: fadeInAnimation 5s forwards;
10 | }
11 |
12 | @keyframes fadeInAnimation {
13 | to {
14 | opacity: 1;
15 | }
16 | }
17 |
18 | body {
19 | background-color: $background-color;
20 | margin: 0;
21 | padding: 0;
22 | font-family: Arial, sans-serif; // Choose your desired font
23 | display: flex;
24 | justify-content: center; // Center content horizontally
25 | align-items: center; // Center content vertically
26 | min-height: 100vh; // Ensure full viewport height
27 | }
28 |
29 | header {
30 | color: darkturquoise;
31 | justify-content: center;
32 | }
33 |
34 | .container {
35 | display: flex;
36 | flex-wrap: wrap;
37 | justify-content: center;
38 | align-items: center;
39 | }
40 |
41 | .logo-animation {
42 | display: flex;
43 | justify-content: center;
44 | align-items: center;
45 | animation: slideInFromTop 2s ease-out forwards;
46 | }
47 |
48 | @keyframes slideInFromTop {
49 | 0% {
50 | transform: translateY(-100%);
51 | /* Start above the screen */
52 | opacity: 0;
53 | }
54 |
55 | 100% {
56 | transform: translateY(0);
57 | /* End at the natural position */
58 | opacity: 1;
59 | }
60 | }
61 |
62 | .form-container {
63 | display: flex;
64 | flex-direction: column; // Stack children vertically
65 | justify-content: center; // Center vertically in the container
66 | align-items: center; // Center horizontally in the container
67 | width: 100%; // Take full width of its parent
68 | // margin: auto;
69 | // min-height: 100vh; //
70 | }
71 |
72 |
73 | .textbox-container {
74 | display: flex;
75 | flex-direction: row; // Stack children vertically
76 | justify-content: center; // Center vertically in the container
77 | align-items: center; // Center horizontally in the container
78 | width: 100%; // Take full width of its parent
79 | margin: auto;
80 | min-height: 20vh;
81 | }
82 |
83 | .error {
84 | display: flex;
85 | color: #007bff;
86 | text-align: center;
87 | margin: auto;
88 | }
89 |
90 | .rounded-input {
91 | border-radius: 10px; // Adjust the value to change the roundness
92 | padding: 8px;
93 | margin: 5px;
94 | border: 1px solid #ccc; // Add border for better visibility
95 |
96 | &:focus {
97 | outline: none; // Remove default focus outline
98 | }
99 | }
100 |
101 | .rounded-button {
102 | border-radius: 10px; // Adjust the value to change the roundness
103 | padding: 8px 16px;
104 | margin: 5px;
105 | background-color: #007bff; // Change background color
106 | color: white; // Change text color
107 | border: none; // Remove border
108 | cursor: pointer;
109 |
110 | &:hover {
111 | background-color: #0056b3; // Change background color on hover
112 | }
113 | }
114 |
115 | .card {
116 | background-color: $card-color;
117 | border-radius: $border-radius;
118 | color: #aa4700;
119 | padding: 20px;
120 | margin: 10px;
121 | min-width: 800px;
122 | // min-height: 400px;
123 | // width: auto;
124 | height: auto;
125 | box-shadow: 5px 4px 8px rgba(255, 255, 255, 0.4);
126 |
127 | .card-header {
128 | display: flex;
129 | flex-direction: column;
130 | align-items: flex-start; // Align items to the start of the flex container
131 |
132 | .view-chart-link {
133 | align-self: flex-end; // Align the link to the end of the flex container (right)
134 | text-decoration: underline;
135 | cursor: pointer;
136 | color: #007bff;
137 | margin: 10px 0;
138 | }
139 | }
140 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig to read more about this file */
4 |
5 | /* Projects */
6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12 |
13 | /* Language and Environment */
14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16 | "jsx": "react", /* Specify what JSX code is generated. */
17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
26 |
27 | /* Modules */
28 | "module": "commonjs", /* Specify what module code is generated. */
29 | // "rootDir": "./", /* Specify the root folder within your source files. */
30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */
36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
42 | // "resolveJsonModule": true, /* Enable importing .json files. */
43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
45 |
46 | /* JavaScript Support */
47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
50 |
51 | /* Emit */
52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */
54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
58 | // "outDir": "./", /* Specify an output folder for all emitted files. */
59 | // "removeComments": true, /* Disable emitting comments. */
60 | // "noEmit": true, /* Disable emitting files from a compilation. */
61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
68 | // "newLine": "crlf", /* Set the newline character for emitting files. */
69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
75 |
76 | /* Interop Constraints */
77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
83 |
84 | /* Type Checking */
85 | "strict": true, /* Enable all strict type-checking options. */
86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
104 |
105 | /* Completeness */
106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 |
4 | module.exports = {
5 | mode: process.env.NODE_ENV,
6 | entry: '/src/index.js',
7 | output: {
8 | path: path.resolve(__dirname, 'dist'),
9 | filename: 'bundle.js',
10 | },
11 | plugins: [
12 | new HtmlWebpackPlugin({
13 | template: './src/index.html',
14 | }),
15 | ],
16 |
17 | module: {
18 | rules: [
19 | {
20 | test: /\.jsx?/,
21 | exclude: /node_modules/,
22 | use: {
23 | loader: 'babel-loader',
24 | options: {
25 | presets: ['@babel/preset-env', '@babel/preset-react'],
26 | },
27 | },
28 | },
29 | {
30 | test: /\.s[ac]ss$/i,
31 | use: ['style-loader', 'css-loader', 'sass-loader'],
32 | },
33 | {
34 | test: /\.(png|jpe?g|gif)$/i,
35 | use: [
36 | {
37 | loader: 'file-loader',
38 | },
39 | ],
40 | },
41 | ],
42 | },
43 |
44 | devServer: {
45 | static: {
46 | directory: path.join(__dirname, 'dist'), // Tells devServer where to serve content from
47 | publicPath: '/',
48 | },
49 | compress: true,
50 | port: 8080,
51 | historyApiFallback: true, // Useful for single-page applications
52 | open: true, // Automatically open the browser
53 | proxy: [{ context: ['/api'], target: 'http://localhost:3000' }],
54 | },
55 | };
56 |
--------------------------------------------------------------------------------