├── .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 | Logo 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 |
16 | Loading...
}> 17 | logo 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 |
13 | setLongitude(e.target.value)} 19 | /> 20 | setLatitude(e.target.value)} 26 | /> 27 |
28 |
29 | 32 |
33 |
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 | --------------------------------------------------------------------------------