group update
This commit is contained in:
@@ -7,6 +7,23 @@ interface ButtonProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
color?: "primary" | "secondary" | "error" | "warning" | "success";
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColorBgVariants = {
|
||||||
|
"primary": "bg-liquid-brightmain group-hover:ring-liquid-brightmain",
|
||||||
|
"secondary": "bg-liquid-darkmain group-hover:ring-liquid-darkmain",
|
||||||
|
"error": "bg-liquid-red group-hover:ring-liquid-red",
|
||||||
|
"warning": "bg-liquid-orange group-hover:ring-liquid-orange",
|
||||||
|
"success": "bg-liquid-green group-hover:ring-liquid-green",
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColorTextVariants = {
|
||||||
|
"primary": "group-hover:text-liquid-brightmain ",
|
||||||
|
"secondary": "group-hover:text-liquid-brightmain ",
|
||||||
|
"error": "group-hover:text-liquid-red ",
|
||||||
|
"warning": "group-hover:text-liquid-orange ",
|
||||||
|
"success": "group-hover:text-liquid-green ",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PrimaryButton: React.FC<ButtonProps> = ({
|
export const PrimaryButton: React.FC<ButtonProps> = ({
|
||||||
@@ -15,6 +32,7 @@ export const PrimaryButton: React.FC<ButtonProps> = ({
|
|||||||
className,
|
className,
|
||||||
onClick,
|
onClick,
|
||||||
children,
|
children,
|
||||||
|
color = "secondary",
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<label
|
<label
|
||||||
@@ -31,7 +49,7 @@ export const PrimaryButton: React.FC<ButtonProps> = ({
|
|||||||
"rounded-[10px]",
|
"rounded-[10px]",
|
||||||
"group-hover:bg-liquid-lighter group-hover:ring-[1px] group-hover:ring-liquid-darkmain group-hover:ring-inset",
|
"group-hover:bg-liquid-lighter group-hover:ring-[1px] group-hover:ring-liquid-darkmain group-hover:ring-inset",
|
||||||
"px-[16px] py-[8px]",
|
"px-[16px] py-[8px]",
|
||||||
"bg-liquid-darkmain",
|
ColorBgVariants[color],
|
||||||
disabled && "bg-liquid-lighter"
|
disabled && "bg-liquid-lighter"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -58,7 +76,7 @@ export const PrimaryButton: React.FC<ButtonProps> = ({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"transition-all duration-300 text-liquid-white text-[18px] font-bold p-0 m-0 leading-[23px]",
|
"transition-all duration-300 text-liquid-white text-[18px] font-bold p-0 m-0 leading-[23px]",
|
||||||
"group-hover:text-liquid-brightmain ",
|
ColorTextVariants[color],
|
||||||
disabled && "text-liquid-light"
|
disabled && "text-liquid-light"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export const Input: React.FC<inputProps> = ({
|
|||||||
React.useEffect(() => onChange(value), [value]);
|
React.useEffect(() => onChange(value), [value]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
"relative",
|
"relative",
|
||||||
@@ -51,6 +52,7 @@ export const Input: React.FC<inputProps> = ({
|
|||||||
"bg-liquid-lighter w-full rounded-[10px] outline-none pl-[16px] py-[8px] placeholder:text-liquid-light",
|
"bg-liquid-lighter w-full rounded-[10px] outline-none pl-[16px] py-[8px] placeholder:text-liquid-light",
|
||||||
type == "password" ? "h-[40px]" : "h-[36px]"
|
type == "password" ? "h-[40px]" : "h-[36px]"
|
||||||
)}
|
)}
|
||||||
|
value={value}
|
||||||
name={name}
|
name={name}
|
||||||
autoComplete={autocomplete}
|
autoComplete={autocomplete}
|
||||||
type={type == "password" ? (visible ? "text" : "password") : type}
|
type={type == "password" ? (visible ? "text" : "password") : type}
|
||||||
|
|||||||
@@ -20,12 +20,17 @@ interface IconComponentProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const IconComponent: React.FC<IconComponentProps> = ({
|
const IconComponent: React.FC<IconComponentProps> = ({
|
||||||
src, onClick = () => void
|
src,
|
||||||
|
onClick
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
return <img
|
return <img
|
||||||
src={src}
|
src={src}
|
||||||
onClick={() => onClick()}
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (onClick)
|
||||||
|
onClick();
|
||||||
|
}}
|
||||||
className="hover:bg-liquid-light rounded-[5px] cursor-pointer transition-all duration-300"
|
className="hover:bg-liquid-light rounded-[5px] cursor-pointer transition-all duration-300"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@@ -52,7 +57,8 @@ const GroupItem: React.FC<GroupItemProps> = ({
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
(role == "menager" || role == "owner") && <IconComponent src={Edit} onClick={() => {
|
(role == "menager" || role == "owner") && <IconComponent src={Edit} onClick={() => {
|
||||||
setUpdateGroup({id, });
|
|
||||||
|
setUpdateGroup({id, name, description });
|
||||||
setUpdateActive(true);
|
setUpdateActive(true);
|
||||||
}} />
|
}} />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ export interface GroupUpdate {
|
|||||||
const Groups = () => {
|
const Groups = () => {
|
||||||
const [modalActive, setModalActive] = useState<boolean>(false);
|
const [modalActive, setModalActive] = useState<boolean>(false);
|
||||||
const [modelUpdateActive, setModalUpdateActive] = useState<boolean>(false);
|
const [modelUpdateActive, setModalUpdateActive] = useState<boolean>(false);
|
||||||
const [updateGroup, setUpdateGroup] = useState<GroupUpdate>({id: 0, name: "", description: ""});
|
const [updateGroup, setUpdateGroup] = useState<GroupUpdate>({ id: 0, name: "", description: "" });
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
|
||||||
// Берём группы из стора
|
// Берём группы из стора
|
||||||
const groups = useAppSelector((store) => store.groups.groups);
|
const groups = useAppSelector((store) => store.groups.groups);
|
||||||
@@ -69,7 +69,7 @@ const Groups = () => {
|
|||||||
Группы
|
Группы
|
||||||
</div>
|
</div>
|
||||||
<SecondaryButton
|
<SecondaryButton
|
||||||
onClick={() => {setModalActive(true);}}
|
onClick={() => { setModalActive(true); }}
|
||||||
text="Создать группу"
|
text="Создать группу"
|
||||||
className="absolute right-0"
|
className="absolute right-0"
|
||||||
/>
|
/>
|
||||||
@@ -81,22 +81,35 @@ const Groups = () => {
|
|||||||
className="mb-[20px]"
|
className="mb-[20px]"
|
||||||
title="Управляемые"
|
title="Управляемые"
|
||||||
groups={managedGroups}
|
groups={managedGroups}
|
||||||
|
setUpdateActive={setModalUpdateActive}
|
||||||
|
setUpdateGroup={setUpdateGroup}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
<GroupsBlock
|
<GroupsBlock
|
||||||
className="mb-[20px]"
|
className="mb-[20px]"
|
||||||
title="Текущие"
|
title="Текущие"
|
||||||
groups={currentGroups}
|
groups={currentGroups}
|
||||||
|
setUpdateActive={setModalUpdateActive}
|
||||||
|
setUpdateGroup={setUpdateGroup}
|
||||||
/>
|
/>
|
||||||
<GroupsBlock
|
<GroupsBlock
|
||||||
className="mb-[20px]"
|
className="mb-[20px]"
|
||||||
title="Скрытые"
|
title="Скрытые"
|
||||||
groups={hiddenGroups} // пока пусто
|
groups={hiddenGroups} // пока пусто
|
||||||
|
setUpdateActive={setModalUpdateActive}
|
||||||
|
setUpdateGroup={setUpdateGroup}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<ModalCreate setActive={setModalActive} active={modalActive} />
|
<ModalCreate setActive={setModalActive} active={modalActive} />
|
||||||
<ModalUpdate setActive={setModalUpdateActive} active={modelUpdateActive} groupId={updateGroup.id} groupName={updateGroup.name}/>
|
<ModalUpdate
|
||||||
|
setActive={setModalUpdateActive}
|
||||||
|
active={modelUpdateActive}
|
||||||
|
groupId={updateGroup.id}
|
||||||
|
groupName={updateGroup.name}
|
||||||
|
groupDescription={updateGroup.description}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,15 +3,18 @@ import GroupItem from "./GroupItem";
|
|||||||
import { cn } from "../../../lib/cn";
|
import { cn } from "../../../lib/cn";
|
||||||
import { ChevroneDown } from "../../../assets/icons/groups";
|
import { ChevroneDown } from "../../../assets/icons/groups";
|
||||||
import { Group } from "../../../redux/slices/groups";
|
import { Group } from "../../../redux/slices/groups";
|
||||||
|
import { GroupUpdate } from "./Groups";
|
||||||
|
|
||||||
interface GroupsBlockProps {
|
interface GroupsBlockProps {
|
||||||
groups: Group[];
|
groups: Group[];
|
||||||
title: string;
|
title: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
setUpdateActive: (value: any) => void;
|
||||||
|
setUpdateGroup: (value: GroupUpdate) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const GroupsBlock: FC<GroupsBlockProps> = ({ groups, title, className }) => {
|
const GroupsBlock: FC<GroupsBlockProps> = ({ groups, title, className, setUpdateActive, setUpdateGroup }) => {
|
||||||
|
|
||||||
|
|
||||||
const [active, setActive] = useState<boolean>(title != "Скрытые");
|
const [active, setActive] = useState<boolean>(title != "Скрытые");
|
||||||
@@ -40,7 +43,15 @@ const GroupsBlock: FC<GroupsBlockProps> = ({ groups, title, className }) => {
|
|||||||
|
|
||||||
<div className="grid grid-cols-3 gap-[20px] pt-[20px] pb-[20px] box-border">
|
<div className="grid grid-cols-3 gap-[20px] pt-[20px] pb-[20px] box-border">
|
||||||
{
|
{
|
||||||
groups.map((v, i) => <GroupItem key={i} id={v.id} visible={true} role={"owner"} name={v.name}/>)
|
groups.map((v, i) => <GroupItem
|
||||||
|
key={i}
|
||||||
|
id={v.id}
|
||||||
|
visible={true}
|
||||||
|
description={v.description}
|
||||||
|
setUpdateActive={setUpdateActive}
|
||||||
|
setUpdateGroup={setUpdateGroup}
|
||||||
|
role={"owner"}
|
||||||
|
name={v.name}/>)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,36 +4,45 @@ import { PrimaryButton } from "../../../components/button/PrimaryButton";
|
|||||||
import { SecondaryButton } from "../../../components/button/SecondaryButton";
|
import { SecondaryButton } from "../../../components/button/SecondaryButton";
|
||||||
import { Input } from "../../../components/input/Input";
|
import { Input } from "../../../components/input/Input";
|
||||||
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
|
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
|
||||||
import { createGroup } from "../../../redux/slices/groups";
|
import { createGroup, deleteGroup, updateGroup } from "../../../redux/slices/groups";
|
||||||
|
|
||||||
interface ModalUpdateProps {
|
interface ModalUpdateProps {
|
||||||
active: boolean;
|
active: boolean;
|
||||||
setActive: (value: boolean) => void;
|
setActive: (value: boolean) => void;
|
||||||
groupId: number;
|
groupId: number;
|
||||||
groupName: string;
|
groupName: string;
|
||||||
|
groupDescription: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalUpdate: FC<ModalUpdateProps> = ({ active, setActive, groupName, groupId }) => {
|
const ModalUpdate: FC<ModalUpdateProps> = ({ active, setActive, groupName, groupId, groupDescription }) => {
|
||||||
const [name, setName] = useState<string>("");
|
const [name, setName] = useState<string>("");
|
||||||
const [description, setDescription] = useState<string>("");
|
const [description, setDescription] = useState<string>("");
|
||||||
const status = useAppSelector((state) => state.groups.statuses.create);
|
const statusUpdate = useAppSelector((state) => state.groups.statuses.update);
|
||||||
|
const statusDelete = useAppSelector((state) => state.groups.statuses.delete);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status == "successful"){
|
if (statusUpdate == "successful"){
|
||||||
setActive(false);
|
setActive(false);
|
||||||
}
|
}
|
||||||
}, [status]);
|
}, [statusUpdate]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (statusDelete == "successful"){
|
||||||
|
setActive(false);
|
||||||
|
}
|
||||||
|
}, [statusDelete]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal className="bg-liquid-background border-liquid-lighter border-[2px] p-[25px] rounded-[20px] text-liquid-white" onOpenChange={setActive} open={active} backdrop="blur" >
|
<Modal className="bg-liquid-background border-liquid-lighter border-[2px] p-[25px] rounded-[20px] text-liquid-white" onOpenChange={setActive} open={active} backdrop="blur" >
|
||||||
<div className="w-[500px]">
|
<div className="w-[500px]">
|
||||||
<div className="font-bold text-[30px]">Изменить группу {groupName} #{groupId}</div>
|
<div className="font-bold text-[30px]">Изменить группу {groupName} #{groupId}</div>
|
||||||
<Input name="name" autocomplete="name" className="mt-[10px]" type="text" label="Новое название" defaultState={groupName} onChange={(v) => { setName(v)}} placeholder="login" />
|
<Input name="name" autocomplete="name" className="mt-[10px]" type="text" label="Новое название" defaultState={groupName} onChange={(v) => { setName(v)}} placeholder="login"/>
|
||||||
<Input name="description" autocomplete="description" className="mt-[10px]" type="text" label="Описание" onChange={(v) => { setDescription(v)}} placeholder="login" />
|
<Input name="description" autocomplete="description" className="mt-[10px]" type="text" label="Описание" onChange={(v) => { setDescription(v)}} placeholder="login" defaultState={groupDescription}/>
|
||||||
|
|
||||||
<div className="flex flex-row w-full items-center justify-end mt-[20px] gap-[20px]">
|
<div className="flex flex-row w-full items-center justify-end mt-[20px] gap-[20px]">
|
||||||
<PrimaryButton onClick={() => {dispatch(createGroup({name, description}))}} text="Обновить" disabled={status=="loading"}/>
|
<PrimaryButton onClick={() => {dispatch(deleteGroup(groupId))}} text="Удалить" disabled={statusDelete=="loading"} color="error"/>
|
||||||
|
<PrimaryButton onClick={() => {dispatch(updateGroup({name, description, groupId}))}} text="Обновить" disabled={statusUpdate=="loading"}/>
|
||||||
<SecondaryButton onClick={() => {setActive(false);}} text="Отмена" />
|
<SecondaryButton onClick={() => {setActive(false);}} text="Отмена" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user