From 5d6b6096989f69c40b533f3cd4a33d1f3b7a0ef9 Mon Sep 17 00:00:00 2001 From: Shakil Ahmed <88922780+Riyad139@users.noreply.github.com> Date: Thu, 30 Nov 2023 11:24:38 -0800 Subject: [PATCH] Riyad/implement message (#263) * 1. implementing messages * 1. now image can be sent 2. image render is available * now file can be sent and emoji can be add * 1. add enter button to send messages 2. now message can be pinned 3. message can be deleted 4. message render is now logical * added review api and migrations * 1. add typing indicator 2. add realtime message count icons * again push * review component ready * 1. pinned message bar is added 2. user details shown * 1. refactor user * 1 * refactored review table for all users * blocked multiple review for a single project and created service functions * 1. implement search function * 1. fix bug m3,m5,m6,m8,m10,m12,m13,m15,m16,m17 * added reviews to freelancer profile * 1. fix bug M7,M8,M9,M11,M14, * added edit component * 1. fix some bugs * complete update and delete * 1. add reactons enable 2. add message popup box 3. add scroll into view of pinned message * 1. redirect user to log in page if not logged in * 1. fix the carusel issue * 1. fix message input * 1. wallet address is coppied * 1. add new line --------- Co-authored-by: ssani7 --- next.config.js | 4 + package.json | 2 + public/MessageIcons/circle.svg | 3 + public/MessageIcons/flag.svg | 3 + public/MessageIcons/page.svg | 3 + public/MessageIcons/pin.svg | 3 + public/message-box-pattern.svg | 130 ++++ public/messages.svg | 68 +++ public/pin.png | Bin 0 -> 1747 bytes src/assets/svgs/warning_animation.json | 1 + .../ChannelListItem/ChannelListItem.tsx | 93 +++ src/components/Chat.tsx | 44 +- src/components/ChatPopup.tsx | 6 +- src/components/Common/InputOutlined.tsx | 29 + src/components/Common/TextAreaOutlined.tsx | 26 + src/components/MessageBox/EmptyMessageBox.tsx | 19 + src/components/MessageBox/ImageCurosal.tsx | 99 +++ src/components/MessageBox/MessageBox.tsx | 574 ++++++++++++++++++ src/components/MessageBox/MessageItem.tsx | 530 ++++++++++++++++ src/components/MessageBox/MessageSideBar.tsx | 192 ++++++ src/components/MessageBox/PinMessages.tsx | 44 ++ src/components/Navbar/NewNavBar.tsx | 23 +- src/components/Navbar/NotificationIcon.tsx | 2 - src/components/Profile/CountrySelector.tsx | 20 +- src/components/Review/Review.tsx | 307 ++++++++++ src/components/Review/ReviewModal.tsx | 173 ++++++ src/components/Review/ReviewSection.tsx | 181 ++++++ ...091011_drop_freelancer_and_add_reviewer.ts | 19 + src/lib/queryServices/reviewQueries.ts | 73 +++ src/model.ts | 4 + src/pages/api/getstream/getnotifications.ts | 5 +- src/pages/api/project/[...id].ts | 25 +- src/pages/api/project/vote/index.ts | 6 - src/pages/api/reviews/index.ts | 192 ++++++ src/pages/api/users/[...id].ts | 6 +- src/pages/api/users/byList/index.ts | 1 + src/pages/api/users/byid/[id].ts | 4 +- src/pages/dashboard/index.tsx | 14 +- src/pages/dashboard/new.tsx | 30 +- src/pages/freelancers/[slug].tsx | 158 +---- src/pages/messages/index.tsx | 168 +++++ src/pages/profile/[id].tsx | 14 +- src/pages/projects/[id].tsx | 54 +- src/redux/reducers/userReducers.ts | 22 +- src/redux/services/reviewServices.ts | 69 +++ src/redux/slices/userSlice.ts | 14 +- src/redux/store/store.ts | 4 + src/utils/MessageOptions.ts | 93 +++ yarn.lock | 18 + 49 files changed, 3289 insertions(+), 283 deletions(-) create mode 100644 public/MessageIcons/circle.svg create mode 100644 public/MessageIcons/flag.svg create mode 100644 public/MessageIcons/page.svg create mode 100644 public/MessageIcons/pin.svg create mode 100644 public/message-box-pattern.svg create mode 100644 public/messages.svg create mode 100644 public/pin.png create mode 100644 src/assets/svgs/warning_animation.json create mode 100644 src/components/ChannelListItem/ChannelListItem.tsx create mode 100644 src/components/Common/InputOutlined.tsx create mode 100644 src/components/Common/TextAreaOutlined.tsx create mode 100644 src/components/MessageBox/EmptyMessageBox.tsx create mode 100644 src/components/MessageBox/ImageCurosal.tsx create mode 100644 src/components/MessageBox/MessageBox.tsx create mode 100644 src/components/MessageBox/MessageItem.tsx create mode 100644 src/components/MessageBox/MessageSideBar.tsx create mode 100644 src/components/MessageBox/PinMessages.tsx create mode 100644 src/components/Review/Review.tsx create mode 100644 src/components/Review/ReviewModal.tsx create mode 100644 src/components/Review/ReviewSection.tsx create mode 100644 src/db/migrations/20231121091011_drop_freelancer_and_add_reviewer.ts create mode 100644 src/lib/queryServices/reviewQueries.ts create mode 100644 src/pages/api/reviews/index.ts create mode 100644 src/pages/messages/index.tsx create mode 100644 src/redux/services/reviewServices.ts create mode 100644 src/utils/MessageOptions.ts diff --git a/next.config.js b/next.config.js index 8fe31640..dfa758cd 100644 --- a/next.config.js +++ b/next.config.js @@ -20,6 +20,10 @@ const nextConfig = { }, images: { remotePatterns: [ + { + protocol: 'https', + hostname: 'dublin.stream-io-cdn.com', + }, { protocol: 'https', hostname: 'avatars.githubusercontent.com', diff --git a/package.json b/package.json index eeeabde5..815e3c5f 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "cookies-next": "^2.1.1", "country-list": "^2.3.0", "csv-parser": "^3.0.0", + "emoji-picker-react": "^4.5.15", "eslint": "^8.42.0", "eslint-config-next": "^13.4.5", "eslint-config-prettier": "^8.8.0", @@ -99,6 +100,7 @@ "swiper": "^11.0.3", "test-utils": "^1.1.1", "typescript": "5.0.2", + "use-onclickoutside": "^0.4.1", "uuidv4": "^6.2.12", "web3modal": "^1.9.12" }, diff --git a/public/MessageIcons/circle.svg b/public/MessageIcons/circle.svg new file mode 100644 index 00000000..e84681c8 --- /dev/null +++ b/public/MessageIcons/circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/MessageIcons/flag.svg b/public/MessageIcons/flag.svg new file mode 100644 index 00000000..2b259441 --- /dev/null +++ b/public/MessageIcons/flag.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/MessageIcons/page.svg b/public/MessageIcons/page.svg new file mode 100644 index 00000000..38942d4c --- /dev/null +++ b/public/MessageIcons/page.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/MessageIcons/pin.svg b/public/MessageIcons/pin.svg new file mode 100644 index 00000000..947a79fc --- /dev/null +++ b/public/MessageIcons/pin.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/message-box-pattern.svg b/public/message-box-pattern.svg new file mode 100644 index 00000000..4d467304 --- /dev/null +++ b/public/message-box-pattern.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/messages.svg b/public/messages.svg new file mode 100644 index 00000000..ba3fe29c --- /dev/null +++ b/public/messages.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/pin.png b/public/pin.png new file mode 100644 index 0000000000000000000000000000000000000000..7d9584690e98af21220dd61e9da28ed808d8f2a0 GIT binary patch literal 1747 zcmV;^1}yoBP)Cys{XesRJu|yAyKsq1{9hv%y91g^#ZJdY<{CeCg}B6xlGRz` z?xN{N<+4 zJHj@QmVmKGfX9vRZ=c=U|1X<;s)zw6Q=hvm9-H+j$~Qs@2`4dfUtP~3&r;W-H(+G- zjf=&1b^!~li3(kbeC=J*+j}~^RD_JJYHCtsKkza8>T)1ao4-Sz?9YZ#acp&GDnqH2 z3l-T*n2V3aU{NE);?q=W%V^H|oo)+v4Q`l|KL|~ws`JkHQwUdw(UE)aNA9`@S+){h zJ_^G_=hh>i&JWD>JB|%LQ*Mk%GGH{8eE?x`XrV;1@PENVhT|N@-{){LhuHfeZ|l{CFPh4gr<7Z0eOzT?6y4EgZl8YDu+&3@LX4KRkXS7jH1+|gP%$WOr2`=(Y8)#Phl2&!q- zfYWE16<^#)y@7cMGu3GkMpxw4E0E?Ft{&xQf zM$g?OR!39G{e6E4Drwz-k(L#WqUI=k5v-*0?u@U?la(X|Mx6|Vh&Q-=kP zs<2BW{+q=9=LVzbU*s8JjOpNi8zmi`ot*=nFaSIYaH_evepWocNL_QeL8?LCcOCzq zwfp+sj=FCUaR#hkzy33h;~b%2^guiwZ``qCN2r&Xwuy8SbR6d~idiNi-<@d}4-sZS zTU*=LfbL@PSc^hM-uX5hs`M3bP1e2?N6A*%XI&-4Bf zMI0Mg&wzF7)_oF~d_F%VA`jY*VH4{HxUTzSpbkJp9`Zb|BH#O!i&X>C>GTTV>&4=$ zu~_WqHua;xrU4=%k5Ig`6mNT>R%(^N+9cT4*0v5<4xp-k_B?NoE$t|=k^!4GZK?x0 zip2@XaqhFBTM4Wfkjv$^0&|PSM|bYr`I-&gN)XzB_V)H`fP0I@6RP^7u$q-5v;nI6 zQ;OdNspsw`z2(AwJS8e<+g>!k23%e& z{v?yhylJaLl_szO8#iuj1in=)9?$3V+dr)ROee4b#+ZkJIDo2d?&|7_`t?_&1lkfy zr_;BI$mI99&wHNt1!m|@&xH~w14Lx^5-^o{J^#uR`002ovPDHLkV1l#5Y3Kj| literal 0 HcmV?d00001 diff --git a/src/assets/svgs/warning_animation.json b/src/assets/svgs/warning_animation.json new file mode 100644 index 00000000..43dace12 --- /dev/null +++ b/src/assets/svgs/warning_animation.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE 3.1.1","a":"Bilal Arief","k":"warning, pending, icon, animation, web, mobile, app, yellow, simple, indicator, caution, alertness, attention, notice, cautionary, warning icon, pending icon.","d":"Conveying caution and alertness, this simple yet eye-catching yellow animation icon is the perfect addition to any web or mobile application as a warning or pending indicator.","tc":"Yellow"},"fr":60,"ip":0,"op":104,"w":1080,"h":1080,"nm":"Warning","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"White-CircleExclamationMark","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":52,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.964],"y":[0]},"t":53,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.89],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.759],"y":[0]},"t":65,"s":[-3]},{"t":67,"s":[0]}],"ix":10},"p":{"a":0,"k":[540.306,540,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.779,0.779,0.333],"y":[0,0,0]},"t":47,"s":[100,100,100]},{"i":{"x":[0.216,0.216,0.667],"y":[1,1,1]},"o":{"x":[0.597,0.597,0.333],"y":[0,0,0]},"t":56,"s":[115,115,100]},{"t":67,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,175],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.19],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":25,"s":[100]},{"t":77,"s":[0]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"gr","it":[{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.19],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":25,"s":[100]},{"t":77,"s":[0]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":1,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":666,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"White-BodyExclamationMark","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":52,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.964],"y":[0]},"t":53,"s":[3]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.89],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.759],"y":[0]},"t":65,"s":[-3]},{"t":67,"s":[0]}],"ix":10},"p":{"a":0,"k":[539.694,540,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.779,0.779,0.333],"y":[0,0,0]},"t":47,"s":[87,87,100]},{"i":{"x":[0.216,0.216,0.667],"y":[1,1,1]},"o":{"x":[0.597,0.597,0.333],"y":[0,0,0]},"t":56,"s":[115,115,100]},{"t":67,"s":[87,87,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[51.5,-203.25],[-49.5,-203.25],[1,129.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":55,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[70.455,95.556],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.19],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":25,"s":[0]},{"t":77,"s":[100]}],"ix":1},"e":{"a":0,"k":0,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"gr","it":[{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":0,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":1,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.19],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":25,"s":[0]},{"t":77,"s":[100]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":1,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":666,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"LightYellow-CircleExclamationMark","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540.306,540,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.803921568627,0.301960784314,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,175],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.19],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":9,"s":[0]},{"t":67,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.221],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":9,"s":[0]},{"t":31,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":666,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"DarkYellow-CircleExclamationMark","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540.306,540,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.929411764706,0.666666666667,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,175],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.19],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":16,"s":[0]},{"t":74,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.221],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":16,"s":[0]},{"t":38,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":666,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"LightYellow-BodyExclamationMark","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[539.694,540,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[87,87,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[51.5,-203.25],[-49.5,-203.25],[1,129.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.803921568627,0.301960784314,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":55,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[70.455,95.556],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.19],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":9,"s":[0]},{"t":67,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.221],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":9,"s":[0]},{"t":31,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":666,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"DarkYellow-BodyExclamationMark","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[539.694,540,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[87,87,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[51.5,-203.25],[-49.5,-203.25],[1,129.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.929411764706,0.666666666667,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":55,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[70.455,95.556],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.19],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":16,"s":[0]},{"t":74,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.221],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":16,"s":[0]},{"t":38,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":666,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"DarkYellow-CircleStroke","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[539.013,535.349,0],"ix":2},"a":{"a":0,"k":[27.013,127.349,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[784,784],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.057],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":17,"s":[100]},{"t":47,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.329],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":17,"s":[100]},{"t":75,"s":[0]}],"ix":2},"o":{"a":0,"k":9000,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.929411764706,0.666989614449,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":35,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[28,132],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":666,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"LightYellow-CircleStroke","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[539.013,535.349,0],"ix":2},"a":{"a":0,"k":[27.013,127.349,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[784,784],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.057],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100]},{"t":41,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.329],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100]},{"t":71,"s":[0]}],"ix":2},"o":{"a":0,"k":9000,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.802906589882,0.301960754395,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":35,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[28,132],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":666,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Yellow-Circle","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":28,"s":[25]},{"t":39,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[544.794,562.601,0],"ix":2},"a":{"a":0,"k":[32.429,152.879,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.354,0.354,0.667],"y":[1.438,1.438,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":13,"s":[0,0,100]},{"t":37,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[784,784],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.717647058824,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[28,132],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":666,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/components/ChannelListItem/ChannelListItem.tsx b/src/components/ChannelListItem/ChannelListItem.tsx new file mode 100644 index 00000000..7fc0e09a --- /dev/null +++ b/src/components/ChannelListItem/ChannelListItem.tsx @@ -0,0 +1,93 @@ +import classNames from 'classnames'; +import TimeAgo from 'javascript-time-ago'; +import en from 'javascript-time-ago/locale/en.json'; +import Image from 'next/image'; +import { useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { Channel, DefaultGenerics, User } from 'stream-chat'; + +import { RootState } from '@/redux/store/store'; +TimeAgo.addLocale(en); + +const timeAgo = new TimeAgo('en-US'); + +export default function ChannelListItem({ + channel, + setChannel, + selectedChannel, + handleChannelState, +}: { + channel: Channel; + setChannel: any; + handleChannelState: any; + selectedChannel: Channel | null; +}) { + const { user } = useSelector((state: RootState) => state.userState); + const [targetUser, setTargetUser] = useState(); + + useEffect(() => { + const key = Object.keys(channel.state?.members); + Number(channel.state.members[key[0]]?.user_id) === user.id + ? setTargetUser(channel.state.members[key[1]]?.user) + : setTargetUser(channel.state.members[key[0]]?.user); + + const myChannelListener = channel.on((event) => { + if (event.type === 'message.new') handleChannelState(); + }); + return () => { + myChannelListener.unsubscribe(); + }; + }, [channel, user.id]); + + return ( +
setChannel(channel)} + className={classNames( + 'flex px-3 rounded-md border-l-2 h-[6rem] border-white hover:border-gray-700 cursor-pointer hover:bg-[#F5F5F5] gap-3 py-4', + selectedChannel?.id === channel.id ? 'bg-imbue-lime-light' : 'bg-white' + )} + > +
+ image +
+
+
+
+

+ {targetUser?.name?.length && targetUser?.name?.length < 15 + ? targetUser?.name + : targetUser?.name?.substring(0, 15) + '...'} +

+

+ {channel?.lastMessage()?.created_at && + timeAgo.format(new Date(channel?.lastMessage()?.created_at))} +

+
+
+

+ {channel?.lastMessage()?.text?.substring(0, 60)} +

+ {channel.countUnread() > 0 && ( + + {channel.countUnread() > 99 ? 99 : channel.countUnread()} + + )} +
+
+
+ ); +} diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx index 4d701b5d..19dbdb85 100644 --- a/src/components/Chat.tsx +++ b/src/components/Chat.tsx @@ -1,21 +1,13 @@ /* eslint-disable react-hooks/exhaustive-deps */ import { Skeleton } from '@mui/material'; import React, { useEffect, useState } from 'react'; -import { - Channel, - Chat, - MessageInput, - MessageList, - Window, -} from 'stream-chat-react'; import 'stream-chat-react/dist/css/v2/index.css'; import { getStreamChat } from '@/utils'; import { User } from '@/model'; -import { CustomChannelHeader } from './StreamChatComponents/CustomChannelHeader'; - +import MessageBox from './MessageBox/MessageBox'; export type ChatProps = { user: User; @@ -26,7 +18,6 @@ export type ChatProps = { showFreelancerProfile: boolean; }; - function CustomSkeletonLoading() { return (
@@ -74,7 +65,6 @@ export const ChatBox = ({ showMessageBox, setShowMessageBox, chatPopUp, - showFreelancerProfile }: ChatProps) => { const [content, setContent] = useState(); @@ -95,7 +85,9 @@ export const ChatBox = ({ ); const channel = client.channel('messaging', { - image: 'https://www.drupal.org/files/project-images/react.png', + image: + targetUser.profile_photo || + 'https://www.drupal.org/files/project-images/react.png', name: currentChannel, members: [String(user.id), String(targetUser.id)], }); @@ -103,29 +95,11 @@ export const ChatBox = ({ await channel.watch(); setContent( - - - -
-
setShowMessageBox(false)} - > - x -
- -
- -
- -
-
- {/* */} -
-
+ ); } } catch (error) { diff --git a/src/components/ChatPopup.tsx b/src/components/ChatPopup.tsx index 3a6f8992..a3e1de0f 100644 --- a/src/components/ChatPopup.tsx +++ b/src/components/ChatPopup.tsx @@ -21,20 +21,20 @@ const ChatPopup = (props: ChatPopupProps) => { setShowMessageBox, browsingUser, targetUser, - showFreelancerProfile + showFreelancerProfile, } = props; return ( -
+
{/*
setShowMessageBox(false)} diff --git a/src/components/Common/InputOutlined.tsx b/src/components/Common/InputOutlined.tsx new file mode 100644 index 00000000..86c3ee95 --- /dev/null +++ b/src/components/Common/InputOutlined.tsx @@ -0,0 +1,29 @@ +import React, { ChangeEventHandler, InputHTMLAttributes } from 'react'; + +interface InputOutlinedProps { + props?: InputHTMLAttributes; + inputProps?: InputHTMLAttributes; + onChange?: ChangeEventHandler; +} + +const InputOutlined = ({ props = {}, inputProps = {}, onChange }: InputOutlinedProps) => { + + if (!props?.className) { + props.className = "h-[2.6rem] my-2 px-[14px] text-[0.875rem] border border-[#BCBCBC] evenShadow focus-within:outline focus-within:outline-1 focus-within:outline-imbue-purple rounded-[4px] flex items-center w-full" + } + + if (!inputProps?.className) { + inputProps.className = "outline-none w-full text-black" + } + return ( +
+ +
+ ); +}; + +export default InputOutlined; \ No newline at end of file diff --git a/src/components/Common/TextAreaOutlined.tsx b/src/components/Common/TextAreaOutlined.tsx new file mode 100644 index 00000000..69d943c9 --- /dev/null +++ b/src/components/Common/TextAreaOutlined.tsx @@ -0,0 +1,26 @@ +import React, { DetailedHTMLProps, InputHTMLAttributes } from 'react'; + +interface InputOutlinedProps { + props?: InputHTMLAttributes; + inputProps?: DetailedHTMLProps, HTMLTextAreaElement>; +} + +const TextAreaOutlined = ({ props = {}, inputProps = {} }: InputOutlinedProps) => { + + if (!props?.className) { + props.className = "my-2 p-[6px] text-[0.875rem] border border-[#BCBCBC] evenShadow focus-within:outline focus-within:outline-1 focus-within:outline-imbue-purple rounded-[4px] w-full" + } + + inputProps.className = "outline-none !border-0 w-full text-black " + inputProps.className + + return ( +
+