refactor: lots updates
This commit is contained in:
@@ -1,72 +1,73 @@
|
||||
// import { Picker } from "emoji-mart";
|
||||
// import "emoji-mart/css/emoji-mart.css";
|
||||
// import Picker from "../EmojiPicker";
|
||||
import { useRef } from "react";
|
||||
import styled from "styled-components";
|
||||
import { useOutsideClick } from "rooks";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useReactMessageMutation } from "../../../app/services/message";
|
||||
import { Emojis } from "../../../app/config";
|
||||
import Emoji from "../Emoji";
|
||||
const StyledPicker = styled.div`
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-radius: 6px;
|
||||
position: absolute;
|
||||
left: -10px;
|
||||
top: 0;
|
||||
transform: translateX(-100%);
|
||||
background-color: #fff;
|
||||
padding: 5px;
|
||||
.emojis {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
padding: 4px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 8px;
|
||||
background: #ffffff;
|
||||
filter: drop-shadow(0px 25px 50px rgba(31, 41, 55, 0.25));
|
||||
border-radius: 12px;
|
||||
&.reacting {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.emoji {
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
border-radius: 8px;
|
||||
padding: 4px;
|
||||
font-size: 30px;
|
||||
&:hover,
|
||||
&.reacted {
|
||||
background-color: #f3f4f6;
|
||||
background-color: #f5f6f7;
|
||||
}
|
||||
> * {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const emojis = {
|
||||
["U+1F44D"]: "👍",
|
||||
["U+1F44C"]: "👌",
|
||||
["U+2764"]: "❤️",
|
||||
};
|
||||
|
||||
export default function EmojiPicker({ mid, hidePicker }) {
|
||||
const wrapperRef = useRef(null);
|
||||
const [reactMessage, { isLoading }] = useReactMessageMutation();
|
||||
const { reactionData, currUid } = useSelector((store) => {
|
||||
return {
|
||||
reactionData: store.reactionMessage[mid],
|
||||
reactionData: store.reactionMessage[mid] || {},
|
||||
currUid: store.authData.uid,
|
||||
};
|
||||
});
|
||||
useOutsideClick(wrapperRef, hidePicker);
|
||||
const handleReact = (action) => {
|
||||
console.log("react", action);
|
||||
reactMessage({ mid, action });
|
||||
const handleReact = (emoji) => {
|
||||
console.log("react", emoji);
|
||||
reactMessage({ mid, action: emoji });
|
||||
hidePicker();
|
||||
};
|
||||
return (
|
||||
<StyledPicker ref={wrapperRef}>
|
||||
{/* <Picker
|
||||
onSelect={handleReact}
|
||||
className={`picker ${isLoading ? "reacting" : ""}`}
|
||||
/> */}
|
||||
<ul className={`emojis ${isLoading ? "reacting" : ""}`}>
|
||||
{Object.entries(emojis).map(([key, emoji]) => {
|
||||
{Emojis.map((emoji) => {
|
||||
let reacted =
|
||||
reactionData &&
|
||||
reactionData[key] &&
|
||||
reactionData[key].includes(currUid);
|
||||
reactionData[emoji] &&
|
||||
reactionData[emoji].findIndex((id) => id == currUid) > -1;
|
||||
|
||||
return (
|
||||
<li
|
||||
className={`emoji ${reacted ? "reacted" : ""}`}
|
||||
key={key}
|
||||
onClick={handleReact.bind(null, key)}
|
||||
key={emoji}
|
||||
onClick={handleReact.bind(null, emoji)}
|
||||
>
|
||||
{emoji}
|
||||
<Emoji native={emoji} size={24} />
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
@@ -74,4 +75,3 @@ export default function EmojiPicker({ mid, hidePicker }) {
|
||||
</StyledPicker>
|
||||
);
|
||||
}
|
||||
export { emojis };
|
||||
|
||||
@@ -1,54 +1,119 @@
|
||||
import React from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import styled from "styled-components";
|
||||
import { emojis } from "./EmojiPicker";
|
||||
import Emoji from "../Emoji";
|
||||
import EmojiPicker from "./EmojiPicker";
|
||||
import { useReactMessageMutation } from "../../../app/services/message";
|
||||
// import { Emojis } from "../../../app/config";
|
||||
import addEmojiIcon from "../../../assets/icons/add.emoji.svg?url";
|
||||
const StyledWrapper = styled.span`
|
||||
z-index: 99;
|
||||
position: relative;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 4px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
font-size: 16px;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
width: fit-content;
|
||||
/* align-items: center; */
|
||||
.reaction {
|
||||
cursor: pointer;
|
||||
background-color: #ecfdff;
|
||||
border-radius: 6px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
em {
|
||||
gap: 4px;
|
||||
padding: 4px;
|
||||
> .emoji {
|
||||
> * {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background-color: #cff9fe;
|
||||
}
|
||||
&.reacted {
|
||||
border: 1px solid #06aed4;
|
||||
background-color: #a5f0fc;
|
||||
}
|
||||
|
||||
> .count {
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
line-height: 16px;
|
||||
color: #06aed4;
|
||||
}
|
||||
}
|
||||
> .add {
|
||||
visibility: hidden;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-color: #ecfdff;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
background-image: url(${addEmojiIcon});
|
||||
background-size: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
&:hover {
|
||||
background-color: #cff9fe;
|
||||
}
|
||||
}
|
||||
.picker {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transform: translateX(105%);
|
||||
}
|
||||
&:hover > .add {
|
||||
visibility: visible;
|
||||
}
|
||||
`;
|
||||
export default function Reaction({ reactions = null }) {
|
||||
// const {
|
||||
// messageData,
|
||||
// reactionMessageData,
|
||||
// contactsData,
|
||||
// loginedUser,
|
||||
// } = useSelector((store) => {
|
||||
// return {
|
||||
// reactionMessageData: store.reactionMessage,
|
||||
// messageData: store.message,
|
||||
// contactsData: store.contacts.byId,
|
||||
// loginedUser: store.authData.user,
|
||||
// };
|
||||
// });
|
||||
|
||||
if (!reactions) return null;
|
||||
export default function Reaction({ mid, reactions = null }) {
|
||||
const [pickerVisible, setPickerVisible] = useState(false);
|
||||
const [reactWithEmoji] = useReactMessageMutation();
|
||||
const { currUid } = useSelector((store) => {
|
||||
return {
|
||||
currUid: store.authData.uid,
|
||||
};
|
||||
});
|
||||
const handleReact = (emoji) => {
|
||||
reactWithEmoji({ mid, action: emoji });
|
||||
};
|
||||
const togglePickerVisible = (wtf) => {
|
||||
console.log("clicked", wtf);
|
||||
setPickerVisible((prev) => !prev);
|
||||
};
|
||||
console.log("curr reactions", reactions);
|
||||
if (!reactions || Object.entries(reactions).length == 0) return null;
|
||||
return (
|
||||
<StyledWrapper className="reactions">
|
||||
{Object.entries(reactions).map(([reaction, uids]) => {
|
||||
const reacted = uids.findIndex((id) => id == currUid) > -1;
|
||||
return uids.length > 0 ? (
|
||||
<i
|
||||
className="reaction"
|
||||
<span
|
||||
onClick={handleReact.bind(null, reaction)}
|
||||
className={`reaction ${reacted ? "reacted" : ""}`}
|
||||
// data-count={count > 1 ? count : ""}
|
||||
key={reaction}
|
||||
>
|
||||
{emojis[reaction]}
|
||||
<i className="emoji">
|
||||
<Emoji native={reaction} />
|
||||
</i>
|
||||
|
||||
{uids.length > 1 ? <em>{`+${uids.length}`} </em> : null}
|
||||
</i>
|
||||
{uids.length > 1 ? (
|
||||
<em className="count">{`${uids.length}`} </em>
|
||||
) : null}
|
||||
</span>
|
||||
) : null;
|
||||
})}
|
||||
<button onClick={togglePickerVisible} className="add"></button>
|
||||
{pickerVisible && (
|
||||
<div className="picker">
|
||||
<EmojiPicker mid={mid} hidePicker={togglePickerVisible} />
|
||||
</div>
|
||||
)}
|
||||
</StyledWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,12 +8,14 @@ import Reply from "./Reply";
|
||||
import Profile from "../Profile";
|
||||
import Avatar from "../Avatar";
|
||||
import { readMessage } from "../../../app/slices/message";
|
||||
import { useReadMessageMutation } from "../../../app/services/message";
|
||||
import StyledWrapper from "./styled";
|
||||
import Commands from "./Commands";
|
||||
|
||||
import EditMessage from "./EditMessage";
|
||||
import renderContent from "./renderContent";
|
||||
function Message({ contextId = 0, mid = "" }) {
|
||||
function Message({ contextId = 0, mid = "", read = true, context = "user" }) {
|
||||
const [updateReadIndex] = useReadMessageMutation();
|
||||
const [myRef, inView] = useInViewRef();
|
||||
const [edit, setEdit] = useState(false);
|
||||
const [emojiPopVisible, setEmojiPopVisible] = useState(false);
|
||||
@@ -47,10 +49,15 @@ function Message({ contextId = 0, mid = "" }) {
|
||||
// console.log("message", mid, messageData[mid]);
|
||||
|
||||
useEffect(() => {
|
||||
if (inView && !message.read) {
|
||||
if (inView && !read) {
|
||||
disptach(readMessage(mid));
|
||||
const data =
|
||||
context == "user"
|
||||
? { users: [{ uid: +contextId, mid }] }
|
||||
: { groups: [{ gid: +contextId, mid }] };
|
||||
updateReadIndex(data);
|
||||
}
|
||||
}, [mid, message, inView]);
|
||||
}, [mid, read, inView]);
|
||||
if (!message) return null;
|
||||
const {
|
||||
reply_mid,
|
||||
@@ -65,6 +72,7 @@ function Message({ contextId = 0, mid = "" }) {
|
||||
const currUser = contactsData[fromUid] || {};
|
||||
return (
|
||||
<StyledWrapper
|
||||
data-mid={mid}
|
||||
ref={myRef}
|
||||
className={`message ${menuVisible ? "menu" : ""} ${
|
||||
inView ? "in_view" : ""
|
||||
@@ -85,7 +93,6 @@ function Message({ contextId = 0, mid = "" }) {
|
||||
<div className="up">
|
||||
<span className="name">{currUser.name}</span>
|
||||
<i className="time">{dayjs(time).format("YYYY-MM-DD h:mm:ss A")}</i>
|
||||
{reactions && <Reaction reactions={reactions} />}
|
||||
</div>
|
||||
<div className={`down ${sending ? "sending" : ""}`}>
|
||||
{edit ? (
|
||||
@@ -97,6 +104,7 @@ function Message({ contextId = 0, mid = "" }) {
|
||||
) : (
|
||||
renderContent(content_type, content, edited)
|
||||
)}
|
||||
{reactions && <Reaction mid={mid} reactions={reactions} />}
|
||||
</div>
|
||||
</div>
|
||||
{!edit && (
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Linkify from "react-linkify";
|
||||
import dayjs from "dayjs";
|
||||
import BASE_URL from "../../../app/config";
|
||||
import MrakdownRender from "../MrakdownRender";
|
||||
const renderContent = (type, content, edited = false) => {
|
||||
let ctn = null;
|
||||
switch (type) {
|
||||
@@ -9,7 +10,12 @@ const renderContent = (type, content, edited = false) => {
|
||||
<>
|
||||
<Linkify
|
||||
componentDecorator={(decoratedHref, decoratedText, key) => (
|
||||
<a target="blank" href={decoratedHref} key={key}>
|
||||
<a
|
||||
target="_blank"
|
||||
href={decoratedHref}
|
||||
key={key}
|
||||
rel="noreferrer"
|
||||
>
|
||||
{decoratedText}
|
||||
</a>
|
||||
)}
|
||||
@@ -27,6 +33,11 @@ const renderContent = (type, content, edited = false) => {
|
||||
</>
|
||||
);
|
||||
break;
|
||||
case "text/markdown":
|
||||
{
|
||||
ctn = <MrakdownRender content={content} />;
|
||||
}
|
||||
break;
|
||||
case "image/png":
|
||||
case "image/jpeg":
|
||||
ctn = (
|
||||
|
||||
@@ -4,7 +4,7 @@ const StyledMsg = styled.div`
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
padding: 4px;
|
||||
padding: 4px 8px;
|
||||
margin: 8px 0;
|
||||
border-radius: 8px;
|
||||
content-visibility: auto;
|
||||
|
||||
Reference in New Issue
Block a user