From 3d67617616f5155076b85770b4482fb5148f22f9 Mon Sep 17 00:00:00 2001 From: Arnold Kocsis Date: Sat, 27 Nov 2021 14:51:30 +0000 Subject: [PATCH] working on comments --- api/database.db | Bin 217088 -> 217088 bytes api/databaseBACKUP.db | Bin 118784 -> 0 bytes ...seBACKUPNEW2.db => databaseBACKUP22-11.db} | Bin 217088 -> 217088 bytes api/databaseBACKUPNEW.db | Bin 217088 -> 0 bytes api/models.py | 6 +- api/views.py | 193 +++++++++--------- flask-react/src/components/Account.js | 57 ++---- flask-react/src/components/AddReview.js | 52 ++--- flask-react/src/components/AllMovies.js | 32 +-- flask-react/src/components/Categories.js | 46 ++--- flask-react/src/components/HomePage.js | 31 +-- flask-react/src/components/Login.js | 39 ++-- flask-react/src/components/MovieForm.js | 49 ----- flask-react/src/components/MoviePage.js | 36 ++-- .../src/components/MoviePageReviews.js | 32 +-- flask-react/src/components/Movies.js | 16 +- .../src/components/MoviesRecommended.js | 14 +- flask-react/src/components/MyReviews.js | 36 ++-- flask-react/src/components/NavBar.js | 43 ++-- flask-react/src/components/Recommended.js | 35 ++-- flask-react/src/components/Register.js | 51 ++--- flask-react/src/components/Reviews.js | 45 ++-- flask-react/src/components/SearchResults.js | 2 +- 23 files changed, 328 insertions(+), 487 deletions(-) delete mode 100644 api/databaseBACKUP.db rename api/{databaseBACKUPNEW2.db => databaseBACKUP22-11.db} (76%) delete mode 100644 api/databaseBACKUPNEW.db delete mode 100644 flask-react/src/components/MovieForm.js diff --git a/api/database.db b/api/database.db index 62b6344ca02d63671cb90205b4bdd8604606f5aa..b00bd15e489507ff125511b244bd3ed8409043b5 100644 GIT binary patch delta 879 zcmYjPOKTHR6rPzROeSMFv*lVH>nXZ zwM7ape2}G-_6KB9iBNFmPEc@B5JVTnpWw!|ccu-KS$uPbIp=$vd)Ifz)_2F=o)I_R zP0ocjgiDiqAF5l$xOy@ZI4|BWJuH_Nm#&v8*UGmSv@x|K#1$jh3tv4Kg9F%&SP={j zY&kq+2KGc%?A|aB96@44C!b^Zz7!+mQ~QY!zQ(JcE;n);#0C@ zdb~}BSe+n)ILwz%OnGe>Psq}-e1p^r+K{M>-2X}k$JE6-mmzJ^^h`4TRYc_#R7T5o z%c}DCn%#Aan%O3ZOXiTnbn5tAOUbaiix*r>4KA#jRYDuwyy>7uhsS8!Eow4?>V(?J zXdSt2*lm*>E7WyPY!IH=vCLYX@tQG0eSwL=_nWVS-Pq^>xOG0|g}i|$WyxLIa1E$# zQ)*LWABj=oQ{@ugNC~IZz%8>`<(kVn?RdU)Wbk-~P0eP_pUA{zK@r6w&d8xVqj~so znsyU;N&NN*{1f6Z-;?iN7=I2=fWitq1`8fR1?C6ixf9UKWrJ5VEff&NnHd+Sr(H~^ zT}-81oSJeGAs3TL7ZV8=Y2LpNin`cH+)!xrHnOGRM1^5bo;0Jt$zpxE`*yoO4 X0z?B?^f}ed{?1l^N8Io4NR_?+0@d7T delta 217 zcmV;~04D!{pbdba4UiiFT#+0@1zZ3wFgmehhd&((5-bBL0a8U)Nkvy*L`76VNla55 z4GVby6AH}&lL$a21PZJQtg}%ddI|&!c>p1iK^?QrN{<8qr;(wf2MQ1N022?2lLt^L z0fe&=Fj5Z&51ar7005JUUwRV<4*~-ZKM&gvx(^=@n-6>s0uPfhpiZ-3Ae|1g0&fBl z0|yV-vj>374+an300s#Olh}_e6bBEi01wI!;Sbdhzz^{ctPi&jx3dv2j1LG4YiVI} TY+(q4te=Ohp8>b5p8`~{UQ$4S diff --git a/api/databaseBACKUP.db b/api/databaseBACKUP.db deleted file mode 100644 index f309ea8bf783cdc97304e858a182e7fec31b2f5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118784 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 Z>i|Tc!t9FG7s3vrg%)B@AaS}s|38e12eSYG diff --git a/api/databaseBACKUPNEW2.db b/api/databaseBACKUP22-11.db similarity index 76% rename from api/databaseBACKUPNEW2.db rename to api/databaseBACKUP22-11.db index 52e932199fa7a47462025170a40c6de48e950d6e..62b6344ca02d63671cb90205b4bdd8604606f5aa 100644 GIT binary patch delta 3994 zcmb_fdvp`mnZFN7GozWg*AHwV+p=eHC?y#5FphC4OHAxg)_@aZ;;=jwTeg+Rk|WC) zLmGn=wva=4bOLjF^1_4!(in&1ipdR$u#%?p^DUB}x|v9={)NuQP6S6%|(Z-5O$^Od^9!#$iJTqqC z?LlLks{#{a*!7YvDsNkvzDw{-pN`W##$wTj1tTIpHnqwvO}jS{jW>i-k!ezE1LQ@4z(`5HaCdDK&eZwfx$e7T$f&L&lZH1 zHQ%+QaeYH$YyFa?E5y3=KjefpHxp@X`fit}X}ZDXsm8y#)uPbK6^$*EqVC#s+jXlY zSjtMWMC5HW(j0Z^T-L z)dqWYO7;5C4STbT*lDadA?Y%I6*wxllsr;H_B}sK+7YG-DkAAYvo}e8W?eM#_o=i~ zB?|JBjMsd(m|U< z%nbO+G*Vt}w))9ILpVItQbjIII ztf4Z?3>UiO6g0lQOuM)^#6LAgUsD@87O zT+VZU|g za!?D$J2V)^VuM;=dpJ3$!>B#c(-VRDXlh7HB|u~_5szr8ZrBuy-WTc9x)aG{BB}Kx zHbx_T!MaJ8)Btj#(o*nCk}7mzc_O8Swa#$-nlFB@y@(riLhED6XjgY?LP?c2kVvMw zL3|*bYVZDP!%%QuK`zXdx?6CxO!(Q^ACC`C?&}66;QLojU-RZ$`MI6_y6mP)QlPjG z)ZY_LX^BpF=tzdU=4j1v*qbv6!D`V?Z7|WVb%!@XvM!ZxPG+ z8`Vpk&NdtCa9kS-w?me6ZSnuf*gynScSK@QuoCIeuLWJB+DfE5b#bCzCSaPQH6-FQ zau}o{xfoN?p2&6E*c2o~)!V+I5}h&%7p8kknm`#Ps{DpTDv0#D7`oihT>Rrtuh;ip1wegzfshY|mjU*x~%zvbunTl^J%hQG*9^5gs{Kfw3$hxsA? z7$4_<bjN$=*3=9Hk{#CqFLyYR zw?eOPSstuz>J9hxLECi94TSuGIye-9b(PqODl7EsVxANV20^IW7OKvng^IjBbYC=_ zjD;u7_ykZsrc@L3%357;P=sfSq& zoTgQ(vH4g_K>?i3OIo$ty2HJxNK$JZNMzqW_B$+!vd&zu%)x5%>t=ukjE0J5W6T&PTY#t!#c^7cY}1 z02bZUiziSOY;$&Q-Nu=rTSElwVQycqP!V54KBX_RPVp1xpV5#Ib*xn-`3$b-)#4oW zS?3IQgX;)!?HgY9LNA`Bnp3Zkmz_V7tzU1krkqw1%8A$y#^0Pm#TjIti~5ykFl%JF7K!> z@m=Zxb%=S`Mb^g-sTcSnc7Ttnud{zt|HRtaDfSw_m)*evVES(UBop{teu=gO!Ea+xr4>1I=9>vz3wd&)ozY z&H6EN)VerE0Gh!(1^H~TT`&E{+AvO@q2f4_pA_23_~`IyBJP~xQqU@rG2dK-Kem2! z8$LqCI;VmvNSd3`#rS*H7mM*BDz0-VXa-3yG>Wz@$BZko^%i4WcSkE$FE21UhFslGnMeknN+x1Au0{D2FCBW`Fc* z_CG&5NW}bf&j_{T z@aXUX03&azUF{j4d6dvUSbHdanu;+`&W6)mPz#kP&V#_kw&Gmwmzc-r;}h1pZ$j=* z9mI}+NL&|?yw!C9oc@hV+F4$i`@jgAU6=4B>(`6vaVma$TCNSZm^+&2S*vX+eU_g3 z9d_hFaEFk5Kqw`LMu#7P;5O)iK+dt_nMY z=~dBjc@(p*lv?X09ZB@E%-MUHB+O5mZ zv-2W;X8SyyzkBXE-}wxlo>Qjhl(Xf<4VrB)uh_SMHc^J2l@6XTQduyL>id|BMTZZoePTdegBdhvKQD zLr+H2@!=!UyczWe)_dR#C%U~}JlnkLjMUE`D)>k5`R#l03kBa)-Y4E%Wp7@0VPx%n z5y{YOt~RNk`>fFD(R;;LHR@Y?(C-uNIs9Fad9#BVmmV;V3lA7K1!g#%6^0?^IwddK z=HBPUXduxS&k8zxb_oD1LfOalR?%Hsi?f~juKWagcBiR@juYEx~QX?5Azg)`%W9H0gfB=b&6f51D#NLudEn?QPb9EfKvjpQ1`CUmMXIz-Zz( zNAzIc`;??^sd4@S9qOnpG3AyLlz*sB%MP1%SdqbYnQF*8te0V)gXX)bM$E<44|hO5a2rT|)HF z0ON1yMF^e-D8cK->lS4z?&Rw5Dw@{7eZ_bsaf>wfn_f$3E9~n&~CbU?hPm3Sx9Y_Nt^;$nbHZ-A)#Cwy&!*K{5N{&FvL^2WA(n)PR zmhSEMHF*7gZ@?Gu?Z$TGaNw+?n%^}NkEOL?6I`egOKGv8AuZh>*J8ctfn>tGX1kUe zO&y6RQl_2mhxCDzmWapu;(ZVLBVJz<)bux)yAbJ(ySuPf0SGV9bC-+r8@TEHqKb+T zqJN~<=_36$JpsHOqnQmh8!!irrs5-w*47(Kc^gm%#YPhT;GpGgaB()^4(eM&9uKhr zMNl8GXK)RBJUAc9PdNDh=yS9jK|8;vzXrm5LK*DnJM zDV7#?T3Sf9v_{F&8XT4uv|Cz0v~#X}6~S1(*ivHRl?NlwT@$anSXJk-x_zdifK{Qj zPv|m)U!pB$xjaxdiSytBI=sx4l&irja3CsI<5)5Ll8^jKS$uEmeVn_}OiGNa znTJ&K?+Zr^L<~`p^@aIa!tN}Q<2?KN56KwMW`0JpyoBXfko*c+7K01(58+bvRpcUi z8?JO$R_ z@&U9Fm6I6}S9+>zPUF2m-LBCSPk0nmN%Va<_o7U$u!9xc97kbHih7AYfh)^{ji=dj zggeiF6Z3X+5AdpB&K9zj;__TqE4eP2uwbY!AAnAJWOlNIyJV&_{xR||Ws$u8Q=I!r z6fk`Ejr*NuG7*DFz9a@Ay-t))B-{$}kQp1!wdC-12K&DwGGUqwlH66D>|^lQt|(#| zB4iTD&yz`cY+-(wFeyha@<0#%42lrlgN@hzeu*70$je-A`~?zV&wq>T=Pw+@a%=-! zT5dKDQVb%4RDs+F;sV(SQVpVkctD&WW}_;IiAE`iIeH1mCJ^`qg(^WzZaP3jm}G;( zGQ)V52v|Oa23hzj5UgO2Gg9wnZD?I``&ZU`Okm8^Z)<(&;Kue{E8FXW;F;s z5u2w{J5%X&>SLyvN~KEpoWW-Vp9A>(2|hV|I{(t0FMrA3QmS{=&0co*As?s_J^uy}n~9{S9^P zGxA#g|K583aOvkBxiC0;eQsuH&Rm)~e`U@*-2Q#Ap8bxh_siXPZK?OkhYOlIncwlV z>HigV5n7{goOLH$>m|L2;bY*eN$>FUP*!r9K!NGyUj&*q8 z(!$c*^K;kDg{w>E!i_6e%xl*#&CguFX45ESWbJE`9vQ+$0{1 zo!GSx4=m07&v>Zw;Kt9P?b;&34GTBs=dNFx?cT#@Ejy}&P9t^#|1T*)#ExHkw011O z3sxNaitX3p`a=cq*NTYkS`aqh?5AMG4zJaNIC$vCO)YDPn*CjFaRa}0;o(LM9viHu z{>#XX6X}%WTlQ`AB7}pNL=p$`{G~^_^`$e9Tsn#}{^)xu$LorD0yD&)p z`(}`HYiIjM=8wKro42ssOJ}y69zD1Ap|}6+=`GLxz`3c6|;2_2Nd`wx0K|_x(tI zINE-TLEUiD;n>Y*@YYKZhuug zut4?01pwBgKR$Q$`rM`G7l^_i?7aDyd42A=x$AQavvZ5);mtg9_=CjqV<>dXbDidF zeQ*m~wx1k4R{ZJI%G({u-<~oe`{l&;E0kzBgLF=FTS)NGk012Wgh||bER{+x6AaD`qEBYmrus)-oO+Xy zIYR*bUM8zkk4!XA;Z>>csf2zNokGUL= z*({HlOg1|(P%wTkl{NlJ%J^6C0Qe`y&-Y;Sbd@y)GzByTGzByTGzByTGzByTGzByT zGzByTdYl3VwDTWKKe}6B*L?P9ddn7=BRfBkeJZ_qUq&C=zH4Cf{-WKJ*<|)ZeLo=#~uxSe4G9!8J_^}<@5#!WMO`kY<>csTP>66CI)c=%D z=RZA>&3tTF(d<%eu8PPk+cEAplMl(7ywtaY4QNeFWV6}D7!h$y*YRyx7h#s2*enMj>Mmc7Gu9E|ahj@~ zlV%i{xGE}jXT`Q;jcb8$OH*gm3#QJU$)UCb>5orjGB4s;)l(@zTh(xncQ=U z?k@focyq?CjI~O#&2)( z|2JO6ss5)apedj!pedj!pedj!pedj!pedj!pedj!pefJ;6rhKHKF?!+KaX$e|IfDU zlnpv$`~_kFd;>86zh(Rhb_4t$#xEiw;D5l*fL}LWGkz2C0bl7fy!9i+;ndTaH9I{% zGIc67vD(+#(`af?yT0J>k;qg$BSt6x+fxlLng? z#R2}J01Nh@I_V?KW{`l~tAU4?uhwA#i_9u&1Or%L!XA`_ur1*Ud|7c;gxe)*!UsZ8 zQ8f85+B74LN$AFQ``Gx6Gf9iq>hN%CG_yXC9v_=HlA2i&u?X|O^MY7LU$)=g5TR(e z=#t7L_@UwA73e!uD_#W)Nb{6!E{NAY|D_cNB&iEn_E6nxuu}%1P&P5M5`+z$Az6jz zL^NuZ%o)jHYzwFl6CbQ#m5SY9Z+j;Af>t!eF-~X(t3E7ccshZ}(y}X#1%lRL{ggFv zgQjp}2SvD!YX52S#B;)rMbs3sRgxRzH`Vgb3=OBwWY*JY`S_vK5}5KCaG$Ms;Kd+x zt^6yzihhhy8Q4c@m@{t$7!Y=oyhcU~bbAe$5Vp1W(wa(KZHF6SwNXMo6+Fdbxvk;|=&0he4CW zlVn_=arL?_TrVnRr|RaJO*Dwn650Rwt46`_;Be|_X5C1SjU7LcdI3xa9-R#nC$jSo zE`%lXiUZr`#UO!U6t%E@*NH#~zDPJ0U%!f5E8w_gRv=n-8njVA7Ycvbd@*pV80;7w z;3Tv@Hn(GVsw{=CGB2nOm1Bh#$ZG1e;h7Lh)}Yy?qEs4as+tFUX6YgT>PxT$k!-4c-3 zb?p!YleL8z8DCjd)z|8(>hFmi!>Oy8^#U4*{$7+z2{g)c)Ucy$uoqs6=fQ&Eat8rH zYbSt(-o?m@&^sP1>Rf?fJFA3kD{3>okgE%5LWCP>xW`>AEv~b-XdVaX)g6me!i%m8 zFYo~x5he+6+fto_N`h{*tbR0|DhCYMtgh;K3xVu;kH_aRZMbUrKwuh4uoQwyVb}mp zz%%7$DT5(!nmE{@l3YFk zbJcY8R8@E!9s&aq?MCY~bHYxB#PoPw~44_%booTU>m}Kez^l^qF3W%mEmSof@ag z$egnzEw12A;AzkYvl{?Tj(0S01H7@!0glIf83E-39|ct;hp0LO+R^>CY?+)7Fo|ML zjN-&&N)50Ki4Kmu0}_&>%4oLb;6%-na+VaXgrF|Ogn_V1xefvG9F0)bPJ>%klmEgBc8A%v$B339$t0Jmf^ohYi)E90dXsWQ^q>EMQ?4 zKxMnb84NCmwUVVgA!{ilLvzS&26cc|7|YQhSJ6P|HqJ{no+gra+hMV0odM48stI^0D3 z5{wXc9FL;bQOs`WAQ_p{_HB>gfF8Y?#E4MtN^Zxn#0z;pSroNE!VU@Kd?xWRu7db>X$kVDXs}&Ns{sbA%ww#b}ylQM=@#m1}AO%*P>btGEwp+Ylr9wW-UD17ADP~-2Kjg>#nbri*j#BH!@ zOCg+b0v}QV2P%reTmTUVF94O)Trc5O{)Wj4C!7c=%PDx2vkdS6SGj!1-4*qa$noye?@0<_TY=Y?gS51POq6m|t7a{i4Aww#H^K z#B~hc$eaOmKo0B*lX5h-ML<5cOsPiJijz4A>;)iWXkLm$*>>goB`CB>-%)`CO9a3*~enbvd&>1~xf<;;-eGfMXF8rGXQkF=wDhfL-TqW6qZNn}2l) zTsebWDdivr+dysw#&Yo$w}tXzmsd>4z#x}7+bm=14FeyyQxH{ikfZ^o0!Rop!{?i` zmu7%k;2W$&1JL~T)F{lbL!>gsV%$^(bf-de2?+!^0rb~uSUKmk3DpenEBlVrvINC5 z(2KoYx7~&!)0r-vfK}aQOUT%CF6jgS=X~0T5)YV<85Qt_x!bd$&;TPL;ltvqP-7%h|((93s3*pi1UVPUP@SvPh?a zn@yWjh=)1_ssVTvVaP7|4#KWx{~I z&bQOK&bL$9&bR5zj_k+)@00QWx&FTq|DXQ<#%~zEX8elrOYi{r1>>8>-!Z;weA)OJ z<0p+T8b4}$*0^nihHF$2G2oNNlCfZ1G|n3zH9lmVd@qwm*G*GEQ$SNdQ$SNdQ$SNd zQ$SNdQ$SNdQ$SPT?Nflh^hb{Hc=#}n6B9g|CXa^>@p$kckK^M!KKUe%V`DrXIKboR zD3AO1^EfiX;}cKtxNjeid-w9VXAh6Nck{Sw7mqu4@@N=57K=O<3Oo)E^EfobT4%A;16iw@(Lsr>20Uz`aA8y`=7^wU?CinceI)rM;x+6ori+ z?}nFD(r_$nL4jWtJn!I13D0YvzGn0%LoF(a+Ys~)gI8YFffpj3WbKf@dI3Dt>2wY^ zGHg$v1FiHvOT3bHaqHpEySF1-*l_o~pMKx_`)Y3PVQ$u)*TbE6&&U)uJniqNwX40Y zg(EE-Y5)JX7EPS)@lZ88lKPmn~@rR3_#p=INTs6L0 z_-948@LR>j;$JU*#rSCP!^Mf>zcC!+rwR{@iQ=CbuN1#-lnY-gKCN|PO#w{-O#w{- zO#w{-O#w{-O#w{-O#w}TM=7u`dm?=y@Q=ob3x)^=2zwSJ?vXv&r`uQ0Gr~I}3QQlS z+x91HKkz07v!m%*1UEp0``yUpwt#5va^L=91K$qq$nHx|otrv)(8wN1UlSDv3moQk z#~UBYj-?r#U?K6JJdv%WRiKO*zn({gu^7<|`0H$ls6R3W$MXoqfT%UA!nMZu^2G)g zMh*;T$J2<>VqOSp(ddEfIb6o#N_c!;_|G89lgHR5*xbLLmAr-!Qg%2}$R0`~QhgIq zb$sgy{;+^R2v&1ne|A@TUhFMqC(;)Yg3H3@{II!aCsNoU`jmx;`=PlI#Jky|>p|e{ z;=6D7MZbH&l@+4NF3VA-aCYz4kvg(n-{pFIPDJQ}ZSXczM8 zZ3$#G$cBgB^%YHlcbNirSBr&>;F9+r9^sFD zbVQ-%Xm#kGrp zw+!MDZI0g;Scu&yg9WxDK*oq-IN8a%1Oaj*n3xJDXyOJ0RlVcjDX*y_KAwhvCd1rT zAwDsf6aVTJIK2X=SKzj71@7*rcNS9Pne{yYou`i8@2WZZSFZ$&IQB_|P()xc-(g6( z8;j;uw~3gF6~>T6KsaU&LjYg~v1P>D27-w(w6Yi3E<iLVR420& z8WtJN(n6eF23w?F7x)NA%0PTJqHR~<2&V#vLXWFJA*(XRGQ*xR=pW(?`*DKkhfTyl ztU(DyTvp~FgTtM}h}ANB@hXC{GKlUJqv%T1Nt6aBBTsg|YxL3RqtR#E(1-eedgxoJ zp>Jh=DSzr+*7P2u*A;&eg5%np6deEQOSD<#e_sWXl~H7gpJkh&FA-wX0%#(1H-tt& zF@k&oGF=&;A5p4h3}}I%rk2kT!GQD^5I2~Z%b2Dx!!ZOdAQsmF|C1Canb82SZ6g?U zg8`p`^MPMQL}eLKn2%Co1ssTMbN2>I_CLS7F&zjx#RzayPT z{Xf(Ho2j8y9P~d;0Zjo-0Zjo-f!?LSy@@@A)I?@|QD$eozsbQc|Ax%TN=qtjqjLR< z*`wMSqmYA@i3i21z*_%|?>op~%6sccRE8N9K_q0NCKyz^Nt2iW%ws-JWu6V9NUi0! zllw9CEp4-wgDkX2ZigTfHnJ)4QXM72l&h?=H6#?QPQvb3aTA%{P`&_95dQaSJHJ zw0nqh(_k(#E;b?O8Zs>+QEwBceo!GKF~c=c3zw0VI)LAjge{pSQ!PDp(or&d^9mi4 zu#P2h$Ds#;Lr(zdH_mGc`Q-Z2DJGHYq)vrHlhq7Dh=R5N#U}N&P>6 zBsKIiIOusbW#oj7v8y@fIV;9`QL+Q@&649Bnn zRD}Z}n7Y1QWn%7*4=%GR!;80V5LiW;U=s<>AwD}0rI8IBa`7@GKw1QFTa=WO5XJ^L z^m@oI4WC_~Dc6-zK_-Fsuql+@WR$gKs$`1rQff!8VseId{^1HRYh19Oh`T!tjbnJe5UgTe2 zOpsmPhvO%A69=g>4y4wWESt-8wRL z#HcBpWS1?W<8%CAEgq%gaN&f-2E$~+{xP z-TMovbD8yVoE|+!x#!Kor{(|PnoSAj8iI)6Pg!8+ex)sQxK0)O@1f=U2#^N90K`m# zEP@UGQKcRPt{KG%MI$o(#}i09(MGHi=^_NZJWvACaR^A}Mg?F$06Y<+Hi8Gx4*N)twz7M=%_p~nN*7u}UCEfN*pETnqMfbFIfQ{jSfs}w^qbL|%B|VyIRtGozZ6=?rNFP8!3%k3dPHl=4>6ooXpEj7jE!~PCPer#f*GM#w4i-IFBMdq7CoSptBl{ zc)DSLcs7ay{6zs!;nmvu77yEwMY1YGwBUZo)ifFM34B>`R)my~d0tN- z(PD|cVwVbPo_GP)fUZ#!t8k*>f(jLS(jq2TN3f4qLG`x4y&zuu{Fhc7^g~^gofuWW z2GRtfkddCzydZ4g3=X~R;DRM{1KmIx8CpD$Sqm zpn-r}YQ*fl^8Iy@j&*gVL) zjL?X3MG&kZXqZ)RH7`J!G3TV=Lz+bJdc}fradIZAVVtojTm;J?Fb>jk3LlG?K>{7d z77f0W8cO0;xnYAfMcz(_mfI@7#bMCwcqK0&^o>qh!QSTe6TFza6A z!e)%pY#-qj(IEDkfTah;tRmhbBBWK8Sx~g>F#L}BTqyiy1W9wNSWyL^(YV9qO$%g{ z56^hw4$9-wDk>EUFRG&ma9TMK^xFt(Hr|0aJ~(2X)D|IJGhk9id+>h+0|a5#q9W5yhwuW+R2w!bB5lOqos6S}+N7&hRvtX48~*Kk^b%= z=XC*xcMJu@*+d{YMkoij(VixvW%Z-!RLRKbHyY(Zhg$)j!#&8~iXOh*a09u5Ab>|m z@CuqB4mo0K`sjpmv$UgiD!1mOXAtQe9AKL-!hxqv5%zG~V@HPEjAKv$&zG@k(2URw zhm5J#4#0__jg3PVUy98(CG!T^wc-ZID~oGUgI&X&L#SE%C14b~(Ql6L2^XLc+B@)* zZ?tdI`sW70GH#<&j~Yl`DX&H(tOLRipg+5K1MG>hQzIxw<{WH^pd`W}KySx5zzl|c zM~ZJzs|_T;wk0fo06`-_239&;keMB$UId%~)oodwD!Yxi)1ZODE4#QWks}g=^bXq1 z7s}lN4o)^06yf9LQ0fkqFc4O$ztx{xGr-AS0thQ3xK){fK{;Rc2m0AjA$zTYI)aR%kcZjY^v__6iC2fDL5 zCO3cvIPMN)+$TK8yaszaAnbzOVF}qE99RzcR!-$J^Yd3(jj|l^8!VT^ zb?|Fs&d}Cm1>LEb1HChW^0{SBE3#HZVNj;MC-71v%C;-tCwn?7LH`|leB@je|L=!V zSRc{TK`Xf4{6u(uRV`VMRpjQn{u(q zDE`vW0o`7zWHPmfvR&PQ2~GW$K%JCs_S|6@Qo^@t9JMsU#to^@a%*#>R~-BkeW+ zsz8_(SSKoFnP`qH{|{Z#>;JR~z#1IdFm9n6U>U=OmB59Cj#l0k8*ZeC?u`zwKuJyD z3>(0(1@l4zQ%4Oxv8E5}8?1Fg$NvMhe3%R-&6k-v!-t6rMm1Q|ki!Bg2BpQ5wDKx} z=?W|p@Fpj6Oc;7#Xv0Gd+-%ykc6nZ41@y#=?3WXoaxbt*L93M$asfbgL$7yUXZ^qM z$HhN2#*Keh`1Qg!3O`*uRQ&hFmEu>8UpCGaf7bX1g;$Dq3;(THD}Jl^tAkx!c4;^{%v|x%c~$zZiDGslU4iq8O73bhQM`|Q zU#GED4#yM}a%ea^o}M~4b(SXw`FlfDoT^g^VZ6bmah8C>{Y384cyc6rD*cebhPRFJ zwcY)#2aN2IH2j1*yU#|MvVO~MkNqsR0go(1g23Y=ya5gwP59&ZvR+T{hK(RJ`v$Y4 zX%!)2FDr>AZHi*MhnGNvP4Ogmvt6AmX1jJ~pGtS~OY(g?`D-WTt?@*5DvgkrA?#wl za%ki|MHUJ#khXgvFBMoRu_9vlAK`SErNnTB|o1ndOO(6M1IZlciazq!>xoq41B1c4Pkk=5Ui6I z`goTYga}={93aoI++Lhx%^gJiK~gz8lx&gZePv<6y(T&>9V+o~W>5C`0Gw?6NE!L$ zdsY0uQ>me^<#qPI_aoNmHfsuK3TO&w3cOtk-1SFfJitCAdu1qrYf`SsKTuxyQ`5>- zlM4eX8}=j}A-Slwd8=+U2x9E*<(^$QSkEEKw{5C|uolG48CYCnST49GHrlaCPjPxgb`W=B#I7m&6?Wr!meihk_d&xL(CiMA{PR zyFC*l*Z>ymO-rgE*!Dt~b!;IpFI_5`7g3yg2K$GwI|Y8~NLdmApTa0XdDtBByxh`n z-Z;+9FOf@FClAe>0xZ4{-4eKN^0nD;mA=`a7_J-c_E$Re$Y?Ogy5 zuUKwA*ASy2MnlZDK};ckAeG5{IyLlnGoKz>d1qBWUAm^gCJNkpaz`O`RpkNT?1qhK zh-bT~++(=#MfWFyBcxG8nhBTlulIV$A(;i|!_eBhIRYN?2-@r+q-RDwGwPXf+h)d8 zD)$oz*Nv!aIVKhR7o;PxIV(Mh^AFxET;<)RJW~Q9VBy#(Qv%+I@~`(+=)xQ!s=H#L z+@6z2BaucTjYQjqL~VU+6o2>NGltKT`0T=G2%iCb7$RUFK2P8?fscs~?;pm8?gK@9 z41D(DvlE})`0U5$06ydR9K`1kK6!lfKTQEm0Zjo-0Zjo-0Zjo-0Zjo-0ZoDTD+Rb0 zealXNX%0Ek2>{U9>MySz=5}@UyFJ=v!>?e>?~4soA8xBJVpgS=y7 zzrVaT&Qf3%#)f}+{^b7bnTL1$%OA%0_Ki%|2e>u8z2{&4KFVF_-A(`U(teh`X$RQ| zZ`r!>;|boP_WjF8_6=pnu<>7h-^=Q5?EIJ4_VC)q)_-|zHyg>l|MF}XV+(XP|H~^o z`8#+2%QJ%^4YqFom)DCdd1L>-yjEcCQ~&^ZKFpFB0YIJ&v6nW70FYM)`Ti|t_5t4a z$im(ZwzO^j%9Ai#U3U9B#n4$$7Tm{T9`T&XvDzD(|K*)o-nn`Azr32+n?12*`@g)Z z;{X46YUsz`uR~C`TT?(&KvO_dKvO_dKvO_dKvQ6QC~)`XCkv^u%z7T1g&0_52|h*( ziJ$*=+wD=M)`O;IBIY|nl)HhzlN6D8Q)MI(fq>~NPK=21NFboxE}5G#Vp2*b8DMc$WM6d=oqiRe1rP&W zW?;p}e<(cWClFs9A=T))xsj6)iR`c$;M9k@>;6jDWH2-JO==-}3waN3A=jPP!=0z% z|K(Cc|4Tjx)Z*rd2=QC*hsPQ@Dj*%D*W7()0!uTQMMdLc|=$U`5 zRbx1{FM}-K<0IpTQqRFalz$bmP9B4V-_jZMG$2<-bLs@X?3%z@KT;e{J)J>H@bQtU zQ>mGDEKGAzX7|p&+DnPTrBfLDj0|>~ z|DE2>TF&;LCQr1tA1Vv3!>a~aTW z6Ae0XYrEF#wc)|x4HwkZ+wef`sf6i-z_S}Hu-QycM%a8leJ@uiYybk}?(P_QA0mR5 z=6YC~)1BADop(1JmT^VZTzo(MKAMa*-}W%y>dx!o&MOS9WB>mbQkgI0$MIGF(-e63 zDR6J!cp-Hpvwjwa?_*ChqPEOQVqSN={3|oCG@I}=LJHe>)wX@Jp1{Vv>>xZJ($<lG-|M(6MwQ4~B!(DAI`C5DwCdn2AhfYlY4V zE;Gq3)Q1|vX$R#faBbMckwvBA!1}#v3nb8`xm_SuA+CnBnA=snCZ_c}5-5Qd@l_c= zR|eeXDV{ILZsP(o8gp>zTuQbM2uWM4q*zph!NSpZaX2?>sEkWfD?%#w}LW9K@cK2G@nJLXn27FY3jD8qWMR$ z-DvP-p;N0feKg;IN(c+^B|PNsu9x~4lZycY6ykJpKy{r%wG`LGQk?F*9_~B@8u<)u z@Z;@#BC`MntVKOgf6Wgr1)g~^KqfffI%YyVsm8#D5Em=BXai5IFlZpdhs2f8YXWC1 z#PA1XTnfd@$Aw>kZ5#4U;4?Q!6KO~&7XgOC#5Ubv1+D>eo`c^$IO~W|nCC;W5*#a; z=b03}isgfLMiK%{SC*kbCjAJmEiGO^J^+*{^OL{>JQQxEFvtp%T2$(TDR#P>1z;mR z-6r34&A&a&zq<2!xbwKszc)RfGH$2mv;VmGhs6&SqT#O(y)yJn?o*i`$h#S8*LKRv(y}o;-Q- zWXZhHRX-u}At@9yJpqlOs|NJoqQ4iX1*UCr{0iN=@Tp3%GIGi;UMhc&@MPVgG)a{h zTD4SRJD^@V()ws_?bGS=xZg5Ypb8_2q`82+Q|gaJ1>7^y2f4d;gm!fHe#k2 zh`&u+gq#@g0;G)zTqw;*LL8g-Z zmL!a?rX@B2(;EceF!7gB52?zBrNgcH946PtWjZxmPv_QdlFMTBR&0iX9ESO~8p7E@ zrr{A#1XgIM0PElf%*WIRV75R;QiuQvm<_53RhIw;4cIQEDZ@*ohJi$3cFDX!3kMk> zw2?L_f{Z|_Z+Rudi$&ls_!UAnQPO}^O~Ab<5UPe%I@J1P4rZOl(uOnMn#-*h(w9L7 zsBdjrM@hA+6hA2{Sx%eAG%7h5_Ay}rSCux$p+?@GK7~%Aq-ECv=#mM zWEGnq74p^{AQdnSFte-#SQ0Es%1KxTgUft;1W=z^w(JZgAA15MZKEnsR(7)jV2l@} z+5Rim)o+dduM@+X0&; zvU;H^f?_`2xa!=2!usrg!qzq$;UvBFs3<@7wpy8M6^}F zH%tnzef~?**1!yfjWDPJ83H8snsI>>=7q##l0b0MBrT%Liihg9D{ZAf-v+5#8f#7E z;7-;{j$_5vb2-Fcd$Uk$J>}>!*t(p9590;Q%5e80|IUNukhx|RS>oj6IWNKry7D}d zO4@O3-UJnz3=iakU5n2xI~a_zR`6RV|9i^#btw{M+m-K=a2S;`tz)^h8|e#T z#j%hMv$7l{cVrvpFu7rRzkmjYs4!+Dh)NAKr)k#U4-ZopMh%eDgWo&S1({{121Mq- zCSt;AT}llc{&IwKRBTx8g!zF}Cr_fr$cu*>Ls-JdPvqdz@Z zV56i&2uj-6M%=p5<-NjWUW>19H8h30I^pAf5%+`Cx1*L;0|8J>&YTc#c6a!hK)rM>{1RYtP4FZ ziH*dawiF7+Gs|ueSgMhbKIFaym^^{EuzsROtX zXi&Vq{@j{@%6JLHZ>Hrf+Z80@ z#Z(@OMgtIm(M+fm9a!${+UblQweX2?sZ4YLK8b0#Es}CZHF2xNT^3S@=B02Q(HAgy zAwOc>5{sUtKI;F)zDp_NQ^lXp|6JjB3x(k;{UbwPAN<|HJ^lZ7;Nv@L_)-7U6wnmV z6wnlSYYMckaa_g5mx&G7nZt& z)+UM(A5UPEg&o;}m4c5(30MdcJ#2!sIUR@1$y{te+zpSC^2@xTQVH5T%$8nqTkj9xEubW_$PmTA=tR%orb;Sc!(+iCsWGQZ`2@-6Vnw zM;6eED;c;E8aVIb56Xr~g$Vw2?UeyA<#hoCRI2{SfYVmGa62dlFBtiw>2Sw6$Sh5l zP^vnH3y(|<9CU-WgH2~6dmUbYu+Bl)EjLR$lwIWU*wAUTj^x%ZrEioLOXh-DX_~X1 z1**-#q61m}awynvY71Rwq`-vHmmZQZ8+&%^|IG@9vo! zBFl^oEP?B0k~qL{r+*jB$Z{VgQ7x1gyM_g6nZ**!Y_klTZ7A`HHuuEmGL@Y6xgZ5@ z#k`7H|I!TXATTnR0gU^J-yS7ct?5|O%8&(M(vk&qM@1XO;F1cDjap4&EoB0Dc>x03 zgRu)zv@_5?TT*8IMfi9C&e#qQ>yEB{9L8oy1IpS10F{v(%o;ps8*E{Bv4Lg`>Yg&J z1Yxj@ku9xFWvuJLeiA`lC5KoL8DLlD7!H8TlC|24$)TiAG4wXe#p% z7DFo1Zq1iSpA>)y?QeEi+N)R!6CfPsz-&wh))9sRSbgS{4=_9sq&qK}7dWq^E>v;T zYNr=qpdeaBBqc2r#AU9InF*F1ppZ>FlG3JOK!Rl(b11Ff=qfITVO>$&K|@G!Y0cuO zQnoXW0$A#$2EJh)4TM$dZyn67J)3^dX6nqT{r@AWp`Xf+ytQzvf6)}s6wnmV6wnlS zUr^xg9aHYb)jqk6DDfc5LfOIs9n?C{hDi!yAAH1%6_BCxs z?_Alooh#ZWw}*Xl?>dJHsbd*9`Kj%Y3s}yV>&J@?e9OPu8?JxMb-ZcA5jI;|r{Pv& zTioKfai+I8(wr6cFuQ83>EX_!{+}NDLJI%uf0_cC0-6Gv0-6Gv0-6Gv0-6Gv0`CR| z?%tj#q((CE9~&P#G;u%u3EL06{A-ViGZ|wYO`pVez;-xZnZk}n0Qp7h|62dohT?5A z6wCGh{@+XW|K8AFeK(*^ze7_%Q$SNdQ$SPT9j3tD&mAr>&B>>+jCTCQ{q%*vKN=&t z6?VYE4RJdEphx4GFtx)e=J&V=w?{btW4m%EPc)_K&F5OU*21+GuD4CNzGogOq)uek zr_$r&C#E_Gw8YpX!dwgzH~#=@`Hxw!D6acYp8`BB)kAFWu_ZvoXtRjW;toP}FKCF; z5Tzk%+aOA>|G&dhs4iYpKvO_dKvO_dKvO_dKvO_d;9&~fy**Ue$VGc!ZlQl)C8O0Y zSpu%yp51vCXT1vCXT1>S!YxR)O+q>g3~BYtd*?gK9* zh^vSoPGN!w(D?^FA2>b>x7@QEUb(kq^D44+T%_B4uGi@F8l7IF+qN~jyEg|4sdE_w zFCQO2ca-J<#FUkxP9+s1Dizpj3I|4Dzk#cz`W_jY6% ztOnUxRIr*$OXh4Hsc#U>6XC=2ud4((J)X0LTi8x>PE#(o4svjmINRnuH^u(TogCT^1G+2t}uvf18r^ z=5vim8j&<2Z66{XN*7X><;H%ANK1%g9w9L4m$(I(_5_kB1NQI5EMaY4UjJ5RV5B@;E-uI55EDjvYMa^E~$V^VrwNV=l*IHp^oslg$ncNd3QXCsp{h;y*9`q46&Z-z@xO z;ZEUCioa0&;o@hZ{Tszq#R&)!$Ra`9o_2O5Ij}|{%oGAVq!!drU@W7ZT{+aPg z@#{vp@U`O8k3|>jMraCX3TO&w3TO&w3TO&w3TO&w3TO)a|4e~>*%R%Mw3`A#9@&$9 z`r$yehX=AFDka3kV0JV;TerioY3|M*OK(jKd1yy=UwZ1?)Y*eZ_DK4gs5n)pVqSN= z@uBRP+%&R~_)nh5R?;dFLyTX~+aikLibB7W*$`VZB6_4eA3DBeyGUtojq&A+4J39w zFq|DvzbHcULQsoF4`k2bvSZod@p<7tV_pnAyAr_Tqqd)wye3@uxQrCChtki7cC#KN zzV!ruSP062)!f&g-IbmfdyCnL^hGpL%Xs^w{G+sWJ5`vM>pIIJe9qgUaX+v<|1C@fOc_UGO#5*I;JdgSWx&;GW175u(wHv%&CDNUzfr92_;%leR3rb% z+`{m8hW=4{+Bmi2P~ZN+GyOl8{`2o|7_>f?ThFF1Ch(v(!8j4ARTYjaX=mA0+qcZR z>7AnfqDJdjDo;7qd0VyQKT?&4{Fvf(hdCD@yPMWVn}Zsike;8 z*P6|(52P0pIBNO+Bp-1s%e9Z=N6TCdJi&{u8?3UpS{Nh^`A*yRaYrcI*$`peB$Hq$ zn`IH%9&1ugVpJOyLiLeg8Dqjhnq}5MNNT7PYF!1F`4$QeZ6sR;Q{#;e8YNp~*q!JETgdYqu%+lPOQ3#q_(u_VItf*wZV<`ZquQzmku4fM7?_q*tzyul z$({`skkm#w*j$SjJ0XbX*wsmPk(*c~ynMTS6)V<#T^SWMtF9Bmf3CJch$sOLVDu-U za7%ky7jx@-(rOn1$+T))vdju<-~~RQriy-Q0-#WY>OH>1w^vbt4Qk z3tm@o8X!Jv4Jn_hMUV4rM9>xwO0 zHh{H@oXWBpI&mT}BHFB~s8`zEn#irqwOi7(1y~6;lx;p*w_VGuU`v9tqH5)vP828x ziLm|7EaSE2vSaz80pd)WF9fO{Y$~ul2JK~cz91^glNbc#RrZS=p;Xx~WXY=ID^_K% z*MvejbXYY+THnAc?NY?P5@3t8`AOm7RcI&2$c;tws@wD$m~!9@$TniO2r<+H7gNZj z*+^V8xHItMI))8cUYHG6U?5jQ5!Fd;l4uc6;`J{EA==FODDXjh)U|Azu3bfn@>t%7 zL0gf%D_OyoWCyK%(iRU?DgO)w)3L>!a4q|<`9;{YhUX31zx<<{)< z92##*AjB)kkdkwVHq|ij4r_jvl>;u>zvnx7q!+UqQxajs*a=T|@O{H30yXSi-g^!q6eNk*9cj-iLaCMN(k7=VTB^TMn&%RyL^<#BW(?6i+3tF|Y=J<+ULKt;-Fo1QFi#wYamS! z3Yh{N%?rW?&Hz7c4l9`(=muVw{3R+CyFmhb!75-Ib@vi*Qk!!yx1vRo z`ax5;F=ZLou}j0PXLIZ6G-jX>lmrV0YK{`-Ey6se8qkBYHaK-2bqLvBP_yHJ4j2DCt1}&mCYd z@S9At6nI{HX5o-g;!2w%fKA{C2q6?J9N;uMl*|FNw;|5p4CArx$k`dg;kv-|jG+Lq z1t1e9!EF>+M6|4aG@U9LdDX!bCmHEhfah?JM-T)4xRA<$+5&i#_#8=)qyVfwCeL!S zw4-$@x8|g0py>$0=Zla++kD1pu`RSv)KaL5=P`|XP0rg68MErt00iJf93uRRmqL{( znK#I;6^K751%TH8)L|k}R8TL8aN|QD4;Tv*44JlYcN>D533*`|w^1@x!`Cb2)rh3{zwyX|CXTmB_GKv$g?4mk}9FZ8LchGKjq?BzOoG3|(FbMT=ndG;CII^R|Kv<>z zR)22I04IA1APgIqFfBlFWCsEq8;Xn^--42s6pW>a3n*{POsF{~LDosu%oFl0Lh=DY zWHU(A(bchJq8cb3gHUbUDD|}t=GLA~&(F`WAEo#@8(@OCDJ4M&b)3h6c5^78zO@9f zFeDjNf;|o?235gpqnLEqG)04@AsMQ^yP80Ap}>MCz>at!?`OwCp`-K#8B@|I@qyoA zWS4TS7joECtDwEdx6fvkH1&9FzJvaI;_;Dl)%yQWrwV^u{8MAx_;-b0FMOl$)5Sx@ ze_vcFe%1J8<6QA)jek&hrFggS--@;3w~D`NIK>;qv&Nut51#*DDeg2TjXx^>mhsub zFBRv$KihzQT2nw%KvO_dKvO_dKvO_dKvO_dKvUp-M**(pGL36DNg{(L9NC*aF0XD* z_Ij9W#jxvR@ddX`a6P>O<5k$?sq_)>u{3iUHYgaTaOn^i(&;0>lY?AHZYVzito`%S zI7^_FE%AB!C57p1cRsP`t}E(dr&7SlqQ52ddF@87{@CX!}({*Fhnwx!$y z_eiP{0-wy;qMjCz3)bU@5^iB zEJZ2&^887<#y_O-%OA%0cB%5q(*smZ+d99zFiQQotMtoD`&qWq`sMiuZ|SQ2^3oH$ zMd|(Wd>^+ectU>P%j#}u{_@%$UfWRp<+a^xBz1pzwu`ofj`APc{T&;CyfVQ1Hmm;f>JGLviRAY@ z3Ded5<)!{kF;xBKl|B};S@)M$bFB7;@-MH+-2j`le|a^tH+y1>`Y*3C|6evUlN$Qr z{$Il%{ZCWid!vAk|NqeF)9FxqI323)ydLg69sgg)|2GBQik*-v9XASZBB3tuV80E;;E<|*zrh;8F zCB$pz-U>UxmIyd)n?a=_>F7Y{r^`|Lw_s(Qs!5_H`Pzytts%{puoK+`U|O>8EjP@A3c6dWyqcFc+$LO zppE>4-rYu*o2r{=Lz~mJ&=h!c z3f#RpP)ME2AQIB}__?+?{b*p${2T9$I7!**x;b?Y)8G;!skyF=Kr(N(HK=n{&xCp= z)HC6>&4l-!+)+qf%^+VQ;+S(G431;cK$)nr>o$~$Jq_RXY(d$ zniV&nYqO#@D{8aiwwV=`{{O|)P_zHPXTJE(YI(YJO@X(jz}?U&r1oWyb!~iv;y5#W z=3hnrn#UjmoAd-YjS2BWC_K@LMB0r>qGh=rmgRKk^>F9iT`d+;PiK%FaeQRz6bz4B zvkB*4?WLrNa)FKZMu{?8V;oWJ-g-p~-dgb1g7>xw-uH5aLh5V=$*{*pk39|RV>k5p zrkv#+7b7H%>%9!9gd;i^&B*kJ8==(*MH^=thBORm7}_=%>iYk$<FR6T~3Q#?8sQ4^h9Fz4Oas3qsW&rV zhe!mx3h+Jdid7`@4Z;diV5?lNOg)PTO$|nfk{Mf(4;C|74SC}cjx(q*?>NP2nb;g| zvSt(@pyh{uj*_W z*obw?X>;RDPn&w$)YIm+O`CTw?xL}BZLV#sypHh0`QKLn)I`o{Ij+k#M||Bz+UJUB z#7OKc!NfP6C~yHSmWjmWGO4&QmmSMz`s;Agd;vMJnM#^igs5=L4voCzxGpNolO{4M zi5ilo2Z$1fQkgy-q3Z&_ifrF9TQ(o9A@?_baFE6vS-dUeMUnwSD2_|xKqpmFH*B)D zV)d{UOLtxmci!Dk?<}OorA#xz5Fs~I;<7OR>XiWQ0Olu=Y#wndePvj*R>Ra}*;Pbw?#^#e{Ogz@ ztHN_I6Rje`vl*`jn6(^CP?5>(Da$}tJjmOkq@09h;bXG&Y|M7H={vQ0OdTGx8f^!j zi0hoWI6XRkMaFMds(loP&N7M=kiS{8c9Cx2*N#Vy$5lg!`XT1R65Vc3aTTtk!f&KC z-IVA=i)=kCvgyw2;m*5T+slo#+-o$>jkNP3|N3HLn=?LiY>aQmvRwPPlxkN4Xxq5x zx&bVN!mL4@Zb*QzZEE3A^8o}j7Sb*#751`-lp0=65E|YGdH`!EXgdsq9T9A#NKS~U zh7QmS1w*Q~l|f+D0Rl<*v1~EPZ%qY2mJ?Ni6$sYSLK&jImAZfi0MshUZTt+k)j=GU zIk}xiNi%B?Gpp{r9`3w*6MG7&iOl+9dx`&IH;Z}x4H-IwW0^KPsYoM25b{7^#D_o> zpd6SO@nTpDYk;KcB!wS0kt-d+ZVEHk#fhRoLj!P~Kz76ntNOoM{yG4AAL z@kGrRV0Y)`M3l@M$lb!EDZ;|U%`Y%aIl`M{nw1E7SRl72$ft4}HY^93Suh2g%;w@% z0#!0^aw3Osl0`ZV+-%wcQ?};?R=}w{vhgaY2^U!8^nA*=ou1GBlcMJ)@O>MAwc)w%=hg(!!$Vk{0*c~zn%lvg%f%uI_L0D16_sY!soJF@t&ir`KAk>~`z?$x%r~gRLI8bP{;@F1 z0?$MvU^_<3&_K2ZRpF{Sr~$cExTabc1K8oI?h05%lpVihUWCmV>tkpw1>nw7ea#77 zHTR%sSh}IlbJdLUaeH2qgz-^tz8?)JW9iJakW*JDQJP zFQ5b4lsA!36{L&sc23@5Qp2>~dOEjulUx>KX)lJ+fgFYhs@Pl5Sx!XDL2 z$khc^eL6b$pdqLQJhn=QTA$3VpH0u;WwMQBJ6@G6l7M%X$xf7F;G#hmN?@ZQ^s<|= z(g0?Fjz!{9F9RpR%3?MgH(;VHJjfLgGz7LA42y@NMj4Okle^LTLIyElFkWbl5N|l5W3=M&BC`TfiLWdSJ@!5lQP?C2}pT+=d--XrXX6Zm{HV0+6 zw?l0Vw?3AGD{T*(4fnM^l3Q!0pU13#K%wUI;33O)R|S}li+2*H!SBdZ2l$k@#3eT8 z4)#Z>-xACa(n5gjbH^biIp9;^F(JNWUZRK@f#W%n7wpy8M0i6CK``NKpZ^m0r#-sD zpbBINu#!0A0w*Bzcx4y<10f#6Xj)c01eXRm&VarRFqKytYfa^_hhh$c{}GIn*4FO$ zA<(sTi1s$6#fHw?abOBRy)Y!Li zD@-UA+oD|sMV0NEqevw%3@d7Ecp^mVK7f)OZMaL$X~ouaIqbjg`K{K2t;;#=nY#dR zgP%30(0N#@%`3rb2-^{xJTJluy7D~c96OH9TLI`#WSfVe?3mXA7a|G-37WB}j7om! zz+`L-&zzZ`ze-pwOI(vu44)5^xbAWunV}$H1zijTuF{ScMHIL3+%i>LSt~3lvzyv# z?xjeSZCAce!eLa(w2tN0Zlo`W6=XrYhV|_rxg*;!hsh1o`vp$us4!+Dh)NAKr)gp( z83-;gYJi-cK--Z?vFt!AmFoetpusmrN)22UmkR^ZF$dG1Q}Z!t2=fD{PM$=Kk%SR7 zhOor7bzm%|0=9Ifvn!~^0p^oRrP0niWtX2_t&6$!J?$#WxvW>+B6qi5$gPjG zTQYrCiIPerxe_3UW@OH~Ntq&|t!92;AC`^U{U^PkXlhkVcv1LRw?W5(8?V{E-&`fC z56%Yb3 zh~S7OX-H8kNH`J5*OW$Dr*a5H*<0Z!^R1yA0*AjhLW2*q`g2GMGy`D{LMaJdhC7Z2 z^ak|64bb8wNvISZSXNyGnHFY_h@zqtn%S#TrvUI#=!BH*z{LlAP)*z_ahHYE;gP6t zogTz7)5}8Ug}_|uqyAs)yOc6MRs8w<&lP^RP#C__KQi?7!QUO+)BkS=KE9)dAN4;? z0Zjo-0ZoCoraW8qo4?_?XAJBI9D+ z2(Q7s4`JI5>7m&+tVK<)>;%}{LVGu@khHf!%c?_JgeeXd0hkO+6G|Cff{+cn3F<`I zx+^cU1+j>h*#zjQl*!fHQ-RS_s-2j~B5GWqfPflD;iD{KtaHg$Lg`y>3r))CN7;yl z-U`Z`_mpjfvWzq*NjFs5CLxVu=4&+gvXHJjxS4OD_-{dy5gt_5dg);6d~Q9DuAnk% zHbLGRa=7C=>_!yEv$Hr^!h0108wDtK1;jE=m~Hyi1r{do zFqY^#W+*>cL9=N_lTsyG4YN%|k6aRn#X0 z(xFMy%2;TtNGcz&p zgfoGK#VTOr#!i4sm#`v(;?y&kN`h6c;b1C?pkIbjg7Sc0&(mYlH*Xv-2O^G2Pqd!R zAp>*o2233y%Zv?x7tNU@h9_#wSr1E1GJpY5EtD6#h6S~)A~t86W!P*(xlloyyP6{8 zw9f@8a4Y6j%=(vRusxK!HiAY31-v~<#D*oUjL8ZnEm=T!RM4qIPIFw$uGJ*ga<0JK z*Iq$Dw{$%-IG55sTT*8I-u7(Ut5^yXAjAkTo4aX}q#<~Y9B#qb8Oo&~ZexLSi;}u9 zX>nN&y+#=F;0nNrH0DEIU9Un|36nO>_Of0bxU0ztL4(DuS3H?tt<6 z!mP>v7^V3ldCJHK7%!Uk0vwBT=_qET;yaK!Rr*-)DGE=<$s9ffEVtV z>z-(rIZA-qWex(ic9}~k2j8yPjo8LA4XoqvfvQx5U4gn^Nico{{Qlqx=u=UZJ9@B^ zP3J69CNOHoS-69veVxrWS)$N32Cs%$BZ*iC4PokH|esec1cY zJxgjKCjUS!1@`8Oj?5LnEd+9(ZbL3D5p&cx4LBNb^d4Q<{9tE=XWF|CI5(dtqz+|Z z02m*k6!bhiJ7DYZt^6DBZHs`6X2g_#5>>GFsH#n1>7Hn8(b%G~W!tbt>HqgqLto7w z&)j?WH9Y-BO#w-PdlO@YR3!r!*zvJbXAu4$wrQ-f!90B)-pg^MGIPy_4xMCR)Z64B zn}4l0y=J>v0ovMrwbSIXY%!{ z!ZrzsEzEqRvH)QFkA=DuTiRbWx@dIK=(26-qV)g!si7b5|1X*QS{Kz6*iH)EtsInL zwP6GpWe&ipb5m#YulJ@Kav#%gpX<(iYzn76{?&7yp7Zpaw{3IYy?x__)R7G0QjE*g zTi9sqVENy??s)lEX5a((*oCT)ennh}Q&MWm+rp&WFa+{ z!QQ3uQ92gU5q%-?^WX02txVDh;6uP36$cRR*4T_i+)>{&=4i~(n6qt|qxAnTr-pti zKa%*wBSEU6>c; z7dY?^#5LJ=(9NJf0_cC0-6Gv0-6H7Pl0>pkwWT3W_=3Y`X{FDr!NHl(b!yK z+7$$w4-yw!_7M{3@k-S~se76cL^{6w7NVKQXtRjWVv62dE@H!`(H1LJpHLqfruYHlJ$*(g>sxXxk9z F{{yGZ7X| ({ +const useStyles = makeStyles((theme) => ({ //page styling title: { color: 'white', height: '50px', @@ -59,8 +44,9 @@ const useStyles = makeStyles((theme) => ({ joinDate: { color: 'white', textAlign: 'center', - fontSize: '10pt', - marginTop: '0px' + fontSize: '12pt', + marginBottom: '5px', + marginTop: '10px' }, reviewDetails: { color: 'white', @@ -143,43 +129,42 @@ const useStyles = makeStyles((theme) => ({ padding: '5px', fontSize: '13pt' }, - joinDate: { - fontSize: '12pt', - color: 'white', - textAlign: 'center', - marginBottom: '5px', - marginTop: '10px' - } })); export default function Account() { - const classes = useStyles(); + const classes = useStyles(); //here the classes is assigned to get access to the styling const [userDetails, setUserDetails] = useState([]); - const [userReviews, setUserReviews] = useState([]); + const [userReviews, setUserReviews] = useState([]); //using useState hook to give states to the components when rendering const [movieDetails, setMovieDetails] = useState([]); const [reviewCount, setReviewCount] = useState(0); const [myReviews] = useState([]); - let { id } = useParams(); - const userID=localStorage.getItem('userid') + let { id } = useParams(); //useParams hook gives us the right routing into the page using the user id + const userID=localStorage.getItem('userid') //localStorage provides the currently logged in users's id and authorisation token const token=localStorage.getItem('authorization') useEffect(()=> { fetch('https://arthur-laura-5000.codio-box.uk/myaccount', { method: "POST", credentials: 'include', headers: {'Content-type': 'application/json','Authorization': token}, body: JSON.stringify(id) }).then(response =>response.json().then(data => {setUserDetails(data.userDetails[0]);setMovieDetails(data.movieDetails[0]);setReviewCount(data.userReviews.length);setUserReviews(data.userReviews.pop());})); - },[]); + },[]); //fetching the data from the API URL, using the right method, credentials and authorisation token console.log(userDetails) console.log(movieDetails) console.log(userReviews) - if (userID==id){ + if (userID==id){ //client side security so that when a user is logged in the data is shown, otherwise the else path will redirect them to the login page return ( + {/*using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows user details therfore using userDetails.*columnName* to show the user information*/}
-  +

{userDetails.userName}

Member since: {userDetails.joinDate}

Reviews: {reviewCount}

Most recent review

+ {/*new div is started below to split up the content of the page into separate boxes + * this container shows movie and review details which is why both movideDetails and userReviews are used to display data + * the review is for the most recent review on the user's account */}
@@ -204,7 +189,7 @@ export default function Account() {
); - }else{ + }else{ //no user is logged in, redirect to login page {window.location.href='/'} } } \ No newline at end of file diff --git a/flask-react/src/components/AddReview.js b/flask-react/src/components/AddReview.js index b3034e5c..2d16fab6 100644 --- a/flask-react/src/components/AddReview.js +++ b/flask-react/src/components/AddReview.js @@ -1,26 +1,10 @@ import React, {useEffect, useState} from 'react'; -import { fade, makeStyles } from '@material-ui/core/styles'; -import AppBar from '@material-ui/core/AppBar'; -import Toolbar from '@material-ui/core/Toolbar'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import InputBase from '@material-ui/core/InputBase'; -import Badge from '@material-ui/core/Badge'; -import MenuItem from '@material-ui/core/MenuItem'; -import Menu from '@material-ui/core/Menu'; -import MenuIcon from '@material-ui/icons/Menu'; -import SearchIcon from '@material-ui/icons/Search'; -import AccountCircle from '@material-ui/icons/AccountCircle'; -import MailIcon from '@material-ui/icons/Mail'; -import NotificationsIcon from '@material-ui/icons/Notifications'; -import MoreIcon from '@material-ui/icons/MoreVert'; -import NavBar from './NavBar.js'; -import SendIcon from '@material-ui/icons/Send'; -import { List, Header, Rating } from "semantic-ui-react"; -import { Reviews } from './Reviews.js'; +import { makeStyles } from '@material-ui/core/styles'; +import SendIcon from '@material-ui/icons/Send'; //essential imports +import { Rating } from "semantic-ui-react"; import { useParams } from "react-router-dom"; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles((theme) => ({ //page styling title: { color: 'white', fontSize: '15pt', @@ -172,42 +156,46 @@ const useStyles = makeStyles((theme) => ({ })); export default function AddReview() { - const classes = useStyles(); + const classes = useStyles(); //here the classes is assigned to get access to the styling const [movies, setMovies] = useState([]); - const [userRating,setUserRating] = useState("1"); + const [userRating,setUserRating] = useState("1"); //using useState hook to give states to the components when rendering const [userReview,setUserReview] = useState(""); var today = new Date(); var dd = String(today.getDate()).padStart(2, '0'); - var mm = String(today.getMonth() + 1).padStart(2, '0'); + var mm = String(today.getMonth() + 1).padStart(2, '0'); //generating the date of when the function is ran so that there is a date for when a review was submitted var yyyy = today.getFullYear(); today = dd + '/' + mm + '/' + yyyy; - const userID=localStorage.getItem('userid') + const userID=localStorage.getItem('userid') //local storage gives userid of current user logged in let { id } = useParams(); useEffect(()=> { fetch('https://arthur-laura-5000.codio-box.uk/addreview', { credentials: 'include', method: 'POST', headers: { 'Content-type': 'application/json'}, body: JSON.stringify(id)}).then(response =>response.json().then(data => {setMovies(data.thisMovie); }) ); - },[]); + },[]); //fetching the data from the API URL, using the right method, credentials and authorisation token console.log(movies) function handleAddReview(event) { - const details = [userRating, userReview, userID, id, today]; + const details = [userRating, userReview, userID, id, today]; //details is an array of data that is taking the user inputs, userID, movies's id and the date console.log(details) fetch('https://arthur-laura-5000.codio-box.uk/addnewreview', { method: 'POST', - credentials: 'include', + credentials: 'include', //the post to the API is then called headers: { 'Content-type': 'application/json', }, body: JSON.stringify(details), - }).then(response =>response.json().then(data => { + }).then(response =>response.json().then(data => { //the response will create some user feedback in the form of an alert and redirect them back to the movie's page which is the previous window alert("Your review has been added") window.history.back() })) event.preventDefault(); } - if (userID!==null){ + if (userID!==null){ //client side security so that when a user is logged in the data is shown, otherwise the else path will redirect them to the login page return (
+ {/*using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows movie details for the movie the user wishes to give a review on + * to show movie details the movies.*columnName* is used to get each piece of information to show on the page*/}
 @@ -230,7 +218,9 @@ export default function AddReview() {
- + {/*new div is started below to split up the content of the page into separate boxes + * this container is created to build the form where the user can use the rating stars to give a rating and type a review below it + * when they are finished with the review the send icon in the bottom right calls the handleAddReview function which posts the review into the database using the API */}

Add your review

Rate the movie:

@@ -242,7 +232,7 @@ export default function AddReview() {
); - }else{ + }else{ //no user is logged in, redirect to login page {window.location.href='/login'} } } \ No newline at end of file diff --git a/flask-react/src/components/AllMovies.js b/flask-react/src/components/AllMovies.js index b20d2977..ee814f3c 100644 --- a/flask-react/src/components/AllMovies.js +++ b/flask-react/src/components/AllMovies.js @@ -1,24 +1,8 @@ import React, {useEffect, useState} from 'react'; -import { fade, makeStyles } from '@material-ui/core/styles'; -import AppBar from '@material-ui/core/AppBar'; -import Toolbar from '@material-ui/core/Toolbar'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import InputBase from '@material-ui/core/InputBase'; -import Badge from '@material-ui/core/Badge'; -import MenuItem from '@material-ui/core/MenuItem'; -import Menu from '@material-ui/core/Menu'; -import MenuIcon from '@material-ui/icons/Menu'; -import SearchIcon from '@material-ui/icons/Search'; -import AccountCircle from '@material-ui/icons/AccountCircle'; -import MailIcon from '@material-ui/icons/Mail'; -import NotificationsIcon from '@material-ui/icons/Notifications'; -import MoreIcon from '@material-ui/icons/MoreVert'; -import NavBar from './NavBar.js'; -import { Movies } from './Movies.js'; -import { List, Header, Rating } from "semantic-ui-react"; +import { makeStyles } from '@material-ui/core/styles'; //essential imports +import { Rating } from "semantic-ui-react"; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles((theme) => ({ //page styling title: { color: 'white', height: '50px', @@ -77,16 +61,20 @@ const useStyles = makeStyles((theme) => ({ })); export default function AllMovies() { - const classes = useStyles(); - const [movies, setMovies] = useState([]); + const classes = useStyles(); //here the classes is assigned to get access to the styling + const [movies, setMovies] = useState([]); //using useState hook to give states to the components when rendering useEffect(()=> { fetch('https://arthur-laura-5000.codio-box.uk/movies', { credentials: 'include' }).then(response =>response.json().then(data => {setMovies(data.movies); }) ); - },[]); + },[]); //fetching the data from the API URL console.log(movies) return (
+ {/*using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows all movies in the database using a loop without the need to be logged in + * to show movie details the movies.*columnName* and uses a hover state so that the data about each movie is hidden under the hover interaction */}

All movies

{movies.map(movie => { return ( diff --git a/flask-react/src/components/Categories.js b/flask-react/src/components/Categories.js index 1992d3f1..c7da44fe 100644 --- a/flask-react/src/components/Categories.js +++ b/flask-react/src/components/Categories.js @@ -1,25 +1,9 @@ import React, {useEffect, useState} from 'react'; -import { fade, makeStyles } from '@material-ui/core/styles'; -import AppBar from '@material-ui/core/AppBar'; -import Toolbar from '@material-ui/core/Toolbar'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import InputBase from '@material-ui/core/InputBase'; -import Badge from '@material-ui/core/Badge'; -import MenuItem from '@material-ui/core/MenuItem'; -import Menu from '@material-ui/core/Menu'; -import MenuIcon from '@material-ui/icons/Menu'; -import SearchIcon from '@material-ui/icons/Search'; -import AccountCircle from '@material-ui/icons/AccountCircle'; -import MailIcon from '@material-ui/icons/Mail'; -import NotificationsIcon from '@material-ui/icons/Notifications'; -import MoreIcon from '@material-ui/icons/MoreVert'; -import NavBar from './NavBar.js'; -import { Movies } from './Movies.js'; -import { List, Header, Rating } from "semantic-ui-react"; +import { makeStyles } from '@material-ui/core/styles'; //essential imports +import { Rating } from "semantic-ui-react"; import { useParams } from "react-router-dom"; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles((theme) => ({ //page styling title: { color: 'white', height: '50px', @@ -39,18 +23,18 @@ const useStyles = makeStyles((theme) => ({ rowGap: '5px', }, cover: { - width:'220px', - height:'320px', + width:'190px', + height:'310px', position: 'relative', }, movieCard: { marginTop: '0px', marginBottom: '10px', - marginRight: '10px', - marginLeft: '10px', + marginRight: '7.5px', + marginLeft: '7.5px', float: 'left', - width: '220px', - height: '320px', + width: '190px', + height: '310px', position: 'relative', '&:hover>div': { opacity:1, @@ -78,16 +62,20 @@ const useStyles = makeStyles((theme) => ({ })); export default function Categories() { - const classes = useStyles(); - const [movies, setMovies] = useState([]); - let { category } = useParams(); + const classes = useStyles(); //here the classes is assigned to get access to the styling + const [movies, setMovies] = useState([]); //using useState hook to give states to the components when rendering + let { category } = useParams(); //useParams hook gives us the right routing into the page for the correct category useEffect(()=> { fetch('https://arthur-laura-5000.codio-box.uk/categories', { credentials: 'include', method: 'POST', headers: { 'Content-type': 'application/json'}, body: JSON.stringify(category)}).then(response =>response.json().then(data => {setMovies(data.categories);})); - },[]); + },[]); //fetching the data from the API URL for a specific category console.log(movies) console.log(category) return (
+ {/* using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows all movies in the database for the specific category using a loop without the need to be logged in + * to show movie details the movie.*columnName* is used and a hover state so that the data about each movie is hidden under the hover interaction */}

{category}

{movies.map(movie => { return ( diff --git a/flask-react/src/components/HomePage.js b/flask-react/src/components/HomePage.js index 404179b6..d752c0e1 100644 --- a/flask-react/src/components/HomePage.js +++ b/flask-react/src/components/HomePage.js @@ -1,23 +1,8 @@ import React, {useEffect, useState} from 'react'; -import { fade, makeStyles } from '@material-ui/core/styles'; -import AppBar from '@material-ui/core/AppBar'; -import Toolbar from '@material-ui/core/Toolbar'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import InputBase from '@material-ui/core/InputBase'; -import Badge from '@material-ui/core/Badge'; -import MenuItem from '@material-ui/core/MenuItem'; -import Menu from '@material-ui/core/Menu'; -import MenuIcon from '@material-ui/icons/Menu'; -import SearchIcon from '@material-ui/icons/Search'; -import AccountCircle from '@material-ui/icons/AccountCircle'; -import MailIcon from '@material-ui/icons/Mail'; -import NotificationsIcon from '@material-ui/icons/Notifications'; -import MoreIcon from '@material-ui/icons/MoreVert'; -import NavBar from './NavBar.js'; +import { makeStyles } from '@material-ui/core/styles'; //essential imports import { Movies } from './Movies.js'; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles((theme) => ({ //page styling title: { color: 'white', height: '50px', @@ -26,19 +11,23 @@ const useStyles = makeStyles((theme) => ({ marginTop: '0px', marginBottom: '0px', marginLeft: '15px', - letterSpacing: '3px' + letterSpacing: '3px', }, })); export default function HomePage() { - const classes = useStyles(); - const [movies, setMovies] = useState([]); + const classes = useStyles(); //here the classes is assigned to get access to the styling + const [movies, setMovies] = useState([]); //using useState hook to give states to the components when rendering useEffect(()=> { fetch('https://arthur-laura-5000.codio-box.uk/movies', { credentials: 'include' }).then(response =>response.json().then(data => {setMovies(data.movies);})); - },[]); + },[]); //fetching the data from the API URL console.log(movies) return ( + {/* using React.Fragment this time to group a list of children without adding extra nodes to the DOM + * this function calles for the Movies function in the AllMovies.js file which means that the styling is copied over + * this page shows the top 10 movies in the database without the need to be logged in + * to show the top 10 movies the data is sliced and sorted by rating, and will only show the first 10 out of the all movies */}

Top 10 movies

(b.rating > a.rating) ? 1 : -1).slice(0, 10)}/>
diff --git a/flask-react/src/components/Login.js b/flask-react/src/components/Login.js index 19833695..b50a26e2 100644 --- a/flask-react/src/components/Login.js +++ b/flask-react/src/components/Login.js @@ -1,22 +1,7 @@ import React, { useState } from "react"; -import { Form, Button } from "semantic-ui-react"; -import { fade, makeStyles } from '@material-ui/core/styles'; -import AppBar from '@material-ui/core/AppBar'; -import Toolbar from '@material-ui/core/Toolbar'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import InputBase from '@material-ui/core/InputBase'; -import Badge from '@material-ui/core/Badge'; -import MenuItem from '@material-ui/core/MenuItem'; -import Menu from '@material-ui/core/Menu'; -import MenuIcon from '@material-ui/icons/Menu'; -import SearchIcon from '@material-ui/icons/Search'; -import AccountCircle from '@material-ui/icons/AccountCircle'; -import MailIcon from '@material-ui/icons/Mail'; -import NotificationsIcon from '@material-ui/icons/Notifications'; -import MoreIcon from '@material-ui/icons/MoreVert'; +import { makeStyles } from '@material-ui/core/styles'; //essential imports -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles((theme) => ({ //page styling container: { marginTop: '14%', backgroundColor: '#16161A', @@ -83,36 +68,40 @@ const useStyles = makeStyles((theme) => ({ })); export default function Login() { - const classes = useStyles(); - const [username, setUsername] = useState(""); + const classes = useStyles(); //here the classes is assigned to get access to the styling + const [username, setUsername] = useState(""); //using useState hook to give states to the components when rendering const [password, setPassword] = useState(""); - const [errorMessage, setErrorMessage] = useState(""); function handleSubmit(event) { - const token = `Basic ` +btoa(`${username}:${password}`) + const token = `Basic ` +btoa(`${username}:${password}`) //the authorisation token is set up console.log(token) fetch('https://arthur-laura-5000.codio-box.uk/login', { method: 'GET', - credentials: 'include', + credentials: 'include', //the login API has a GET request to get the user input confirmed headers: { 'Content-type': 'application/json', 'Authorization': token }, }).then(response =>response.json().then(data => { if(data.userID==null){ - alert("Incorrect credentials!") + alert("Incorrect credentials!") //if the API returns null the user details that were input are incorrect }else{ localStorage.setItem('userid',data.userID) - localStorage.setItem('authorization',token) + localStorage.setItem('authorization',token) //if the login details are right, the localStorage items are set to the input data so the user is logged in localStorage.setItem('username', username) window.location.href='/' - alert("Your have logged in successfully") + alert("Your have logged in successfully") //the user is then alerted to let them know they are logged in and redirected to the home page }})) event.preventDefault(); } return (
+ {/* using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows is used to create the login form for the user to fill in when logging in + * the input tags allow the user to input their details, the password type hides the text by replacing it with dots + * the login button calles the function handleSubmit to initiate the login API */}
 diff --git a/flask-react/src/components/MovieForm.js b/flask-react/src/components/MovieForm.js deleted file mode 100644 index ddccd258..00000000 --- a/flask-react/src/components/MovieForm.js +++ /dev/null @@ -1,49 +0,0 @@ -import React, {useState} from 'react'; -import { Form, Input, Rating, Button } from "semantic-ui-react"; - -export const MovieForm = ({onNewMovie}) => { - const [title, setTitle] = useState(''); - const [rating, setRating] = useState(1); - - return ( -
- - setTitle(e.target.value)}/> - - - - {setRating(data.rating); - }} - /> - - - - - - -
- ) -} diff --git a/flask-react/src/components/MoviePage.js b/flask-react/src/components/MoviePage.js index 8325ce03..8dae6a7d 100644 --- a/flask-react/src/components/MoviePage.js +++ b/flask-react/src/components/MoviePage.js @@ -1,23 +1,7 @@ import React, {useEffect, useState} from 'react'; -import { fade, makeStyles } from '@material-ui/core/styles'; -import AppBar from '@material-ui/core/AppBar'; -import Toolbar from '@material-ui/core/Toolbar'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import InputBase from '@material-ui/core/InputBase'; -import Badge from '@material-ui/core/Badge'; -import MenuItem from '@material-ui/core/MenuItem'; -import Menu from '@material-ui/core/Menu'; -import MenuIcon from '@material-ui/icons/Menu'; -import SearchIcon from '@material-ui/icons/Search'; -import AccountCircle from '@material-ui/icons/AccountCircle'; -import MailIcon from '@material-ui/icons/Mail'; -import NotificationsIcon from '@material-ui/icons/Notifications'; -import MoreIcon from '@material-ui/icons/MoreVert'; -import NavBar from './NavBar.js'; -import { Movies } from './Movies.js'; +import { makeStyles } from '@material-ui/core/styles'; import { useParams } from "react-router-dom"; -import { List, Header, Rating } from "semantic-ui-react"; +import { Rating } from "semantic-ui-react"; import { AllReviews } from "./MoviePageReviews.js"; const useStyles = makeStyles((theme) => ({ @@ -183,19 +167,23 @@ const useStyles = makeStyles((theme) => ({ })); export default function MoviePage() { - const classes = useStyles(); + const classes = useStyles(); //here the classes is assigned to get access to the styling const [movies, setMovies] = useState([]); - const [reviews, setReviews] = useState([]); - let { id } = useParams(); + const [reviews, setReviews] = useState([]); //using useState hook to give states to the components when rendering + let { id } = useParams(); //useParams hook gives us the right routing into the correct movie page useEffect(()=> { - fetch('https://arthur-laura-5000.codio-box.uk/movieReviews', { method: "POST", credentials: 'include', headers: {'Content-type': 'application/json'}, body:JSON.stringify(id) }).then(response =>response.json().then(data => {setMovies(data.movieDetails[0]);setReviews(data.movieReviews);})); - },[]); + fetch('https://arthur-laura-5000.codio-box.uk/movieReviews', { method: "POST", credentials: 'include', headers: {'Content-type': 'application/json'}, body:JSON.stringify(id) }).then(response =>response.json().then(data => {setMovies(data.movieDetails[0]);setReviews(data.movieReviews.reverse());})); + },[]); //fetching the data from the API URL for the specific movie id console.log(movies) console.log(id) console.log(reviews) return (
+ {/* using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows the specific movie's cover pagePhoto with details about the movie with the average rating below and a link to the add review page + * to show movie details the movies.*columnName* is used */}

Average rating

@@ -210,11 +198,13 @@ export default function MoviePage() {
{(() => { + {/* if a movie has no reviews yet it will show a message */} if(reviews.length==0){ return(

No reviews yet

) }else{ + {/* otherwise it will import the reviews of the movie using the AllReviews function from MoviePageReviews.js */} return (

Movie reviews

diff --git a/flask-react/src/components/MoviePageReviews.js b/flask-react/src/components/MoviePageReviews.js index 42948bb9..0feb8e8e 100644 --- a/flask-react/src/components/MoviePageReviews.js +++ b/flask-react/src/components/MoviePageReviews.js @@ -1,9 +1,7 @@ -import React, {useEffect,useState} from 'react'; -import NavBar from './NavBar.js'; -import { List, Header, Rating } from "semantic-ui-react"; -import { fade, makeStyles } from '@material-ui/core/styles'; +import { Rating } from "semantic-ui-react"; //essential imports +import { makeStyles } from '@material-ui/core/styles'; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles((theme) => ({ //page styling title: { color: 'white', fontSize: '25pt', @@ -42,22 +40,6 @@ const useStyles = makeStyles((theme) => ({ float: 'left', marginTop: '20px' }, - profileCover: { - width: '100px', - height: '100px', - position: 'relative', - backgroundColor: '#16161A', - marginBottom: '8px', - marginTop: '80px', - marginLeft: '30px', - float: 'left' - }, - container2: { - width: '98%', - backgroundColor: '#16161A', - rowGap: '5px', - margin: '15px', - }, reviewCard: { backgroundColor: '#0B0C0D', height: '275px', @@ -112,10 +94,14 @@ const useStyles = makeStyles((theme) => ({ } })); -export const AllReviews = ({ myReviews }) => { - const classes = useStyles(); +export const AllReviews = ({ myReviews }) => { //myReviews is a list of reviews to show on the page + const classes = useStyles(); //here the classes is assigned to get access to the styling return (
+ {/* using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows all reviews under the movie details on the movie page + * to show reviews the review.*columnName* is used */} {myReviews.map(review => { return (
diff --git a/flask-react/src/components/Movies.js b/flask-react/src/components/Movies.js index a57ffa8e..8af6717b 100644 --- a/flask-react/src/components/Movies.js +++ b/flask-react/src/components/Movies.js @@ -1,9 +1,7 @@ -import React, {useEffect,useState} from 'react'; -import NavBar from './NavBar.js'; -import { List, Header, Rating } from "semantic-ui-react"; -import { fade, makeStyles } from '@material-ui/core/styles'; +import { Rating } from "semantic-ui-react"; //essential imports +import { makeStyles } from '@material-ui/core/styles'; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles((theme) => ({ //page styling title: { color: 'white', fontSize: '12pt', @@ -54,10 +52,14 @@ const useStyles = makeStyles((theme) => ({ } })); -export const Movies = ({ movies }) => { - const classes = useStyles(); +export const Movies = ({ movies }) => { //movies is a list of movies to show on the page + const classes = useStyles(); //here the classes is assigned to get access to the styling return (
+ {/* using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows the movies details and can be used by page to import the styling and data such as the HomePage.js + * to show the data the movie.*columnName* is used through a loop of each movie */} {movies.map(movie => { return (
{window.location.href='/movies/'+movie.id}}> diff --git a/flask-react/src/components/MoviesRecommended.js b/flask-react/src/components/MoviesRecommended.js index ee317ddc..af8d1602 100644 --- a/flask-react/src/components/MoviesRecommended.js +++ b/flask-react/src/components/MoviesRecommended.js @@ -1,7 +1,5 @@ -import React, {useEffect,useState} from 'react'; -import NavBar from './NavBar.js'; -import { List, Header, Rating } from "semantic-ui-react"; -import { fade, makeStyles } from '@material-ui/core/styles'; +import { Rating } from "semantic-ui-react"; +import { makeStyles } from '@material-ui/core/styles'; const useStyles = makeStyles((theme) => ({ title: { @@ -53,10 +51,14 @@ const useStyles = makeStyles((theme) => ({ } })); -export const MoviesRecommended = ({ movies }) => { - const classes = useStyles(); +export const MoviesRecommended = ({ movies }) => { //movies is a list of movies to show on the page + const classes = useStyles(); //here the classes is assigned to get access to the styling return (
+ {/* using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows the movie details of the reccommended movies to the logged in user + * to show the data the movie.*columnName* is used through a loop of each movie*/} {movies.map(movie => { return (
{window.location.href='/movies/'+movie.id}}> diff --git a/flask-react/src/components/MyReviews.js b/flask-react/src/components/MyReviews.js index 1d111b91..aca72cf7 100644 --- a/flask-react/src/components/MyReviews.js +++ b/flask-react/src/components/MyReviews.js @@ -1,23 +1,8 @@ import React, {useEffect, useState} from 'react'; -import { fade, makeStyles } from '@material-ui/core/styles'; -import AppBar from '@material-ui/core/AppBar'; -import Toolbar from '@material-ui/core/Toolbar'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import InputBase from '@material-ui/core/InputBase'; -import Badge from '@material-ui/core/Badge'; -import MenuItem from '@material-ui/core/MenuItem'; -import Menu from '@material-ui/core/Menu'; -import MenuIcon from '@material-ui/icons/Menu'; -import SearchIcon from '@material-ui/icons/Search'; -import AccountCircle from '@material-ui/icons/AccountCircle'; -import MailIcon from '@material-ui/icons/Mail'; -import NotificationsIcon from '@material-ui/icons/Notifications'; -import MoreIcon from '@material-ui/icons/MoreVert'; -import NavBar from './NavBar.js'; +import { makeStyles } from '@material-ui/core/styles'; //essential imports import { Reviews } from './Reviews.js'; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles((theme) => ({ //page styling title: { color: 'white', fontSize: '25pt', @@ -29,23 +14,26 @@ const useStyles = makeStyles((theme) => ({ })); export default function MyReviews() { - const classes = useStyles(); - const [myReviews, setReviews] = useState([]); - const userID=localStorage.getItem('userid') + const classes = useStyles(); //here the classes is assigned to get access to the styling + const [myReviews, setReviews] = useState([]); //using useState hook to give states to the components when rendering + const userID=localStorage.getItem('userid') //local storage gives userid and token of current user logged in const token=localStorage.getItem('authorization') useEffect(()=> { fetch('https://arthur-laura-5000.codio-box.uk/myReviews', { credentials: 'include', headers: {'Content-type': 'application/json','Authorization': token} }).then(response =>response.json().then(data => {setReviews(data.myReviews);})); - },[]); + },[]); //fetching the data from the API URL to get the reviews of the currently logged in user console.log(myReviews) console.log(myReviews.length) - if (userID!==null){ + if (userID!==null){ //client side security so that when a user is logged in the data is shown, otherwise the else path will redirect them to the login page return ( -

My Reviews

+ {/* using React.Fragment this time to group a list of children without adding extra nodes to the DOM + * this function calles for the Reviews function in the Reviews.js file which means that the styling is copied over + * this page shows the currently logged in user's reviews */} +

My Reviews - Highest to Lowest rated

); - }else{ + }else{ //no user is logged in, redirect to login page {window.location.href='/login'} } } \ No newline at end of file diff --git a/flask-react/src/components/NavBar.js b/flask-react/src/components/NavBar.js index 416ca627..a0821d26 100644 --- a/flask-react/src/components/NavBar.js +++ b/flask-react/src/components/NavBar.js @@ -1,5 +1,4 @@ - -import React, {useEffect, useState} from 'react'; +import React from 'react'; import { fade, makeStyles } from '@material-ui/core/styles'; import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; @@ -7,7 +6,7 @@ import IconButton from '@material-ui/core/IconButton'; import Typography from '@material-ui/core/Typography'; import InputBase from '@material-ui/core/InputBase'; import Badge from '@material-ui/core/Badge'; -import MenuItem from '@material-ui/core/MenuItem'; +import MenuItem from '@material-ui/core/MenuItem'; //essential imports import Menu from '@material-ui/core/Menu'; import MenuIcon from '@material-ui/icons/Menu'; import SearchIcon from '@material-ui/icons/Search'; @@ -16,9 +15,8 @@ import MailIcon from '@material-ui/icons/Mail'; import NotificationsIcon from '@material-ui/icons/Notifications'; import MoreIcon from '@material-ui/icons/MoreVert'; import CloseIcon from '@material-ui/icons/Close'; -import { Movies } from './Movies.js'; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles((theme) => ({ //page styling grow: { flexGrow: 1, }, @@ -190,21 +188,19 @@ const useStyles = makeStyles((theme) => ({ title: { '&:hover': { textDecoration: 'underline', - transition:'backgroundColor color .25s ease-in-out', }, } })); export default function NavBar() { - const classes = useStyles(); + const classes = useStyles(); //here the classes is assigned to get access to the styling const [account, setAccount] = React.useState(false); - const [sideDrawer, setSideDrawer] = React.useState(false); + const [sideDrawer, setSideDrawer] = React.useState(false); //using useState hook to give states to the components when rendering const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = React.useState(null); const isMobileMenuOpen = Boolean(mobileMoreAnchorEl); - - const handleMobileMenuClose = () => { + const handleMobileMenuClose = () => { //functions to handle mobile version of the navbar setMobileMoreAnchorEl(null); }; @@ -217,21 +213,21 @@ export default function NavBar() { }; const menuId = 'primary-search-account-menu'; - const userID=localStorage.getItem('userid') + const userID=localStorage.getItem('userid') //get localStorage when user is logged in const username=localStorage.getItem('username') - const handleLogout = () => { + const handleLogout = () => { //handle logout when the logout button is clicked localStorage.removeItem('userid') - localStorage.removeItem('authorization') + localStorage.removeItem('authorization') //removes localStorage to remove access to secure pages localStorage.removeItem('username') window.location.href='/' - alert("Your have logged out successfully") + alert("Your have logged out successfully") //give alert to user that they are logged out }; const mobileMenuId = 'primary-search-account-menu-mobile'; const renderMobileMenu = ( + {/* using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this div is used to display all the text and icons in in the navbar and use them to call functions such as onclick and redirect */} {setSideDrawer(sideDrawer => !sideDrawer)}} @@ -281,7 +280,7 @@ export default function NavBar() { aria-label="open drawer" disableRipple= "true" > - {window.location.href='/allmovies'}} variant="h6" style = {{fontSize: 15,textAlign:'left', marginLeft:'30px', width:'49px', position:'relative', cursor:'pointer'}} noWrap> + {window.location.href='/allmovies'}} variant="h6" style = {{fontSize: 15,textAlign:'left', marginLeft:'30px', width:'50px', position:'relative', cursor:'pointer'}} noWrap> Movies { if (event.key === 'Enter'){ - window.location=('/search/'+event.target.value)}}} + window.location=('/search/'+event.target.value)}}} //the search bar is craeted to call the search API and display the results depending on the input />
- {setAccount(account => !account)}} + {setAccount(account => !account)}} //onclick display account side drawer edge="end" aria-label="account of current user" aria-controls={menuId} @@ -358,7 +357,7 @@ export default function NavBar() { {renderMobileMenu} {(() => { - if(account){ + if(account){ //if account side darawer is open styling is called by the classes return(
@@ -367,7 +366,7 @@ export default function NavBar() {
{(() => { - if(userID==null){ + if(userID==null){ // if there is no user logged in, the links are to the login or register page or a close icon to get rid of the side drawer return(

Not logged in @@ -377,7 +376,7 @@ export default function NavBar() {

{window.location.href='/register'}}>Register

- )}else{ + )}else{ // if there is a user logged in, the links are to the account page or log out which calls the handleLogout function or a close icon to get rid of the side drawer return(

{username} @@ -393,7 +392,7 @@ export default function NavBar() { )} })()} {(() => { - if(sideDrawer){ + if(sideDrawer){ //if the hamburger icon is click whether logged in or not, it reveals a side drawer on the left with links to the different category movies and a close icon to get rid off the side drawer return(

diff --git a/flask-react/src/components/Recommended.js b/flask-react/src/components/Recommended.js index 58cfc771..501ff5a5 100644 --- a/flask-react/src/components/Recommended.js +++ b/flask-react/src/components/Recommended.js @@ -1,21 +1,5 @@ import React, {useEffect, useState} from 'react'; -import { fade, makeStyles } from '@material-ui/core/styles'; -import AppBar from '@material-ui/core/AppBar'; -import Toolbar from '@material-ui/core/Toolbar'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import InputBase from '@material-ui/core/InputBase'; -import Badge from '@material-ui/core/Badge'; -import MenuItem from '@material-ui/core/MenuItem'; -import Menu from '@material-ui/core/Menu'; -import MenuIcon from '@material-ui/icons/Menu'; -import { List, Header, Rating } from "semantic-ui-react"; -import SearchIcon from '@material-ui/icons/Search'; -import AccountCircle from '@material-ui/icons/AccountCircle'; -import MailIcon from '@material-ui/icons/Mail'; -import NotificationsIcon from '@material-ui/icons/Notifications'; -import MoreIcon from '@material-ui/icons/MoreVert'; -import NavBar from './NavBar.js'; +import { makeStyles } from '@material-ui/core/styles'; import { MoviesRecommended } from './MoviesRecommended.js'; const useStyles = makeStyles((theme) => ({ @@ -78,19 +62,23 @@ const useStyles = makeStyles((theme) => ({ })); export default function Recommended() { - const classes = useStyles(); - const [moviesRecommended, setMoviesRecommended] = useState([]); - const [copy, setCopy] = useState([]); - const userID=localStorage.getItem('userid') + const classes = useStyles(); //here the classes is assigned to get access to the styling + const [moviesRecommended, setMoviesRecommended] = useState([]); //using useState hook to give states to the components when rendering + const userID=localStorage.getItem('userid') //local storage gives userid and token of current user logged in const token=localStorage.getItem('authorization') useEffect(()=> { fetch('https://arthur-laura-5000.codio-box.uk/recommended', { method: "POST", credentials: 'include', headers: {'Content-type': 'application/json','Authorization': token}, body: JSON.stringify(userID) }).then(response =>response.json().then(data => {setMoviesRecommended(data.moviesRecommended); - }) + }) //fetching the data from the API URL to get the recommended movies of the currently logged in user ); },[]); console.log(moviesRecommended) + if (userID!==null){ //client side security so that when a user is logged in the data is shown, otherwise the else path will redirect them to the login page return (
+ {/*using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows a list of movies for each category that the user has reviewed only when the user is logged in + * to show recommended movies this function calls for the function MoviesRecommend from MoviesRecommended.js to get the data and styling */} {moviesRecommended.map(movie => { return (
@@ -101,4 +89,7 @@ export default function Recommended() { })}
); + }else{ //no user is logged in, redirect to login page + {window.location.href='/login'} + } } \ No newline at end of file diff --git a/flask-react/src/components/Register.js b/flask-react/src/components/Register.js index 060863f4..564bae0f 100644 --- a/flask-react/src/components/Register.js +++ b/flask-react/src/components/Register.js @@ -1,22 +1,7 @@ import React, { useState } from "react"; -import { Form, Button } from "semantic-ui-react"; -import { fade, makeStyles } from '@material-ui/core/styles'; -import AppBar from '@material-ui/core/AppBar'; -import Toolbar from '@material-ui/core/Toolbar'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import InputBase from '@material-ui/core/InputBase'; -import Badge from '@material-ui/core/Badge'; -import MenuItem from '@material-ui/core/MenuItem'; -import Menu from '@material-ui/core/Menu'; -import MenuIcon from '@material-ui/icons/Menu'; -import SearchIcon from '@material-ui/icons/Search'; -import AccountCircle from '@material-ui/icons/AccountCircle'; -import MailIcon from '@material-ui/icons/Mail'; -import NotificationsIcon from '@material-ui/icons/Notifications'; -import MoreIcon from '@material-ui/icons/MoreVert'; +import { makeStyles } from '@material-ui/core/styles'; //essential imports -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles((theme) => ({ //page styling container: { marginTop: '12%', backgroundColor: '#16161A', @@ -83,42 +68,46 @@ const useStyles = makeStyles((theme) => ({ })); export default function Register() { - const classes = useStyles(); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const [passwordConfirm, setpasswordConfirm] = useState(""); - const [errorMessage, setErrorMessage] = useState(""); + const classes = useStyles(); //here the classes is assigned to get access to the styling + const [username, setUsername] = useState(""); //using useState hook to give states to the components when rendering + const [password, setPassword] = useState(""); + const [passwordConfirm, setpasswordConfirm] = useState(""); var today = new Date(); var dd = String(today.getDate()).padStart(2, '0'); - var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0! + var mm = String(today.getMonth() + 1).padStart(2, '0'); //generating the date of when the function is ran so that there is a date for when a user account is created var yyyy = today.getFullYear(); today = dd + '/' + mm + '/' + yyyy; function handleSubmit(event) { - const details = [username, password, today]; + const details = [username, password, today]; //details is an array of data that is taking the user inputs, username, password and the date fetch('https://arthur-laura-5000.codio-box.uk/register', { method: 'POST', - credentials: 'include', + credentials: 'include', //the post to the API is then called headers: { 'Content-type': 'application/json', }, body: JSON.stringify(details), }).then(response =>response.json().then(data => { - if(password!=passwordConfirm){ - alert("Passwords don't match!") + if(password!=passwordConfirm){ //a client side check is ran to check whethere the password and passwordConfirm match + alert("Passwords don't match!") //if they don't, an alert is displayed for the user }else{ - localStorage.setItem('userid',data.userID) - const token = `Basic ` +btoa(`${username}:${password}`) + localStorage.setItem('userid',data.userID) //if the passwords match and the username isn't yet taken, the userID is set in the localStorage + const token = `Basic ` +btoa(`${username}:${password}`) //the token is assigned localStorage.setItem('authorization', token) - localStorage.setItem('username', username) + localStorage.setItem('username', username) //the token and username are set in the localStorage window.location.href='/' - alert("Your have successfully registered") + alert("Your have successfully registered") //the user is redirected to the home page and recives an alert to say they have been registered }})) event.preventDefault(); } return (
+ {/* using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows is used to create the register form for the user to fill in when registering + * the input tags allow the user to input their details, the password type hides the text by replacing it with dots + * the register button calles the function handleSubmit to initiate the register API */}
 setUsername(e.target.value)}/> diff --git a/flask-react/src/components/Reviews.js b/flask-react/src/components/Reviews.js index e518d505..aed8554b 100644 --- a/flask-react/src/components/Reviews.js +++ b/flask-react/src/components/Reviews.js @@ -1,11 +1,9 @@ -import React, {useEffect,useState} from 'react'; -import NavBar from './NavBar.js'; -import { List, Header, Rating } from "semantic-ui-react"; -import { fade, makeStyles } from '@material-ui/core/styles'; +import React from 'react'; +import { Rating } from "semantic-ui-react"; +import { makeStyles } from '@material-ui/core/styles'; //essential imports import DeleteForeverIcon from '@material-ui/icons/DeleteForever'; -import CloseIcon from '@material-ui/icons/Close'; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles((theme) => ({ //page styling title: { color: 'white', fontSize: '25pt', @@ -48,6 +46,7 @@ const useStyles = makeStyles((theme) => ({ marginBottom: '8px', marginLeft: '15px', marginTop: '8px', + cursor: 'pointer' }, reviewDateCSS: { marginTop: '80px', @@ -87,12 +86,12 @@ const useStyles = makeStyles((theme) => ({ }, confirmBox: { width: '450px', - height: '220px', + height: '160px', backgroundColor: '#0B0C0D', position: 'absolute', left: '500px', zIndex: '1', - top: '280px', + top: '300px', }, topConfirmBox: { backgroundColor: '#16161A', @@ -110,7 +109,7 @@ const useStyles = makeStyles((theme) => ({ }, option1: { color: 'white', - marginTop: '20px', + marginTop: '0px', marginLeft: '75px', fontSize: '15pt', textAlign: 'center', @@ -128,7 +127,7 @@ const useStyles = makeStyles((theme) => ({ }, option2: { color: 'white', - marginTop: '60px', + marginTop: '20px', marginLeft: '50px', fontSize: '15pt', textAlign: 'center', @@ -154,27 +153,27 @@ const useStyles = makeStyles((theme) => ({ })); export const Reviews = ({ myReviews }) => { - const classes = useStyles(); + const classes = useStyles(); //here the classes is assigned to get access to the styling const userID=localStorage.getItem('userid') - const token=localStorage.getItem('authorization') + const token=localStorage.getItem('authorization') //local storage gives userid and token of current user logged in console.log(myReviews) - const [removeConfirm, setRemoveConfirm] = React.useState(false); - const [movieID, setMovieID] = React.useState(''); - async function removeReview(movieId){ - const details={userID,movieId} + const [removeConfirm, setRemoveConfirm] = React.useState(false); //using useState hook to give states to the components when rendering + const [movieID, setMovieID] = React.useState(''); + async function removeReview(movieId){ + const details={userID,movieId} //details are taken from the page so that the API knows which userID is removed which review by the movieID console.log(details) const response = await fetch('https://arthur-laura-5000.codio-box.uk/removereview', { method: 'POST', - credentials: 'include', + credentials: 'include', //the post to the API is then called headers: { 'Content-type': 'application/json', 'Authorization': token }, body: JSON.stringify(details), }) - if(response.ok){ + if(response.ok){ //if the response of the API is 201 an alert will be display to feedback to the user alert("Your review has been removed") - window.location.reload() + window.location.reload() //the page is then reloaded to show the review is removed from the user's my reviews page } } return ( @@ -182,7 +181,11 @@ export const Reviews = ({ myReviews }) => { {(() => { if(removeConfirm){ return( - + = + {/*using divs the different parts of the page is built up + * classes are used to use styling for specific elements of the page + * this container shows movie details for the movie the user wishes to give a review on + * to show movie details the movies.*columnName* is used to get each piece of information to show on the page*/}
@@ -200,7 +203,7 @@ export const Reviews = ({ myReviews }) => { return (
-  + {window.location.href='/movies/'+review.movieId}} alt=" " />

Your rating

diff --git a/flask-react/src/components/SearchResults.js b/flask-react/src/components/SearchResults.js index 2a9972b6..e73702b4 100644 --- a/flask-react/src/components/SearchResults.js +++ b/flask-react/src/components/SearchResults.js @@ -78,7 +78,7 @@ const useStyles = makeStyles((theme) => ({ })); export default function SearchResults() { - const classes = useStyles(); + const classes = useStyles(); //here the classes is assigned to get access to the styling const [movies, setMovies] = useState([]); let { searchTerm } = useParams(); useEffect(()=> {