удаление без реактивности, выведен корректный список линков
This commit is contained in:
parent
c2d79c04cc
commit
e7121cb06a
@ -47,13 +47,13 @@ export interface AuditoryAddParams {
|
||||
}
|
||||
|
||||
// API calls
|
||||
export const auditoryGet = async ({ quizId }: AuditoryGetParams): Promise<[AuditoryResponse | null, string?]> => {
|
||||
export const auditoryGet = async ({ quizId }: AuditoryGetParams): Promise<[AuditoryItem[] | null, string?]> => {
|
||||
if (!quizId) {
|
||||
return [null, "Quiz ID is required"];
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await makeRequest<AuditoryGetRequest, AuditoryResponse>({
|
||||
const response = await makeRequest<AuditoryGetRequest, AuditoryItem[]>({
|
||||
url: `${API_URL}/quiz/${quizId}/auditory`,
|
||||
method: "GET",
|
||||
});
|
||||
@ -72,10 +72,7 @@ export const auditoryDelete = async ({ quizId, auditoryId }: AuditoryDeleteParam
|
||||
|
||||
try {
|
||||
const response = await makeRequest<AuditoryDeleteRequest, AuditoryResponse>({
|
||||
url: `${API_URL}/quiz/${quizId}/auditory`,
|
||||
body: {
|
||||
id: auditoryId
|
||||
},
|
||||
url: `${API_URL}/quiz/${quizId}/auditory/${auditoryId}`,
|
||||
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 ArrowDownIcon from "@/assets/icons/ArrowDownIcon";
|
||||
import CopyIcon from "@/assets/icons/CopyIcon";
|
||||
import { useCurrentQuiz } from "@/stores/quizes/hooks";
|
||||
import { InfoPopover } from "@/ui_kit/InfoPopover";
|
||||
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 { AuditoryLink } from "./AuditoryLink";
|
||||
|
||||
const PURPLE = "#7E2AEA";
|
||||
|
||||
export const AuditoryList = () => {
|
||||
export const AuditoryList = ({auditory, deleteModal}:{auditory:AuditoryItem[], deleteModal:(id:number) => void}) => {
|
||||
const theme = useTheme();
|
||||
const quiz = useCurrentQuiz();
|
||||
const { isTestServer } = useDomainDefine();
|
||||
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)
|
||||
@ -51,7 +31,7 @@ export const AuditoryList = () => {
|
||||
Ваши сохраненные ссылки
|
||||
</Typography>
|
||||
<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)}
|
||||
size="large"
|
||||
>
|
||||
@ -60,52 +40,9 @@ export const AuditoryList = () => {
|
||||
</Box>
|
||||
<Collapse in={linksOpen} timeout="auto" unmountOnExit sx={{ mt: "3px" }}>
|
||||
<List sx={{ gap: '8px', p: 0, m: 0 }}>
|
||||
{auditory.map((item, idx) => {
|
||||
const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}?_paud=${item.id}`;
|
||||
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>
|
||||
);
|
||||
})}
|
||||
{auditory.map((item, idx) => (
|
||||
<AuditoryLink deleteModal={deleteModal} key={idx} item={item} index={idx} />
|
||||
))}
|
||||
</List>
|
||||
</Collapse>
|
||||
</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 CheckboxIcon from "@icons/Checkbox";
|
||||
|
||||
@ -7,6 +7,7 @@ interface GenderAndAgeSelectorProps {
|
||||
setGender: (gender: string) => void;
|
||||
}
|
||||
|
||||
|
||||
export default function GenderAndAgeSelector({ gender, setGender }: GenderAndAgeSelectorProps) {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
@ -167,6 +168,21 @@ export default function GenderAndAgeSelector({ gender, setGender }: GenderAndAge
|
||||
|
||||
</Select>
|
||||
</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>
|
||||
);
|
||||
}
|
@ -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 CopyIcon from "@/assets/icons/CopyIcon";
|
||||
import GenderAndAgeSelector from "./GenderAndAgeSelector";
|
||||
@ -7,60 +7,80 @@ import CustomTextField from "@ui_kit/CustomTextField";
|
||||
import Collapse from '@mui/material/Collapse';
|
||||
import { ArrowDownIcon } from "../../assets/icons/questionsPage/ArrowDownIcon";
|
||||
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 { AuditoryList } from "./AuditoryList";
|
||||
|
||||
const PURPLE = "#7E2AEA";
|
||||
|
||||
export default function PersonalizationAI() {
|
||||
const theme = useTheme();
|
||||
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 (
|
||||
<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" }}>
|
||||
Персонализация вопросов с помощью AI
|
||||
</Typography>
|
||||
<Typography sx={{
|
||||
color: theme.palette.grey3.main, fontSize: "18px", maxWidth: 796, m: 0,
|
||||
mt: "19px",
|
||||
letterSpacing: "0.009px",
|
||||
wordSpacing: "0.1px",
|
||||
lineHeight: "21.4px"
|
||||
}}>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</Typography>
|
||||
<>
|
||||
<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" }}>
|
||||
Персонализация вопросов с помощью AI
|
||||
</Typography>
|
||||
<Typography sx={{
|
||||
color: theme.palette.grey3.main, fontSize: "18px", maxWidth: 796, m: 0,
|
||||
mt: "19px",
|
||||
letterSpacing: "0.009px",
|
||||
wordSpacing: "0.1px",
|
||||
lineHeight: "21.4px"
|
||||
}}>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</Typography>
|
||||
|
||||
{/* Первый белый блок */}
|
||||
<Box sx={{
|
||||
bgcolor: "#fff",
|
||||
borderRadius: "12px",
|
||||
mt: "40px",
|
||||
p: "20px 20px 30px",
|
||||
boxShadow: "none",
|
||||
maxWidth: "796px"
|
||||
}}>
|
||||
<GenderAndAgeSelector gender={gender} setGender={setGender} />
|
||||
{/* Первый белый блок */}
|
||||
<Box sx={{
|
||||
bgcolor: "#fff",
|
||||
borderRadius: "12px",
|
||||
mt: "40px",
|
||||
p: "20px 20px 30px",
|
||||
boxShadow: "none",
|
||||
maxWidth: "796px"
|
||||
}}>
|
||||
<GenderAndAgeSelector gender={gender} setGender={setGender} />
|
||||
|
||||
{/* Ссылка */}
|
||||
<Box sx={{ mt: "34px" }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
|
||||
<Typography sx={{ color: theme.palette.grey3.main, fontSize: "18px", fontWeight: 500 }}>Ссылка</Typography>
|
||||
<InfoPopover />
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
lineHeight: "100%",
|
||||
letterSpacing: "0 %",
|
||||
color: theme.palette.grey2.main,
|
||||
mt: "16px"
|
||||
}}
|
||||
>
|
||||
Вставьте ссылку со всеми utm-метками
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', gap: 2, alignItems: 'center', mt: "6px" }}>
|
||||
{/* Ссылка */}
|
||||
<Box sx={{ mt: "34px" }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
|
||||
<Typography sx={{ color: theme.palette.grey3.main, fontSize: "18px", fontWeight: 500 }}>Ссылка</Typography>
|
||||
<InfoPopover />
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
lineHeight: "100%",
|
||||
letterSpacing: "0 %",
|
||||
color: theme.palette.grey2.main,
|
||||
mt: "16px"
|
||||
}}
|
||||
>
|
||||
Вставьте ссылку со всеми utm-метками
|
||||
</Typography>
|
||||
<CustomTextField
|
||||
placeholder="linkexample.com"
|
||||
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>
|
||||
|
||||
<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 { 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 handleClick = (event: MouseEvent<HTMLButtonElement>) => {
|
||||
@ -43,9 +51,7 @@ export const InfoPopover = ({ blink = false, sx }: {blink?: boolean, sx?: SxProp
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Typography>
|
||||
подсказка
|
||||
</Typography>
|
||||
{children}
|
||||
</Paper>
|
||||
</Popover>
|
||||
</>
|
||||
|
@ -26,6 +26,10 @@ export default function TooltipClickInfo({ title }: { title: string }) {
|
||||
disableFocusListener
|
||||
disableHoverListener
|
||||
disableTouchListener
|
||||
sx={{
|
||||
fontSize: "12px",
|
||||
p:"10px"
|
||||
}}
|
||||
title={title}
|
||||
>
|
||||
<IconButton onClick={handleTooltipOpen}>
|
||||
|
Loading…
Reference in New Issue
Block a user