refactor: setting page

This commit is contained in:
zerosoul
2022-04-15 13:18:03 +08:00
parent eb8717da8e
commit 19a4861819
9 changed files with 56 additions and 63 deletions
@@ -6,12 +6,6 @@ export default async function handler({ operation, payload }) {
return; return;
} }
switch (operation) { switch (operation) {
case "updateInviteLink":
{
const data = payload;
await table.setItem("inviteLink", data);
}
break;
case "updateInfo": case "updateInfo":
{ {
const data = payload; const data = payload;
+17
View File
@@ -72,6 +72,21 @@ export const channelApi = createApi({
// } // }
// }, // },
}), }),
createInviteLink: builder.query({
query: (gid) => ({
headers: {
"content-type": "text/plain",
accept: "text/plain",
},
url: `/group/${gid}/create_invite_link`,
responseHandler: (response) => response.text(),
}),
transformResponse: (link) => {
// 替换掉域名
const invite = new URL(link);
return `${location.origin}${invite.pathname}${invite.search}${invite.hash}`;
},
}),
removeChannel: builder.query({ removeChannel: builder.query({
query: (id) => ({ query: (id) => ({
url: `group/${id}`, url: `group/${id}`,
@@ -126,6 +141,8 @@ export const channelApi = createApi({
}); });
export const { export const {
useLazyCreateInviteLinkQuery,
useCreateInviteLinkQuery,
useLazyGetHistoryMessagesQuery, useLazyGetHistoryMessagesQuery,
useGetChannelQuery, useGetChannelQuery,
useUpdateChannelMutation, useUpdateChannelMutation,
+1 -13
View File
@@ -1,6 +1,6 @@
import { createApi } from "@reduxjs/toolkit/query/react"; import { createApi } from "@reduxjs/toolkit/query/react";
import BASE_URL from "../config"; import BASE_URL from "../config";
import { updateInviteLink, updateInfo } from "../slices/server"; import { updateInfo } from "../slices/server";
import baseQuery from "./base.query"; import baseQuery from "./base.query";
const defaultExpireDuration = 7 * 24 * 60 * 60; const defaultExpireDuration = 7 * 24 * 60 * 60;
export const serverApi = createApi({ export const serverApi = createApi({
@@ -108,18 +108,6 @@ export const serverApi = createApi({
const invite = new URL(link); const invite = new URL(link);
return `${location.origin}${invite.pathname}${invite.search}${invite.hash}`; return `${location.origin}${invite.pathname}${invite.search}${invite.hash}`;
}, },
async onQueryStarted(
expire = defaultExpireDuration,
{ dispatch, queryFulfilled }
) {
try {
const { data: link } = await queryFulfilled;
console.log("link", link);
dispatch(updateInviteLink({ expire, link }));
} catch {
console.log("invite link error");
}
},
}), }),
updateServer: builder.mutation({ updateServer: builder.mutation({
query: (data) => ({ query: (data) => ({
+1 -10
View File
@@ -32,16 +32,7 @@ const serverSlice = createSlice({
state[_key] = values[_key]; state[_key] = values[_key];
}); });
}, },
updateInviteLink(state, action) {
const { link, expire = 7 * 24 * 60 * 60 } = action.payload;
state.inviteLink = { link, expire };
},
}, },
}); });
export const { export const { updateInfo, resetServer, fullfillServer } = serverSlice.actions;
updateInfo,
resetServer,
fullfillServer,
updateInviteLink,
} = serverSlice.actions;
export default serverSlice.reducer; export default serverSlice.reducer;
+8 -5
View File
@@ -1,12 +1,12 @@
import { useState } from "react"; import { useState } from "react";
import { useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import { useDrop } from "react-dnd"; import { useDrop } from "react-dnd";
import { NativeTypes } from "react-dnd-html5-backend"; import { NativeTypes } from "react-dnd-html5-backend";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import Tippy from "@tippyjs/react"; import Tippy from "@tippyjs/react";
import useContextMenu from "../../../common/hook/useContextMenu"; import useContextMenu from "../../../common/hook/useContextMenu";
import ContextMenu from "../../../common/component/ContextMenu"; import ContextMenu from "../../../common/component/ContextMenu";
import InviteModal from "../../../common/component/InviteModal"; import InviteModal from "../../../common/component/ChannelInviteModal";
import Tooltip from "../../../common/component/Tooltip"; import Tooltip from "../../../common/component/Tooltip";
// import { useDebounce} from "rooks"; // import { useDebounce} from "rooks";
import { useReadMessageMutation } from "../../../app/services/message"; import { useReadMessageMutation } from "../../../app/services/message";
@@ -17,6 +17,7 @@ import ChannelIcon from "../../../common/component/ChannelIcon";
import { getUnreadCount } from "../utils"; import { getUnreadCount } from "../utils";
const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => { const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => {
const { pathname } = useLocation();
const [inviteModalVisible, setInviteModalVisible] = useState(false); const [inviteModalVisible, setInviteModalVisible] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
const [muteChannel] = useUpdateMuteSettingMutation(); const [muteChannel] = useUpdateMuteSettingMutation();
@@ -52,7 +53,7 @@ const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => {
evt.stopPropagation(); evt.stopPropagation();
const { id } = evt.target.dataset; const { id } = evt.target.dataset;
if (id) { if (id) {
navigate(`/setting/channel/${id}`); navigate(`/setting/channel/${id}?f=${pathname}`);
} }
}; };
const [{ isActive }, drop] = useDrop(() => ({ const [{ isActive }, drop] = useDrop(() => ({
@@ -91,7 +92,7 @@ const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => {
: { add_groups: [{ gid: id }] }; : { add_groups: [{ gid: id }] };
muteChannel(data); muteChannel(data);
}; };
const { is_public, name } = channel; const { is_public, name, owner } = channel;
const { unreads = 0, mentions = [] } = getUnreadCount({ const { unreads = 0, mentions = [] } = getUnreadCount({
mids, mids,
messageData, messageData,
@@ -99,6 +100,7 @@ const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => {
loginUid, loginUid,
}); });
const isMentions = mentions.length !== 0; const isMentions = mentions.length !== 0;
const inviteIconVisible = loginUser?.is_admin || owner == loginUid;
return ( return (
<> <>
<Tippy <Tippy
@@ -154,7 +156,7 @@ const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => {
<span className={`txt ${unreads == 0 ? "read" : ""}`}>{name}</span> <span className={`txt ${unreads == 0 ? "read" : ""}`}>{name}</span>
</div> </div>
<div className="icons"> <div className="icons">
{loginUser?.is_admin && ( {inviteIconVisible && (
<Tooltip placement="bottom" tip="Add Member"> <Tooltip placement="bottom" tip="Add Member">
<i <i
className="icon invite" className="icon invite"
@@ -180,6 +182,7 @@ const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => {
</Tippy> </Tippy>
{inviteModalVisible && ( {inviteModalVisible && (
<InviteModal <InviteModal
cid={id}
title={channel.name} title={channel.name}
closeModal={toggleInviteModalVisible} closeModal={toggleInviteModalVisible}
/> />
+3 -2
View File
@@ -1,5 +1,5 @@
// import React from 'react' // import React from 'react'
import { NavLink } from "react-router-dom"; import { NavLink, useLocation } from "react-router-dom";
import Tooltip from "../../common/component/Tooltip"; import Tooltip from "../../common/component/Tooltip";
import settingIcon from "../../assets/icons/setting.svg?url"; import settingIcon from "../../assets/icons/setting.svg?url";
import styled from "styled-components"; import styled from "styled-components";
@@ -32,11 +32,12 @@ const StyledMenus = styled.ul`
} }
`; `;
export default function Menu() { export default function Menu() {
const { pathname } = useLocation();
return ( return (
<StyledMenus> <StyledMenus>
<li className="menu"> <li className="menu">
<Tooltip placement="right" tip="Settings"> <Tooltip placement="right" tip="Settings">
<NavLink to={"/setting"}> <NavLink to={`/setting?f=${pathname}`}>
<img src={settingIcon} alt="setting icon" className="icon" /> <img src={settingIcon} alt="setting icon" className="icon" />
</NavLink> </NavLink>
</Tooltip> </Tooltip>
+8 -11
View File
@@ -1,37 +1,34 @@
import { useState } from "react"; import { useState } from "react";
// import { useDispatch } from "react-redux"; // import { useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import StyledSettingContainer from "../../common/component/StyledSettingContainer"; import StyledSettingContainer from "../../common/component/StyledSettingContainer";
import useNavs from "./navs"; import useNavs from "./navs";
import LogoutConfirmModal from "./LogoutConfirmModal"; import LogoutConfirmModal from "./LogoutConfirmModal";
let from = null;
export default function Setting() { export default function Setting() {
const [searchParams] = useSearchParams();
const navs = useNavs(); const navs = useNavs();
const flatenNavs = navs const flatenNavs = navs
.map(({ items }) => { .map(({ items }) => {
return items; return items;
}) })
.flat(); .flat();
const [currNav, setCurrNav] = useState(flatenNavs[0]); const navKey = searchParams.get("nav");
from = from ?? (searchParams.get("f") || "/");
const [logoutConfirm, setLogoutConfirm] = useState(false); const [logoutConfirm, setLogoutConfirm] = useState(false);
const navgateTo = useNavigate(); const navgateTo = useNavigate();
const close = () => { const close = () => {
// dispatch(toggleSetting()); // dispatch(toggleSetting());
navgateTo(-1); navgateTo(from);
from = null;
}; };
const toggleLogoutConfrim = () => { const toggleLogoutConfrim = () => {
setLogoutConfirm((prev) => !prev); setLogoutConfirm((prev) => !prev);
}; };
const updateNav = (name) => { const currNav = flatenNavs.find((n) => n.name == navKey) || flatenNavs[0];
const tmp = flatenNavs.find((n) => n.name == name);
if (tmp) {
setCurrNav(tmp);
}
};
return ( return (
<> <>
<StyledSettingContainer <StyledSettingContainer
updateNav={updateNav}
nav={currNav} nav={currNav}
closeModal={close} closeModal={close}
title="Settings" title="Settings"
+10 -6
View File
@@ -41,9 +41,12 @@ const StyledWrapper = styled.div`
} }
`; `;
export default function Overview({ id = 0 }) { export default function Overview({ id = 0 }) {
const loginUser = useSelector( const { loginUser, channel } = useSelector((store) => {
(store) => store.contacts.byId[store.authData.uid] return {
); loginUser: store.contacts.byId[store.authData.uid],
channel: store.channels.byId[id],
};
});
const { data, refetch } = useGetChannelQuery(id); const { data, refetch } = useGetChannelQuery(id);
const [changed, setChanged] = useState(false); const [changed, setChanged] = useState(false);
const [values, setValues] = useState(null); const [values, setValues] = useState(null);
@@ -89,14 +92,15 @@ export default function Overview({ id = 0 }) {
if (!values || !id) return null; if (!values || !id) return null;
const { name, description } = values; const { name, description } = values;
const isAdmin = loginUser?.is_admin; const readOnly = !loginUser?.is_admin && channel?.owner != loginUser?.uid;
return ( return (
<StyledWrapper> <StyledWrapper>
<div className="inputs"> <div className="inputs">
<div className="input"> <div className="input">
<Label htmlFor="name">Channel Name</Label> <Label htmlFor="name">Channel Name</Label>
<Input <Input
disabled={!isAdmin} disabled={readOnly}
className="name" className="name"
data-type="name" data-type="name"
onChange={handleChange} onChange={handleChange}
@@ -109,7 +113,7 @@ export default function Overview({ id = 0 }) {
<div className="input"> <div className="input">
<Label htmlFor="desc">Channel Topic</Label> <Label htmlFor="desc">Channel Topic</Label>
<Textarea <Textarea
disabled={!isAdmin} disabled={readOnly}
data-type="description" data-type="description"
onChange={handleChange} onChange={handleChange}
value={description ?? ""} value={description ?? ""}
+8 -10
View File
@@ -1,10 +1,12 @@
import { useState } from "react"; import { useState } from "react";
import { useParams, useNavigate } from "react-router-dom"; import { useParams, useNavigate, useSearchParams } from "react-router-dom";
import StyledSettingContainer from "../../common/component/StyledSettingContainer"; import StyledSettingContainer from "../../common/component/StyledSettingContainer";
import DeleteConfirmModal from "./DeleteConfirmModal"; import DeleteConfirmModal from "./DeleteConfirmModal";
import useNavs from "./navs"; import useNavs from "./navs";
let from = null;
export default function ChannelSetting() { export default function ChannelSetting() {
const navigate = useNavigate(); const navigate = useNavigate();
const [searchParams] = useSearchParams();
const { cid } = useParams(); const { cid } = useParams();
const navs = useNavs(cid); const navs = useNavs(cid);
const flatenNavs = navs const flatenNavs = navs
@@ -12,25 +14,21 @@ export default function ChannelSetting() {
return items; return items;
}) })
.flat(); .flat();
const [currNav, setCurrNav] = useState(flatenNavs[0]); const navKey = searchParams.get("nav");
from = from ?? (searchParams.get("f") || "/");
const [deleteConfirm, setDeleteConfirm] = useState(false); const [deleteConfirm, setDeleteConfirm] = useState(false);
const close = () => { const close = () => {
navigate(-1); navigate(from);
from = null;
}; };
const toggleDeleteConfrim = () => { const toggleDeleteConfrim = () => {
setDeleteConfirm((prev) => !prev); setDeleteConfirm((prev) => !prev);
}; };
const updateNav = (name) => {
const tmp = flatenNavs.find((n) => n.name == name);
if (tmp) {
setCurrNav(tmp);
}
};
if (!cid) return null; if (!cid) return null;
const currNav = flatenNavs.find((n) => n.name == navKey) || flatenNavs[0];
return ( return (
<> <>
<StyledSettingContainer <StyledSettingContainer
updateNav={updateNav}
nav={currNav} nav={currNav}
closeModal={close} closeModal={close}
title="Channel Setting" title="Channel Setting"