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:
@@ -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,
|
||||
|
||||
@@ -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]
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user