feat: lots of updates

This commit is contained in:
zerosoul
2022-01-27 22:06:44 +08:00
commit e18c7323a6
72 changed files with 12432 additions and 0 deletions
+168
View File
@@ -0,0 +1,168 @@
import { useState, useEffect } from "react";
import toast from "react-hot-toast";
import { useNavigate } from "react-router-dom";
import { useSelector } from "react-redux";
import Modal from "../Modal";
import ChannelIcon from "../ChannelIcon";
import Contact from "../Contact";
import StyledWrapper from "./styled";
import useFilteredUsers from "../../hook/useFilteredUsers";
import { useGetChannelsQuery } from "../../../app/services/channel";
import { useCreateChannelMutation } from "../../../app/services/channel";
export default function ChannelModal({ personal = false, closeModal }) {
const navigateTo = useNavigate();
const [data, setData] = useState({
name: "",
dsecription: "",
members: [],
is_public: !personal,
});
const { contacts, input, updateInput } = useFilteredUsers();
const { refetch: refetchChannels } = useGetChannelsQuery();
const [
createChannel,
{ isSuccess, isError, isLoading, data: newChannel },
] = useCreateChannelMutation();
const currentUser = useSelector((state) => {
return state.authData.user;
});
const handleToggle = () => {
const { is_public } = data;
setData((prev) => {
return { ...prev, is_public: !is_public };
});
};
const handleCreate = () => {
if (!data.name) {
toast("please input channel name");
return;
}
createChannel(data);
};
useEffect(() => {
if (isError) {
toast.error("create new channel failed");
}
}, [isError]);
useEffect(() => {
if (isSuccess) {
toast.success("create new channel success");
closeModal();
refetchChannels();
navigateTo(`/chat/channel/${newChannel.gid}`);
}
}, [isSuccess, newChannel]);
const handleNameInput = (evt) => {
setData((prev) => {
return { ...prev, name: evt.target.value };
});
};
const handleInputChange = (evt) => {
updateInput(evt.target.value);
};
const toggleCheckMember = ({ currentTarget }) => {
const { members } = data;
const { uid } = currentTarget.dataset;
let tmp = members.includes(+uid)
? members.filter((m) => m != uid)
: [...members, +uid];
console.log(uid, currentTarget);
setData((prev) => {
return { ...prev, members: tmp };
});
console.log({ data });
};
console.log("contacts", contacts);
if (!currentUser) return null;
const { name, members, is_public } = data;
return (
<Modal>
<StyledWrapper>
{!is_public && (
<div className="left">
<div className="search">
<input
value={input}
onChange={handleInputChange}
placeholder="Type username to search"
/>
</div>
{contacts && (
<ul className="users">
{contacts.map((u) => {
const { uid } = u;
const checked = members.includes(uid);
console.log({ checked });
return (
<li
key={uid}
data-uid={uid}
className="user"
onClick={toggleCheckMember}
>
<input
readOnly
checked={checked}
type="checkbox"
name="cb"
id="cb"
/>
<Contact uid={uid} interactive={false} />
</li>
);
})}
</ul>
)}
</div>
)}
<div className={`right ${!is_public ? "private" : ""}`}>
<h3 className="title">Create New Channel</h3>
<p className="desc normal">
{!is_public
? "This is a private channel, only select members will bee able to join."
: "This is a public channel, everyone in this team can see it."}
</p>
<div className="name">
<span className="label normal">Channel Name</span>
<div className="input">
<input
onChange={handleNameInput}
value={name}
placeholder="new channel"
/>
<ChannelIcon personal={!is_public} className="icon" />
</div>
</div>
{/* admin or */}
{
<div className="private">
<span className="txt normal">Private Channel</span>
<input
disabled={!currentUser?.is_admin}
onChange={handleToggle}
checked={!is_public}
type="checkbox"
name="private"
id="private"
/>
</div>
}
<div className="btns">
<button onClick={closeModal} className="btn normal cancel">
Cancel
</button>
<button
disabled={isLoading}
onClick={handleCreate}
className="btn normal create"
>
Create
</button>
</div>
</div>
</StyledWrapper>
</Modal>
);
}
+144
View File
@@ -0,0 +1,144 @@
import styled from "styled-components";
const StyledWrapper = styled.div`
display: flex;
/* max-width: 604px; */
max-height: 402px;
background: #fff;
box-shadow: 0px 25px 50px rgba(31, 41, 55, 0.25);
border-radius: 8px;
transition: all 0.5s ease;
.left {
width: 260px;
height: 100%;
box-shadow: inset -1px 0px 0px rgba(0, 0, 0, 0.1);
overflow-y: scroll;
.search {
box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.1);
padding: 8px;
width: -webkit-fill-available;
input {
outline: none;
width: -webkit-fill-available;
padding: 8px;
font-size: 14px;
line-height: 20px;
border: none;
}
}
.users {
display: flex;
flex-direction: column;
height: 260px;
padding-bottom: 20px;
overflow-y: scroll;
.user {
cursor: pointer;
display: flex;
align-items: center;
padding: 0 16px;
width: -webkit-fill-available;
> div {
width: 100%;
}
}
}
}
.right {
display: flex;
flex-direction: column;
align-items: center;
padding: 32px;
box-sizing: border-box;
&.private {
width: 344px;
.desc {
text-align: center;
/* padding: 0 20px; */
}
}
> .title {
font-weight: 600;
font-size: 20px;
line-height: 30px;
color: #374151;
margin-bottom: 16px;
}
.desc {
font-weight: normal;
color: #6b7280;
margin-bottom: 48px;
}
.name {
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
gap: 8px;
margin-bottom: 34px;
.label {
font-weight: 600;
color: #6b7280;
}
.input {
position: relative;
input {
width: -webkit-fill-available;
border: 1px solid #e5e7eb;
box-shadow: 0px 1px 2px rgba(31, 41, 55, 0.08);
border-radius: 4px;
padding: 8px;
color: #78787c;
padding-left: 36px;
}
.icon {
position: absolute;
left: 8px;
top: 50%;
transform: translateY(-50%);
}
}
}
.private {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 50px;
.txt {
font-weight: 600;
color: #6b7280;
}
input {
cursor: pointer;
}
}
.btns {
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 16px;
.btn {
cursor: pointer;
padding: 8px 16px;
background: none;
border: 1px solid #e5e7eb;
box-shadow: 0px 1px 2px rgba(31, 41, 55, 0.08);
border-radius: 4px;
font-weight: 500;
color: #374151;
&.create {
border: none;
background: #1fe1f9;
color: #fff;
}
}
}
.normal {
font-size: 14px;
line-height: 20px;
}
}
`;
export default StyledWrapper;