From 531a0e2af785b55e6cbaffce2e5146dd566f698b Mon Sep 17 00:00:00 2001 From: many-to-one Date: Thu, 30 Nov 2023 21:44:41 +0100 Subject: [PATCH] Redux logic with reduxjs/toolkit --- dump.rdb | Bin 42768 -> 31036 bytes public/index.html | 2 +- src/components/AllUsers.js | 83 ++++++++++--- src/components/Chat.js | 155 +++++++++++++----------- src/components/ChatWithUser.js | 26 ++-- src/components/Conversation.js | 157 ++++++------------------- src/components/Header.js | 9 ++ src/components/auth/Logout.js | 9 ++ src/features/messages/messagesSlice.js | 64 +--------- src/features/messages/usersSlice.js | 38 ++++++ src/media/profile.png | Bin 0 -> 6586 bytes src/store.js | 2 + 12 files changed, 270 insertions(+), 275 deletions(-) create mode 100644 src/features/messages/usersSlice.js create mode 100644 src/media/profile.png diff --git a/dump.rdb b/dump.rdb index 41c66a70a0512537009146485d68b7ce9652ac6e..0833eb658d625c534eaf580b00b7927b01d4cebf 100644 GIT binary patch literal 31036 zcmd6wdAJ-^x$e97oSk`MQt0YEBw+~Du&Qb;5XitBnG}J8Kv-3^3ZjI>Bp?tYhs!L2 z$Y4NlL?)3zILPF{prC+?M{xiygoH^{98fvp@pyh~@9drKPA7fq-sia|fAPRme7lCV zzV&_Y`+je~Z{K|me81~@?mJ_anQYPW*{7LhUGc8&uAcW!@9=*~7OhzR(42QV(-n&r zn@5(tb&`3f=hWpUo4wd9eq_$eQ%mpk=q35=L@zfFmHw;r_i5Aq^G9pmu70vyDs}Fv zm!G(3`BIZE$`_@(21%R-I*W7~xk5{=lGH?L=0#B?MBt^>@|@pyedh~L-qbt(;bYq8 zExPC{E6!MI?o3b8E0!%;vUuTQvwXQe(R_JP_S6M8rAtm(VNO|b!%2%AFTR-@T6T(F zY;HWlEMMVxH`#w*xG3ws@zhh68J#_P!_t$MtXT4^>TZj9O1<0CWlQo!C!2*s|8@Du zzwWy9loRhDF7IHuUa@G&DK^5L3m4jlSjb(Ra*8>5;lfY<>Y)GgCrTro1VJQXPbb2U z!X)*KjPqRkaU?vQuh{SM=ihV8ujX#*mHFDwb5Dn^j6)%Xt9>{1;?T_#-z099Rm+dg z|I_|wR4$(JLFWfA{B_Z7_wMyzv)5K>_1?PHzqmOQE3MvJ8!zsJ>80flP3RbUW6n`M zqi<}^+|d{2oL3osVb7Pgu6bp(PgH68NWOGaH^>sD#k5p-%9kq4@>sHL{G0`puIXP; zQDKmVQt)vjW8)c?oc48?a7~X& z{U{4!9Xl^h6o-~P+T6n%n;v^KAkY1Wg>BTPBO!h*Z zhCz_XFf#0kNQ&xCW3z`#bw+odBw->`vv%<9ZIqXYD0hu;bK(2B7A}iihQ9B- z(xxIqjOsfRBOT;n?rK-$kC+J+5M0iri zNhXYNj%v%a96Y(*XzBOeS(2?1hZh<@iDc|Wc0IBLg3yh#%w%4k*ri3{*#Fmu-By|T ziMMXQS-iMv=Rdq~_?DMAqMF1}`$UzdkCeJf`Yfh6OQ*47WRw`YyU3l9WN-RxjRh5* zxl)Kc&0}^zqFwe@nq@&2ve{FWv1k`eS9z2RFUymh?GObbQGwRE)6tc=tPo`rN4p4w zaL(N(jb)MuH}kb(ea2Z5N*S;MCD(Mu(vQ=;I#`OGE61if)vR%!-5ykr;6I(jCEaOc z!c3c_x?-vkEH1^K%rn74H=*|BO9LyXx;iG!rAEq}Gb6~9@!jgG9_jkZ%cV^%t4ppE zbqUT<-xbbhCZs_UhN)%`n3zOWy^6myDTpICkAm2kI3Vj7?Ho|{qrSoRJWPf26)q_! zvTC-?qR>-$DiX<7%%rD9Z0x3sNj{JFkZNP{pR1icy2!Vo%!9snkCA@lrg7wFsnR%ij_qPwv+vo_3&z=ukh{wF$cCc-`UxtJgD95L%@UHTSv&A{ zuM}aTWTu2L&V}V9t?pJ1U7j`XKddeD12+BEv52FDjS;KF7m=rB-kgiJCHfYjd0)aj{kL(gOpY1I=ZaCMaVDjyuvsXZ^s z#F~M1U7nIb7-fCa%f_od&?c4dOdOLWxskbXRr1QfQRBS8*w2PcPR9P(bfLk?7G5HmQjlDbLBe`Soy@*r|K!`0x`-JZ-iR%5Sv>CAVPgmXPhZ9;7P+>fXkIVU+* z2Gd@}A?yc%_QPn_(zX3lXH>gffU`@G`2cD9bb7zAPjA&n?I9jDIiX zGoI`FTFI|2>-J)matNohs3TUlN0I9en076ayt;B`rIc6aw7Ws5`VVL`am?B%yMEu7 z+fvW#pEH4M%~3Agz$kmJ&$^);XKM#;?a*18`Ocy3i4NjwUwb4Ib-;dQU(Y?eEL^s5 zhnwk04=kyEq}^~(&bp)|`=;*no_482f5sb}=_Nh$eQnZBX8fdE2wx}UeCIgl?M_=3 zhv91jl{Qk=jME3wa^TK7c-Eo4nNe9FUG609JB_#5<%gM@h2G2$@AT(cT@#g(Zs2l~ zDji6wBKAQ!&SxH3o!K5`SvWYhq-Lz_Q9+b?5oOBYy}uc_qNMtcul}0w48@kSu$$|7nF2$$|M(D z`)NtcxUkLD!Ay6?MQv_mc!q&H`s21Jm4gSi30~?y`w!aZj2Uy-1uko9u&wMTJN;Kl z4(vEa_#EW94x`|tZQ7$y26nl4zVWs8gT%}T_rIep@>Sp69T7!fIP0}n2Cgr;`|e3* zSY_AZ2TOV1!uDMGe&6k#BBPj8?7p3jXpfX1&g`9aZF`g?+PS(d&)vS;I#isRlm%B( zgTLs`!h{k{%9&Gn`U?h+aXwhm&X}@@)(t#YO6H$Y73|$z_ihXPe8xOp$+J5xDup}k z_{!k*yuZtcMd{K1QkzimPG2pheK+m=fs)!~pR&$gA82pWMh!eL`^#-vZ7~eTK2M?=a-_su{$klBgf6&zE! zY!$79qO>Mu2jokcO6niaP%q3~H^03yarg4WWq;b6JI}F(kvou1!yuX=MtjBUFrerQ}U7Ef!Pu>yP*h3scqWokJkhpN-E$g8Wi3n?GynQgm8 z!KYm5lV>SYILf)5vLEz~DamSoTkb~Ax=A@bdEk4I7X>thp&PYYEHtPxrl@5Fvo}(Y zdRz0PE`KeTUSt=`yyy4bx^l;^r~mYOvnJni$*;eA<(9TszEG1^>Yu05k5~cByHFpR+5Sxt%oiG?C8hWoa9g9Xu~hGQ+y^$>+)q zN$Me`GX1Bry%HtPyZq2iKwL6gY5^AnI?)mog)&wK&RZp0C{;A&H1(LK-lZN)=(|0N zNZO-J2*m>8Pj%88Q6cyFTcrRcDVY=~g&vedM8nUKVs9r)SaF#&-~}10J|#<1;)OA_ zjPR3`s(yT?d=Ns`G~Kz#s;9Qcvr|-ydNe*h^yUL_Vs0I!y zOVRgrHc+cAVvJ%l1lr>zkra3#AQ=3yDDn9`p|bgO<-AJeg1^1*vOk=#YRBxs+2t*5 zi(FN+Me3iY(&T}FFipsspyrQ7kL2X_1KzMRt;?u5%*k^73wl#hZsvIbSc;=31gYIF zei#ZvzBJBwE~$X8`7(*oL$_5c*ljSN7;K>@|s(+ddwYheQZO#kR~`<9W6R z_Jh>ogxiGyh)s~XDd3CEnJUs8@0_(^?A%rM;#OZURVLw&NS0nk?+EZfmrv~t#LGt4 ziN&=a|Ky_c^M6kH+LYhT9M|mYwZdor|Ki#$pC}7R2DDLL#OVcgDCz&H6@9RMFcRUn zdSzagc_y|TfC&IaLzS4+qlDl)8d`bZF8Y@#BL1|O|GQ+Lb+7I=Y5La9Ufcg9u3cMh z);~|B$peuQePuM@1~tJH1=_0POt8pg7}BH<9my3%8qV1pES*p!kp>?j^?{DkJ4e9W ztk$j^NJplrvsVYSi3yyC=6tafI8SxD3B{p3v@4Xf%4Pipe&`9A0yjr)lm{ZD4`=s~ z&KFFiij`3e8ADM6;+s|v7|UrBQMV?M3PXC*iUq_1`g1R^+ad-NNV7chX@BW~Q`Z)) zTV>#1G@eNY89}qjc>z#G4ful&4FG9-@NL;maTu~GC9oJcBu847d$!W3oHmbO%CONjdC0gv41 zfno>;(0aBO?PRByQv7+2H-;_e2XUS#TOLdR!33`~WIl@U+;{dG?`e(Sizb`bQOvF4zr#i0Y_;EDO#snk?3;4FN>9XK38 zzPyzDOO@e)E4wV87#u~#fPP%k2JYz`IF?hHbRZ)=sk+e8{DVTR`4}cQbP6(#=Bq*yFK}(3f+uJFEYzfwz1_6zm zpzw;SE8F}qnK!A|r&7)W6$12eNm+-^i>1W*QD>alli4|BJiJbtrHX1+(L(`>jN#m( z*yGHLs!vZ0ARj=L!R!;Adr?eFKZO#6w3z!Yg_DT2E4APMrw%Ymx`4aN7MfWNRtcyz zcZV{pLHFc9E6_5^bh-j|dK{TnJH$fI0LB3wAH`h;u9>MAa0m8@?dW#k+-r{V>K*7X(;{l-Y`6`ssB8&y; zD2EN;cw*s(tgg@ld`LP+$0V%=jrLRSW%Qv8S}yY)YsJA6eX>`U`D}7!AFwg#rj2)eOufYe7-cPrV6ZmqDs?8f>To_GMot6 zG>cWhR{+T8uru_R83!uwz749}d1{*steMh4r0fhGi9Dq4v!4LSW5Hw?-T;Urfk+5x zEa4BFYkFyz$)ACx4B239GL4*YTZmrik-?yRpa?nF0JbdLli7sO6_IqnW#+7&=84eo zJ*5KNhv%c^^*oy^dty$w&lq5YB zi-d*&!rAxi2|k5{CxB61ODV$^C~DYh*kdGzGz^hsL6zLTw(V&147m-&*d7to1>ig+ ztV{j2dJhaw{PnX z7$umlfdy^k4JYVOaw&X1@KAAS=X5Z!sg03rYtk( z$PW6@*d9h*RBkb)xO4G%nptQa;4w~r>GmJkL6TLrS9Pu|rTtI#$7I$1`D3ICOi0Sk z!s_fcP9RWpD2=G^xPiXjEO!Mt7?2~Xe!QdyKGs1im$sBjWG*zTWRv;^Xu`yb7BSRN zJiK|4g+p~h_xwXE%TMk2?PqRJ&%1x+6`$MEvfwqfJE-n?Doq|pxU3nvWQcQDObLMt zT=2Jq6#%1`(|_>VE5_n3r~_C&aBrLtq%Rljo)gPc9QF1ZjMP&fb1ucLq#s$HqvVppNseiW$;DDd82{XEBC|uAMj$e`otfb03>9)$q zka_4YBrvVdRtR${+?3sjIK#7;TxNT^4?p<}1W|p8l$)Z$~UPoWq+xu=mb4cDb&MKpJKXKWTQO(Q{B6xSA5umh5p%3!QoKrT_b!!ZBS^H~keIL=M%HQNSh;0h9*( zlh+yia^b4NF`-OFYNazA4;%-4DNT|VE`m3Y+#FnT>_;18)~foNiuxM#OeA$=8}zwW z&jdIuFFfF>#~Qv-%b1(eQBl7S>8Q$QzVW@HF-PQEC;AT~_O`Z0s|~Jz6;Cs9Fu!6SW#(b-h~c>NoB!9FuHmivT2YkTq~!$S%90I=HOK&e6vzaW9O&`ONSy`U$_{G=0Tl5<>Q3Jw!jj92o#e3dTIOe8Rh(qr} zJ^A@H-zj>Z$T}OvkEmHk#gFENo)>Q{8WWCx6Pn8qWmsh1ebcKq6pe}c8s-;Cax$d! zWa-oUB(NOAO3&=9mCqNB2}rj=U#d{rHRwzKH1VFoG3m;Y@+KUXXtXw{TG7i6sanPU zU%0JsOpTb9(sv^#fV+}8>ox*CphBtc8`M>%~(QibRv{~)&Gb^4c z98;l_Mi)s@)?BlE;@@=Pn60$Z{eL;WaLiGSHoK>pMti|uK3F(ry*3<)eSzr(4AG{&swBAQSUn?~e0_*toM95L_H4ePUI%uNsh@Eb!! zfc$FD{L6~QY(+qvIcbl=F&lXgAnID)L%#Ug@r7fy;#+>{brg=dp5=M;_EN@TO+V?Qh$b4c8S_{T#&)J)v7jk>;Y%oduW z_?4HhEF5!#mINOg&71x}16K8Z5p`bMTRK6KhgipGS+v+`-6XFG3{8RY6PBHGH-0lxh- zJY-qnn05*c2@MDsY#W#~5*m0yJHx_l(&D^);QYcdksw9}Fb^P)(G2EitdauZDU7un z10#Lphr1V!33RR#I5?k?4)&3hVGL*?4a_6zHl3dG%5H^YDkMyZK^eC~^u)lD1z+u8 z2Cx;XAwPR{_RdR-ej{i^VILcHRtnCL)4$uLhV-7ntUO9?QnL!jR3Rc6bOvxpP>u-% zB=jP}&f;#iIDy5wof<4tfgn0 zva^tJa5QkPHEbOGAwpH8Nw9Gr`gAn6;XYf&1g3-x2w`4fs|IL`i&Tc6PqEk z(^rq$v2e^L96G%ID2E=tbLo?A(fe%0-T&nMf7-2R%u&ezXJ)Nrz|O)c^a_K2Tw6Hi zdZmI@JT#RmJpJU43&(`(Locyug~X04?k^m3V`T=rvPPNlt(WgC91}qZ>3EZZkZkw) zy@g}eC{daUQNB07t1)Jppd$jpj+qTdVwo~Ag#^OH%(4TQr(TsoM}}=FYbfMlPSD#U zri1X|_zZm=n78Ks$A9k8z;CvUiS7)MEHnE)G(EEZ7~;zhkVh)lDr44db3x&lRD|eI zsl;$mKrxC+iuq&;TH>SU4ZWq6GYiK=s6uOmaMhq{LVEz=AE?y8NE%*JB-b8wV&Rx5 zQIQB!f}x7w1zVjIQdI<4;J}E3vV-0@uyD+P!ZWgS8mJ8g6A4t|kl)-gnGdOrzwV>+ z3&$kQ3&s}^+VG7)Dsq#M2}>} z4V^!DtTATouzb^5`Jq`snk_URK)|TkJU60~LGHk~AcNm+&tLlUhWl(86D?$n0wbll zW@wwqB+h!@M+jnTu-H!z-v8plF-ImMV{}y1?+o87Mx}G+Z;|Jb2+m%6LE)H;VcNk0 zBr14cAaFow1cksjJ;mV9UTcNdPC z*!f=Aas%(q*cH7Y-3LNk*iF6e*?Y-00=Q%M1#Pg)SqbW@Ul?I242>MW7^qlZV3yJ+`1D$_`&Fc-xweq#$jS~%vAg#uDLYoWkQp|w!J{)AG=T0U5b*qgF& zOr|0kKmb?}6lHbJ4JgdxOji%@FC5eQMIhF)Lr+%6!#=g$H--^*zJ){TrDLZRj>#l7 z(q0$u7EVe|cI{^oGl;`B6`;#k&OG)1KGOURcCqR1peY+NpiPVspV+LGE&P~imxLvUhA`B2N{9Ym}*q+&5IBCV$u5? zF?Ru%X7S?zg-gxQ3K+I`(J#Mu&%!b7$Zw;k3^zUEDU-bU`CSUfOhT-3tkn$$2jpZl zh8&sTA?SjwiZQJ|c+VG#K6{;a4&Fl6naR56Fw<$>bAry#-M6Z6%wfwOqTzNxLq}9P zkx|PYbN;e>3dd~j6hu8T>=YDyahtme$K*jbXHb;=;lT$!R`l7;P#I%wk?@NewMC-C z9kxXhKkE5f@tD?)$uc~(ZcLOlBW_HO<(C(ZxhWSY#?gmdpl*Hbg2FLt%%?D|N>V$A zLs3s55z*QO;i@OjEF81W^9s#-gXdLp%LRuOj@jI63kmRgudUZEoLe~NsK*zRFY7(N z*hw2az9#%4EF2T(6hvB^v=);G&!1U1=0=WYIG*_&Be``nBlq3C|MrDrGN#8FJY=Ls z3)^6%hAG_X^QRS$X}hZi12^WRM-ALAy89<9i|)-4-#9$(n)$|s|N57Q3dbC_tHU%e z#`BJpKWbNpZy+O>Vz2!^RX8U98~tX!Nt?XmAHA?}%;xrdc=WBe=ljVHD+|YLWeYg_ z%u@@;tnnjkYDc*E*|*MY`0gz&aev@tB*RHWH8j_K3nU8;6{jcB&n665l@VnZFc$ zcD?!8swjB-p5ifwM!JBKHZjsQaM5jrW40P4n|#?dg=4lFVcR`fQ8;GZ>|B%4xn9-r z=Z0_e|2#m|_xyF&NA+vI-cP8Boe<_S4A(JqQRgm$AW2e)AR0ON?)@(;8WSI)T2C8m z5>@MI$PvMxuRyx-FW7tZE{aBoew})94&@ zclU*bW7hi>;jLu-imbho>*Dhii~Elc&MkVMEo_qFOYdF$uSH`H+cQBTZNi@E?mNn7 z6^+@-7HZWO%f}auxj8#3oUqdQSA6!kqA^>zU?uy1^W4HQH+J8$;-w+?E$qG+-QW4X zV~gHrE7vb?mwO7wY~?og*NZ-UOws$SvpH+xa(3j0j&F=vZ|l&+)nUDh0`x?47lp?@ z`jNdG?z45w4dxA?U>lh?B)fK8yjRhftxO{(o3jhYY-Lul)8dQwEPS7}E*VWsGTM(j zzcHq@BgE~586(m-hAIFk5x%}dHslOHdR5GLaL2+|1Cuib&MmK*!|;{1K0nLHBsT1c#bjK4%){wy#QIz z+%H@b+IQw;aRB=FuLO-T>kZbL_^WNk&kV~nFMj*5$NnpT+Et=eU(6#xXBt{rE~XP{%FydHFi!+Ga_`h9#%DePRA}Xg<}RoHh3d8QjiHF zHc~ioSsST~zxCe2F>BqcK&m!!uX=IZ{K7G7U9-r~Rw`2Gn)RV~+`=*I&AJc+)thxi zCr+7BJSH|D%(c{*gy9HLV-hy~t%-$Wa!hT`n=JhEbv=b+wy;DKbN@Exk)rE!#EK1C zzo`}5b*1jYF&ix4m~g7MfV*J96W=L%pLO1I!`5@?%QjfgedHhaH^xNq!J!=~#vdV> znSsGgi(k?StRf~s&tHYmL>L5Ribw#RKVul!Z(>t}hZ7F8k$!gj%Wi47&z3RKGlYPY z)-64NDW`rww1x{8lg1b&$HC$w$~PB{$uII?)RqDT;topbKyisp0XimYpu?EYf>U3= zsc1~gK}HyXF))AzEZ_!HP9b64b@+jyDD8N7;dMo0niL-fexL)rzqE5G{1y~!Z;XeN z{VP)Kc-FCnV@3=EqglaP3tk)Aok0&YCt;f5{G|Eail1No`O}KtCuWiCPJSxG3dy0) zaGON*>@$gEaHE#)^!=__S~Mn#y@=noz&Vh&h?gLKMtD@>r3DesuQbVPZjP4}jfq`f z%rEfxSa8@MIthnt5M0!{=#Qc-jXwU*fxhK_Lwl(CiVA!%SmByJ^q zXK~^CG!RkvJMsoOJn51+H&KJ)g2!wQg@oDu?Z%jVO7=$rRf`Z6N*tLAmcqt! zrV5*fy9e~9HDYC6%IetoX(}WLRN&Tn?2=19F6wK=mNEI?Bj&X6x1f)M)5TO83o&e$ zQCp@sU%YbcVMp7ToBGkSmVW?q*hzEusC1sxn?AC0c=YFff8~YE{FnYG&0#OEaq_Bv zo=TIiQ1`~BGoO{j*-6NlB)Sqb+Kfl+q5976d45R5g_de^% z4_$R|*_-{x=eD%hT5A(o|2&l@&1zk9HKj>+WzEl8b#+|RGull$pBh)!O*-Ffx80g-y5@G*bw`=N~;-1oFw_(!OhQB@~5UW zndzMS+3t~%PJVoEhZcjR{2_kmrTXA@n;Br`5A}==&dzy#N|U)+F5#E0zWJ`r&Fk80 zw6nTnXij+E;S(ChgsV?kH%h-cqjPvTx$m{{oL)7<$rhEIYKAjcK)3S~dq{!9(Z2R_VXzQeiT X*?Lo5>d316XZyADR<1sI+0p+EtFTy| literal 42768 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 diff --git a/public/index.html b/public/index.html index aa069f2..f24465b 100644 --- a/public/index.html +++ b/public/index.html @@ -24,7 +24,7 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - React App + Lister diff --git a/src/components/AllUsers.js b/src/components/AllUsers.js index 452ed7b..0a15b9e 100644 --- a/src/components/AllUsers.js +++ b/src/components/AllUsers.js @@ -9,15 +9,17 @@ import axios from 'axios'; import { useDispatch, useSelector } from 'react-redux'; import { setMessages } from '../features/messages/messagesSlice.js'; +import { setUser, addUser, removeUser } from '../features/messages/usersSlice.js'; + const AllUsers = (params) => { - const [users, setUsers] = useState([]) + // const [users, setUsers] = useState([]) const [socket, setSocket] = useState([]) const [incomingRequest, setIncomingRequest] = useState([]) - const [selectedUser, setSelectedUser] = useState(null); - const [conversation, setConversation] = useState([]); - const [friend, setFriend] = useState(null) + // const [selectedUser, setSelectedUser] = useState(null); + // const [conversation, setConversation] = useState([]); + // const [friend, setFriend] = useState(null) const conv_name = 1 @@ -26,6 +28,9 @@ const AllUsers = (params) => { const dispatch = useDispatch(); const allMessages = useSelector((state) => state.messages); + const users = useSelector((state) => state.users); + console.log('users before', users) + // setUsers(usersList) useEffect(() => { console.log('allMessages', allMessages) @@ -48,6 +53,37 @@ const AllUsers = (params) => { } }, []) + + useEffect(() => { + + if ( users.length === 0 ) { + friendList() + } + + }, [user]) + + + const friendList = () => { + + axios + .get(`${ serverIP }/auth/friends/`, { + headers: { + Authorization: `Bearer ${user.token}`, + } + }) + .then((response) => { + dispatch(setUser(response.data.user_data)); + console.log('users after', users) + console.log('friends', response.data.user_data) + }) + .catch((error) => { + console.log('Error friendsList', error) + // navigate('/login') + }) + + } + + useEffect(() => { if ( user ) { @@ -64,8 +100,15 @@ const AllUsers = (params) => { if (data.type === 'allUsers') { console.log('allUsers', data, data.type); - console.log('friendReq', data.incomingFriendRequest); - setUsers(data.users) + console.log('friends_count', data.friends_count.count); + + if ( users.length < data.friends_count.count ) { + friendList() + console.log('count < '); + } + // dispatch(setUser(data.users)); + + // setUsers(data.users) setIncomingRequest(data.incomingFriendRequest) } else if (data.type === 'addFriend') { @@ -78,16 +121,17 @@ const AllUsers = (params) => { } else if (data.type === 'confirmRequest') { - console.log('confirmRequest data', data); - setUsers(data.users) + console.log('confirmRequest data', data.user); + // setUser(data.users) + dispatch(addUser(data.user)); // Remove the added user from request list - {data.users.map((user) => { + // {data.user.map((user) => { setIncomingRequest((prevUsers) => { // Use the filter method to remove the user with the specified id - const updatedUsers = prevUsers.filter((u) => u.id !== user.id); + const updatedUsers = prevUsers.filter((u) => u.id !== data.user.id); return updatedUsers; }); - })} + // })} } else if (data.type === 'blockResponse') { console.log('blockResponse', data) @@ -124,6 +168,11 @@ const AllUsers = (params) => { console.log('confirmRequest', 'socket OPEN', id) socket.send(JSON.stringify({type: 'confirmRequest', requestId: id, userId: user.id})); } + setIncomingRequest((prevUsers) => { + // Use the filter method to remove the user with the specified id + const updatedUsers = prevUsers.filter((u) => u.id !== id); + return updatedUsers; + }); } @@ -152,7 +201,7 @@ const AllUsers = (params) => { const searchUsers = (text) => { - setUsers((prevUsers) => { + setUser((prevUsers) => { const updatedUsers = prevUsers.filter((u) => u.username.toLowerCase().includes(text.toLowerCase())) return updatedUsers; }); @@ -165,12 +214,12 @@ const AllUsers = (params) => { {incomingRequest ? (
- {incomingRequest.map((user) => ( + {incomingRequest.map((userR) => ( blockUser(user.id)} - denyRequest={() => denyRequest(user.id)} - confirmRequest={() => confirmRequest(user.id)} + user={userR} + blockUser={() => blockUser(userR.id)} + denyRequest={() => denyRequest(userR.id)} + confirmRequest={() => confirmRequest(userR.id)} /> ))}
diff --git a/src/components/Chat.js b/src/components/Chat.js index a152962..c800268 100644 --- a/src/components/Chat.js +++ b/src/components/Chat.js @@ -8,14 +8,27 @@ import ConfirmationDialog from './ConfirmationDialog.js'; import { useUser } from '../context/userContext.js'; import AddUsersToChat from './AddUsersToChat.js'; +import { useDispatch, useSelector } from 'react-redux'; +import { addMessage, removeMessage } from '../features/messages/messagesSlice.js'; + const Chat = (props) => { const { user } = useUser(); const navigate = useNavigate(); + // Reseived props: + const location = useLocation() + const chat = location.state + const chatID = chat.id + + const dispatch = useDispatch(); + const allChatMessages = useSelector((state) => state.messages); + const messages = allChatMessages.filter((message) => message.chat_id === chat.id); + console.log('allChatMessages', allChatMessages) + const [data, setData] = useState(null) - const [messages, setMessages] = useState([]); + // const [messages, setMessages] = useState([]); const [usersPhotos, setUsersPhotos] = useState([]); const [newMessage, setNewMessage] = useState(''); const [socket, setSocket] = useState(null); @@ -33,11 +46,6 @@ const Chat = (props) => { // const to make a new message been on the bottom of the chat const chatContainerRef = useRef(null); - // Reseived props: - const location = useLocation() - const chat = location.state - const chatID = chat.id - const nav = useNavigate() @@ -62,43 +70,43 @@ const Chat = (props) => { // ################################################################################################### // - const allMessages = async () => { - - axios - .get( - `${serverIP}/allMessages/${chatID}/`, - { - headers: { - Authorization: `Bearer ${user.token}`, - }, - } - ) - .then((response) => { - console.log('response.data Chat', response.data) - for (const message of response.data.messages) { - const messageObject = { - id: message.id, - username: message.username, - message: message.content, - photo: message.photo, - }; - mess.push(messageObject); - } - setMessages(mess) - setChatUsers(response.data.chat.user) - setUsersPhotos(response.data.photos) - console.log('usersPhotos', usersPhotos) - }) - .catch((error) => { - console.error('Error fetching conversation data:', error); - if(error.response.status === 403){ - nav('/login') - }else if (error.response.status === 404){ - nav('/404') - } - }); - - } + // const allMessages = async () => { + + // axios + // .get( + // `${serverIP}/allMessages/${chatID}/`, + // { + // headers: { + // Authorization: `Bearer ${user.token}`, + // }, + // } + // ) + // .then((response) => { + // console.log('response.data Chat', response.data) + // for (const message of response.data.messages) { + // const messageObject = { + // id: message.id, + // username: message.username, + // message: message.content, + // photo: message.photo, + // }; + // mess.push(messageObject); + // } + // setMessages(mess) + // setChatUsers(response.data.chat.user) + // setUsersPhotos(response.data.photos) + // console.log('usersPhotos', usersPhotos) + // }) + // .catch((error) => { + // console.error('Error fetching conversation data:', error); + // if(error.response.status === 403){ + // nav('/login') + // }else if (error.response.status === 404){ + // nav('/404') + // } + // }); + + // } @@ -106,25 +114,25 @@ const Chat = (props) => { // ##################################### CONNECT TO THE SOCKET ####################################### // // ################################################################################################### // - + const ws = new WebSocket(`${wsIP}/ws/chat/${chatID}/?userId=${user.id}&token=${user.token}`); useEffect(() => { - const ws = new WebSocket(`${wsIP}/ws/chat/${chatID}/?userId=${user.id}&token=${user.token}`); - setSocket(ws); + // const ws = new WebSocket(`${wsIP}/ws/chat/${chatID}/?userId=${user.id}&token=${user.token}`); + // setSocket(ws); - if(ws) { - ws.onopen = () => { - console.log('WebSocket connection opened'); - allMessages() - }; - ws.onclose = () => { - console.log('WebSocket connection closed'); - nav('/login'); - }; - } else { - nav('/login') - } + // if(ws) { + // ws.onopen = () => { + // console.log('WebSocket connection opened'); + // // allMessages() + // }; + // ws.onclose = () => { + // console.log('WebSocket connection closed'); + // nav('/login'); + // }; + // } else { + // nav('/login') + // } // Receive data from server via socket @@ -134,13 +142,26 @@ const Chat = (props) => { if (message.type === 'message_deleted') { console.log('message_deleted', message.id); // Handle message deletion by filtering out the deleted message - setMessages((prevMessages) => { - const updatedMessages = prevMessages.filter((msg) => msg.id !== message.id); - console.log('updatedMessages', updatedMessages); - return updatedMessages; - }); + // setMessages((prevMessages) => { + // const updatedMessages = prevMessages.filter((msg) => msg.id !== message.id); + // console.log('updatedMessages', updatedMessages); + // return updatedMessages; + // }); } else if (message.type == 'added_message') { - setMessages((prevMessages) => [...prevMessages, { id: message.id, message: message.message, username: message.username, photo: message.photo }]); + + dispatch(addMessage({ + id: message.id, + message: message.message, + username: message.username, + user_id: message.user_id, + unread: message.unread, + photo: message.photo, + chat_id: message.chat_id, + })); + + console.log('addMessage'); + + // setMessages((prevMessages) => [...prevMessages, { id: message.id, message: message.message, username: message.username, photo: message.photo }]); // scrollToBottom(); } else if (message.type == 'added_users') { setSelectedUsers((prevMessages) => [...prevMessages, { users: message, }]); @@ -178,11 +199,11 @@ const Chat = (props) => { } } - // setSocket(ws); + setSocket(ws); return () => { - if (socket) { - socket.close(); + if (ws) { + ws.close(); } }; diff --git a/src/components/ChatWithUser.js b/src/components/ChatWithUser.js index b5098f8..059bb3b 100644 --- a/src/components/ChatWithUser.js +++ b/src/components/ChatWithUser.js @@ -1,31 +1,37 @@ import React from 'react' import { serverIP } from '../config' import { Link } from 'react-router-dom'; +import profile from '../media/profile.png' const ChatWithUser = ({ user }) => { + console.log('user', user) return (
+
+ {/* {user.username} */} {user.photo ? + {user.username} : - {user.username} + {user.username} }

{user.count}

+
- - {user.username} -
- {user.last_mess.unread ? -

- {user.last_mess.content}

- : -

+ {user.last_mess.content}

- } -
+ + {user.username} +
+ {user.last_mess.unread ? +

- {user.last_mess.content}

+ : +

+ {user.last_mess.content}

+ } +

{user.last_mess.timestamp}

diff --git a/src/components/Conversation.js b/src/components/Conversation.js index 81028f4..5f1c978 100644 --- a/src/components/Conversation.js +++ b/src/components/Conversation.js @@ -4,10 +4,10 @@ import { wsIP, serverIP } from '../config.js'; import { useLocation, useNavigate } from 'react-router-dom'; import ConfirmationDialog from './ConfirmationDialog.js'; import { useUser } from '../context/userContext.js'; -import Cookies from 'js-cookie'; import { useDispatch, useSelector } from 'react-redux'; -import { setMessages, addMessage, removeMessage } from '../features/messages/messagesSlice.js'; +import { addMessage, removeMessage } from '../features/messages/messagesSlice.js'; +import { lastMessage } from '../features/messages/usersSlice.js'; const Conversation = ( props ) => { @@ -21,6 +21,7 @@ const Conversation = ( props ) => { // User data from the useContext.js const { user } = useUser(); + console.log('user', user) const dispatch = useDispatch(); const allMessages = useSelector((state) => state.messages); @@ -46,12 +47,6 @@ const Conversation = ( props ) => { const ws = new WebSocket(`${wsIP}/ws/conversation/${conv_name}/?userId=${user.id}&receiverId=${receiver.id}&token=${user.token}`); const wsu = new WebSocket(`${wsIP}/ws/AllUsers/${conv_name}/?userId=${user.id}&token=${user.token}`); - // const messages = null - - // if (conversation) { - // messages = useSelector((state) => state.messages.filter((message) => message.conversation === conversation)); - // } - // Show the bottom message with open the chat; // chatContainerRef is a var of useRef; // current means the curren element(chat): '
'; @@ -59,101 +54,53 @@ const Conversation = ( props ) => { const [hasScrolled, setHasScrolled] = useState(false); + // useEffect(() => { + // if ( !hasScrolled ) { + // window.scrollTo({ top: chatContainerRef.current.scrollHeight}) + // } + // // console.log('window.scrollTo', chatContainerRef.current.scrollHeight) + // }, []) + useEffect(() => { - if ( !hasScrolled ) { - window.scrollTo({ top: chatContainerRef.current.scrollHeight}) - } - // console.log('window.scrollTo', chatContainerRef.current.scrollHeight) - }, []) + window.scrollTo({ top: chatContainerRef.current.scrollHeight}) + }) useEffect(() => { - // // Fetch conversation data for the selected user based on userId. - // axios - // .post( - // `${serverIP}/conversations/`, - // { - // user: [parseInt(user.id), receiver.id], - // }, - // { - // headers: { - // Authorization: `Bearer ${user.token}`, - // }, - // } - // ) - // .then((response) => { - // const conversationData = response.data.conversation; - // setConversation(conversationData.id); - - // // console.log('messages before axios', messages) - - // // Check if messages for this conversation already exist in the state - // // setMessages_(allMessages.filter((message) => message.conversation === conversationData.id)); - // // console.log('messages setMymessages', messages.filter((message) => message.user_id === receiver.id)) - - // console.log('conversation ID before', conversation, conversationData.id); - // // dispatch(setConvId(conversationData.id)); - // // if (messages.length === 0 || Cookies.get('userId') !== conversationData.id) { - // // console.log('conversation ID previouse', Cookies.get('userId'), conversationData.id); - // // getConvMess(conversationData.id) - // // } - // console.log('conversationData', conversationData); - // // checkConversation(conversationData.id) - - // }) - // .catch((error) => { - // console.error('Error fetching conversation data:', error); - // if(error.response.status === 403){ - // navigate('/login') - // }else if (error.response.status === 404){ - // navigate('/404') - // } - // }); - - - // wsu.onmessage = (event) => { - // const dataU = JSON.parse(event.data); - // console.log('dataU', dataU); - // if (dataU.type === 'mess_count'){ - // console.log('mess_count', dataU); - // } - // } - // message logic ws.onmessage = (event) => { const message = JSON.parse(event.data); console.log('message', message); if (message.type === 'message_deleted') { console.log('message_deleted', message.id); - // Handle message deletion by filtering out the deleted message - // setMessages((prevMessages) => { - // const updatedMessages = prevMessages.filter((msg) => msg.id !== message.id); - // console.log('updatedMessages', updatedMessages); - // return updatedMessages; - // }); dispatch(removeMessage(message.id)); - } else { + } else if ( message.type === 'resend_message' ) { + console.log('resend_message', message.id); + } + else { console.log('received new message', message); setHasScrolled(false) // Get you to the bottom of the page if is incoming data from the server - // setMessages((prevMessages) => [ - // ...prevMessages, - // { - // id: message.id, - // content: message.content, - // username: message.username, - // unread: message.unread, - // photo: message.photo - // } - // ]); + dispatch(addMessage({ id: message.id, content: message.content, username: message.username, + user_id: message.user_id, unread: message.unread, photo: message.photo, conversation_id: message.conversation_id, })); + + dispatch(lastMessage({ + user_id: receiver.id, + last_mess: { + content: message.content, + timestamp: '10', + unread: message.unread, + }, + })); + } } @@ -168,37 +115,8 @@ const Conversation = ( props ) => { }, []); - - // const checkConversation = (id) => { - // if (messages.length === 0 || conversation === id) { - // console.log('conversation ID previouse', conversation, id); - // getConvMess(id) - // } - // } - - -// const getConvMess = ((id) => { -// console.log('getConvMess', id) -// axios.get(`${serverIP}/getConversation/${id}/`,{ - -// headers: { -// Authorization: `Bearer ${user.token}`, -// userId: user.id, -// }, - -// }) -// .then((response) => { -// console.log('getConvMess-response', response.data.messages) -// // setMessages(response.data.messages) -// // Use the setMessages action to store messages in the Redux store -// // dispatch(setMessages(response.data.messages)); -// }) -// .catch((error) => { -// console.error('Error fetching getConvMess data:', error); -// }) -// }) - const sendMessage = () => { + if (socket && socket.readyState === WebSocket.OPEN) { if (newMessage) { // dispatch(addMessage(newMessage)); @@ -212,14 +130,9 @@ const Conversation = ( props ) => { } } - // if (socketU && socketU.readyState === WebSocket.OPEN) { - // console.log('socketU', 'ok'); - // console.log('socketU data', socketU); - // socketU.send(JSON.stringify({type: 'new_message_count', count: 1 })); - // } - }; + const handleChange = (e) => { setNewMessage(e.target.value); }; @@ -317,7 +230,7 @@ const delQuest = () => { { receiver.photo ? {receiver.username} : - {receiver.username} + {receiver.username} }
{showConfirmation ? @@ -355,13 +268,13 @@ const delQuest = () => { {messages.map((message, index) => (
- {message.username === user.username ? + {message.user_id === user.id ?
{message.photo ? {message.username} : - {message.username} + {message.username} }

confirmDelete(message.id)}>{message.content}{' '}

@@ -379,7 +292,7 @@ const delQuest = () => { {message.photo ? {message.username} : - {message.username} + {message.username} }

{message.content}

@@ -391,7 +304,7 @@ const delQuest = () => { {message.photo ? {message.username} : - {message.username} + {message.username} }

{message.content}

diff --git a/src/components/Header.js b/src/components/Header.js index 35daa03..e57ec85 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -7,14 +7,23 @@ import {serverIP} from '../config.js'; import '../styles/Header.css'; import { useUser } from '../context/userContext.js'; +import { useDispatch, useSelector } from 'react-redux'; +import { setUser, clearUsers } from '../features/messages/usersSlice.js' +import { setMessages, clearMessages } from '../features/messages/messagesSlice.js'; + const Header = () => { + const dispatch = useDispatch(); + const navigate = useNavigate(); const { user } = useUser(); // Handle user logout const handleLogout = async () => { + dispatch(clearUsers()) + dispatch(clearMessages()) + try { const userId = user.id; // Send a POST request with user ID and token diff --git a/src/components/auth/Logout.js b/src/components/auth/Logout.js index 58b091c..2b64a3e 100644 --- a/src/components/auth/Logout.js +++ b/src/components/auth/Logout.js @@ -4,8 +4,14 @@ import axios from 'axios'; import {serverIP} from '../../config'; import {useUser} from '../../context/userContext.js' +import { useDispatch, useSelector } from 'react-redux'; +import { setUser } from '../../features/messages/usersSlice.js' +import { setMessages } from '../../features/messages/messagesSlice.js'; + const Logout = () => { + const dispatch = useDispatch(); + const { user } = useUser(); const navigate = useNavigate(); const userId = user.id; @@ -14,6 +20,9 @@ const Logout = () => { // Handle user logout const handleLogout = async () => { + dispatch(setUser(null)) + dispatch(setMessages(null)) + try { console.log('token', user.token) diff --git a/src/features/messages/messagesSlice.js b/src/features/messages/messagesSlice.js index fd00c12..8cc610b 100644 --- a/src/features/messages/messagesSlice.js +++ b/src/features/messages/messagesSlice.js @@ -1,7 +1,4 @@ -import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; -import axios from 'axios'; -import { serverIP } from '../../config'; -import { useUser } from '../../context/userContext'; +import { createSlice } from '@reduxjs/toolkit'; // Users slice const messagesSlice = createSlice({ @@ -17,60 +14,11 @@ const messagesSlice = createSlice({ removeMessage: (state, action) => { return state.filter((message) => message.id !== action.payload); }, + clearMessages: (state) => { + return []; + }, }, }); - export const { setConvId, setMessages, addMessage, removeMessage } = messagesSlice.actions; - export default messagesSlice.reducer; - - -// import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; -// import axios from 'axios'; -// import { serverIP } from '../../config'; -// import { useUser } from '../../context/userContext'; - -// // Async thunk for fetching messages for a specific conversation -// export const fetchMessages = createAsyncThunk('messages/fetchMessages', async (conversationId) => { -// const { user } = useUser(); -// // const existingMessages = getState().messages[conversationId]; // Check if messages for this conversation already exist in the state - -// // If messages are already in the state, return them -// // if (existingMessages) { -// // return existingMessages; -// // } - -// const response = await axios.get(`${serverIP}/getConversation/${conversationId}/`, { -// headers: { -// Authorization: `Bearer ${user.token}`, -// userId: user.id, -// }, -// }); - -// return response.data.messages; -// }); - -// // Messages slice -// const messagesSlice = createSlice({ -// name: 'messages', -// initialState: {}, -// reducers: { -// setMessages: (state, action) => { -// const { conversationId, messages } = action.payload; -// state[conversationId] = messages; -// }, -// addMessage: (state, action) => { -// const { conversationId, message } = action.payload; -// state[conversationId].push(message); -// }, -// removeMessage: (state, action) => { -// const { conversationId, messageId } = action.payload; -// state[conversationId] = state[conversationId].filter((message) => message.id !== messageId); -// }, -// }, -// }); - -// // Export action creators -// export const { setMessages, addMessage, removeMessage } = messagesSlice.actions; - -// // Export the reducer -// export default messagesSlice.reducer; + export const { setConvId, setMessages, addMessage, removeMessage, clearMessages } = messagesSlice.actions; + export default messagesSlice.reducer; \ No newline at end of file diff --git a/src/features/messages/usersSlice.js b/src/features/messages/usersSlice.js new file mode 100644 index 0000000..49c6b6e --- /dev/null +++ b/src/features/messages/usersSlice.js @@ -0,0 +1,38 @@ +import { createSlice } from '@reduxjs/toolkit'; + +// Users slice +const usersSlice = createSlice({ + name: 'users', + initialState: [], + reducers: { + setUser: (state, action) => { + return action.payload; + }, + addUser: (state, action) => { + state.push(action.payload); + }, + lastMessage: (state, action) => { + console.log('lastMessage reducer called with action:', action); + // Find the user by user_id + const userToUpdate = state.find((user) => user.id === action.payload.user_id); + + // If the user is found, update their lastMessage + if (userToUpdate) { + userToUpdate.last_mess = { + content: action.payload.last_mess.content, + timestamp: action.payload.last_mess.timestamp, + unread: action.payload.last_mess.unread, + }; + } + }, + removeUser: (state, action) => { + return state.filter((user) => user.id !== action.payload); + }, + clearUsers: (state) => { + return []; + }, + }, + }); + + export const { setUser, addUser, lastMessage, removeUser, clearUsers } = usersSlice.actions; + export default usersSlice.reducer; \ No newline at end of file diff --git a/src/media/profile.png b/src/media/profile.png new file mode 100644 index 0000000000000000000000000000000000000000..e1a28b3e6f5283b47679b0573e8639daab2a6f22 GIT binary patch literal 6586 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