From 960e341b9d74f0c4903762dc374d69573aa2df14 Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Sat, 6 Jul 2024 11:49:40 -0400 Subject: [PATCH 01/14] Initial Commit, installed Typescript and Bootstrap --- app/layout.js | 1 + app/page.js | 89 +------------ package-lock.json | 309 +++++++++++++++++++++++++++++----------------- package.json | 8 +- tsconfig.json | 34 +++++ 5 files changed, 243 insertions(+), 198 deletions(-) create mode 100644 tsconfig.json diff --git a/app/layout.js b/app/layout.js index c93f806..f130148 100644 --- a/app/layout.js +++ b/app/layout.js @@ -1,3 +1,4 @@ +import 'bootstrap/dist/css/bootstrap.css'; import './globals.css' import { Inter } from 'next/font/google' diff --git a/app/page.js b/app/page.js index f049c39..fa5a5fa 100644 --- a/app/page.js +++ b/app/page.js @@ -3,93 +3,8 @@ import styles from './page.module.css' export default function Home() { return ( -
-
-

- Get started by editing  - app/page.js -

-
- - By{' '} - Vercel Logo - -
-
- -
- Next.js Logo -
- -
- -

- Docs -> -

-

Find in-depth information about Next.js features and API.

-
- - -

- Learn -> -

-

Learn about Next.js in an interactive course with quizzes!

-
- - -

- Templates -> -

-

Explore the Next.js 13 playground.

-
- - -

- Deploy -> -

-

- Instantly deploy your Next.js site to a shareable URL with Vercel. -

-
-
+
+

RTK Weather

) } diff --git a/package-lock.json b/package-lock.json index 90f6bb1..1288fbd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,17 @@ "name": "parsity_rtk_weather", "version": "0.1.0", "dependencies": { + "bootstrap": "^5.3.3", "eslint": "8.50.0", "eslint-config-next": "13.5.3", - "next": "13.5.3", + "next": "^14.2.4", "react": "18.2.0", "react-dom": "18.2.0" + }, + "devDependencies": { + "@types/node": "^20.14.10", + "@types/react": "^18.3.3", + "typescript": "^5.5.3" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -117,9 +123,10 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, "node_modules/@next/env": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.3.tgz", - "integrity": "sha512-X4te86vsbjsB7iO4usY9jLPtZ827Mbx+WcwNBGUOIuswuTAKQtzsuoxc/6KLxCMvogKG795MhrR1LDhYgDvasg==" + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.4.tgz", + "integrity": "sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==", + "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { "version": "13.5.3", @@ -130,12 +137,13 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.3.tgz", - "integrity": "sha512-6hiYNJxJmyYvvKGrVThzo4nTcqvqUTA/JvKim7Auaj33NexDqSNwN5YrrQu+QhZJCIpv2tULSHt+lf+rUflLSw==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.4.tgz", + "integrity": "sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -145,12 +153,13 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.3.tgz", - "integrity": "sha512-UpBKxu2ob9scbpJyEq/xPgpdrgBgN3aLYlxyGqlYX5/KnwpJpFuIHU2lx8upQQ7L+MEmz+fA1XSgesoK92ppwQ==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.4.tgz", + "integrity": "sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -160,12 +169,13 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.3.tgz", - "integrity": "sha512-5AzM7Yx1Ky+oLY6pHs7tjONTF22JirDPd5Jw/3/NazJ73uGB05NqhGhB4SbeCchg7SlVYVBeRMrMSZwJwq/xoA==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.4.tgz", + "integrity": "sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -175,12 +185,13 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.3.tgz", - "integrity": "sha512-A/C1shbyUhj7wRtokmn73eBksjTM7fFQoY2v/0rTM5wehpkjQRLOXI8WJsag2uLhnZ4ii5OzR1rFPwoD9cvOgA==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.4.tgz", + "integrity": "sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -190,12 +201,13 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.3.tgz", - "integrity": "sha512-FubPuw/Boz8tKkk+5eOuDHOpk36F80rbgxlx4+xty/U71e3wZZxVYHfZXmf0IRToBn1Crb8WvLM9OYj/Ur815g==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.4.tgz", + "integrity": "sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -205,12 +217,13 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.3.tgz", - "integrity": "sha512-DPw8nFuM1uEpbX47tM3wiXIR0Qa+atSzs9Q3peY1urkhofx44o7E1svnq+a5Q0r8lAcssLrwiM+OyJJgV/oj7g==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.4.tgz", + "integrity": "sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -220,12 +233,13 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.3.tgz", - "integrity": "sha512-zBPSP8cHL51Gub/YV8UUePW7AVGukp2D8JU93IHbVDu2qmhFAn9LWXiOOLKplZQKxnIPUkJTQAJDCWBWU4UWUA==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.4.tgz", + "integrity": "sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -235,12 +249,13 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.3.tgz", - "integrity": "sha512-ONcL/lYyGUj4W37D4I2I450SZtSenmFAvapkJQNIJhrPMhzDU/AdfLkW98NvH1D2+7FXwe7yclf3+B7v28uzBQ==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.4.tgz", + "integrity": "sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -250,12 +265,13 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.3.tgz", - "integrity": "sha512-2Vz2tYWaLqJvLcWbbTlJ5k9AN6JD7a5CN2pAeIzpbecK8ZF/yobA39cXtv6e+Z8c5UJuVOmaTldEAIxvsIux/Q==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.4.tgz", + "integrity": "sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -296,16 +312,35 @@ "node": ">= 8" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.5.0.tgz", "integrity": "sha512-EF3948ckf3f5uPgYbQ6GhyA56Dmv8yg0+ir+BroRjwdxyZJsekhZzawOecC2rOTPCz173t7ZcR1HHZu0dZgOCw==" }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, "node_modules/@swc/helpers": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", - "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", + "license": "Apache-2.0", "dependencies": { + "@swc/counter": "^0.1.3", "tslib": "^2.4.0" } }, @@ -314,6 +349,34 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "node_modules/@types/node": { + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@typescript-eslint/parser": { "version": "6.7.3", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.3.tgz", @@ -647,6 +710,25 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT", + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -657,11 +739,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -699,9 +782,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001541", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz", - "integrity": "sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw==", + "version": "1.0.30001640", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz", + "integrity": "sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==", "funding": [ { "type": "opencollective", @@ -715,7 +798,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chalk": { "version": "4.1.2", @@ -771,6 +855,13 @@ "node": ">= 8" } }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -1448,9 +1539,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1604,11 +1696,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" - }, "node_modules/globals": { "version": "13.22.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz", @@ -1965,6 +2052,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -2295,15 +2383,16 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -2317,38 +2406,39 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, "node_modules/next": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/next/-/next-13.5.3.tgz", - "integrity": "sha512-4Nt4HRLYDW/yRpJ/QR2t1v63UOMS55A38dnWv3UDOWGezuY0ZyFO1ABNbD7mulVzs9qVhgy2+ppjdsANpKP1mg==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.4.tgz", + "integrity": "sha512-R8/V7vugY+822rsQGQCjoLhMuC9oFj9SOi4Cl4b2wjDrseD0LRZ10W7R6Czo4w9ZznVSshKjuIomsRjvm9EKJQ==", + "license": "MIT", "dependencies": { - "@next/env": "13.5.3", - "@swc/helpers": "0.5.2", + "@next/env": "14.2.4", + "@swc/helpers": "0.5.5", "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1", - "watchpack": "2.4.0", - "zod": "3.21.4" + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=16.14.0" + "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.5.3", - "@next/swc-darwin-x64": "13.5.3", - "@next/swc-linux-arm64-gnu": "13.5.3", - "@next/swc-linux-arm64-musl": "13.5.3", - "@next/swc-linux-x64-gnu": "13.5.3", - "@next/swc-linux-x64-musl": "13.5.3", - "@next/swc-win32-arm64-msvc": "13.5.3", - "@next/swc-win32-ia32-msvc": "13.5.3", - "@next/swc-win32-x64-msvc": "13.5.3" + "@next/swc-darwin-arm64": "14.2.4", + "@next/swc-darwin-x64": "14.2.4", + "@next/swc-linux-arm64-gnu": "14.2.4", + "@next/swc-linux-arm64-musl": "14.2.4", + "@next/swc-linux-x64-gnu": "14.2.4", + "@next/swc-linux-x64-musl": "14.2.4", + "@next/swc-win32-arm64-msvc": "14.2.4", + "@next/swc-win32-ia32-msvc": "14.2.4", + "@next/swc-win32-x64-msvc": "14.2.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" @@ -2357,6 +2447,9 @@ "@opentelemetry/api": { "optional": true }, + "@playwright/test": { + "optional": true + }, "sass": { "optional": true } @@ -2572,9 +2665,10 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -2588,9 +2682,9 @@ } }, "node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -2599,10 +2693,15 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -2906,9 +3005,10 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -3073,6 +3173,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -3103,9 +3204,10 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", @@ -3191,10 +3293,10 @@ } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "peer": true, + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3217,6 +3319,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "license": "MIT" + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -3225,18 +3334,6 @@ "punycode": "^2.1.0" } }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3343,14 +3440,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } } } } diff --git a/package.json b/package.json index 6ca0f8f..62c63da 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,16 @@ "lint": "next lint" }, "dependencies": { + "bootstrap": "^5.3.3", "eslint": "8.50.0", "eslint-config-next": "13.5.3", - "next": "13.5.3", + "next": "^14.2.4", "react": "18.2.0", "react-dom": "18.2.0" + }, + "devDependencies": { + "@types/node": "^20.14.10", + "@types/react": "^18.3.3", + "typescript": "^5.5.3" } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ccb2ed9 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "noEmit": true, + "incremental": true, + "module": "esnext", + "esModuleInterop": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + ".next/types/**/*.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} From 0152258f49d104a0f78d1f410c03736db59e4e32 Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Tue, 16 Jul 2024 07:13:54 -0400 Subject: [PATCH 02/14] Initial commit --- app/components/App.jsx | 13 ++++ app/components/Search.jsx | 40 ++++++++++ app/features/cityList/CityList.jsx | 50 ++++++++++++ app/features/cityList/cityListSlice.js | 25 ++++++ app/layout.js | 15 ++-- app/page.js | 8 ++ app/store.js | 15 ++++ package-lock.json | 103 ++++++++++++++++++++++++- package.json | 4 +- tsconfig.json | 17 ++-- 10 files changed, 269 insertions(+), 21 deletions(-) create mode 100644 app/components/App.jsx create mode 100644 app/components/Search.jsx create mode 100644 app/features/cityList/CityList.jsx create mode 100644 app/features/cityList/cityListSlice.js create mode 100644 app/store.js diff --git a/app/components/App.jsx b/app/components/App.jsx new file mode 100644 index 0000000..81c4ec0 --- /dev/null +++ b/app/components/App.jsx @@ -0,0 +1,13 @@ +import CityList from "../features/cityList/CityList"; +import Search from "./Search"; + +const App = () => { + return ( + <> + + + + ); +}; + +export default App; diff --git a/app/components/Search.jsx b/app/components/Search.jsx new file mode 100644 index 0000000..d459a56 --- /dev/null +++ b/app/components/Search.jsx @@ -0,0 +1,40 @@ +"use client"; +import { useState } from "react"; +import { useDispatch } from 'react-redux'; +import { addCity } from "../features/cityList/cityListSlice"; + + +const Search = () => { + const [newSearch, setNewSearch] = useState(""); + const dispatch = useDispatch(); + + const handleSubmit = (event) => { + event.preventDefault(); + console.log("add new city to list"); + dispatch( + addCity({ + name: newSearch, + id: Math.floor(Math.random() * 90000000) + 10000000, + temp: 56, + }) + ); + }; + + return ( + <> +
+ + +
+ + ) + +} + +export default Search; diff --git a/app/features/cityList/CityList.jsx b/app/features/cityList/CityList.jsx new file mode 100644 index 0000000..1dcd44f --- /dev/null +++ b/app/features/cityList/CityList.jsx @@ -0,0 +1,50 @@ +"use client"; +import React from 'react'; +import { useSelector, useDispatch } from "react-redux"; +import { useRouter } from 'next/navigation'; +import { deleteCity } from "./cityListSlice"; + + +const CityList = () => { + const cities = useSelector((state) => state.cityList.cityList); + const dispatch = useDispatch(); + const router = useRouter(); + console.log(cities); + + + const handleDeleteClick = (id) => { + console.log("delete button clicked: id = ", id); + dispatch( + deleteCity(id) + ); + router.push('/'); + }; + + + const renderCities = () => { + if (!Array.isArray(cities) || cities.length === 0) { + return

No cities available.

; + } + return cities.map((city) => { + return ( +
  • + + {city.name}: {city.temp} Degrees +
  • + ); + }); + + }; + + + return ( + <> +

    List of Cities

    +
      + {renderCities()} +
    + + ); +}; + +export default CityList; diff --git a/app/features/cityList/cityListSlice.js b/app/features/cityList/cityListSlice.js new file mode 100644 index 0000000..5bb9ce8 --- /dev/null +++ b/app/features/cityList/cityListSlice.js @@ -0,0 +1,25 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const initialState = { + cityList: [ + { name: "Chicago", temp: 56, id: 84658893 }, + { name: "Denver", temp: 52, id: 66387769 }, + { name: "Nashville", temp: 65, id: 31339895 }, + ] +}; + +export const cityListSlice = createSlice({ + name: "cityList", + initialState, + reducers: { + addCity: (state, action) => { + state.cityList.push(action.payload); + }, + deleteCity: (state, action) => { + state.cityList = state.cityList.filter(city => city.id !== action.payload); + }, + }, +}); + +export const { addCity, deleteCity } = cityListSlice.actions; +export default cityListSlice.reducer; diff --git a/app/layout.js b/app/layout.js index f130148..31a75fe 100644 --- a/app/layout.js +++ b/app/layout.js @@ -1,18 +1,19 @@ +"use client"; import 'bootstrap/dist/css/bootstrap.css'; -import './globals.css' -import { Inter } from 'next/font/google' +import './globals.css'; +import { Inter } from 'next/font/google'; +import { Provider } from 'react-redux'; +import store from './store'; const inter = Inter({ subsets: ['latin'] }) -export const metadata = { - title: 'Create Next App', - description: 'Generated by create next app', -} export default function RootLayout({ children }) { return ( - {children} + + {children} + ) } diff --git a/app/page.js b/app/page.js index fa5a5fa..d8bbc5f 100644 --- a/app/page.js +++ b/app/page.js @@ -1,10 +1,18 @@ +"use client"; import Image from 'next/image' import styles from './page.module.css' +import App from './components/App' + export default function Home() { + + + return (

    RTK Weather

    + +
    ) } diff --git a/app/store.js b/app/store.js new file mode 100644 index 0000000..aca36f6 --- /dev/null +++ b/app/store.js @@ -0,0 +1,15 @@ +"use client"; +import { configureStore } from "@reduxjs/toolkit"; +import cityListReducer from "./features/cityList/cityListSlice"; + +const store = configureStore({ + reducer: { + cityList: cityListReducer, + }, +}); + +store.subscribe(() => { + console.log("Store State: ", store.getState()); +}); + +export default store; diff --git a/package-lock.json b/package-lock.json index 1288fbd..fa6a2de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,12 +8,14 @@ "name": "parsity_rtk_weather", "version": "0.1.0", "dependencies": { + "@reduxjs/toolkit": "^2.2.6", "bootstrap": "^5.3.3", "eslint": "8.50.0", "eslint-config-next": "13.5.3", "next": "^14.2.4", "react": "18.2.0", - "react-dom": "18.2.0" + "react-dom": "18.2.0", + "react-redux": "^9.1.2" }, "devDependencies": { "@types/node": "^20.14.10", @@ -323,6 +325,30 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.6.tgz", + "integrity": "sha512-kH0r495c5z1t0g796eDQAkYbEQ3a1OLYN9o8jQQVZyKyw367pfRGS+qZLkHYvFHiUUdafpoSlQ2QYObIApjPWA==", + "license": "MIT", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.5.0.tgz", @@ -363,20 +389,26 @@ "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", + "license": "MIT" + }, "node_modules/@typescript-eslint/parser": { "version": "6.7.3", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.3.tgz", @@ -859,7 +891,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -1846,6 +1878,16 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -2782,6 +2824,44 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-redux": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", + "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25", + "react": "^18.0", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", @@ -2822,6 +2902,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.6", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", @@ -3334,6 +3420,15 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 62c63da..c6c929b 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,14 @@ "lint": "next lint" }, "dependencies": { + "@reduxjs/toolkit": "^2.2.6", "bootstrap": "^5.3.3", "eslint": "8.50.0", "eslint-config-next": "13.5.3", "next": "^14.2.4", "react": "18.2.0", - "react-dom": "18.2.0" + "react-dom": "18.2.0", + "react-redux": "^9.1.2" }, "devDependencies": { "@types/node": "^20.14.10", diff --git a/tsconfig.json b/tsconfig.json index ccb2ed9..4830cfb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,10 +1,6 @@ { "compilerOptions": { - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": false, @@ -26,9 +22,12 @@ "next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", - "**/*.tsx" + "**/*.tsx", + "app/components/App.jsx", + "app/components/Search.jsx", + "app/features/cityList/CityList.jsx", + "app/features/cityList/cityListSlice.js", + "app/store.js" ], - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] } From 8a8cb78c76e746f08357cfa3bd1a3dea5cf3c401 Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Sat, 20 Jul 2024 08:14:32 -0400 Subject: [PATCH 03/14] fetch geoCodes --- app/features/cityList/CityList.jsx | 31 ++++++-- app/features/cityList/cityListSlice.js | 33 +++++++- package-lock.json | 100 +++++++++++++++++++++++++ package.json | 1 + 4 files changed, 156 insertions(+), 9 deletions(-) diff --git a/app/features/cityList/CityList.jsx b/app/features/cityList/CityList.jsx index 1dcd44f..ec3846d 100644 --- a/app/features/cityList/CityList.jsx +++ b/app/features/cityList/CityList.jsx @@ -1,16 +1,25 @@ "use client"; -import React from 'react'; +import React, { useEffect } from 'react'; import { useSelector, useDispatch } from "react-redux"; import { useRouter } from 'next/navigation'; -import { deleteCity } from "./cityListSlice"; +import { deleteCity, fetchGeoCodes } from "./cityListSlice"; const CityList = () => { const cities = useSelector((state) => state.cityList.cityList); + const status = useSelector((state) => state.cityList.status); + const error = useSelector((state) => state.cityList.error); const dispatch = useDispatch(); const router = useRouter(); console.log(cities); + useEffect(() => { + cities.forEach(city => { + console.log("fetchGeoCodes for : ",city.name); + dispatch(fetchGeoCodes(city.name)); + }); + }, [cities, dispatch]); + const handleDeleteClick = (id) => { console.log("delete button clicked: id = ", id); @@ -25,14 +34,22 @@ const CityList = () => { if (!Array.isArray(cities) || cities.length === 0) { return

    No cities available.

    ; } - return cities.map((city) => { - return ( -
  • + + if (status === 'loading') { + return

    Loading...

    ; + } + + if (status === 'failed') { + return

    Error: {error}

    ; + } + + return cities.map((city) => ( +
  • {city.name}: {city.temp} Degrees
  • - ); - }); + + )); }; diff --git a/app/features/cityList/cityListSlice.js b/app/features/cityList/cityListSlice.js index 5bb9ce8..e250d52 100644 --- a/app/features/cityList/cityListSlice.js +++ b/app/features/cityList/cityListSlice.js @@ -1,13 +1,28 @@ -import { createSlice } from "@reduxjs/toolkit"; +import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; +import axios from 'axios'; + +const APIkey = "dd9d476f3e18502da2edd15a3502cd8d"; + const initialState = { cityList: [ { name: "Chicago", temp: 56, id: 84658893 }, { name: "Denver", temp: 52, id: 66387769 }, { name: "Nashville", temp: 65, id: 31339895 }, - ] + ], + status: 'idle', + error: null, }; +export const fetchGeoCodes = createAsyncThunk('cityList/fetchGeoCodes', + async (city) => { + const response = await axios.get(`https://api.openweathermap.org/geo/1.0/direct?q=${city}&limit=1&appid=${APIkey}`); + console.log(city, " geocode = ", response.data); + return response.data; + } + +); + export const cityListSlice = createSlice({ name: "cityList", initialState, @@ -19,6 +34,20 @@ export const cityListSlice = createSlice({ state.cityList = state.cityList.filter(city => city.id !== action.payload); }, }, + extraReducers: (builder) => { + builder + .addCase(fetchGeoCodes.pending, (state) => { + state.status = 'loading'; + }) + .addCase(fetchGeoCodes.fulfilled, (state, action) => { + state.status = 'succeeded'; + + }) + .addCase(fetchGeoCodes.rejected, (state, action) => { + state.status = 'failed'; + state.error = action.error.message; + }); + }, }); export const { addCity, deleteCity } = cityListSlice.actions; diff --git a/package-lock.json b/package-lock.json index fa6a2de..5ef4213 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "@reduxjs/toolkit": "^2.2.6", + "axios": "^1.7.2", "bootstrap": "^5.3.3", "eslint": "8.50.0", "eslint-config-next": "13.5.3", @@ -710,6 +711,12 @@ "has-symbols": "^1.0.3" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -729,6 +736,17 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -869,6 +887,18 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -949,6 +979,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -1615,6 +1654,26 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==" }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -1623,6 +1682,20 @@ "is-callable": "^1.1.3" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2400,6 +2473,27 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2769,6 +2863,12 @@ "react-is": "^16.13.1" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", diff --git a/package.json b/package.json index c6c929b..adf0c84 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@reduxjs/toolkit": "^2.2.6", + "axios": "^1.7.2", "bootstrap": "^5.3.3", "eslint": "8.50.0", "eslint-config-next": "13.5.3", From a23113ddc1cd120cb4d4aad160584476940dc2e7 Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Mon, 22 Jul 2024 11:27:40 -0400 Subject: [PATCH 04/14] added bootstrap --- app/features/cityList/CityList.jsx | 36 ++++-- app/layout.js | 3 +- package-lock.json | 198 ++++++++++++++++++++++++++++- package.json | 1 + tsconfig.json | 33 ----- 5 files changed, 219 insertions(+), 52 deletions(-) delete mode 100644 tsconfig.json diff --git a/app/features/cityList/CityList.jsx b/app/features/cityList/CityList.jsx index ec3846d..8a8de76 100644 --- a/app/features/cityList/CityList.jsx +++ b/app/features/cityList/CityList.jsx @@ -44,10 +44,21 @@ const CityList = () => { } return cities.map((city) => ( -
  • - - {city.name}: {city.temp} Degrees -
  • +
      +
    • + {city.name} +
    • +
    • + {city.temp} +
    • +
    • + +
    • +
    • + Humidy +
    • +
    + )); @@ -55,12 +66,17 @@ const CityList = () => { return ( - <> -

    List of Cities

    -
      - {renderCities()} -
    - +
    +
    List of Cities
    +
    +
    City
    +
    Temperature (F)
    +
    Pressure (hPa)
    +
    Humidity (%)
    +
    + {renderCities()} + +
    ); }; diff --git a/app/layout.js b/app/layout.js index 31a75fe..c26568e 100644 --- a/app/layout.js +++ b/app/layout.js @@ -1,6 +1,5 @@ "use client"; -import 'bootstrap/dist/css/bootstrap.css'; -import './globals.css'; +import 'bootstrap/dist/css/bootstrap.min.css'; import { Inter } from 'next/font/google'; import { Provider } from 'react-redux'; import store from './store'; diff --git a/package-lock.json b/package-lock.json index 5ef4213..87bd05d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "eslint-config-next": "13.5.3", "next": "^14.2.4", "react": "18.2.0", + "react-bootstrap": "^2.10.4", "react-dom": "18.2.0", "react-redux": "^9.1.2" }, @@ -33,9 +34,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz", - "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -320,12 +322,26 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" } }, + "node_modules/@react-aria/ssr": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.4.tgz", + "integrity": "sha512-4jmAigVq409qcJvQyuorsmBR4+9r3+JEC60wC+Y0MZV0HCtTmm8D9guYXlJMdx0SSkgj0hHAyFm/HvPNFofCoQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, "node_modules/@reduxjs/toolkit": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.6.tgz", @@ -350,6 +366,48 @@ } } }, + "node_modules/@restart/hooks": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", + "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.9.tgz", + "integrity": "sha512-mUbygUsJcRurjZCt1f77gg4DpheD1D+Sc7J3JjAkysUj7t8m4EBJVOqWC9788Qtbc69cJ+HlJc6jBguKwS8Mcw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@popperjs/core": "^2.11.6", + "@react-aria/ssr": "^3.5.0", + "@restart/hooks": "^0.4.9", + "@types/warning": "^3.0.0", + "dequal": "^2.0.3", + "dom-helpers": "^5.2.0", + "uncontrollable": "^8.0.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/@restart/ui/node_modules/uncontrollable": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", + "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.14.0" + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.5.0.tgz", @@ -390,26 +448,39 @@ "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "devOptional": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/use-sync-external-store": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", "license": "MIT" }, + "node_modules/@types/warning": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", + "license": "MIT" + }, "node_modules/@typescript-eslint/parser": { "version": "6.7.3", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.3.tgz", @@ -866,6 +937,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -921,7 +998,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -1018,6 +1094,16 @@ "node": ">=6.0.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -2011,6 +2097,15 @@ "node": ">= 0.4" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/is-array-buffer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", @@ -2863,6 +2958,19 @@ "react-is": "^16.13.1" } }, + "node_modules/prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "license": "MIT", + "dependencies": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + }, + "peerDependencies": { + "react": ">=0.14.0" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -2907,6 +3015,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-bootstrap": { + "version": "2.10.4", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.4.tgz", + "integrity": "sha512-W3398nBM2CBfmGP2evneEO3ZZwEMPtHs72q++eNw60uDGDAdiGn0f9yNys91eo7/y8CTF5Ke1C0QO8JFVPU40Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.6.9", + "@types/react-transition-group": "^4.4.6", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "@types/react": ">=16.14.8", + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -2924,6 +3062,12 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "license": "MIT" + }, "node_modules/react-redux": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", @@ -2947,6 +3091,22 @@ } } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/redux": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", @@ -3505,6 +3665,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -3529,6 +3704,15 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index adf0c84..6bad4e1 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "eslint-config-next": "13.5.3", "next": "^14.2.4", "react": "18.2.0", + "react-bootstrap": "^2.10.4", "react-dom": "18.2.0", "react-redux": "^9.1.2" }, diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 4830cfb..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": false, - "noEmit": true, - "incremental": true, - "module": "esnext", - "esModuleInterop": true, - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "plugins": [ - { - "name": "next" - } - ] - }, - "include": [ - "next-env.d.ts", - ".next/types/**/*.ts", - "**/*.ts", - "**/*.tsx", - "app/components/App.jsx", - "app/components/Search.jsx", - "app/features/cityList/CityList.jsx", - "app/features/cityList/cityListSlice.js", - "app/store.js" - ], - "exclude": ["node_modules"] -} From dd972d0d819f96bc7b53667dd31710d08b3c175c Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Mon, 22 Jul 2024 13:22:35 -0400 Subject: [PATCH 05/14] removed 'temp' placeholder, ready to call API --- app/components/Search.jsx | 1 - app/features/cityList/CityList.jsx | 3 +-- app/features/cityList/cityListSlice.js | 6 +++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/components/Search.jsx b/app/components/Search.jsx index d459a56..b758c73 100644 --- a/app/components/Search.jsx +++ b/app/components/Search.jsx @@ -15,7 +15,6 @@ const Search = () => { addCity({ name: newSearch, id: Math.floor(Math.random() * 90000000) + 10000000, - temp: 56, }) ); }; diff --git a/app/features/cityList/CityList.jsx b/app/features/cityList/CityList.jsx index 8a8de76..e5aac60 100644 --- a/app/features/cityList/CityList.jsx +++ b/app/features/cityList/CityList.jsx @@ -49,7 +49,7 @@ const CityList = () => { {city.name}
  • - {city.temp} + Temperature
  • @@ -67,7 +67,6 @@ const CityList = () => { return (
    -
    List of Cities
    City
    Temperature (F)
    diff --git a/app/features/cityList/cityListSlice.js b/app/features/cityList/cityListSlice.js index e250d52..4206550 100644 --- a/app/features/cityList/cityListSlice.js +++ b/app/features/cityList/cityListSlice.js @@ -6,9 +6,9 @@ const APIkey = "dd9d476f3e18502da2edd15a3502cd8d"; const initialState = { cityList: [ - { name: "Chicago", temp: 56, id: 84658893 }, - { name: "Denver", temp: 52, id: 66387769 }, - { name: "Nashville", temp: 65, id: 31339895 }, + { name: "Chicago", id: 84658893 }, + { name: "Denver", id: 66387769 }, + { name: "Nashville", id: 31339895 }, ], status: 'idle', error: null, From d2c0b908be1f290a81bdbdbea2307f40fa28b11a Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Wed, 24 Jul 2024 11:28:26 -0400 Subject: [PATCH 06/14] adding new city to store with geocodes --- app/components/Search.jsx | 8 ++--- app/features/cityList/CityList.jsx | 8 +---- app/features/cityList/cityListSlice.js | 48 ++++++++++++++++++++------ 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/app/components/Search.jsx b/app/components/Search.jsx index b758c73..a4f5569 100644 --- a/app/components/Search.jsx +++ b/app/components/Search.jsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { useDispatch } from 'react-redux'; import { addCity } from "../features/cityList/cityListSlice"; +import { fetchGeoCodes } from "../features/cityList/cityListSlice"; const Search = () => { @@ -12,11 +13,8 @@ const Search = () => { event.preventDefault(); console.log("add new city to list"); dispatch( - addCity({ - name: newSearch, - id: Math.floor(Math.random() * 90000000) + 10000000, - }) - ); + fetchGeoCodes(newSearch)); + }; return ( diff --git a/app/features/cityList/CityList.jsx b/app/features/cityList/CityList.jsx index e5aac60..3ceab05 100644 --- a/app/features/cityList/CityList.jsx +++ b/app/features/cityList/CityList.jsx @@ -11,14 +11,8 @@ const CityList = () => { const error = useSelector((state) => state.cityList.error); const dispatch = useDispatch(); const router = useRouter(); - console.log(cities); - useEffect(() => { - cities.forEach(city => { - console.log("fetchGeoCodes for : ",city.name); - dispatch(fetchGeoCodes(city.name)); - }); - }, [cities, dispatch]); + const handleDeleteClick = (id) => { diff --git a/app/features/cityList/cityListSlice.js b/app/features/cityList/cityListSlice.js index 4206550..b1ced93 100644 --- a/app/features/cityList/cityListSlice.js +++ b/app/features/cityList/cityListSlice.js @@ -1,27 +1,53 @@ import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; import axios from 'axios'; +import { useDispatch } from "react-redux"; const APIkey = "dd9d476f3e18502da2edd15a3502cd8d"; +const API_URL_GEOCODE = "https://api.openweathermap.org/geo/1.0/direct"; +//const API_URL_FORECAST = +export const fetchGeoCodes = createAsyncThunk('newCity/fetchGeoCodes', async (city, { dispatch }) => { + const response = await axios.get(`https://api.openweathermap.org/geo/1.0/direct?q=${city}&limit=1&appid=${APIkey}`); + + const newCity = { + name: city, + id: Math.floor(Math.random() * 90000000) + 10000000, + lat: response.data[0].lat, + lon: response.data[0].lon, + }; + + console.log("new City = ", newCity); + dispatch( + addCity(newCity) + ); + +} ); const initialState = { cityList: [ - { name: "Chicago", id: 84658893 }, - { name: "Denver", id: 66387769 }, - { name: "Nashville", id: 31339895 }, + { name: "Chicago", id: 84658893, lat: 41.8755616, lon: -87.6244212 }, + { name: "Denver", id: 66387769, lat: 39.7392364, lon: -104.984862 }, + { name: "Nashville", id: 31339895, lat: 36.1622767, lon: -86.7742984 }, ], status: 'idle', error: null, }; -export const fetchGeoCodes = createAsyncThunk('cityList/fetchGeoCodes', - async (city) => { - const response = await axios.get(`https://api.openweathermap.org/geo/1.0/direct?q=${city}&limit=1&appid=${APIkey}`); - console.log(city, " geocode = ", response.data); - return response.data; - } +// export const fetchGeoCodes = createAsyncThunk('cityList/fetchGeoCodes', +// async (city) => { +// const response = await axios.get(`https://api.openweathermap.org/geo/1.0/direct?q=${city}&limit=1&appid=${APIkey}`); +// console.log(city, " geocode = ", response.data); + +// const newCity = { +// name: city, +// id: Math.floor(Math.random() * 90000000) + 10000000, +// lat: response.data[0].lat, +// lon: response.data[0].lon, +// } + +// } -); +// ); export const cityListSlice = createSlice({ name: "cityList", @@ -41,6 +67,8 @@ export const cityListSlice = createSlice({ }) .addCase(fetchGeoCodes.fulfilled, (state, action) => { state.status = 'succeeded'; + + //state.cityList.push(action.payload); }) .addCase(fetchGeoCodes.rejected, (state, action) => { From 166eeb568af7e7a2460e38c473d598b14de0c83e Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Thu, 25 Jul 2024 11:18:56 -0400 Subject: [PATCH 07/14] added component and forecast API --- app/components/CityForecast.jsx | 49 ++++++++++++++++++++ app/components/Search.jsx | 2 - app/features/cityList/CityList.jsx | 63 ++++---------------------- app/features/cityList/cityListSlice.js | 50 +++++++++++--------- app/store.js | 6 +-- 5 files changed, 89 insertions(+), 81 deletions(-) create mode 100644 app/components/CityForecast.jsx diff --git a/app/components/CityForecast.jsx b/app/components/CityForecast.jsx new file mode 100644 index 0000000..f2034e5 --- /dev/null +++ b/app/components/CityForecast.jsx @@ -0,0 +1,49 @@ +"use client"; +import React from "react"; +import { useRouter } from 'next/navigation' +import { useDispatch } from 'react-redux'; +import { deleteCity } from "../features/cityList/cityListSlice"; +import { fetchForecast } from "../features/cityList/cityListSlice"; + + +function CityForecast({name, id, lat, lon}) { + const dispatch = useDispatch(); + const router = useRouter(); + + + dispatch( + fetchForecast({lat, lon}) + ); + ; + + + + const handleDeleteClick = (id) => { + dispatch( + deleteCity(id) + ); + router.push('/'); + }; + + return ( + <> +
      +
    • +

      {name}

      +
    • +
    • + ID = {id} lat = {lat} lon = {lon} +
    • +
    • + +
    • +
    • + Humidity +
    • +
    + + ) + +} + +export default CityForecast; diff --git a/app/components/Search.jsx b/app/components/Search.jsx index a4f5569..db93c40 100644 --- a/app/components/Search.jsx +++ b/app/components/Search.jsx @@ -1,7 +1,6 @@ "use client"; import { useState } from "react"; import { useDispatch } from 'react-redux'; -import { addCity } from "../features/cityList/cityListSlice"; import { fetchGeoCodes } from "../features/cityList/cityListSlice"; @@ -11,7 +10,6 @@ const Search = () => { const handleSubmit = (event) => { event.preventDefault(); - console.log("add new city to list"); dispatch( fetchGeoCodes(newSearch)); diff --git a/app/features/cityList/CityList.jsx b/app/features/cityList/CityList.jsx index 3ceab05..ffcf697 100644 --- a/app/features/cityList/CityList.jsx +++ b/app/features/cityList/CityList.jsx @@ -1,63 +1,13 @@ "use client"; -import React, { useEffect } from 'react'; +import React from 'react'; import { useSelector, useDispatch } from "react-redux"; -import { useRouter } from 'next/navigation'; -import { deleteCity, fetchGeoCodes } from "./cityListSlice"; +import CityForecast from '@/app/components/CityForecast'; const CityList = () => { const cities = useSelector((state) => state.cityList.cityList); const status = useSelector((state) => state.cityList.status); const error = useSelector((state) => state.cityList.error); - const dispatch = useDispatch(); - const router = useRouter(); - - - - - const handleDeleteClick = (id) => { - console.log("delete button clicked: id = ", id); - dispatch( - deleteCity(id) - ); - router.push('/'); - }; - - - const renderCities = () => { - if (!Array.isArray(cities) || cities.length === 0) { - return

    No cities available.

    ; - } - - if (status === 'loading') { - return

    Loading...

    ; - } - - if (status === 'failed') { - return

    Error: {error}

    ; - } - - return cities.map((city) => ( -
      -
    • - {city.name} -
    • -
    • - Temperature -
    • -
    • - -
    • -
    • - Humidy -
    • -
    - - - )); - - }; - return (
    @@ -66,10 +16,13 @@ const CityList = () => {
    Temperature (F)
    Pressure (hPa)
    Humidity (%)
    +
    + { + cities.map((city, index) => ( + + )) + }
    - {renderCities()} - -
    ); }; diff --git a/app/features/cityList/cityListSlice.js b/app/features/cityList/cityListSlice.js index b1ced93..0d16158 100644 --- a/app/features/cityList/cityListSlice.js +++ b/app/features/cityList/cityListSlice.js @@ -1,10 +1,8 @@ import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; import axios from 'axios'; -import { useDispatch } from "react-redux"; const APIkey = "dd9d476f3e18502da2edd15a3502cd8d"; -const API_URL_GEOCODE = "https://api.openweathermap.org/geo/1.0/direct"; -//const API_URL_FORECAST = + export const fetchGeoCodes = createAsyncThunk('newCity/fetchGeoCodes', async (city, { dispatch }) => { const response = await axios.get(`https://api.openweathermap.org/geo/1.0/direct?q=${city}&limit=1&appid=${APIkey}`); @@ -16,38 +14,35 @@ export const fetchGeoCodes = createAsyncThunk('newCity/fetchGeoCodes', async (ci lon: response.data[0].lon, }; - console.log("new City = ", newCity); dispatch( addCity(newCity) ); } ); +export const fetchForecast = createAsyncThunk('cityList/fetchForecast', async ({lat, lon}) => { + console.log("forecast API lat: ",lat ); + console.log("forecast API lon: ",lon ); + + const response = await axios.get(`https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&appid=${APIkey}`); + + return response.data.list + +} ); + const initialState = { cityList: [ - { name: "Chicago", id: 84658893, lat: 41.8755616, lon: -87.6244212 }, + { name: "Chicago", id: 84658893, lat: 41.8755616, lon: -87.6244212, weather: { + temp: [], pressure: [], humidity: [] + } }, { name: "Denver", id: 66387769, lat: 39.7392364, lon: -104.984862 }, { name: "Nashville", id: 31339895, lat: 36.1622767, lon: -86.7742984 }, ], + status: 'idle', error: null, }; -// export const fetchGeoCodes = createAsyncThunk('cityList/fetchGeoCodes', -// async (city) => { -// const response = await axios.get(`https://api.openweathermap.org/geo/1.0/direct?q=${city}&limit=1&appid=${APIkey}`); -// console.log(city, " geocode = ", response.data); - -// const newCity = { -// name: city, -// id: Math.floor(Math.random() * 90000000) + 10000000, -// lat: response.data[0].lat, -// lon: response.data[0].lon, -// } - -// } - -// ); export const cityListSlice = createSlice({ name: "cityList", @@ -74,7 +69,20 @@ export const cityListSlice = createSlice({ .addCase(fetchGeoCodes.rejected, (state, action) => { state.status = 'failed'; state.error = action.error.message; - }); + }) + // .addCase(fetchForecast.pending, (state) => { + // state.status = 'loading'; + // }) + // .addCase(fetchForecast.fulfilled, (state, action) => { + // state.status = 'succeeded'; + + // //state.cityList.push(action.payload); + + // }) + // .addCase(fetchForecast.rejected, (state, action) => { + // state.status = 'failed'; + // state.error = action.error.message; + // }); }, }); diff --git a/app/store.js b/app/store.js index aca36f6..149d208 100644 --- a/app/store.js +++ b/app/store.js @@ -8,8 +8,8 @@ const store = configureStore({ }, }); -store.subscribe(() => { - console.log("Store State: ", store.getState()); -}); +// store.subscribe(() => { +// console.log("Store State: ", store.getState()); +// }); export default store; From 43b2c07e21d027504cdbc1bfa754fc83f2cdfc39 Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Wed, 31 Jul 2024 08:54:58 -0400 Subject: [PATCH 08/14] fetching weather forecast, added Sparklines --- app/components/CityForecast.jsx | 38 +++++++----- app/features/cityList/CityList.jsx | 21 ++++++- app/features/cityList/cityListSlice.js | 82 ++++++++++++++++++-------- package-lock.json | 16 ++++- package.json | 3 +- 5 files changed, 116 insertions(+), 44 deletions(-) diff --git a/app/components/CityForecast.jsx b/app/components/CityForecast.jsx index f2034e5..7c27df6 100644 --- a/app/components/CityForecast.jsx +++ b/app/components/CityForecast.jsx @@ -1,22 +1,19 @@ "use client"; import React from "react"; -import { useRouter } from 'next/navigation' import { useDispatch } from 'react-redux'; +import { useRouter } from 'next/navigation' import { deleteCity } from "../features/cityList/cityListSlice"; -import { fetchForecast } from "../features/cityList/cityListSlice"; +import { Sparklines, SparklinesLine, SparklinesReferenceLine } from "react-sparklines"; -function CityForecast({name, id, lat, lon}) { - const dispatch = useDispatch(); - const router = useRouter(); +function CityForecast({city}, index) { - - dispatch( - fetchForecast({lat, lon}) - ); - ; - + const router = useRouter(); + const dispatch = useDispatch(); + const tempArray = city.weatherArrays.temp; + const pressureArray = city.weatherArrays.pressure; + const humidityArray = city.weatherArrays.humidity; const handleDeleteClick = (id) => { dispatch( @@ -29,16 +26,27 @@ function CityForecast({name, id, lat, lon}) { <>
    • -

      {name}

      +

      {city.name}

      +
    • - ID = {id} lat = {lat} lon = {lon} + + + + + 56 Degrees
    • - + + + +
    • - Humidity + + + +
    diff --git a/app/features/cityList/CityList.jsx b/app/features/cityList/CityList.jsx index ffcf697..7bebf88 100644 --- a/app/features/cityList/CityList.jsx +++ b/app/features/cityList/CityList.jsx @@ -1,13 +1,28 @@ "use client"; -import React from 'react'; +import React, { useEffect } from 'react'; import { useSelector, useDispatch } from "react-redux"; import CityForecast from '@/app/components/CityForecast'; +import { fetchForecast } from './cityListSlice'; const CityList = () => { const cities = useSelector((state) => state.cityList.cityList); const status = useSelector((state) => state.cityList.status); const error = useSelector((state) => state.cityList.error); + const dispatch = useDispatch(); + + useEffect(() => { + + + + cities.forEach((city, index) => { + + dispatch(fetchForecast({lat:city.lat, lon:city.lat, index})); + + }); + + }, [cities.length, dispatch]); + return (
    @@ -19,7 +34,9 @@ const CityList = () => {
    { cities.map((city, index) => ( - + + + )) } diff --git a/app/features/cityList/cityListSlice.js b/app/features/cityList/cityListSlice.js index 0d16158..f76cdb9 100644 --- a/app/features/cityList/cityListSlice.js +++ b/app/features/cityList/cityListSlice.js @@ -12,6 +12,7 @@ export const fetchGeoCodes = createAsyncThunk('newCity/fetchGeoCodes', async (ci id: Math.floor(Math.random() * 90000000) + 10000000, lat: response.data[0].lat, lon: response.data[0].lon, + weatherArrays: {}, }; dispatch( @@ -20,23 +21,53 @@ export const fetchGeoCodes = createAsyncThunk('newCity/fetchGeoCodes', async (ci } ); -export const fetchForecast = createAsyncThunk('cityList/fetchForecast', async ({lat, lon}) => { - console.log("forecast API lat: ",lat ); - console.log("forecast API lon: ",lon ); +export const fetchForecast = createAsyncThunk('city/fetchForecast', async ({lat, lon, index}) => { - const response = await axios.get(`https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&appid=${APIkey}`); + const response = await axios.get(`https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&units=imperial&appid=${APIkey}`); - return response.data.list + let humidityArray = []; + let tempArray = []; + let pressureArray = []; + + for (let i = 0; i < 40; i++) { + humidityArray[i] = response.data.list[i].main.humidity; + tempArray[i] = Math.round(response.data.list[i].main.temp); + pressureArray[i] = response.data.list[i].main.pressure; + }; + + const forecastArrays = { + temp: tempArray, + pressure: pressureArray, + humidity: humidityArray + }; + + return {index , arrays: forecastArrays}; } ); const initialState = { cityList: [ - { name: "Chicago", id: 84658893, lat: 41.8755616, lon: -87.6244212, weather: { - temp: [], pressure: [], humidity: [] - } }, - { name: "Denver", id: 66387769, lat: 39.7392364, lon: -104.984862 }, - { name: "Nashville", id: 31339895, lat: 36.1622767, lon: -86.7742984 }, + { + name: "Chicago", + id: 84658893, + lat: 41.8755616, + lon: -87.6244212, + weatherArrays: [], + }, + { + name: "Denver", + id: 66387769, + lat: 39.7392364, + lon: -104.984862, + weatherArrays: [], + }, + { + name: "Nashville", + id: 31339895, + lat: 36.1622767, + lon: -86.7742984, + weatherArrays: [], + }, ], status: 'idle', @@ -62,29 +93,30 @@ export const cityListSlice = createSlice({ }) .addCase(fetchGeoCodes.fulfilled, (state, action) => { state.status = 'succeeded'; - - //state.cityList.push(action.payload); }) .addCase(fetchGeoCodes.rejected, (state, action) => { state.status = 'failed'; state.error = action.error.message; }) - // .addCase(fetchForecast.pending, (state) => { - // state.status = 'loading'; - // }) - // .addCase(fetchForecast.fulfilled, (state, action) => { - // state.status = 'succeeded'; + .addCase(fetchForecast.pending, (state) => { + state.status = 'loading'; + }) + .addCase(fetchForecast.fulfilled, (state, action) => { + state.status = 'succeeded'; + const { index , arrays} = action.payload; + const cityToUpdate = state.cityList[index]; + if (cityToUpdate) { + cityToUpdate.weatherArrays = arrays + } - // //state.cityList.push(action.payload); - - // }) - // .addCase(fetchForecast.rejected, (state, action) => { - // state.status = 'failed'; - // state.error = action.error.message; - // }); + }) + .addCase(fetchForecast.rejected, (state, action) => { + state.status = 'failed'; + state.error = action.error.message; + }); }, }); export const { addCity, deleteCity } = cityListSlice.actions; -export default cityListSlice.reducer; +export default cityListSlice.reducer; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 87bd05d..b81bcbb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,8 @@ "react": "18.2.0", "react-bootstrap": "^2.10.4", "react-dom": "18.2.0", - "react-redux": "^9.1.2" + "react-redux": "^9.1.2", + "react-sparklines": "^1.7.0" }, "devDependencies": { "@types/node": "^20.14.10", @@ -3091,6 +3092,19 @@ } } }, + "node_modules/react-sparklines": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/react-sparklines/-/react-sparklines-1.7.0.tgz", + "integrity": "sha512-bJFt9K4c5Z0k44G8KtxIhbG+iyxrKjBZhdW6afP+R7EnIq+iKjbWbEFISrf3WKNFsda+C46XAfnX0StS5fbDcg==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.5.10" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", diff --git a/package.json b/package.json index 6bad4e1..e4b8f83 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "react": "18.2.0", "react-bootstrap": "^2.10.4", "react-dom": "18.2.0", - "react-redux": "^9.1.2" + "react-redux": "^9.1.2", + "react-sparklines": "^1.7.0" }, "devDependencies": { "@types/node": "^20.14.10", From 031d2c0fcd8f41facf55421e0fb236fc9025f8bb Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Wed, 31 Jul 2024 15:22:55 -0400 Subject: [PATCH 09/14] added averages, capitalize first letter of city --- app/components/CityForecast.jsx | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/app/components/CityForecast.jsx b/app/components/CityForecast.jsx index 7c27df6..034657c 100644 --- a/app/components/CityForecast.jsx +++ b/app/components/CityForecast.jsx @@ -6,14 +6,27 @@ import { deleteCity } from "../features/cityList/cityListSlice"; import { Sparklines, SparklinesLine, SparklinesReferenceLine } from "react-sparklines"; -function CityForecast({city}, index) { +function CityForecast({city}) { const router = useRouter(); const dispatch = useDispatch(); - const tempArray = city.weatherArrays.temp; + const tempArray = city.weatherArrays.temp; const pressureArray = city.weatherArrays.pressure; const humidityArray = city.weatherArrays.humidity; + const cityName = (city.name).charAt(0).toUpperCase() + (city.name).slice(1); + + const computeAverage = (array) => { + if(!Array.isArray(array) || array.length === 0) { + console.log("Error with array"); + return 0; + } + + let sum = array.reduce((a, b) => a + b, 0); + let avg = (sum / array.length); + console.log(`The sum is: ${sum} and the average is ${avg}`); + return Math.round(avg); + }; const handleDeleteClick = (id) => { dispatch( @@ -26,27 +39,29 @@ function CityForecast({city}, index) { <>
    • -

      {city.name}

      +

      {cityName}

    • - + - 56 Degrees + {computeAverage(tempArray)} F
    • - + + {computeAverage(pressureArray)} hPa
    • - + + {computeAverage(humidityArray)}%
    From 4a9427b2e5b99f5d3c1669900554a1aa9c452525 Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Wed, 31 Jul 2024 15:25:45 -0400 Subject: [PATCH 10/14] clear input form after submitting --- app/components/Search.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/components/Search.jsx b/app/components/Search.jsx index db93c40..8acc04d 100644 --- a/app/components/Search.jsx +++ b/app/components/Search.jsx @@ -12,6 +12,8 @@ const Search = () => { event.preventDefault(); dispatch( fetchGeoCodes(newSearch)); + + setNewSearch(""); }; From a9f9880200e73440dc78308143e658708002e44e Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Thu, 1 Aug 2024 12:04:14 -0400 Subject: [PATCH 11/14] adjusted spacing, cleaned up code --- app/components/CityForecast.jsx | 13 ++++++------- app/components/Search.jsx | 2 ++ app/features/cityList/CityList.jsx | 25 ++++++++++++++++++------- app/globals.css | 6 +++--- app/page.js | 5 ++++- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/app/components/CityForecast.jsx b/app/components/CityForecast.jsx index 034657c..cfb6094 100644 --- a/app/components/CityForecast.jsx +++ b/app/components/CityForecast.jsx @@ -18,13 +18,12 @@ function CityForecast({city}) { const computeAverage = (array) => { if(!Array.isArray(array) || array.length === 0) { - console.log("Error with array"); + console.error("Error with array"); return 0; } let sum = array.reduce((a, b) => a + b, 0); let avg = (sum / array.length); - console.log(`The sum is: ${sum} and the average is ${avg}`); return Math.round(avg); }; @@ -38,25 +37,25 @@ function CityForecast({city}) { return ( <>
      -
    • +
    • {cityName}

      - +
    • -
    • +
    • {computeAverage(tempArray)} F
    • -
    • +
    • {computeAverage(pressureArray)} hPa
    • -
    • +
    • diff --git a/app/components/Search.jsx b/app/components/Search.jsx index 8acc04d..597cc61 100644 --- a/app/components/Search.jsx +++ b/app/components/Search.jsx @@ -19,6 +19,7 @@ const Search = () => { return ( <> +
      +
      ) diff --git a/app/features/cityList/CityList.jsx b/app/features/cityList/CityList.jsx index 7bebf88..bc78ae5 100644 --- a/app/features/cityList/CityList.jsx +++ b/app/features/cityList/CityList.jsx @@ -11,6 +11,7 @@ const CityList = () => { const error = useSelector((state) => state.cityList.error); const dispatch = useDispatch(); + useEffect(() => { @@ -23,17 +24,27 @@ const CityList = () => { }, [cities.length, dispatch]); + const renderCities = () => { + + } + return ( -
      -
      -
      City
      -
      Temperature (F)
      -
      Pressure (hPa)
      -
      Humidity (%)
      +
      +
      +
      <>City
      +
      <>Temperature (F)
      +
      Pressure (hPa)
      +
      <>Humidity (%)
      + + { + !Array.isArray(cities) || cities.length === 0 && ( +

      No cities: Enter a city above to see forecast

      + ) + } { - cities.map((city, index) => ( + cities?.map((city, index) => ( diff --git a/app/globals.css b/app/globals.css index d4f491e..f4bd77c 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,9 +1,9 @@ :root { --max-width: 1100px; --border-radius: 12px; - --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono', - 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro', - 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace; + --font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", + "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", + "Fira Mono", "Droid Sans Mono", "Courier New", monospace; --foreground-rgb: 0, 0, 0; --background-start-rgb: 214, 219, 220; diff --git a/app/page.js b/app/page.js index d8bbc5f..5297dbb 100644 --- a/app/page.js +++ b/app/page.js @@ -10,7 +10,10 @@ export default function Home() { return (
      -

      RTK Weather

      +
      +

      RTK Weather

      +
      +
      From 3938064c167994bba9316b57353b7267c2ed70dd Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Thu, 1 Aug 2024 17:25:14 -0400 Subject: [PATCH 12/14] styling for 'no cities' message --- app/features/cityList/CityList.jsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/features/cityList/CityList.jsx b/app/features/cityList/CityList.jsx index bc78ae5..2c5b62c 100644 --- a/app/features/cityList/CityList.jsx +++ b/app/features/cityList/CityList.jsx @@ -24,10 +24,6 @@ const CityList = () => { }, [cities.length, dispatch]); - const renderCities = () => { - - } - return (
      @@ -40,7 +36,7 @@ const CityList = () => { { !Array.isArray(cities) || cities.length === 0 && ( -

      No cities: Enter a city above to see forecast

      +

      No cities: Enter a city above to see forecast

      ) } { From 2d42d3e089aaf9a2ee04b1d97304c16950288096 Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Fri, 2 Aug 2024 09:53:54 -0400 Subject: [PATCH 13/14] improved layout --- app/components/CityForecast.jsx | 8 ++++---- app/components/Search.jsx | 14 +++++++------- app/page.js | 4 ++-- package-lock.json | 17 +++++++++++++++++ package.json | 1 + 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/app/components/CityForecast.jsx b/app/components/CityForecast.jsx index cfb6094..2c4e53a 100644 --- a/app/components/CityForecast.jsx +++ b/app/components/CityForecast.jsx @@ -39,23 +39,23 @@ function CityForecast({city}) {
      • {cityName}

        - +
      • -
      • +
      • {computeAverage(tempArray)} F
      • -
      • +
      • {computeAverage(pressureArray)} hPa
      • -
      • +
      • diff --git a/app/components/Search.jsx b/app/components/Search.jsx index 597cc61..00fce33 100644 --- a/app/components/Search.jsx +++ b/app/components/Search.jsx @@ -19,18 +19,18 @@ const Search = () => { return ( <> -
        -
        - - +
        -
        +
      ) diff --git a/app/page.js b/app/page.js index 5297dbb..263fe11 100644 --- a/app/page.js +++ b/app/page.js @@ -10,8 +10,8 @@ export default function Home() { return (
      -
      -

      RTK Weather

      +
      +

      RTK Weather

      diff --git a/package-lock.json b/package-lock.json index b81bcbb..22e6b7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "react": "18.2.0", "react-bootstrap": "^2.10.4", "react-dom": "18.2.0", + "react-hook-form": "^7.52.1", "react-redux": "^9.1.2", "react-sparklines": "^1.7.0" }, @@ -3058,6 +3059,22 @@ "react": "^18.2.0" } }, + "node_modules/react-hook-form": { + "version": "7.52.1", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.1.tgz", + "integrity": "sha512-uNKIhaoICJ5KQALYZ4TOaOLElyM+xipord+Ha3crEFhTntdLvWZqVY49Wqd/0GiVCA/f9NjemLeiNPjG7Hpurg==", + "license": "MIT", + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index e4b8f83..a2de278 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "react": "18.2.0", "react-bootstrap": "^2.10.4", "react-dom": "18.2.0", + "react-hook-form": "^7.52.1", "react-redux": "^9.1.2", "react-sparklines": "^1.7.0" }, From 463fffd99b58b06f0ac0ed3980f54674e482e0a2 Mon Sep 17 00:00:00 2001 From: Mark Smyth Date: Fri, 2 Aug 2024 10:38:02 -0400 Subject: [PATCH 14/14] edited README file --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 99d321a..587d4c7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,17 @@ ## Weather Project -This project has been created by a student at Parsity, an online software engineering course. The work in this repository is wholly of the student based on a sample starter project that can be accessed by looking at the repository that this project forks. +This project has been created by Mark Smyth, a student at Parsity, an online software engineering course. The work in this repository is wholly of the student based on a sample starter project that can be accessed by looking at the repository that this project forks. + +This application allows the user to enter a city and it returns a 5 day forecast in the form of sparkline charts. The user can add multiple cities which will create a list of weather forecasts. Individual city forecasts can be deleted by clicking the "Delete" button. If you have any questions about this project or the program in general, visit [parsity.io](https://parsity.io/) or email hello@parsity.io. +Instructions to Run Application + +1. Open terminal +2. Open directory that includes project +3. In terminal, type : "npm install" +4. Once npm is installed, type: "npm run dev" +5. In browser, go to URL provided (usually: http://localhost:3000) + +NOTE: To run this program, a valid API key for OpenWeather is needed. If needed, I will send via Slack.