From c0b9c8b72b807584e4e101acfecb5f0f2c7ffc2a Mon Sep 17 00:00:00 2001 From: nsLittle Date: Wed, 24 Apr 2024 14:27:25 -0400 Subject: [PATCH 1/4] initial commit --- app/favicon.ico | Bin 25931 -> 0 bytes app/globals.css | 106 +---------------- app/layout.js | 20 ++-- app/page.js | 184 +++++++++++++++-------------- app/page.module.css | 229 ------------------------------------ app/store/configureStore.js | 8 ++ app/store/rootReducer.js | 8 ++ app/store/slices/search.js | 46 ++++++++ package-lock.json | 200 ++++++++++++++++++++++++++++++- package.json | 9 +- 10 files changed, 376 insertions(+), 434 deletions(-) delete mode 100644 app/favicon.ico delete mode 100644 app/page.module.css create mode 100644 app/store/configureStore.js create mode 100644 app/store/rootReducer.js create mode 100644 app/store/slices/search.js diff --git a/app/favicon.ico b/app/favicon.ico deleted file mode 100644 index 718d6fea4835ec2d246af9800eddb7ffb276240c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25931 zcmeHv30#a{`}aL_*G&7qml|y<+KVaDM2m#dVr!KsA!#An?kSQM(q<_dDNCpjEux83 zLb9Z^XxbDl(w>%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m diff --git a/app/globals.css b/app/globals.css index d4f491e..cdf802a 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,107 +1,3 @@ -: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; - - --foreground-rgb: 0, 0, 0; - --background-start-rgb: 214, 219, 220; - --background-end-rgb: 255, 255, 255; - - --primary-glow: conic-gradient( - from 180deg at 50% 50%, - #16abff33 0deg, - #0885ff33 55deg, - #54d6ff33 120deg, - #0071ff33 160deg, - transparent 360deg - ); - --secondary-glow: radial-gradient( - rgba(255, 255, 255, 1), - rgba(255, 255, 255, 0) - ); - - --tile-start-rgb: 239, 245, 249; - --tile-end-rgb: 228, 232, 233; - --tile-border: conic-gradient( - #00000080, - #00000040, - #00000030, - #00000020, - #00000010, - #00000010, - #00000080 - ); - - --callout-rgb: 238, 240, 241; - --callout-border-rgb: 172, 175, 176; - --card-rgb: 180, 185, 188; - --card-border-rgb: 131, 134, 135; -} - -@media (prefers-color-scheme: dark) { - :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; - - --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); - --secondary-glow: linear-gradient( - to bottom right, - rgba(1, 65, 255, 0), - rgba(1, 65, 255, 0), - rgba(1, 65, 255, 0.3) - ); - - --tile-start-rgb: 2, 13, 46; - --tile-end-rgb: 2, 5, 19; - --tile-border: conic-gradient( - #ffffff80, - #ffffff40, - #ffffff30, - #ffffff20, - #ffffff10, - #ffffff10, - #ffffff80 - ); - - --callout-rgb: 20, 20, 20; - --callout-border-rgb: 108, 108, 108; - --card-rgb: 100, 100, 100; - --card-border-rgb: 200, 200, 200; - } -} - -* { - box-sizing: border-box; - padding: 0; - margin: 0; -} - -html, body { - max-width: 100vw; - overflow-x: hidden; -} - -body { - color: rgb(var(--foreground-rgb)); - background: linear-gradient( - to bottom, - transparent, - rgb(var(--background-end-rgb)) - ) - rgb(var(--background-start-rgb)); -} - -a { - color: inherit; - text-decoration: none; -} - -@media (prefers-color-scheme: dark) { - html { - color-scheme: dark; - } + background-color: white; } diff --git a/app/layout.js b/app/layout.js index c93f806..71e7584 100644 --- a/app/layout.js +++ b/app/layout.js @@ -1,17 +1,17 @@ +'use client'; +import React from 'react'; +import { Provider } from 'react-redux'; +import store from './store/configureStore'; import './globals.css' -import { Inter } from 'next/font/google' - -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} + + ) -} +}; \ No newline at end of file diff --git a/app/page.js b/app/page.js index f049c39..52afa44 100644 --- a/app/page.js +++ b/app/page.js @@ -1,95 +1,107 @@ -import Image from 'next/image' -import styles from './page.module.css' +'use client'; +import React, { useState} from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { Sparklines, SparklinesLine } from 'react-sparklines'; +import { fetchWeather } from './store/slices/search'; +import { toFormData } from 'axios'; export default function Home() { + const [searchInput, setSearchInput] = useState(''); + const [data, setData] = useState(''); + const dispatch = useDispatch(); + const { city, temperature, pressure, humidity, loading, error } = + useSelector((state) => state.weather); + + const handleSearch = () => { + console.log(searchInput); + if (searchInput.trim() !=='') { + dispatch(fetchWeather(searchInput)) + .then((response) => { + console.log(response.payload); + setData(response.payload); + console.log(toFormData); + }); + } + }; + + const calculateAverage = (dataList, property) => { + if (!dataList || dataList.length === 0) return 0; + const sum = dataList.reduce((acc, item) => acc + item.main[property], 0); + return (sum / dataList.length).toFixed(2); + } + return ( -
-
-

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

- -
+
+

Sparkly Sparkles Weather

+ setSearchInput(e.target.value)} /> +
+ + + {data?.city &&

{data.city.name}

} -
- Next.js Logo -
-
- -

- Docs -> -

-

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

-
+ {data && data.list && data.list.length > 0 && ( + <> +

Temperature

+ {data && data.list && data.list.length > 0 && ( + datum.main.temp)} height={50} dataLabelSettings={{visible:['All']}}> + + + )} - -

- Learn -> -

-

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

-
+ {data && ( +
+
    + {data.list ? data.list.slice(0, 5).map((datum, index) => ( +
  • {datum.main && datum.main.temp}
  • + ), + ) : ''} +
+
    +
  • 5-day average: {calculateAverage(data.list, 'temp')}
  • +
+
+ )} - -

- Templates -> -

-

Explore the Next.js 13 playground.

-
+

Pressure

+ {data?.list && ( + item.main.pressure)} height={50} dataLabelSettings={{visible:['All']}}> + + + )} + {data && ( +
+
    + {data.list && data.list.slice(0, 5).map((item, index) => ( +
  • {item.main && item.main.pressure}
  • + ))} +
+
    +
  • 5-day average: {calculateAverage(data.list, 'pressure')}
  • +
+
+ )} - -

- Deploy -> -

-

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

-
-
+

Humidity

+ {data?.list && ( + item.main.humidity)} height={50} dataLabelSettings={{visible:['All']}}> + + + )} + {data && ( +
+
    + {data.list && data.list.slice(0, 5).map((item, index) => ( +
  • {item.main && item.main.humidity}
  • + ))} +
+
    +
  • 5-day average: {calculateAverage(data.list, 'humidity')}
  • +
+
+ )} + + )}
- ) -} + ); +}; \ No newline at end of file diff --git a/app/page.module.css b/app/page.module.css deleted file mode 100644 index 6676d2c..0000000 --- a/app/page.module.css +++ /dev/null @@ -1,229 +0,0 @@ -.main { - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: center; - padding: 6rem; - min-height: 100vh; -} - -.description { - display: inherit; - justify-content: inherit; - align-items: inherit; - font-size: 0.85rem; - max-width: var(--max-width); - width: 100%; - z-index: 2; - font-family: var(--font-mono); -} - -.description a { - display: flex; - justify-content: center; - align-items: center; - gap: 0.5rem; -} - -.description p { - position: relative; - margin: 0; - padding: 1rem; - background-color: rgba(var(--callout-rgb), 0.5); - border: 1px solid rgba(var(--callout-border-rgb), 0.3); - border-radius: var(--border-radius); -} - -.code { - font-weight: 700; - font-family: var(--font-mono); -} - -.grid { - display: grid; - grid-template-columns: repeat(4, minmax(25%, auto)); - max-width: 100%; - width: var(--max-width); -} - -.card { - padding: 1rem 1.2rem; - border-radius: var(--border-radius); - background: rgba(var(--card-rgb), 0); - border: 1px solid rgba(var(--card-border-rgb), 0); - transition: background 200ms, border 200ms; -} - -.card span { - display: inline-block; - transition: transform 200ms; -} - -.card h2 { - font-weight: 600; - margin-bottom: 0.7rem; -} - -.card p { - margin: 0; - opacity: 0.6; - font-size: 0.9rem; - line-height: 1.5; - max-width: 30ch; -} - -.center { - display: flex; - justify-content: center; - align-items: center; - position: relative; - padding: 4rem 0; -} - -.center::before { - background: var(--secondary-glow); - border-radius: 50%; - width: 480px; - height: 360px; - margin-left: -400px; -} - -.center::after { - background: var(--primary-glow); - width: 240px; - height: 180px; - z-index: -1; -} - -.center::before, -.center::after { - content: ''; - left: 50%; - position: absolute; - filter: blur(45px); - transform: translateZ(0); -} - -.logo { - position: relative; -} -/* Enable hover only on non-touch devices */ -@media (hover: hover) and (pointer: fine) { - .card:hover { - background: rgba(var(--card-rgb), 0.1); - border: 1px solid rgba(var(--card-border-rgb), 0.15); - } - - .card:hover span { - transform: translateX(4px); - } -} - -@media (prefers-reduced-motion) { - .card:hover span { - transform: none; - } -} - -/* Mobile */ -@media (max-width: 700px) { - .content { - padding: 4rem; - } - - .grid { - grid-template-columns: 1fr; - margin-bottom: 120px; - max-width: 320px; - text-align: center; - } - - .card { - padding: 1rem 2.5rem; - } - - .card h2 { - margin-bottom: 0.5rem; - } - - .center { - padding: 8rem 0 6rem; - } - - .center::before { - transform: none; - height: 300px; - } - - .description { - font-size: 0.8rem; - } - - .description a { - padding: 1rem; - } - - .description p, - .description div { - display: flex; - justify-content: center; - position: fixed; - width: 100%; - } - - .description p { - align-items: center; - inset: 0 0 auto; - padding: 2rem 1rem 1.4rem; - border-radius: 0; - border: none; - border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25); - background: linear-gradient( - to bottom, - rgba(var(--background-start-rgb), 1), - rgba(var(--callout-rgb), 0.5) - ); - background-clip: padding-box; - backdrop-filter: blur(24px); - } - - .description div { - align-items: flex-end; - pointer-events: none; - inset: auto 0 0; - padding: 2rem; - height: 200px; - background: linear-gradient( - to bottom, - transparent 0%, - rgb(var(--background-end-rgb)) 40% - ); - z-index: 1; - } -} - -/* Tablet and Smaller Desktop */ -@media (min-width: 701px) and (max-width: 1120px) { - .grid { - grid-template-columns: repeat(2, 50%); - } -} - -@media (prefers-color-scheme: dark) { - .vercelLogo { - filter: invert(1); - } - - .logo { - filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70); - } -} - -@keyframes rotate { - from { - transform: rotate(360deg); - } - to { - transform: rotate(0deg); - } -} diff --git a/app/store/configureStore.js b/app/store/configureStore.js new file mode 100644 index 0000000..2d9387f --- /dev/null +++ b/app/store/configureStore.js @@ -0,0 +1,8 @@ +import { configureStore } from "@reduxjs/toolkit"; +import rootReducer from "./rootReducer"; + +const store = configureStore({ + reducer: rootReducer, +}); + +export default store; \ No newline at end of file diff --git a/app/store/rootReducer.js b/app/store/rootReducer.js new file mode 100644 index 0000000..fa7de40 --- /dev/null +++ b/app/store/rootReducer.js @@ -0,0 +1,8 @@ +import { combineReducers } from "@reduxjs/toolkit"; +import weatherReducer from "./slices/search"; + +const rootReducer = combineReducers({ + weather: weatherReducer +}); + +export default rootReducer; \ No newline at end of file diff --git a/app/store/slices/search.js b/app/store/slices/search.js new file mode 100644 index 0000000..b70c8a3 --- /dev/null +++ b/app/store/slices/search.js @@ -0,0 +1,46 @@ +import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; +import axios from "axios"; + +export const fetchWeather = createAsyncThunk( + 'weather/fetchWeatherData', + async (city, thunkAPI) => { + try { + const response = await axios.get(`https://api.openweathermap.org/data/2.5/forecast?q=${city}&appid=1a8c344b0aaddd77f2a53a70916ddc5b&units=imperial`); + return response.data; + } catch (error) { + return thunkAPI.rejectWithValue(error.response.data); + } + } +); + +export const weatherSlice = createSlice({ + name: 'weather', + initialState: { + city: '', + weatherData: null, + loading: false, + error: null + }, + reducers: {}, + extraReducers: (builder) => { + builder + .addCase(fetchWeather.pending, (state) => { + state.loading = true; + state.error = null; + }) + .addCase(fetchWeather.fulfilled, (state, action) => { + state.loading = false; + state.weatherData = action.payload; + }) + .addCase(fetchWeather.rejected, (state, action) => { + state.loading = false; + state.error = action.payload; + }); + }, +}); + +export const selectWeatherData = (state) => state.weather.weatherData; +export const selectWeatherLoading = (state) => state.weather.loading; +export const selectWeatherError = (state) => state.weather.error; + +export default weatherSlice.reducer; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 90f6bb1..3bedf17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,16 @@ "name": "parsity_rtk_weather", "version": "0.1.0", "dependencies": { + "@reduxjs/toolkit": "^2.2.3", + "axios": "^1.6.8", "eslint": "8.50.0", "eslint-config-next": "13.5.3", "next": "13.5.3", - "react": "18.2.0", - "react-dom": "18.2.0" + "react": "^18.2.0", + "react-dom": "18.2.0", + "react-redux": "^9.1.1", + "react-sparklines": "^1.7.0", + "redux-thunk": "^3.1.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -296,6 +301,29 @@ "node": ">= 8" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.3.tgz", + "integrity": "sha512-76dll9EnJXg4EVcI5YNxZA/9hSAmZsFqzMmNRHvIlzw2WS/twfcVX3ysYrWGJMClwEmChQFC4yRq74tn6fdzRA==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.0.1" + }, + "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", @@ -314,6 +342,11 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "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==" + }, "node_modules/@typescript-eslint/parser": { "version": "6.7.3", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.3.tgz", @@ -615,6 +648,11 @@ "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==" + }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -634,6 +672,16 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "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", @@ -753,6 +801,17 @@ "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==", + "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", @@ -826,6 +885,14 @@ "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==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -1491,6 +1558,25 @@ "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" + } + ], + "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", @@ -1499,6 +1585,19 @@ "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==", + "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", @@ -1759,6 +1858,15 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.4.tgz", + "integrity": "sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==", + "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", @@ -2270,6 +2378,25 @@ "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==", + "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==", + "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", @@ -2628,6 +2755,11 @@ "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==" + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -2683,6 +2815,57 @@ "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.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.1.tgz", + "integrity": "sha512-5ynfGDzxxsoV73+4czQM56qF43vsmgJsO22rmAvU5tZT2z5Xow/A2uhhxwXuGTxgdReF3zcp7A80gma2onRs1A==", + "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", + "react-native": ">=0.69", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "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==", + "dependencies": { + "prop-types": "^15.5.10" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "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==" + }, + "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==", + "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", @@ -2723,6 +2906,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/reselect": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz", + "integrity": "sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg==" + }, "node_modules/resolve": { "version": "1.22.6", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", @@ -3225,6 +3413,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", diff --git a/package.json b/package.json index 6ca0f8f..203072c 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,15 @@ "lint": "next lint" }, "dependencies": { + "@reduxjs/toolkit": "^2.2.3", + "axios": "^1.6.8", "eslint": "8.50.0", "eslint-config-next": "13.5.3", "next": "13.5.3", - "react": "18.2.0", - "react-dom": "18.2.0" + "react": "^18.2.0", + "react-dom": "18.2.0", + "react-redux": "^9.1.1", + "react-sparklines": "^1.7.0", + "redux-thunk": "^3.1.0" } } From b979b194695eb7d45f1ded8be09cfe8a6f085f30 Mon Sep 17 00:00:00 2001 From: nsLittle Date: Fri, 17 May 2024 06:27:15 -0400 Subject: [PATCH 2/4] Still need to allow user to add other cities while maintaining previous city data --- README.md | 36 +++++++++++++++++++++++++++++++++++- app/page.js | 37 ++++++++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 99d321a..404477b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,40 @@ ## 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 was created by Mutsumi Hata, a student at Parsity, an online software engineering program. The work in this repository is wholly of the student based on a sample starter project that can be accessed by looking at the original repository from which this project forks. If you have any questions about this project or the program in general, visit [parsity.io](https://parsity.io/) or email hello@parsity.io. +### Project Description + +This simple Redux application builds upon my knowledge of React. I used React's ability to manage components in separate, and more manageble files. I then added Redux's ability to make state management more predictable and scalable. This application also uses React's Sparkline feature to create a line graph of the 5-day temperature, air pressure, and humidity forecasts. + +The application allows a user to input the name of a city and returns a 5-day forecast for temperatutre, air pressure and humidity. Along with the daily average, the application returns a 5-day average, along with a line graph of the returned data. + +I would like to become more familiar with customizing SparkLine charts. + +### Table of Contents + +RTK-Weather + +- store + - slices + - search.js + - configureStore.js + - rootReducer.js + - globals.css + - layout.js + - page.js + - README.md + +### How to Run Application + +1. Open terminal +2. Locate file: rtk-weather +3. Type: npm run dev +4. Type: open http://localhost:3000 (or other appropriate host) + +### Things to Add/Edit + +1. Fix sizing issue with SparklineLines chart +2. Clear input field onClick +3. Allow user to input a second city while maintaining first city to remain diff --git a/app/page.js b/app/page.js index 52afa44..654be21 100644 --- a/app/page.js +++ b/app/page.js @@ -3,7 +3,6 @@ import React, { useState} from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { Sparklines, SparklinesLine } from 'react-sparklines'; import { fetchWeather } from './store/slices/search'; -import { toFormData } from 'axios'; export default function Home() { const [searchInput, setSearchInput] = useState(''); @@ -14,12 +13,23 @@ export default function Home() { const handleSearch = () => { console.log(searchInput); + if (searchInput.trim() == '') { + alert('Error! You must enter a ciry name.'); + return; + } + if (searchInput.trim() !=='') { dispatch(fetchWeather(searchInput)) .then((response) => { console.log(response.payload); + + if(response.payload.cod == '404') { + alert('Error! You did not enter a correctly spelled city.'); + } else if(response.payload === ' ') { + alert('Error! You must enter a city name.') + } else { setData(response.payload); - console.log(toFormData); + } }); } }; @@ -28,7 +38,7 @@ export default function Home() { if (!dataList || dataList.length === 0) return 0; const sum = dataList.reduce((acc, item) => acc + item.main[property], 0); return (sum / dataList.length).toFixed(2); - } + }; return (
@@ -44,11 +54,12 @@ export default function Home() { <>

Temperature

{data && data.list && data.list.length > 0 && ( - datum.main.temp)} height={50} dataLabelSettings={{visible:['All']}}> - - +
+ datum.main.temp)} height={50} dataLabelSettings={{visible:['All']}}> + + +
)} - {data && (
    @@ -65,9 +76,11 @@ export default function Home() {

    Pressure

    {data?.list && ( +
    item.main.pressure)} height={50} dataLabelSettings={{visible:['All']}}> +
    )} {data && (
    @@ -84,10 +97,12 @@ export default function Home() {

    Humidity

    {data?.list && ( - item.main.humidity)} height={50} dataLabelSettings={{visible:['All']}}> - - - )} +
    + item.main.humidity)} height={50} dataLabelSettings={{visible:['All']}}> + + +
    + )} {data && (
      From ad9f17c971f21b282d57d9999d2dde185f8a6e08 Mon Sep 17 00:00:00 2001 From: nsLittle Date: Sun, 19 May 2024 06:24:58 -0400 Subject: [PATCH 3/4] changes made based on eval suggestions --- README.md | 5 +- app/page.js | 158 +++++++++++++++++++++++----------------------------- 2 files changed, 73 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 404477b..bff3a4b 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,5 @@ RTK-Weather ### Things to Add/Edit -1. Fix sizing issue with SparklineLines chart -2. Clear input field onClick -3. Allow user to input a second city while maintaining first city to remain +1. Clear input field onClick +2. Tighen visuals diff --git a/app/page.js b/app/page.js index 654be21..f139570 100644 --- a/app/page.js +++ b/app/page.js @@ -1,37 +1,31 @@ 'use client'; -import React, { useState} from 'react'; -import { useSelector, useDispatch } from 'react-redux'; +import React, { useState } from 'react'; +import { useDispatch } from 'react-redux'; import { Sparklines, SparklinesLine } from 'react-sparklines'; import { fetchWeather } from './store/slices/search'; export default function Home() { const [searchInput, setSearchInput] = useState(''); - const [data, setData] = useState(''); + const [searchResults, setSearchResults] = useState([]); // <-- Change 1: Using searchResults to store data const dispatch = useDispatch(); - const { city, temperature, pressure, humidity, loading, error } = - useSelector((state) => state.weather); const handleSearch = () => { - console.log(searchInput); - if (searchInput.trim() == '') { - alert('Error! You must enter a ciry name.'); + if (searchInput.trim() === '') { + alert('Error! You must enter a city name.'); return; } - if (searchInput.trim() !=='') { - dispatch(fetchWeather(searchInput)) - .then((response) => { - console.log(response.payload); - - if(response.payload.cod == '404') { + dispatch(fetchWeather(searchInput)) + .then((response) => { + if (response.payload.cod === '404') { alert('Error! You did not enter a correctly spelled city.'); - } else if(response.payload === ' ') { - alert('Error! You must enter a city name.') } else { - setData(response.payload); + setSearchResults((prevResults) => [ + ...prevResults, + { city: searchInput, data: response.payload } // <-- Change 2: Storing new search result + ]); } - }); - } + }); }; const calculateAverage = (dataList, property) => { @@ -47,76 +41,66 @@ export default function Home() {
      - {data?.city &&

      {data.city.name}

      } - + {searchResults.map((result, index) => ( // <-- Change 3: Iterating over searchResults +
      +

      {result.city}

      - {data && data.list && data.list.length > 0 && ( - <> -

      Temperature

      - {data && data.list && data.list.length > 0 && ( -
      - datum.main.temp)} height={50} dataLabelSettings={{visible:['All']}}> - - -
      - )} - {data && ( -
      -
        - {data.list ? data.list.slice(0, 5).map((datum, index) => ( -
      • {datum.main && datum.main.temp}
      • - ), - ) : ''} -
      -
        -
      • 5-day average: {calculateAverage(data.list, 'temp')}
      • -
      -
      - )} + {result.data && result.data.list && result.data.list.length > 0 && ( + <> +

      Temperature

      +
      + datum.main.temp)} height={50}> + + +
      +
      +
        + {result.data.list.slice(0, 5).map((datum, index) => ( +
      • {datum.main && datum.main.temp}
      • + ))} +
      +
        +
      • 5-day average: {calculateAverage(result.data.list, 'temp')}
      • +
      +
      -

      Pressure

      - {data?.list && ( -
      - item.main.pressure)} height={50} dataLabelSettings={{visible:['All']}}> - - -
      - )} - {data && ( -
      -
        - {data.list && data.list.slice(0, 5).map((item, index) => ( -
      • {item.main && item.main.pressure}
      • - ))} -
      -
        -
      • 5-day average: {calculateAverage(data.list, 'pressure')}
      • -
      -
      - )} +

      Pressure

      +
      + item.main.pressure)} height={50}> + + +
      +
      +
        + {result.data.list.slice(0, 5).map((item, index) => ( +
      • {item.main && item.main.pressure}
      • + ))} +
      +
        +
      • 5-day average: {calculateAverage(result.data.list, 'pressure')}
      • +
      +
      -

      Humidity

      - {data?.list && ( -
      - item.main.humidity)} height={50} dataLabelSettings={{visible:['All']}}> - - -
      - )} - {data && ( -
      -
        - {data.list && data.list.slice(0, 5).map((item, index) => ( -
      • {item.main && item.main.humidity}
      • - ))} -
      -
        -
      • 5-day average: {calculateAverage(data.list, 'humidity')}
      • -
      -
      - )} - - )} +

      Humidity

      +
      + item.main.humidity)} height={50}> + + +
      +
      +
        + {result.data.list.slice(0, 5).map((item, index) => ( +
      • {item.main && item.main.humidity}
      • + ))} +
      +
        +
      • 5-day average: {calculateAverage(result.data.list, 'humidity')}
      • +
      +
      + + )} +
      + ))}
- ); + ); }; \ No newline at end of file From 3a5581f085d9776ab1466538067ab4f3dff1c047 Mon Sep 17 00:00:00 2001 From: nsLittle Date: Thu, 23 May 2024 09:54:04 -0400 Subject: [PATCH 4/4] committing for second round of evaluation --- README.md | 2 +- app/page.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bff3a4b..d0cbe4a 100644 --- a/README.md +++ b/README.md @@ -36,4 +36,4 @@ RTK-Weather ### Things to Add/Edit 1. Clear input field onClick -2. Tighen visuals +2. Cleaner visual - each city result should be on one line diff --git a/app/page.js b/app/page.js index f139570..36ec413 100644 --- a/app/page.js +++ b/app/page.js @@ -6,11 +6,11 @@ import { fetchWeather } from './store/slices/search'; export default function Home() { const [searchInput, setSearchInput] = useState(''); - const [searchResults, setSearchResults] = useState([]); // <-- Change 1: Using searchResults to store data + const [searchResults, setSearchResults] = useState([]); const dispatch = useDispatch(); const handleSearch = () => { - if (searchInput.trim() === '') { + if (searchInput.trim() === ''){ alert('Error! You must enter a city name.'); return; } @@ -22,7 +22,7 @@ export default function Home() { } else { setSearchResults((prevResults) => [ ...prevResults, - { city: searchInput, data: response.payload } // <-- Change 2: Storing new search result + { city: searchInput, data: response.payload } ]); } }); @@ -41,7 +41,7 @@ export default function Home() {
- {searchResults.map((result, index) => ( // <-- Change 3: Iterating over searchResults + {searchResults.map((result, index) => (

{result.city}