реактивное удаление

This commit is contained in:
Nastya 2025-06-02 00:36:55 +03:00
parent e7121cb06a
commit 1e8a50077b
3 changed files with 61 additions and 17 deletions

@ -2,17 +2,16 @@ import { AuditoryItem } from "@/api/auditory";
import CopyIcon from "@/assets/icons/CopyIcon"; import CopyIcon from "@/assets/icons/CopyIcon";
import Trash from "@/assets/icons/trash"; import Trash from "@/assets/icons/trash";
import { InfoPopover } from "@/ui_kit/InfoPopover"; import { InfoPopover } from "@/ui_kit/InfoPopover";
import TooltipClickInfo from "@/ui_kit/Toolbars/TooltipClickInfo";
import { useDomainDefine } from "@/utils/hooks/useDomainDefine"; import { useDomainDefine } from "@/utils/hooks/useDomainDefine";
import { IconButton, ListItem, Typography, useTheme } from "@mui/material"; import { IconButton, ListItem, Typography, useTheme } from "@mui/material";
interface AuditoryLinkProps { interface AuditoryLinkProps {
item: AuditoryItem; item: AuditoryItem;
index: number; index: number;
deleteModal: (id:number) => void onDelete: (id: number) => void;
} }
export const AuditoryLink = ({ item, index, deleteModal }: AuditoryLinkProps) => { export const AuditoryLink = ({ item, index, onDelete }: AuditoryLinkProps) => {
const theme = useTheme(); const theme = useTheme();
const { isTestServer } = useDomainDefine(); const { isTestServer } = useDomainDefine();
@ -20,6 +19,10 @@ export const AuditoryLink = ({ item, index, deleteModal }: AuditoryLinkProps) =>
navigator.clipboard.writeText(text); navigator.clipboard.writeText(text);
}; };
const handleDelete = () => {
onDelete(item.id);
};
const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}?_paud=${item.id}`; const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}?_paud=${item.id}`;
return ( return (
@ -39,13 +42,18 @@ export const AuditoryLink = ({ item, index, deleteModal }: AuditoryLinkProps) =>
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
gap: '12px', gap: '12px',
width: "70px", width: "60px",
justifyContent: "space-between", justifyContent: "space-between",
}, },
}} }}
secondaryAction={ secondaryAction={
<> <>
<IconButton onClick={() => deleteModal(item.id)} edge="end" aria-label="info" sx={{ color: theme.palette.brightPurple.main, p: 0, width: 18, height: 18 }}> <IconButton
edge="end"
aria-label="delete"
sx={{ color: theme.palette.brightPurple.main, p: 0, width: 18, height: 18 }}
onClick={handleDelete}
>
<Trash sx={{ <Trash sx={{
"& path": { "& path": {
stroke: theme.palette.brightPurple.main, stroke: theme.palette.brightPurple.main,
@ -53,11 +61,11 @@ export const AuditoryLink = ({ item, index, deleteModal }: AuditoryLinkProps) =>
}} /> }} />
</IconButton> </IconButton>
<IconButton edge="end" aria-label="info" sx={{ color: theme.palette.brightPurple.main, p: 0, width: 18, height: 18 }}> <IconButton edge="end" aria-label="info" sx={{ color: theme.palette.brightPurple.main, p: 0, width: 18, height: 18 }}>
<TooltipClickInfo title={`Возраст: ${item.age}\n Пол: ${item.sex ? "мужской" : "женский"}`} /> <InfoPopover />
</IconButton> </IconButton>
<IconButton <IconButton
edge="end" edge="end"
aria-label="copy" aria-label="copy"
sx={{ color: theme.palette.brightPurple.main, p: 0, width: 18, height: 18, marginRight: "-2px" }} sx={{ color: theme.palette.brightPurple.main, p: 0, width: 18, height: 18, marginRight: "-2px" }}
onClick={() => handleCopy(linkText)} onClick={() => handleCopy(linkText)}
> >

@ -6,13 +6,11 @@ import { Box, Collapse, IconButton, List, Typography, useTheme } from "@mui/mate
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { AuditoryLink } from "./AuditoryLink"; import { AuditoryLink } from "./AuditoryLink";
export const AuditoryList = ({auditory, onDelete}:{auditory:AuditoryItem[], onDelete: (id: number) => void}) => {
export const AuditoryList = ({auditory, deleteModal}:{auditory:AuditoryItem[], deleteModal:(id:number) => void}) => {
const theme = useTheme(); const theme = useTheme();
const { isTestServer } = useDomainDefine(); const { isTestServer } = useDomainDefine();
const [linksOpen, setLinksOpen] = useState(true); const [linksOpen, setLinksOpen] = useState(true);
console.log("auditory-___---_auditory__---__-__auditory_------__---__-__---_------__---__-__---_------__---__-____--__") console.log("auditory-___---_auditory__---__-__auditory_------__---__-__---_------__---__-__---_------__---__-____--__")
console.log(auditory) console.log(auditory)
@ -41,7 +39,7 @@ export const AuditoryList = ({auditory, deleteModal}:{auditory:AuditoryItem[], d
<Collapse in={linksOpen} timeout="auto" unmountOnExit sx={{ mt: "3px" }}> <Collapse in={linksOpen} timeout="auto" unmountOnExit sx={{ mt: "3px" }}>
<List sx={{ gap: '8px', p: 0, m: 0 }}> <List sx={{ gap: '8px', p: 0, m: 0 }}>
{auditory.map((item, idx) => ( {auditory.map((item, idx) => (
<AuditoryLink deleteModal={deleteModal} key={idx} item={item} index={idx} /> <AuditoryLink key={idx} item={item} index={idx} onDelete={onDelete} />
))} ))}
</List> </List>
</Collapse> </Collapse>

@ -10,6 +10,7 @@ import { useTheme } from "@mui/material";
import { AuditoryItem, auditoryAdd, auditoryDelete, auditoryGet } from "@/api/auditory"; import { AuditoryItem, auditoryAdd, auditoryDelete, auditoryGet } from "@/api/auditory";
import { useCurrentQuiz } from "@/stores/quizes/hooks"; import { useCurrentQuiz } from "@/stores/quizes/hooks";
import { AuditoryList } from "./AuditoryList"; import { AuditoryList } from "./AuditoryList";
import { useSnackbar } from "notistack";
export default function PersonalizationAI() { export default function PersonalizationAI() {
@ -18,6 +19,7 @@ export default function PersonalizationAI() {
const [auditory, setAuditory] = useState<AuditoryItem[]>([]); const [auditory, setAuditory] = useState<AuditoryItem[]>([]);
const [deleteModal, setDeleteModal] = useState<number>(0); const [deleteModal, setDeleteModal] = useState<number>(0);
const quiz = useCurrentQuiz(); const quiz = useCurrentQuiz();
const { enqueueSnackbar } = useSnackbar();
useEffect(() => { useEffect(() => {
(async () => { (async () => {
@ -32,9 +34,45 @@ export default function PersonalizationAI() {
})(); })();
}, [quiz]); }, [quiz]);
const handleDelete = () => { const handleDelete = async () => {
setDeleteModal(0) // 1. Закрываем модалку
auditoryDelete({ quizId: quiz?.backendId, auditoryId: deleteModal }) setDeleteModal(0);
// 2. Находим индекс объекта в стейте
const indexToDelete = auditory.findIndex(item => item.id === deleteModal);
if (indexToDelete === -1) return;
// 3. Сохраняем удаляемый объект
const deletedItem = auditory[indexToDelete];
// 4. Меняем стейт, вырезая объект
setAuditory(prev => prev.filter(item => item.id !== deleteModal));
try {
// 5. Вызываем функцию удаления
const [result, error] = await auditoryDelete({
quizId: quiz?.backendId,
auditoryId: deleteModal
});
if (error) {
// 6. Если удалить не удалось - показываем снекбар и возвращаем ссылку
enqueueSnackbar('Не удалось удалить ссылку', { variant: 'error' });
setAuditory(prev => {
const newArray = [...prev];
newArray.splice(indexToDelete, 0, deletedItem);
return newArray;
});
}
} catch (error) {
// Обработка ошибки сети или других ошибок
enqueueSnackbar('Произошла ошибка при удалении', { variant: 'error' });
setAuditory(prev => {
const newArray = [...prev];
newArray.splice(indexToDelete, 0, deletedItem);
return newArray;
});
}
} }
return ( return (
@ -92,7 +130,7 @@ export default function PersonalizationAI() {
</Box> </Box>
</Box> </Box>
<AuditoryList deleteModal={setDeleteModal} auditory={auditory} /> <AuditoryList onDelete={setDeleteModal} auditory={auditory} />
</Container> </Container>
<Modal <Modal