Merge remote-tracking branch 'upstream/main' into refactor/typescript

# Conflicts:
#	src/common/component/ForwardModal/index.tsx
#	src/common/component/GoogleLoginButton.tsx
#	src/common/component/ManageMembers.tsx
#	src/routes/settingChannel/Overview.tsx
#	src/routes/settingChannel/index.tsx
This commit is contained in:
HD
2022-06-29 17:04:22 +08:00
44 changed files with 207 additions and 292 deletions
+3 -5
View File
@@ -58,15 +58,13 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
userIds,
data,
messageData,
loginUid,
loginUser,
footprint
} = useSelector((store) => {
return {
selects: store.ui.selectMessages[`channel_${cid}`],
footprint: store.footprint,
loginUser: store.contacts.byId[store.authData.uid],
loginUid: store.authData.uid,
loginUser: store.authData.user,
// msgIds: store.channelMessage[cid] || [],
userIds: store.contacts.ids,
data: store.channels.byId[cid] || {},
@@ -93,7 +91,7 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
if (!data) return null;
const { name, description, is_public, members = [], owner } = data;
const memberIds = is_public ? userIds : members.slice(0).sort((n) => (n == owner ? -1 : 0));
const addVisible = loginUser?.is_admin || owner == loginUid;
const addVisible = loginUser?.is_admin || owner == loginUser.uid;
console.log("channel message list", msgIds);
const readIndex = footprint.readChannels[cid];
const pinCount = data?.pinned_messages?.length || 0;
@@ -236,7 +234,7 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
if (!curr) return null;
const isFirst = idx == 0;
const prev = isFirst ? null : messageData[feeds[idx - 1]];
const read = curr?.from_uid == loginUid || mid <= readIndex;
const read = curr?.from_uid == loginUser.uid || mid <= readIndex;
return renderMessageFragment({
selectMode: !!selects,
updateReadIndex: updateReadDebounced,
+2 -11
View File
@@ -29,21 +29,12 @@ const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => {
handleContextMenuEvent,
hideContextMenu
} = useContextMenu();
const {
channel,
mids,
messageData,
readIndex,
muted,
loginUid
// loginUser,
} = useSelector((store) => {
const { channel, mids, messageData, readIndex, muted, loginUid } = useSelector((store) => {
return {
// loginUser: store.contacts.byId[store.authData.uid],
channel: store.channels.byId[id],
mids: store.channelMessage[id],
messageData: store.message,
loginUid: store.authData.uid,
loginUid: store.authData.user?.uid,
readIndex: store.footprint.readChannels[id],
muted: store.footprint.muteChannels[id]
};
+3 -3
View File
@@ -1,5 +1,4 @@
// import { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { useDebounce } from "rooks";
import Tippy from "@tippyjs/react";
import FavList from "../FavList";
@@ -15,6 +14,7 @@ import { StyledHeader, StyledDMChat } from "./styled";
import LoadMore from "../LoadMore";
import { renderMessageFragment } from "../utils";
import useMessageFeed from "../../../common/hook/useMessageFeed";
import { useAppSelector } from "../../../app/store";
export default function DMChat({ uid = "", dropFiles = [] }) {
const {
@@ -29,10 +29,10 @@ export default function DMChat({ uid = "", dropFiles = [] }) {
const [updateReadIndex] = useReadMessageMutation();
const updateReadDebounced = useDebounce(updateReadIndex, 300);
console.log("dm files", dropFiles);
const { currUser, messageData, footprint, loginUid, selects } = useSelector((store) => {
const { currUser, messageData, footprint, loginUid, selects } = useAppSelector((store) => {
return {
selects: store.ui.selectMessages[`user_${uid}`],
loginUid: store.authData.uid,
loginUid: store.authData.user?.uid,
footprint: store.footprint,
currUser: store.contacts.byId[uid],
messageData: store.message
+1 -1
View File
@@ -11,7 +11,7 @@ interface Props {
const DMList: FC<Props> = ({ uids, setDropFiles }) => {
const { userMessage, messageData, readUsers, loginUid } = useAppSelector((store) => {
return {
loginUid: store.authData.uid,
loginUid: store.authData.user?.uid,
readUsers: store.footprint.readUsers,
contactData: store.contacts.byId,
userMessage: store.userMessage.byId,
+1 -1
View File
@@ -55,7 +55,7 @@ export default function Session({
(store) => {
return {
mids: type == "user" ? store.userMessage.byId[id] : store.channelMessage[id],
loginUid: store.authData.uid,
loginUid: store.authData.user?.uid,
readIndex:
type == "user" ? store.footprint.readUsers[id] : store.footprint.readChannels[id],
messageData: store.message,
+1 -1
View File
@@ -12,7 +12,7 @@ export default function SessionList({ tempSession = null }) {
const { channelIDs, DMs, readChannels, readUsers, channelMessage, userMessage, loginUid } =
useAppSelector((store) => {
return {
loginUid: store.authData.uid,
loginUid: store.authData.user?.uid,
channelIDs: store.channels.ids,
DMs: store.userMessage.ids,
userMessage: store.userMessage.byId,
-58
View File
@@ -1,58 +0,0 @@
// import React from 'react';
import styled from "styled-components";
// import { HiChevronDoubleLeft } from "react-icons/hi";
const StyledWrapper = styled.div`
min-height: 56px;
display: flex;
justify-content: space-between;
align-items: center;
/* &.expand {
padding-right: 16px;
} */
.server {
display: flex;
align-items: center;
gap: 10px;
.logo {
width: 28px;
height: 28px;
border-radius: 50%;
}
.info {
display: flex;
flex-direction: column;
gap: 4px;
white-space: nowrap;
.title {
font-weight: bold;
font-size: 14px;
line-height: 100%;
color: #374151;
text-transform: capitalize;
}
.count {
font-weight: normal;
font-size: 12px;
line-height: 100%;
color: #78787c;
}
}
}
`;
export default function ServerDropList({ data, memberCount, expand = true }) {
if (!data) return null;
return (
<StyledWrapper className={expand ? "expand" : ""}>
<div className="server">
<img className="logo" src={data.logo} alt="logo" />
{expand && (
<div className="info">
<h2 className="title animate__animated animate__fadeIn">{data.name}</h2>
<span className="count">{memberCount} members</span>
</div>
)}
</div>
</StyledWrapper>
);
}
+3 -3
View File
@@ -1,7 +1,6 @@
// import React from 'react';
// import { useEffect } from "react";
import { Outlet, NavLink, useLocation, useMatch } from "react-router-dom";
import { useSelector } from "react-redux";
import StyledWrapper from "./styled";
import User from "./User";
// import Tools from "./Tools";
@@ -17,6 +16,7 @@ import ChatIcon from "../../assets/icons/chat.svg";
import ContactIcon from "../../assets/icons/contact.svg";
import FavIcon from "../../assets/icons/bookmark.svg";
import FolderIcon from "../../assets/icons/folder.svg";
import { useAppSelector } from "../../app/store";
// const routes = ["/setting", "/setting/channel/:cid"];
export default function HomePage() {
usePWABadge();
@@ -29,10 +29,10 @@ export default function HomePage() {
ready,
remeberedNavs: { chat: chatPath, contact: contactPath }
}
} = useSelector((store) => {
} = useAppSelector((store) => {
return {
ui: store.ui,
loginUid: store.authData.uid
loginUid: store.authData.user?.uid
};
});
const { loading } = usePreload();
+3 -1
View File
@@ -13,7 +13,7 @@ import { useAppSelector } from "../../app/store";
export default function usePreload() {
const { rehydrate, rehydrated } = useRehydrate();
const { loginUid, token } = useAppSelector((store) => {
return { loginUid: store.authData.uid, token: store.authData.token };
return { loginUid: store.authData.user?.uid, token: store.authData.token };
});
const { setStreamingReady } = useStreaming();
const [
@@ -54,6 +54,8 @@ export default function usePreload() {
}
}, [rehydrated]);
const canStreaming = loginUid && rehydrated && !!token;
console.log("ttt", loginUid, rehydrated, token);
useEffect(() => {
setStreamingReady(canStreaming);
}, [canStreaming]);
-2
View File
@@ -19,8 +19,6 @@ const InvitePage: FC = () => {
const [samePwd, setSamePwd] = useState(true);
const [token, setToken] = useState<string | null>("");
const [valid, setValid] = useState(false);
// const [sp] = useSearchParams();
// const navigateTo = useNavigate();
const [register, { data, isLoading, isSuccess, isError, error }] = useRegisterMutation();
const [checkToken, { data: isValid, isLoading: checkLoading, isSuccess: checkSuccess }] =
useCheckMagicTokenValidMutation();
+1 -1
View File
@@ -116,7 +116,7 @@ export default function MyAccount() {
const [editModal, setEditModal] = useState(null);
const [uploadAvatar, { isSuccess: uploadSuccess }] = useUpdateAvatarMutation();
const loginUser = useAppSelector((store) => {
return store.contacts.byId[store.authData.uid];
return store.authData.user;
});
useEffect(() => {
+10 -11
View File
@@ -2,7 +2,6 @@ import { useState, useEffect } from "react";
import styled from "styled-components";
import toast from "react-hot-toast";
import {
useGetServerQuery,
useUpdateServerMutation,
useUpdateLogoMutation,
useUpdateLoginConfigMutation,
@@ -99,13 +98,12 @@ const StyledWrapper = styled.div`
`;
export default function Overview() {
const loginUser = useAppSelector((store) => {
return store.contacts.byId[store.authData.uid];
const { loginUser, server } = useAppSelector((store) => {
return { loginUser: store.authData.user, server: store.server };
});
const [changed, setChanged] = useState(false);
const [serverValues, setServerValues] = useState(null);
const [serverValues, setServerValues] = useState<typeof server>(server);
const [loginConfigValues, setLoginConfigValues] = useState(null);
const { data: server, refetch: refetchServer } = useGetServerQuery();
const { data: loginConfig, refetch: refetchLoginConfig } = useGetLoginConfigQuery();
const [updateServer, { isSuccess: serverUpdated }] = useUpdateServerMutation();
const [uploadLogo, { isSuccess: uploadSuccess }] = useUpdateLogoMutation();
@@ -113,10 +111,12 @@ export default function Overview() {
const handleUpdate = () => {
const { name, description } = serverValues;
updateServer({ name, description });
updateLoginConfig({
...loginConfig,
who_can_sign_up: loginConfigValues.who_can_sign_up
});
if (loginUser?.is_admin) {
updateLoginConfig({
...loginConfig,
who_can_sign_up: loginConfigValues.who_can_sign_up
});
}
};
const handleChange = (evt) => {
const newValue = evt.target.value;
@@ -133,7 +133,6 @@ export default function Overview() {
useEffect(() => {
if (uploadSuccess) {
toast.success("Update logo successfully!");
refetchServer();
}
}, [uploadSuccess]);
useEffect(() => {
@@ -162,7 +161,6 @@ export default function Overview() {
useEffect(() => {
if (serverUpdated && loginConfigUpdated) {
toast.success("Configuration updated!");
refetchServer();
refetchLoginConfig();
}
}, [serverUpdated, loginConfigUpdated]);
@@ -171,6 +169,7 @@ export default function Overview() {
const { name, description, logo } = serverValues;
const { who_can_sign_up: whoCanSignUp } = loginConfigValues;
const isAdmin = loginUser?.is_admin;
return (
<StyledWrapper>
<div className="logo">
+1 -1
View File
@@ -96,7 +96,7 @@ const navs = [
const useNavs = () => {
const loginUser = useAppSelector((store) => {
return store.contacts.byId[store.authData.uid];
return store.authData.user;
});
return navs.filter((nav) => {
if (loginUser?.is_admin) {
+7 -15
View File
@@ -1,4 +1,4 @@
import { useState, useEffect, ChangeEvent } from "react";
import { useState, useEffect } from "react";
import styled from "styled-components";
import toast from "react-hot-toast";
import {
@@ -43,44 +43,37 @@ const StyledWrapper = styled.div`
}
}
`;
interface ChannelFormData {
name: string;
description: string;
}
export default function Overview({ id = 0 }) {
const { loginUser, channel } = useAppSelector((store) => {
const { uid } = store.authData;
return {
loginUser: uid ? store.contacts.byId[Number(uid)] : undefined,
loginUser: store.authData.user,
channel: store.channels.byId[id]
};
});
const { data, refetch } = useGetChannelQuery(id);
const [changed, setChanged] = useState(false);
const [values, setValues] = useState<ChannelFormData>({ name: "", description: "" });
const [values, setValues] = useState(null);
const [updateChannelIcon] = useUpdateIconMutation();
const [updateChannel, { isSuccess: updated }] = useUpdateChannelMutation();
const handleUpdate = () => {
const { name, description } = values;
updateChannel({ id, name, description });
};
const handleChange = (evt: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const handleChange = (evt) => {
const newValue = evt.target.value;
const { type } = evt.target.dataset as { type: keyof ChannelFormData };
const { type } = evt.target.dataset;
setValues((prev) => {
return { ...prev, [type]: newValue };
});
};
const updateIcon = (image: File) => {
const updateIcon = (image) => {
updateChannelIcon({ gid: id, image });
};
const handleReset = () => {
console.log("reset", data);
setValues(data);
};
@@ -107,7 +100,6 @@ export default function Overview({ id = 0 }) {
toast.success("Channel updated!");
refetch();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [updated]);
if (!values || !id) return null;
+28 -34
View File
@@ -1,7 +1,7 @@
import { useState } from "react";
import { useParams, useNavigate, useSearchParams } from "react-router-dom";
import LeaveChannel from "../../common/component/LeaveChannel";
import StyledSettingContainer, { Danger } from "../../common/component/StyledSettingContainer";
import StyledSettingContainer from "../../common/component/StyledSettingContainer";
import DeleteConfirmModal from "./DeleteConfirmModal";
import useNavs from "./navs";
import { useAppSelector } from "../../app/store";
@@ -9,54 +9,39 @@ import { useAppSelector } from "../../app/store";
let from: string | null = null;
export default function ChannelSetting() {
const { cid } = useParams<{ cid: string }>();
const cidNum = Number(cid);
const { isAdmin, loginUid, channel } = useAppSelector((store) => {
const { cid } = useParams();
const { loginUser, channel } = useAppSelector((store) => {
return {
loginUid: store.authData.uid,
isAdmin: store.authData.uid
? store.contacts.byId[Number(store.authData.uid)]?.is_admin
: false,
channel: store.channels.byId[cidNum]
loginUser: store.authData.user,
channel: store.channels.byId[cid]
};
});
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const navs = useNavs(cidNum);
const flattenNaves = navs.map(({ items }) => items).flat();
const navs = useNavs(cid);
const flatenNavs = navs
.map(({ items }) => {
return items;
})
.flat();
const navKey = searchParams.get("nav");
from = from ?? (searchParams.get("f") || "/");
const [deleteConfirm, setDeleteConfirm] = useState(false);
const [leaveConfirm, setLeaveConfirm] = useState(false);
const close = () => {
// todo: check usage
navigate(from!);
navigate(from);
from = null;
};
const toggleDeleteConfirm = () => {
const toggleDeleteConfrim = () => {
setDeleteConfirm((prev) => !prev);
};
const toggleLeaveConfirm = () => {
const toggleLeaveConfrim = () => {
setLeaveConfirm((prev) => !prev);
};
if (!cid) return null;
const currNav = flattenNaves.find((n) => n.name == navKey) || flattenNaves[0];
const canDelete = isAdmin || channel?.owner === Number(loginUid);
const currNav = flatenNavs.find((n) => n.name == navKey) || flatenNavs[0];
const canDelete = loginUser.isAdmin || channel?.owner == loginUser.uid;
const canLeave = !channel?.is_public;
const dangers: Danger[] = [];
if (canLeave) {
dangers.push({
title: "Leave Channel",
handler: toggleLeaveConfirm
});
}
if (canDelete) {
dangers.push({
title: "Delete Channel",
handler: toggleDeleteConfirm
});
}
return (
<>
@@ -65,12 +50,21 @@ export default function ChannelSetting() {
closeModal={close}
title="Channel Setting"
navs={navs}
dangers={dangers}
dangers={[
canLeave && {
title: "Leave Channel",
handler: toggleLeaveConfrim
},
canDelete && {
title: "Delete Channel",
handler: toggleDeleteConfrim
}
]}
>
{currNav.component}
</StyledSettingContainer>
{deleteConfirm && <DeleteConfirmModal closeModal={toggleDeleteConfirm} id={Number(cid)} />}
{leaveConfirm && <LeaveChannel closeModal={toggleLeaveConfirm} id={cidNum} />}
{deleteConfirm && <DeleteConfirmModal closeModal={toggleDeleteConfrim} id={cid} />}
{leaveConfirm && <LeaveChannel closeModal={toggleLeaveConfrim} id={cid} />}
</>
);
}