refactor: setting modals to pages

This commit is contained in:
zerosoul
2022-04-12 18:21:59 +08:00
parent bcfadfb2d4
commit 20373c4376
28 changed files with 473 additions and 477 deletions
+1 -8
View File
@@ -6,7 +6,6 @@ import { updateChannel, removeChannel } from "../slices/channels";
import { removeMessage } from "../slices/message";
import { removeChannelSession } from "../slices/message.channel";
import { removeReactionMessage } from "../slices/message.reaction";
import { toggleChannelSetting } from "../slices/ui";
import { onMessageSendStarted } from "./handlers";
export const channelApi = createApi({
reducerPath: "channelApi",
@@ -79,16 +78,10 @@ export const channelApi = createApi({
method: "DELETE",
}),
async onQueryStarted(id, { dispatch, getState, queryFulfilled }) {
const {
ui: { channelSetting },
channelMessage,
} = getState();
const { channelMessage } = getState();
try {
await queryFulfilled;
dispatch(removeChannel(id));
if (id == channelSetting) {
dispatch(toggleChannelSetting());
}
// 删掉该channel下的所有消息&reaction
const mids = channelMessage[id];
if (mids) {
-12
View File
@@ -5,8 +5,6 @@ const initialState = {
ready: false,
inputMode: "text",
menuExpand: false,
setting: false,
channelSetting: null,
fileListView: Views.item,
};
const uiSlice = createSlice({
@@ -31,14 +29,6 @@ const uiSlice = createSlice({
updateFileListView(state, action) {
state.fileListView = action.payload;
},
toggleSetting(state) {
state.setting = !state.setting;
},
toggleChannelSetting(state, action) {
console.log("toggle channel setting payload", action);
const id = action.payload;
state.channelSetting = state.channelSetting ? null : id;
},
},
});
export const {
@@ -46,9 +36,7 @@ export const {
setReady,
updateOnline,
updateInputMode,
toggleSetting,
toggleMenuExpand,
toggleChannelSetting,
updateFileListView,
} = uiSlice.actions;
export default uiSlice.reducer;
@@ -1,115 +0,0 @@
// import { useState, useEffect } from "react";
import StyledContainer from './StyledContainer';
// import Input from "../../styled/Input";
import Textarea from '../../styled/Textarea';
import Toggle from '../../styled/Toggle';
import Label from '../../styled/Label';
import SaveTip from '../../SaveTip';
import useConfig from './useConfig';
export default function Logins() {
const { values, updateConfig, setValues, reset, changed } = useConfig('login');
const handleUpdate = () => {
// const { token_url, description } = values;
updateConfig(values);
};
const handleChange = (evt) => {
const newValue = evt.target.value;
const { type } = evt.target.dataset;
const items = newValue ? newValue.split('\n') : [];
setValues((prev) => {
return { ...prev, [type]: items };
});
};
const handleToggle = (val) => {
setValues((prev) => {
return { ...prev, ...val };
});
};
if (!values) return null;
const { google, metamask, password, oidc = [] } = values ?? {};
return (
<StyledContainer>
<div className="inputs">
<div className="input row">
<Label>Password</Label>
<Toggle
onClick={handleToggle.bind(null, { password: !password })}
data-checked={password}
></Toggle>
</div>
<div className="input row">
<Label>Google</Label>
<Toggle onClick={handleToggle.bind(null, { google: !google })} data-checked={google}></Toggle>
</div>
<div className="input row">
<Label>Metamask</Label>
<Toggle
onClick={handleToggle.bind(null, { metamask: !metamask })}
data-checked={metamask}
></Toggle>
</div>
<div className="input">
<Label htmlFor="desc">OIDC</Label>
<Textarea
rows={10}
data-type="oidc"
onChange={handleChange}
value={oidc.join('\n')}
name="oidc"
placeholder="Input issuer list, one line, one issuer"
/>
</div>
{/* <div className="input">
<Label htmlFor="name">Token Url</Label>
<Input
disabled={!enabled}
data-type="token_url"
onChange={handleChange}
value={token_url || "https://oauth2.googleapis.com/token"}
name="token_url"
placeholder="Token URL"
/>
</div>
<div className="input">
<Label htmlFor="desc">Project ID</Label>
<Input
disabled={!enabled}
type={"number"}
data-type="project_id"
onChange={handleChange}
value={project_id}
name="project_id"
placeholder="Project ID"
/>
</div>
<div className="input">
<Label htmlFor="desc">Private Key</Label>
<Textarea
rows={10}
disabled={!enabled}
data-type="private_key"
onChange={handleChange}
value={private_key}
name="private_key"
placeholder="Private key"
/>
</div>
<div className="input">
<Label htmlFor="desc">Client Email</Label>
<Input
disabled={!enabled}
data-type="client_email"
onChange={handleChange}
value={client_email}
name="client_email"
placeholder="Client Email address"
/>
</div> */}
</div>
{changed && <SaveTip saveHandler={handleUpdate} resetHandler={reset} />}
{/* <button onClick={handleUpdate} className="btn">update</button> */}
</StyledContainer>
);
}
@@ -1,92 +0,0 @@
import { useEffect, useState } from 'react';
import { isObjectEqual } from '../../../utils';
import toast from 'react-hot-toast';
import {
useGetAgoraConfigQuery,
useGetFirebaseConfigQuery,
useGetSMTPConfigQuery,
useGetLoginConfigQuery,
useUpdateLoginConfigMutation,
useUpdateSMTPConfigMutation,
useUpdateAgoraConfigMutation,
useUpdateFirebaseConfigMutation
} from '../../../../app/services/server';
export default function useConfig(config = 'smtp') {
const [changed, setChanged] = useState(false);
const [values, setValues] = useState({});
const { data: Login, refetch: refetchLogin } = useGetLoginConfigQuery();
const [updateLoginConfig, { isSuccess: LoginUpdated }] = useUpdateLoginConfigMutation();
const { data: SMTP, refetch: refetchSMTP } = useGetSMTPConfigQuery();
const [updateSMTPConfig, { isSuccess: SMTPUpdated }] = useUpdateSMTPConfigMutation();
const { data: Agora, refetch: refetchAgora } = useGetAgoraConfigQuery();
const [updateAgoraConfig, { isSuccess: AgoraUpdated }] = useUpdateAgoraConfigMutation();
const { data: Firebase, refetch: refetchFirebase } = useGetFirebaseConfigQuery();
const [updateFirebaseConfig, { isSuccess: FirebaseUpdated }] = useUpdateFirebaseConfigMutation();
const datas = {
login: Login,
smtp: SMTP,
agora: Agora,
firebase: Firebase
};
const updateFns = {
login: updateLoginConfig,
smtp: updateSMTPConfig,
agora: updateAgoraConfig,
firebase: updateFirebaseConfig
};
const refetchs = {
smtp: refetchSMTP,
agora: refetchAgora,
firebase: refetchFirebase,
login: refetchLogin
};
const updateds = {
login: LoginUpdated,
smtp: SMTPUpdated,
agora: AgoraUpdated,
firebase: FirebaseUpdated
};
const data = datas[config];
const updateConfig = updateFns[config];
const refetch = refetchs[config];
const updated = updateds[config];
const reset = () => {
setValues(data ?? {});
};
const toggleEnable = () => {
setValues((prev) => {
return { ...prev, enabled: !prev.enabled };
});
};
useEffect(() => {
if (updated) {
toast.success('Configuration Updated!');
refetch();
}
}, [updated]);
useEffect(() => {
console.log('wtf', data);
// if (data) {
setValues(data ?? {});
// }
}, [data]);
useEffect(() => {
// if (data && values) {
if (!isObjectEqual(data, values)) {
setChanged(true);
} else {
setChanged(false);
}
// }
}, [data, values]);
return {
reset,
changed,
updateConfig,
values,
setValues,
toggleEnable
};
}
-104
View File
@@ -1,104 +0,0 @@
import { useSelector } from 'react-redux';
import MyAccount from './MyAccount';
import Overview from './Overview';
import Logins from './config/Logins';
import ConfigFirebase from './config/Firebase';
import ConfigSMTP from './config/SMTP';
import Notifications from './Notifications';
import ManageMembers from '../ManageMembers';
import FAQ from '../FAQ';
import ConfigAgora from './config/Agora';
const navs = [
{
title: 'General',
items: [
{
name: 'overview',
title: 'Overview',
component: <Overview />
},
{
name: 'members',
title: 'Members',
component: <ManageMembers />,
admin: true
},
{
name: 'notification',
title: 'Notification',
component: <Notifications />
}
]
},
{
title: 'User',
items: [
{
name: 'my_account',
title: 'My Account',
component: <MyAccount />
}
]
},
{
title: 'Configuration',
items: [
{
name: 'firebase',
title: 'Firebase',
component: <ConfigFirebase />
},
{
name: 'agora',
title: 'Agora',
component: <ConfigAgora />
},
{
name: 'smtp',
title: 'SMTP',
component: <ConfigSMTP />
},
{
name: 'social_login',
title: 'Social Login',
component: <Logins />
}
],
admin: true
},
{
title: 'About',
items: [
{
name: 'faq',
title: 'FAQ',
component: <FAQ />
},
{
name: 'terms',
title: 'Terms & Privacy',
component: 'Terms & Privacy'
},
{
name: 'feedback',
title: 'Feedback',
component: 'feedback'
}
]
}
];
const useNavs = () => {
const loginUser = useSelector((store) => {
return store.contacts.byId[store.authData.uid];
});
const Navs = navs.filter((nav) => {
if (loginUser.is_admin) {
return true;
} else {
return !nav.admin;
}
});
return Navs;
};
export default useNavs;
@@ -1,10 +1,9 @@
// import React from 'react'
import styled from "styled-components";
import Modal from "./Modal";
import backIcon from "../../assets/icons/arrow.left.svg?url";
const StyledWrapper = styled.div`
width: 100%;
height: 100%;
width: 100vw;
height: 100vh;
display: flex;
> .left {
max-height: 100vh;
@@ -89,7 +88,6 @@ export default function StyledSettingContainer({
updateNav(name);
};
return (
<Modal>
<StyledWrapper>
<div className="left">
<h2 onClick={closeModal} className="title">
@@ -130,6 +128,5 @@ export default function StyledSettingContainer({
{children}
</div>
</StyledWrapper>
</Modal>
);
}
+10 -5
View File
@@ -1,7 +1,7 @@
import { useNavigate } from "react-router-dom";
import { useDrop } from "react-dnd";
import { NativeTypes } from "react-dnd-html5-backend";
import { useDispatch, useSelector } from "react-redux";
import { useSelector } from "react-redux";
import Tippy from "@tippyjs/react";
import useContextMenu from "../../../common/hook/useContextMenu";
import ContextMenu from "../../../common/component/ContextMenu";
@@ -11,12 +11,10 @@ import { useReadMessageMutation } from "../../../app/services/message";
import { useUpdateMuteSettingMutation } from "../../../app/services/contact";
import StyledLink from "./styled";
import { toggleChannelSetting } from "../../../app/slices/ui";
import ChannelIcon from "../../../common/component/ChannelIcon";
import { getUnreadCount } from "../utils";
const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => {
const dispatch = useDispatch();
const navigate = useNavigate();
const [muteChannel] = useUpdateMuteSettingMutation();
const [updateReadIndex] = useReadMessageMutation();
@@ -47,7 +45,10 @@ const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => {
const handleChannelSetting = (evt) => {
evt.preventDefault();
evt.stopPropagation();
dispatch(toggleChannelSetting(id));
const { id } = evt.target.dataset;
if (id) {
navigate(`/setting/channel/${id}`);
}
};
const [{ isActive }, drop] = useDrop(() => ({
accept: [NativeTypes.FILE],
@@ -138,7 +139,11 @@ const NavItem = ({ id, setFiles, toggleRemoveConfirm }) => {
</div>
<div className="icons">
<Tooltip placement="bottom" tip="Channel Setting">
<i className="setting" onClick={handleChannelSetting}></i>
<i
className="setting"
data-id={id}
onClick={handleChannelSetting}
></i>
</Tooltip>
{unreads > 0 && (
<i className={`badge ${isDot ? "dot" : ""}`}>
+1 -1
View File
@@ -1,7 +1,7 @@
import { useState } from "react";
import { useSelector } from "react-redux";
import DeleteConfirmModal from "../../../common/component/ChannelSetting/DeleteConfirmModal";
import DeleteConfirmModal from "../../settingChannel/DeleteConfirmModal";
import NavItem from "./NavItem";
export default function ChannelList({ setDropFiles }) {
+4 -9
View File
@@ -1,10 +1,7 @@
// import React from 'react'
import { useDispatch } from "react-redux";
import { toggleSetting } from "../../app/slices/ui";
import { NavLink } from "react-router-dom";
import Tooltip from "../../common/component/Tooltip";
import settingIcon from "../../assets/icons/setting.svg?url";
// import foldIcon from "../../assets/icons/fold.svg?url";
// import unfoldIcon from "../../assets/icons/unfold.svg?url";
import styled from "styled-components";
const StyledMenus = styled.ul`
display: flex;
@@ -35,15 +32,13 @@ const StyledMenus = styled.ul`
}
`;
export default function Menu() {
const dispatch = useDispatch();
const handleSetting = () => {
dispatch(toggleSetting());
};
return (
<StyledMenus>
<li className="menu" onClick={handleSetting}>
<li className="menu">
<Tooltip placement="right" tip="Settings">
<NavLink to={"/setting"}>
<img src={settingIcon} alt="setting icon" className="icon" />
</NavLink>
</Tooltip>
{/* {expand && (
<span className="txt animate__animated animate__fadeIn">
+15 -14
View File
@@ -1,8 +1,7 @@
// import React from 'react';
// import { useEffect } from "react";
import { Outlet, NavLink } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import { toggleMenuExpand } from "../../app/slices/ui";
import { Outlet, NavLink, useLocation } from "react-router-dom";
import { useSelector } from "react-redux";
import StyledWrapper from "./styled";
import ServerDropList from "./ServerDropList";
// import Tools from "./Tools";
@@ -11,30 +10,34 @@ import Menu from "./Menu";
import usePreload from "./usePreload";
import Tooltip from "../../common/component/Tooltip";
import Notification from "../../common/component/Notification";
import SettingModal from "../../common/component/Setting";
import ChannelSettingModal from "../../common/component/ChannelSetting";
import ChatIcon from "../../assets/icons/chat.svg?url";
import ContactIcon from "../../assets/icons/contact.svg?url";
import FolderIcon from "../../assets/icons/folder.svg?url";
// const routes = ["/setting", "/setting/channel/:cid"];
export default function HomePage() {
const dispatch = useDispatch();
const { pathname } = useLocation();
const {
ui: { ready, setting, channelSetting },
ui: { ready },
} = useSelector((store) => {
return {
ui: store.ui,
};
});
const { data, loading } = usePreload();
const toggleExpand = () => {
dispatch(toggleMenuExpand());
};
// console.log("index loading", loading, ready);
if (loading || !ready) {
return <Loading />;
}
const isSettingPage = pathname.startsWith("/setting");
if (isSettingPage) {
return (
<>
<Notification />
<Outlet />
</>
);
}
return (
<>
<Notification />
@@ -75,14 +78,12 @@ export default function HomePage() {
</nav>
<div className="divider"></div>
{/* <Tools expand={menuExpand} /> */}
<Menu toggle={toggleExpand} />
<Menu />
</div>
<div className="col right">
<Outlet />
</div>
</StyledWrapper>
{setting && <SettingModal />}
{channelSetting && <ChannelSettingModal id={channelSetting} />}
</>
);
}
+6
View File
@@ -13,6 +13,8 @@ import Meta from "../common/component/Meta";
import store from "../app/store";
import InvitePage from "./invite";
import SettingPage from "./setting";
import SettingChannelPage from "./settingChannel";
import toast from "react-hot-toast";
import ResourceManagement from "./resources";
@@ -53,6 +55,10 @@ const PageRoutes = () => {
</RequireAuth>
}
>
<Route path="setting">
<Route index element={<SettingPage />} />
<Route path="channel/:cid" element={<SettingChannelPage />} />
</Route>
<Route index element={<ChatPage />} />
<Route path="chat">
<Route index element={<ChatPage />} />
@@ -1,14 +1,12 @@
// import React from "react";
import { useEffect, useState } from "react";
import styled from "styled-components";
import { useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom";
import { toggleSetting } from "../../../app/slices/ui";
// import BASE_URL from "../../app/config";
import StyledModal from "../styled/Modal";
import Button from "../styled/Button";
import Checkbox from "../styled/Checkbox";
import useLogout from "../../hook/useLogout";
import StyledModal from "../../common/component/styled/Modal";
import Button from "../../common/component/styled/Button";
import Checkbox from "../../common/component/styled/Checkbox";
import useLogout from "../../common/hook/useLogout";
const StyledConfirm = styled(StyledModal)`
.clear {
font-weight: normal;
@@ -28,9 +26,9 @@ const StyledConfirm = styled(StyledModal)`
}
}
`;
import Modal from "../Modal";
import Modal from "../../common/component/Modal";
export default function LogoutConfirmModal({ closeModal }) {
const dispatch = useDispatch();
const navigate = useNavigate();
const [clearLocal, setClearLocal] = useState(false);
const { logout, exited, exiting, clearLocalData } = useLogout();
const handleLogout = () => {
@@ -45,8 +43,7 @@ export default function LogoutConfirmModal({ closeModal }) {
console.log("clear all store");
clearLocalData();
}
// closeModal();
dispatch(toggleSetting());
navigate("/");
}
}, [exited, clearLocal]);
return (
@@ -2,8 +2,8 @@ import { useEffect, useState } from "react";
import styled from "styled-components";
import { useSelector } from "react-redux";
import toast from "react-hot-toast";
import { useUpdateAvatarMutation } from "../../../app/services/contact";
import AvatarUploader from "../AvatarUploader";
import { useUpdateAvatarMutation } from "../../app/services/contact";
import AvatarUploader from "../../common/component/AvatarUploader";
import ProfileBasicEditModal from "./ProfileBasicEditModal";
const StyledWrapper = styled.div`
display: flex;
@@ -1,8 +1,8 @@
// import React from "react";
import styled from "styled-components";
import useNotification from "../../hook/useNotification";
import StyledToggle from "../styled/Toggle";
import Label from "../styled/Label";
import useNotification from "../../common/hook/useNotification";
import StyledToggle from "../../common/component/styled/Toggle";
import Label from "../../common/component/styled/Label";
const StyledWrapper = styled.div`
display: flex;
flex-direction: column;
@@ -5,12 +5,12 @@ import {
useGetServerQuery,
useUpdateServerMutation,
useUpdateLogoMutation,
} from "../../../app/services/server";
import LogoUploader from "../AvatarUploader";
import Input from "../styled/Input";
import Label from "../styled/Label";
import Textarea from "../styled/Textarea";
import SaveTip from "../SaveTip";
} from "../../app/services/server";
import LogoUploader from "../../common/component/AvatarUploader";
import Input from "../../common/component/styled/Input";
import Label from "../../common/component/styled/Label";
import Textarea from "../../common/component/styled/Textarea";
import SaveTip from "../../common/component/SaveTip";
import toast from "react-hot-toast";
const StyledWrapper = styled.div`
position: relative;
@@ -1,12 +1,10 @@
// import React from "react";
import { useEffect, useState } from "react";
import styled from "styled-components";
// import { useDispatch } from "react-redux";
import Input from "../styled/Input";
// import BASE_URL from "../../app/config";
import { useUpdateInfoMutation } from "../../../app/services/contact";
import StyledModal from "../styled/Modal";
import Button from "../styled/Button";
import Input from "../../common/component/styled/Input";
import { useUpdateInfoMutation } from "../../app/services/contact";
import StyledModal from "../../common/component/styled/Modal";
import Button from "../../common/component/styled/Button";
const StyledEdit = styled(StyledModal)`
.input {
margin: 48px 0;
@@ -22,7 +20,7 @@ const StyledEdit = styled(StyledModal)`
}
}
`;
import Modal from "../Modal";
import Modal from "../../common/component/Modal";
import toast from "react-hot-toast";
export default function ProfileBasicEditModal({
label = "Username",
@@ -1,10 +1,10 @@
// import { useState, useEffect } from "react";
import StyledContainer from "./StyledContainer";
import Input from "../../styled/Input";
import Textarea from "../../styled/Textarea";
import Label from "../../styled/Label";
import Toggle from "../../styled/Toggle";
import SaveTip from "../../SaveTip";
import Input from "../../../common/component/styled/Input";
import Textarea from "../../../common/component/styled/Textarea";
import Label from "../../../common/component/styled/Label";
import Toggle from "../../../common/component/styled/Toggle";
import SaveTip from "../../../common/component/SaveTip";
import useConfig from "./useConfig";
export default function ConfigAgora() {
const {
@@ -1,10 +1,10 @@
// import { useState, useEffect } from "react";
import StyledContainer from "./StyledContainer";
import Input from "../../styled/Input";
import Textarea from "../../styled/Textarea";
import Toggle from "../../styled/Toggle";
import Label from "../../styled/Label";
import SaveTip from "../../SaveTip";
import Input from "../../../common/component/styled/Input";
import Textarea from "../../../common/component/styled/Textarea";
import Toggle from "../../../common/component/styled/Toggle";
import Label from "../../../common/component/styled/Label";
import SaveTip from "../../../common/component/SaveTip";
import useConfig from "./useConfig";
export default function ConfigFirebase() {
+119
View File
@@ -0,0 +1,119 @@
// import { useState, useEffect } from "react";
import StyledContainer from "./StyledContainer";
import Textarea from "../../../common/component/styled/Textarea";
import Toggle from "../../../common/component/styled/Toggle";
import Label from "../../../common/component/styled/Label";
import SaveTip from "../../../common/component/SaveTip";
import useConfig from "./useConfig";
export default function Logins() {
const { values, updateConfig, setValues, reset, changed } = useConfig(
"login"
);
const handleUpdate = () => {
// const { token_url, description } = values;
updateConfig(values);
};
const handleChange = (evt) => {
const newValue = evt.target.value;
const { type } = evt.target.dataset;
const items = newValue ? newValue.split("\n") : [];
setValues((prev) => {
return { ...prev, [type]: items };
});
};
const handleToggle = (val) => {
setValues((prev) => {
return { ...prev, ...val };
});
};
if (!values) return null;
const { google, metamask, password, oidc = [] } = values ?? {};
return (
<StyledContainer>
<div className="inputs">
<div className="input row">
<Label>Password</Label>
<Toggle
onClick={handleToggle.bind(null, { password: !password })}
data-checked={password}
></Toggle>
</div>
<div className="input row">
<Label>Google</Label>
<Toggle
onClick={handleToggle.bind(null, { google: !google })}
data-checked={google}
></Toggle>
</div>
<div className="input row">
<Label>Metamask</Label>
<Toggle
onClick={handleToggle.bind(null, { metamask: !metamask })}
data-checked={metamask}
></Toggle>
</div>
<div className="input">
<Label htmlFor="desc">OIDC</Label>
<Textarea
rows={10}
data-type="oidc"
onChange={handleChange}
value={oidc.join("\n")}
name="oidc"
placeholder="Input issuer list, one line, one issuer"
/>
</div>
{/* <div className="input">
<Label htmlFor="name">Token Url</Label>
<Input
disabled={!enabled}
data-type="token_url"
onChange={handleChange}
value={token_url || "https://oauth2.googleapis.com/token"}
name="token_url"
placeholder="Token URL"
/>
</div>
<div className="input">
<Label htmlFor="desc">Project ID</Label>
<Input
disabled={!enabled}
type={"number"}
data-type="project_id"
onChange={handleChange}
value={project_id}
name="project_id"
placeholder="Project ID"
/>
</div>
<div className="input">
<Label htmlFor="desc">Private Key</Label>
<Textarea
rows={10}
disabled={!enabled}
data-type="private_key"
onChange={handleChange}
value={private_key}
name="private_key"
placeholder="Private key"
/>
</div>
<div className="input">
<Label htmlFor="desc">Client Email</Label>
<Input
disabled={!enabled}
data-type="client_email"
onChange={handleChange}
value={client_email}
name="client_email"
placeholder="Client Email address"
/>
</div> */}
</div>
{changed && <SaveTip saveHandler={handleUpdate} resetHandler={reset} />}
{/* <button onClick={handleUpdate} className="btn">update</button> */}
</StyledContainer>
);
}
@@ -6,15 +6,15 @@ const StyledTest = styled.div`
white-space: nowrap;
margin-top: 24px;
`;
import { useSendTestEmailMutation } from "../../../../app/services/server";
import iconQuestion from "../../../../assets/icons/question.svg?url";
import { useSendTestEmailMutation } from "../../../app/services/server";
import iconQuestion from "../../../assets/icons/question.svg?url";
import useConfig from "./useConfig";
import StyledContainer from "./StyledContainer";
import Input from "../../styled/Input";
import Button from "../../styled/Button";
import Toggle from "../../styled/Toggle";
import Label from "../../styled/Label";
import SaveTip from "../../SaveTip";
import Input from "../../../common/component/styled/Input";
import Button from "../../../common/component/styled/Button";
import Toggle from "../../../common/component/styled/Toggle";
import Label from "../../../common/component/styled/Label";
import SaveTip from "../../../common/component/SaveTip";
import toast from "react-hot-toast";
export default function ConfigSMTP() {
+107
View File
@@ -0,0 +1,107 @@
import { useEffect, useState } from "react";
import { isObjectEqual } from "../../../common/utils";
import toast from "react-hot-toast";
import {
useGetAgoraConfigQuery,
useGetFirebaseConfigQuery,
useGetSMTPConfigQuery,
useGetLoginConfigQuery,
useUpdateLoginConfigMutation,
useUpdateSMTPConfigMutation,
useUpdateAgoraConfigMutation,
useUpdateFirebaseConfigMutation,
} from "../../../app/services/server";
export default function useConfig(config = "smtp") {
const [changed, setChanged] = useState(false);
const [values, setValues] = useState({});
const { data: Login, refetch: refetchLogin } = useGetLoginConfigQuery();
const [
updateLoginConfig,
{ isSuccess: LoginUpdated },
] = useUpdateLoginConfigMutation();
const { data: SMTP, refetch: refetchSMTP } = useGetSMTPConfigQuery();
const [
updateSMTPConfig,
{ isSuccess: SMTPUpdated },
] = useUpdateSMTPConfigMutation();
const { data: Agora, refetch: refetchAgora } = useGetAgoraConfigQuery();
const [
updateAgoraConfig,
{ isSuccess: AgoraUpdated },
] = useUpdateAgoraConfigMutation();
const {
data: Firebase,
refetch: refetchFirebase,
} = useGetFirebaseConfigQuery();
const [
updateFirebaseConfig,
{ isSuccess: FirebaseUpdated },
] = useUpdateFirebaseConfigMutation();
const datas = {
login: Login,
smtp: SMTP,
agora: Agora,
firebase: Firebase,
};
const updateFns = {
login: updateLoginConfig,
smtp: updateSMTPConfig,
agora: updateAgoraConfig,
firebase: updateFirebaseConfig,
};
const refetchs = {
smtp: refetchSMTP,
agora: refetchAgora,
firebase: refetchFirebase,
login: refetchLogin,
};
const updateds = {
login: LoginUpdated,
smtp: SMTPUpdated,
agora: AgoraUpdated,
firebase: FirebaseUpdated,
};
const data = datas[config];
const updateConfig = updateFns[config];
const refetch = refetchs[config];
const updated = updateds[config];
const reset = () => {
setValues(data ?? {});
};
const toggleEnable = () => {
setValues((prev) => {
return { ...prev, enabled: !prev.enabled };
});
};
useEffect(() => {
if (updated) {
toast.success("Configuration Updated!");
refetch();
}
}, [updated]);
useEffect(() => {
console.log("wtf", data);
// if (data) {
setValues(data ?? {});
// }
}, [data]);
useEffect(() => {
// if (data && values) {
if (!isObjectEqual(data, values)) {
setChanged(true);
} else {
setChanged(false);
}
// }
}, [data, values]);
return {
reset,
changed,
updateConfig,
values,
setValues,
toggleEnable,
};
}
@@ -1,7 +1,7 @@
import { useState } from "react";
import { useDispatch } from "react-redux";
import { toggleSetting } from "../../../app/slices/ui";
import StyledSettingContainer from "../StyledSettingContainer";
// import { useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom";
import StyledSettingContainer from "../../common/component/StyledSettingContainer";
import useNavs from "./navs";
import LogoutConfirmModal from "./LogoutConfirmModal";
@@ -14,9 +14,10 @@ export default function Setting() {
.flat();
const [currNav, setCurrNav] = useState(flatenNavs[0]);
const [logoutConfirm, setLogoutConfirm] = useState(false);
const dispatch = useDispatch();
const navgateTo = useNavigate();
const close = () => {
dispatch(toggleSetting());
// dispatch(toggleSetting());
navgateTo(-1);
};
const toggleLogoutConfrim = () => {
setLogoutConfirm((prev) => !prev);
+104
View File
@@ -0,0 +1,104 @@
import { useSelector } from "react-redux";
import MyAccount from "./MyAccount";
import Overview from "./Overview";
import Logins from "./config/Logins";
import ConfigFirebase from "./config/Firebase";
import ConfigSMTP from "./config/SMTP";
import Notifications from "./Notifications";
import ManageMembers from "../../common/component/ManageMembers";
import FAQ from "../../common/component/FAQ";
import ConfigAgora from "./config/Agora";
const navs = [
{
title: "General",
items: [
{
name: "overview",
title: "Overview",
component: <Overview />,
},
{
name: "members",
title: "Members",
component: <ManageMembers />,
admin: true,
},
{
name: "notification",
title: "Notification",
component: <Notifications />,
},
],
},
{
title: "User",
items: [
{
name: "my_account",
title: "My Account",
component: <MyAccount />,
},
],
},
{
title: "Configuration",
items: [
{
name: "firebase",
title: "Firebase",
component: <ConfigFirebase />,
},
{
name: "agora",
title: "Agora",
component: <ConfigAgora />,
},
{
name: "smtp",
title: "SMTP",
component: <ConfigSMTP />,
},
{
name: "social_login",
title: "Social Login",
component: <Logins />,
},
],
admin: true,
},
{
title: "About",
items: [
{
name: "faq",
title: "FAQ",
component: <FAQ />,
},
{
name: "terms",
title: "Terms & Privacy",
component: "Terms & Privacy",
},
{
name: "feedback",
title: "Feedback",
component: "feedback",
},
],
},
];
const useNavs = () => {
const loginUser = useSelector((store) => {
return store.contacts.byId[store.authData.uid];
});
const Navs = navs.filter((nav) => {
if (loginUser.is_admin) {
return true;
} else {
return !nav.admin;
}
});
return Navs;
};
export default useNavs;
@@ -2,11 +2,10 @@
import { useEffect } from "react";
import toast from "react-hot-toast";
import { useNavigate, useMatch } from "react-router-dom";
import Modal from "../Modal";
// import BASE_URL from "../../app/config";
import { useLazyRemoveChannelQuery } from "../../../app/services/channel";
import StyledModal from "../styled/Modal";
import Button from "../styled/Button";
import Modal from "../../common/component/Modal";
import { useLazyRemoveChannelQuery } from "../../app/services/channel";
import StyledModal from "../../common/component/styled/Modal";
import Button from "../../common/component/styled/Button";
export default function DeleteConfirmModal({ id, closeModal }) {
const navigateTo = useNavigate();
@@ -18,10 +17,8 @@ export default function DeleteConfirmModal({ id, closeModal }) {
useEffect(() => {
if (isSuccess) {
toast.success("delete channel successfully!");
if (pathMatched) {
navigateTo("/chat");
}
closeModal();
navigateTo("/chat");
}
}, [isSuccess, id, pathMatched]);
if (!id) return null;
@@ -32,7 +29,6 @@ export default function DeleteConfirmModal({ id, closeModal }) {
description="Are you sure want to delete this channel?"
buttons={
<>
{" "}
<Button onClick={closeModal.bind(null, undefined)}>Cancel</Button>
<Button onClick={handleDelete} className="danger">
{isLoading ? "Deleting" : `Delete`}
@@ -4,12 +4,12 @@ import toast from "react-hot-toast";
import {
useGetChannelQuery,
useUpdateChannelMutation,
} from "../../../app/services/channel";
import Input from "../styled/Input";
import Label from "../styled/Label";
import Textarea from "../styled/Textarea";
import SaveTip from "../SaveTip";
import channelIcon from "../../../assets/icons/channel.svg?url";
} from "../../app/services/channel";
import Input from "../../common/component/styled/Input";
import Label from "../../common/component/styled/Label";
import Textarea from "../../common/component/styled/Textarea";
import SaveTip from "../../common/component/SaveTip";
import channelIcon from "../../assets/icons/channel.svg?url";
import { useSelector } from "react-redux";
const StyledWrapper = styled.div`
position: relative;
@@ -89,7 +89,7 @@ export default function Overview({ id = 0 }) {
if (!values || !id) return null;
const { name, description } = values;
const isAdmin = loginUser.is_admin;
const isAdmin = loginUser?.is_admin;
return (
<StyledWrapper>
<div className="inputs">
@@ -1,11 +1,12 @@
import { useState } from "react";
import { useDispatch } from "react-redux";
import { toggleChannelSetting } from "../../../app/slices/ui";
import StyledSettingContainer from "../StyledSettingContainer";
import { useParams, useNavigate } from "react-router-dom";
import StyledSettingContainer from "../../common/component/StyledSettingContainer";
import DeleteConfirmModal from "./DeleteConfirmModal";
import useNavs from "./navs";
export default function ChannelSetting({ id = 0 }) {
const navs = useNavs(id);
export default function ChannelSetting() {
const navigate = useNavigate();
const { cid } = useParams();
const navs = useNavs(cid);
const flatenNavs = navs
.map(({ items }) => {
return items;
@@ -13,9 +14,8 @@ export default function ChannelSetting({ id = 0 }) {
.flat();
const [currNav, setCurrNav] = useState(flatenNavs[0]);
const [deleteConfirm, setDeleteConfirm] = useState(false);
const dispatch = useDispatch();
const close = () => {
dispatch(toggleChannelSetting());
navigate(-1);
};
const toggleDeleteConfrim = () => {
setDeleteConfirm((prev) => !prev);
@@ -26,7 +26,7 @@ export default function ChannelSetting({ id = 0 }) {
setCurrNav(tmp);
}
};
if (!id) return null;
if (!cid) return null;
return (
<>
<StyledSettingContainer
@@ -45,7 +45,7 @@ export default function ChannelSetting({ id = 0 }) {
{currNav.component}
</StyledSettingContainer>
{deleteConfirm && (
<DeleteConfirmModal closeModal={toggleDeleteConfrim} id={id} />
<DeleteConfirmModal closeModal={toggleDeleteConfrim} id={cid} />
)}
</>
);
@@ -1,5 +1,5 @@
import Overview from "./Overview";
import ManageMembers from "../ManageMembers";
import ManageMembers from "../../common/component/ManageMembers";
const useNavs = (channelId) => {
const navs = [
{