refactor: setting page
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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,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) => ({
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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 ?? ""}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user