refactor: setting modals to pages
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
// import React from "react";
|
||||
import { useEffect } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useNavigate, useMatch } from "react-router-dom";
|
||||
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();
|
||||
const pathMatched = useMatch(`/chat/channel/${id}`);
|
||||
const [deleteChannel, { isLoading, isSuccess }] = useLazyRemoveChannelQuery();
|
||||
const handleDelete = () => {
|
||||
deleteChannel(id);
|
||||
};
|
||||
useEffect(() => {
|
||||
if (isSuccess) {
|
||||
toast.success("delete channel successfully!");
|
||||
closeModal();
|
||||
navigateTo("/chat");
|
||||
}
|
||||
}, [isSuccess, id, pathMatched]);
|
||||
if (!id) return null;
|
||||
return (
|
||||
<Modal id="modal-modal">
|
||||
<StyledModal
|
||||
title="Delete Channel"
|
||||
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`}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
// className="animate__animated animate__fadeInDown animate__faster"
|
||||
></StyledModal>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import styled from "styled-components";
|
||||
import toast from "react-hot-toast";
|
||||
import {
|
||||
useGetChannelQuery,
|
||||
useUpdateChannelMutation,
|
||||
} 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;
|
||||
width: 512px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
.inputs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 24px;
|
||||
.input {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
.name {
|
||||
padding-left: 36px;
|
||||
background-image: url(${channelIcon});
|
||||
background-size: 20px;
|
||||
background-position-x: 8px;
|
||||
background-position-y: 8px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export default function Overview({ id = 0 }) {
|
||||
const loginUser = useSelector(
|
||||
(store) => store.contacts.byId[store.authData.uid]
|
||||
);
|
||||
const { data, refetch } = useGetChannelQuery(id);
|
||||
const [changed, setChanged] = useState(false);
|
||||
const [values, setValues] = useState(null);
|
||||
const [updateChannel, { isSuccess: updated }] = useUpdateChannelMutation();
|
||||
const handleUpdate = () => {
|
||||
const { name, description } = values;
|
||||
updateChannel({ id, name, description });
|
||||
};
|
||||
const handleChange = (evt) => {
|
||||
const newValue = evt.target.value;
|
||||
const { type } = evt.target.dataset;
|
||||
setValues((prev) => {
|
||||
return { ...prev, [type]: newValue };
|
||||
});
|
||||
};
|
||||
const handleReset = () => {
|
||||
console.log("reset", data);
|
||||
setValues(data);
|
||||
};
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
setValues(data);
|
||||
}
|
||||
}, [data]);
|
||||
useEffect(() => {
|
||||
if (data && values) {
|
||||
const { name, description } = values;
|
||||
const { name: oName, description: oDescription } = data;
|
||||
if (oName !== name || oDescription !== description) {
|
||||
setChanged(true);
|
||||
} else {
|
||||
setChanged(false);
|
||||
}
|
||||
}
|
||||
}, [data, values]);
|
||||
|
||||
useEffect(() => {
|
||||
if (updated) {
|
||||
toast.success("Channel updated!");
|
||||
refetch();
|
||||
}
|
||||
}, [updated]);
|
||||
|
||||
if (!values || !id) return null;
|
||||
const { name, description } = values;
|
||||
const isAdmin = loginUser?.is_admin;
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<div className="inputs">
|
||||
<div className="input">
|
||||
<Label htmlFor="name">Channel Name</Label>
|
||||
<Input
|
||||
disabled={!isAdmin}
|
||||
className="name"
|
||||
data-type="name"
|
||||
onChange={handleChange}
|
||||
value={name}
|
||||
name="name"
|
||||
id="name"
|
||||
placeholder="Channel Name"
|
||||
/>
|
||||
</div>
|
||||
<div className="input">
|
||||
<Label htmlFor="desc">Channel Topic</Label>
|
||||
<Textarea
|
||||
disabled={!isAdmin}
|
||||
data-type="description"
|
||||
onChange={handleChange}
|
||||
value={description ?? ""}
|
||||
rows={4}
|
||||
name="name"
|
||||
id="name"
|
||||
placeholder="Let everyone know how to use this channel."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{changed && (
|
||||
<SaveTip saveHandler={handleUpdate} resetHandler={handleReset} />
|
||||
)}
|
||||
{/* <button onClick={handleUpdate} className="btn">update</button> */}
|
||||
</StyledWrapper>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { useState } from "react";
|
||||
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() {
|
||||
const navigate = useNavigate();
|
||||
const { cid } = useParams();
|
||||
const navs = useNavs(cid);
|
||||
const flatenNavs = navs
|
||||
.map(({ items }) => {
|
||||
return items;
|
||||
})
|
||||
.flat();
|
||||
const [currNav, setCurrNav] = useState(flatenNavs[0]);
|
||||
const [deleteConfirm, setDeleteConfirm] = useState(false);
|
||||
const close = () => {
|
||||
navigate(-1);
|
||||
};
|
||||
const toggleDeleteConfrim = () => {
|
||||
setDeleteConfirm((prev) => !prev);
|
||||
};
|
||||
const updateNav = (name) => {
|
||||
const tmp = flatenNavs.find((n) => n.name == name);
|
||||
if (tmp) {
|
||||
setCurrNav(tmp);
|
||||
}
|
||||
};
|
||||
if (!cid) return null;
|
||||
return (
|
||||
<>
|
||||
<StyledSettingContainer
|
||||
updateNav={updateNav}
|
||||
nav={currNav}
|
||||
closeModal={close}
|
||||
title="Channel Setting"
|
||||
navs={navs}
|
||||
dangers={[
|
||||
{
|
||||
title: "Delete Channel",
|
||||
handler: toggleDeleteConfrim,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{currNav.component}
|
||||
</StyledSettingContainer>
|
||||
{deleteConfirm && (
|
||||
<DeleteConfirmModal closeModal={toggleDeleteConfrim} id={cid} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import Overview from "./Overview";
|
||||
import ManageMembers from "../../common/component/ManageMembers";
|
||||
const useNavs = (channelId) => {
|
||||
const navs = [
|
||||
{
|
||||
title: "General",
|
||||
items: [
|
||||
{
|
||||
name: "overview",
|
||||
title: "Overview",
|
||||
component: <Overview id={channelId} />,
|
||||
},
|
||||
{
|
||||
name: "members",
|
||||
title: "Members",
|
||||
component: <ManageMembers cid={channelId} />,
|
||||
},
|
||||
// {
|
||||
// name: "permissions",
|
||||
// title: "Permissions",
|
||||
// },
|
||||
// {
|
||||
// name: "invites",
|
||||
// title: "Invites",
|
||||
// },
|
||||
// {
|
||||
// name: "integrations",
|
||||
// title: "Integrations",
|
||||
// },
|
||||
],
|
||||
},
|
||||
// {
|
||||
// title: "User Management",
|
||||
// items: [
|
||||
|
||||
// ],
|
||||
// },
|
||||
];
|
||||
return navs;
|
||||
};
|
||||
|
||||
export default useNavs;
|
||||
Reference in New Issue
Block a user