удаление без реактивности, выведен корректный список линков
This commit is contained in:
parent
c2d79c04cc
commit
e7121cb06a
@ -47,13 +47,13 @@ export interface AuditoryAddParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// API calls
|
// API calls
|
||||||
export const auditoryGet = async ({ quizId }: AuditoryGetParams): Promise<[AuditoryResponse | null, string?]> => {
|
export const auditoryGet = async ({ quizId }: AuditoryGetParams): Promise<[AuditoryItem[] | null, string?]> => {
|
||||||
if (!quizId) {
|
if (!quizId) {
|
||||||
return [null, "Quiz ID is required"];
|
return [null, "Quiz ID is required"];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await makeRequest<AuditoryGetRequest, AuditoryResponse>({
|
const response = await makeRequest<AuditoryGetRequest, AuditoryItem[]>({
|
||||||
url: `${API_URL}/quiz/${quizId}/auditory`,
|
url: `${API_URL}/quiz/${quizId}/auditory`,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
});
|
});
|
||||||
@ -72,10 +72,7 @@ export const auditoryDelete = async ({ quizId, auditoryId }: AuditoryDeleteParam
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await makeRequest<AuditoryDeleteRequest, AuditoryResponse>({
|
const response = await makeRequest<AuditoryDeleteRequest, AuditoryResponse>({
|
||||||
url: `${API_URL}/quiz/${quizId}/auditory`,
|
url: `${API_URL}/quiz/${quizId}/auditory/${auditoryId}`,
|
||||||
body: {
|
|
||||||
id: auditoryId
|
|
||||||
},
|
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
74
src/pages/PersonalizationAI/AuditoryLink.tsx
Normal file
74
src/pages/PersonalizationAI/AuditoryLink.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { AuditoryItem } from "@/api/auditory";
|
||||||
|
import CopyIcon from "@/assets/icons/CopyIcon";
|
||||||
|
import Trash from "@/assets/icons/trash";
|
||||||
|
import { InfoPopover } from "@/ui_kit/InfoPopover";
|
||||||
|
import TooltipClickInfo from "@/ui_kit/Toolbars/TooltipClickInfo";
|
||||||
|
import { useDomainDefine } from "@/utils/hooks/useDomainDefine";
|
||||||
|
import { IconButton, ListItem, Typography, useTheme } from "@mui/material";
|
||||||
|
|
||||||
|
interface AuditoryLinkProps {
|
||||||
|
item: AuditoryItem;
|
||||||
|
index: number;
|
||||||
|
deleteModal: (id:number) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AuditoryLink = ({ item, index, deleteModal }: AuditoryLinkProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const { isTestServer } = useDomainDefine();
|
||||||
|
|
||||||
|
const handleCopy = (text: string) => {
|
||||||
|
navigator.clipboard.writeText(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}?_paud=${item.id}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListItem
|
||||||
|
key={index}
|
||||||
|
disablePadding
|
||||||
|
sx={{
|
||||||
|
bgcolor: "#F2F3F7",
|
||||||
|
borderRadius: "10px",
|
||||||
|
p: "13px 14px 13px 20px",
|
||||||
|
mb: "8px",
|
||||||
|
maxWidth: "756px",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
transition: 'background 0.2s, border 0.2s',
|
||||||
|
'& .MuiListItemSecondaryAction-root': {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '12px',
|
||||||
|
width: "70px",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
secondaryAction={
|
||||||
|
<>
|
||||||
|
<IconButton onClick={() => deleteModal(item.id)} edge="end" aria-label="info" sx={{ color: theme.palette.brightPurple.main, p: 0, width: 18, height: 18 }}>
|
||||||
|
<Trash sx={{
|
||||||
|
"& path": {
|
||||||
|
stroke: theme.palette.brightPurple.main,
|
||||||
|
}
|
||||||
|
}} />
|
||||||
|
</IconButton>
|
||||||
|
<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 ? "мужской" : "женский"}`} />
|
||||||
|
</IconButton>
|
||||||
|
<IconButton
|
||||||
|
edge="end"
|
||||||
|
aria-label="copy"
|
||||||
|
sx={{ color: theme.palette.brightPurple.main, p: 0, width: 18, height: 18, marginRight: "-2px" }}
|
||||||
|
onClick={() => handleCopy(linkText)}
|
||||||
|
>
|
||||||
|
<CopyIcon color={theme.palette.brightPurple.main} />
|
||||||
|
</IconButton>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Typography sx={{ color: 'black', fontWeight: 400, fontSize: "16px" }}>
|
||||||
|
{linkText}
|
||||||
|
</Typography>
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
};
|
@ -1,37 +1,17 @@
|
|||||||
import { auditoryGet, AuditoryResponse, AuditoryItem } from "@/api/auditory";
|
import { auditoryGet, AuditoryResponse, AuditoryItem } from "@/api/auditory";
|
||||||
import ArrowDownIcon from "@/assets/icons/ArrowDownIcon";
|
import ArrowDownIcon from "@/assets/icons/ArrowDownIcon";
|
||||||
import CopyIcon from "@/assets/icons/CopyIcon";
|
|
||||||
import { useCurrentQuiz } from "@/stores/quizes/hooks";
|
import { useCurrentQuiz } from "@/stores/quizes/hooks";
|
||||||
import { InfoPopover } from "@/ui_kit/InfoPopover";
|
|
||||||
import { useDomainDefine } from "@/utils/hooks/useDomainDefine";
|
import { useDomainDefine } from "@/utils/hooks/useDomainDefine";
|
||||||
import { Box, Collapse, IconButton, List, ListItem, Typography, useTheme } from "@mui/material";
|
import { Box, Collapse, IconButton, List, Typography, useTheme } from "@mui/material";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { AuditoryLink } from "./AuditoryLink";
|
||||||
|
|
||||||
const PURPLE = "#7E2AEA";
|
|
||||||
|
|
||||||
export const AuditoryList = () => {
|
export const AuditoryList = ({auditory, deleteModal}:{auditory:AuditoryItem[], deleteModal:(id:number) => void}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const quiz = useCurrentQuiz();
|
|
||||||
const { isTestServer } = useDomainDefine();
|
const { isTestServer } = useDomainDefine();
|
||||||
const [linksOpen, setLinksOpen] = useState(true);
|
const [linksOpen, setLinksOpen] = useState(true);
|
||||||
const [auditory, setAuditory] = useState<AuditoryItem[]>([]);
|
|
||||||
|
|
||||||
const handleCopy = (text: string) => {
|
|
||||||
navigator.clipboard.writeText(text);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
if (quiz?.backendId) {
|
|
||||||
const [result, error] = await auditoryGet({ quizId: quiz.backendId });
|
|
||||||
console.log("result-___---_------__---__-__---_------__---__-__---_------__---__-__---_------__---__-____--__")
|
|
||||||
console.log(result)
|
|
||||||
if (result) {
|
|
||||||
setAuditory(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}, [quiz]);
|
|
||||||
|
|
||||||
console.log("auditory-___---_auditory__---__-__auditory_------__---__-__---_------__---__-__---_------__---__-____--__")
|
console.log("auditory-___---_auditory__---__-__auditory_------__---__-__---_------__---__-__---_------__---__-____--__")
|
||||||
console.log(auditory)
|
console.log(auditory)
|
||||||
@ -51,7 +31,7 @@ export const AuditoryList = () => {
|
|||||||
Ваши сохраненные ссылки
|
Ваши сохраненные ссылки
|
||||||
</Typography>
|
</Typography>
|
||||||
<IconButton
|
<IconButton
|
||||||
sx={{ cursor: 'pointer', color: PURPLE, display: 'flex', alignItems: 'center', transition: 'transform 0.2s', transform: linksOpen ? 'rotate(0deg)' : 'rotate(180deg)' }}
|
sx={{ cursor: 'pointer', color: theme.palette.brightPurple.main, display: 'flex', alignItems: 'center', transition: 'transform 0.2s', transform: linksOpen ? 'rotate(0deg)' : 'rotate(180deg)' }}
|
||||||
onClick={() => setLinksOpen((prev) => !prev)}
|
onClick={() => setLinksOpen((prev) => !prev)}
|
||||||
size="large"
|
size="large"
|
||||||
>
|
>
|
||||||
@ -60,52 +40,9 @@ export const AuditoryList = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
<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) => (
|
||||||
const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}?_paud=${item.id}`;
|
<AuditoryLink deleteModal={deleteModal} key={idx} item={item} index={idx} />
|
||||||
console.log(item)
|
))}
|
||||||
return (
|
|
||||||
<ListItem
|
|
||||||
key={idx}
|
|
||||||
disablePadding
|
|
||||||
sx={{
|
|
||||||
bgcolor: "#F2F3F7",
|
|
||||||
borderRadius: "10px",
|
|
||||||
p: "13px 14px 13px 20px",
|
|
||||||
mb: "8px",
|
|
||||||
maxWidth: "756px",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
transition: 'background 0.2s, border 0.2s',
|
|
||||||
'& .MuiListItemSecondaryAction-root': {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '12px',
|
|
||||||
width: "60px",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
secondaryAction={
|
|
||||||
<>
|
|
||||||
<IconButton edge="end" aria-label="info" sx={{ color: PURPLE, p: 0, width: 18, height: 18 }}>
|
|
||||||
<InfoPopover />
|
|
||||||
</IconButton>
|
|
||||||
<IconButton
|
|
||||||
edge="end"
|
|
||||||
aria-label="copy"
|
|
||||||
sx={{ color: PURPLE, p: 0, width: 18, height: 18, marginRight: "-2px" }}
|
|
||||||
onClick={() => handleCopy(linkText)}
|
|
||||||
>
|
|
||||||
<CopyIcon color={PURPLE} />
|
|
||||||
</IconButton>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Typography sx={{ color: 'black', fontWeight: 400, fontSize: "16px" }}>
|
|
||||||
{linkText}
|
|
||||||
</Typography>
|
|
||||||
</ListItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</List>
|
</List>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Box, FormControl, FormLabel, RadioGroup, FormControlLabel, Radio, Select, MenuItem, useTheme } from "@mui/material";
|
import { Box, FormControl, FormLabel, RadioGroup, FormControlLabel, Radio, Select, MenuItem, useTheme, Button } from "@mui/material";
|
||||||
import { InfoPopover } from '@ui_kit/InfoPopover';
|
import { InfoPopover } from '@ui_kit/InfoPopover';
|
||||||
import CheckboxIcon from "@icons/Checkbox";
|
import CheckboxIcon from "@icons/Checkbox";
|
||||||
|
|
||||||
@ -7,6 +7,7 @@ interface GenderAndAgeSelectorProps {
|
|||||||
setGender: (gender: string) => void;
|
setGender: (gender: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default function GenderAndAgeSelector({ gender, setGender }: GenderAndAgeSelectorProps) {
|
export default function GenderAndAgeSelector({ gender, setGender }: GenderAndAgeSelectorProps) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
@ -167,6 +168,21 @@ export default function GenderAndAgeSelector({ gender, setGender }: GenderAndAge
|
|||||||
|
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
bgcolor: theme.palette.brightPurple.main,
|
||||||
|
borderRadius: "8px",
|
||||||
|
width: "130px",
|
||||||
|
height: "48px",
|
||||||
|
boxShadow: "none",
|
||||||
|
textTransform: "none",
|
||||||
|
fontSize: "18px",
|
||||||
|
'&:hover': { bgcolor: theme.palette.brightPurple.main },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Ок
|
||||||
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { Box, Container, Typography, TextField, Button, List, ListItem, IconButton } from "@mui/material";
|
import { Box, Container, Typography, TextField, Button, List, ListItem, IconButton, Modal } from "@mui/material";
|
||||||
import { InfoPopover } from '@ui_kit/InfoPopover';
|
import { InfoPopover } from '@ui_kit/InfoPopover';
|
||||||
import CopyIcon from "@/assets/icons/CopyIcon";
|
import CopyIcon from "@/assets/icons/CopyIcon";
|
||||||
import GenderAndAgeSelector from "./GenderAndAgeSelector";
|
import GenderAndAgeSelector from "./GenderAndAgeSelector";
|
||||||
@ -7,17 +7,38 @@ import CustomTextField from "@ui_kit/CustomTextField";
|
|||||||
import Collapse from '@mui/material/Collapse';
|
import Collapse from '@mui/material/Collapse';
|
||||||
import { ArrowDownIcon } from "../../assets/icons/questionsPage/ArrowDownIcon";
|
import { ArrowDownIcon } from "../../assets/icons/questionsPage/ArrowDownIcon";
|
||||||
import { useTheme } from "@mui/material";
|
import { useTheme } from "@mui/material";
|
||||||
import { auditoryAdd, 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";
|
||||||
|
|
||||||
const PURPLE = "#7E2AEA";
|
|
||||||
|
|
||||||
export default function PersonalizationAI() {
|
export default function PersonalizationAI() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [gender, setGender] = useState('');
|
const [gender, setGender] = useState('');
|
||||||
|
const [auditory, setAuditory] = useState<AuditoryItem[]>([]);
|
||||||
|
const [deleteModal, setDeleteModal] = useState<number>(0);
|
||||||
|
const quiz = useCurrentQuiz();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
if (quiz?.backendId) {
|
||||||
|
const [result, error] = await auditoryGet({ quizId: quiz.backendId });
|
||||||
|
console.log("result-___---_------__---__-__---_------__---__-__---_------__---__-__---_------__---__-____--__")
|
||||||
|
console.log(result)
|
||||||
|
if (result) {
|
||||||
|
setAuditory(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, [quiz]);
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
setDeleteModal(0)
|
||||||
|
auditoryDelete({ quizId: quiz?.backendId, auditoryId: deleteModal })
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<Container id="PersonalizationAI" maxWidth={false} sx={{ minHeight: "100%", p: "20px" }}>
|
<Container id="PersonalizationAI" maxWidth={false} sx={{ minHeight: "100%", p: "20px" }}>
|
||||||
<Typography variant="h5" color={theme.palette.grey3.main} fontWeight={700} sx={{ fontSize: 24, letterSpacing: "-0.2px" }}>
|
<Typography variant="h5" color={theme.palette.grey3.main} fontWeight={700} sx={{ fontSize: 24, letterSpacing: "-0.2px" }}>
|
||||||
Персонализация вопросов с помощью AI
|
Персонализация вопросов с помощью AI
|
||||||
@ -60,7 +81,6 @@ export default function PersonalizationAI() {
|
|||||||
>
|
>
|
||||||
Вставьте ссылку со всеми utm-метками
|
Вставьте ссылку со всеми utm-метками
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box sx={{ display: 'flex', gap: 2, alignItems: 'center', mt: "6px" }}>
|
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
placeholder="linkexample.com"
|
placeholder="linkexample.com"
|
||||||
maxLength={5}
|
maxLength={5}
|
||||||
@ -69,27 +89,41 @@ export default function PersonalizationAI() {
|
|||||||
}}
|
}}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
sx={{
|
|
||||||
bgcolor: PURPLE,
|
|
||||||
borderRadius: "8px",
|
|
||||||
width: "130px",
|
|
||||||
height: "48px",
|
|
||||||
boxShadow: "none",
|
|
||||||
textTransform: "none",
|
|
||||||
fontSize: "18px",
|
|
||||||
'&:hover': { bgcolor: PURPLE },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Ок
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<AuditoryList />
|
<AuditoryList deleteModal={setDeleteModal} auditory={auditory} />
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
|
<Modal
|
||||||
|
open={Boolean(deleteModal)}
|
||||||
|
onClose={() => setDeleteModal(0)}
|
||||||
|
aria-labelledby="modal-modal-title"
|
||||||
|
aria-describedby="modal-modal-description"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute" as "absolute",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
maxWidth: "620px",
|
||||||
|
width: "100%",
|
||||||
|
bgcolor: "background.paper",
|
||||||
|
borderRadius: "12px",
|
||||||
|
|
||||||
|
boxShadow: 24,
|
||||||
|
p: "20px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ width: "100%" ,textAlign: "center", mb: "25px"}}>Уверены, что хотите удалить ссылку?</Typography>
|
||||||
|
<Button sx={{mb: "20px"}} onClick={handleDelete}>Удалить</Button>
|
||||||
|
<Button variant="contained" onClick={() => setDeleteModal(0)} >Отмена</Button>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
import { useState, MouseEvent } from "react";
|
import { useState, MouseEvent, ReactNode } from "react";
|
||||||
import Info from "@icons/Info";
|
import Info from "@icons/Info";
|
||||||
|
|
||||||
import { Paper, Popover, SxProps, Typography } from "@mui/material";
|
import { Paper, Popover, SxProps, Typography } from "@mui/material";
|
||||||
|
|
||||||
export const InfoPopover = ({ blink = false, sx }: {blink?: boolean, sx?: SxProps}) => {
|
export const InfoPopover = ({
|
||||||
|
blink = false,
|
||||||
|
sx,
|
||||||
|
children = "подсказка"
|
||||||
|
}: {
|
||||||
|
blink?: boolean,
|
||||||
|
sx?: SxProps,
|
||||||
|
children?: ReactNode
|
||||||
|
}) => {
|
||||||
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
||||||
|
|
||||||
const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
|
const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
|
||||||
@ -43,9 +51,7 @@ export const InfoPopover = ({ blink = false, sx }: {blink?: boolean, sx?: SxProp
|
|||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography>
|
{children}
|
||||||
подсказка
|
|
||||||
</Typography>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
</Popover>
|
</Popover>
|
||||||
</>
|
</>
|
||||||
|
@ -26,6 +26,10 @@ export default function TooltipClickInfo({ title }: { title: string }) {
|
|||||||
disableFocusListener
|
disableFocusListener
|
||||||
disableHoverListener
|
disableHoverListener
|
||||||
disableTouchListener
|
disableTouchListener
|
||||||
|
sx={{
|
||||||
|
fontSize: "12px",
|
||||||
|
p:"10px"
|
||||||
|
}}
|
||||||
title={title}
|
title={title}
|
||||||
>
|
>
|
||||||
<IconButton onClick={handleTooltipOpen}>
|
<IconButton onClick={handleTooltipOpen}>
|
||||||
|
Loading…
Reference in New Issue
Block a user