Viewing File: /home/ubuntu/voice-assistant-frontend/src/components/GenerateVoice/GeneratedVoiceListIndex.jsx
import React, { useEffect, useState } from "react";
import { Container, Row, Col, Pagination, Button } from "react-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import { generatedVoiceListStart, generatedVoiceDeleteStart } from "../../store/slices/GeneratedSlice";
import { Link } from "react-router-dom";
import GenerateLoader from "../Helper/GenerateLoader";
import NoDataFound from "../Helper/NoDataFound";
import Skeleton from 'react-loading-skeleton'
import { ButtonLoader } from "../Helper/Loader";
import LandingFooterIndex from "../layouts/Footer/LandingFooterIndex";
const GeneratedVoiceListIndex = (props) => {
const dispatch = useDispatch();
const generateVoiceList = useSelector(state => state.generated.generatedVoiceList);
const generatedVoiceDelete = useSelector(state => state.generated.generatedVoiceDelete);
const [audio, setAudio] = useState(null);
const [isPlaying, setIsPlaying] = useState(false);
const [selectedFiles, setSelectedFiles] = useState([]);
const [selectAll, setSelectAll] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
useEffect(() => {
dispatch(generatedVoiceListStart({
skip: (currentPage - 1) * 12,
take: 12,
}));
}, [currentPage]);
const handlePageChange = (page) => {
setCurrentPage(page);
};
const handleDeleteVoice = (values) => {
dispatch(generatedVoiceDeleteStart({ generated_voice_unique_id: values.unique_id }));
}
const playAudio = (audioUrl) => {
if (audio && audio.src === audioUrl) {
if (isPlaying) {
audio.pause();
setIsPlaying(false);
} else {
audio.play();
setIsPlaying(true);
}
} else {
if (audio) {
audio.pause();
audio.currentTime = 0;
}
const newAudio = new Audio(audioUrl);
newAudio.play();
setAudio(newAudio);
setIsPlaying(true);
}
};
const toggleCheckbox = (audioUrl) => {
if (audioUrl === 'select-all') {
setSelectAll(!selectAll);
setSelectedFiles(selectAll ? [] : generateVoiceList.data.generated_voices.map(voice => voice));
} else {
setSelectedFiles((prevSelectedFiles) => {
setSelectAll(false);
if (prevSelectedFiles.includes(audioUrl)) {
return prevSelectedFiles.filter((file) => file !== audioUrl);
} else {
return [...prevSelectedFiles, audioUrl];
}
});
}
};
const downloadSelectedFiles = () => {
selectedFiles.forEach((selectedFile, index) => {
const fileName = `selected_voice_${index + 1}.webm`;
downloadAudio(selectedFile.output, fileName);
});
setSelectedFiles([]);
setSelectAll(false);
};
const downloadAudio = (audioUrl, fileName) => {
const blob = new Blob([audioUrl]);
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
return (
<>
<div className="landing-page-sec">
<div className="voicelab-sec">
<Container>
<Row className="justify-content-md-center">
<Col md={12} lg={12} xl={8}>
<div className="voicelab-box">
<div className="voicelab-header-sec">
<div className="voicelab-header-left-sec">
<h3>Generated Voice</h3>
<p>
Full list of all your generated samples, ready for
download.
</p>
</div>
<div className="voicelab-header-action-btn-sec">
<Link to="/generate-voice" className="default-btn">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
fill="none"
viewBox="0 0 17 20"
>
<path
stroke="#fff"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="3"
d="M8.5 2v16M2 7v6m13-8v10"
></path>
</svg>
<span>Genrate Voice</span>
</Link>
</div>
</div>
{generateVoiceList.loading ? (<div className="voicelab-action-btn-sec">
<div className="voicelab-select-all-btn-sec">
<div class="checkbox">
<Skeleton height={40} width={200} />
</div>
</div>
<div className="voicelab-selected-action-btn-sec">
<Skeleton height={40} width={200} />
<Skeleton height={40} width={200} />
</div>
</div>) :
(Object.keys(generateVoiceList.data).length > 0 && generateVoiceList.data.generated_voices.length > 0) ?
<div className="voicelab-action-btn-sec">
<div className="voicelab-select-all-btn-sec">
<div class="checkbox">
<label class="checkbox-wrapper" for="select-all">
<input
type="checkbox"
class="checkbox-input"
id="select-all"
checked={selectAll}
onChange={() => toggleCheckbox('select-all')}
/>
<span class="checkbox-tile">
<span class="checkbox-label">Select All</span>
</span>
</label>
</div>
</div>
<div className="voicelab-selected-action-btn-sec">
<Button className="download-selected-btn" disabled={selectedFiles.length == 0} onClick={downloadSelectedFiles}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
fill="none"
viewBox="0 0 17 18"
>
<path
fill="url(#paint0_linear_151_35913)"
d="M13.222 17.5H3.778a3.753 3.753 0 01-2.671-1.107A3.753 3.753 0 010 13.723v-.945a.944.944 0 111.889 0v.944c0 .505.196.98.553 1.336.357.357.831.553 1.336.553h9.444c.505 0 .979-.196 1.336-.553.357-.357.553-.831.553-1.336v-.944a.944.944 0 111.889 0v.944a3.753 3.753 0 01-1.107 2.671 3.753 3.753 0 01-2.67 1.107zM8.5 13.722a.942.942 0 01-.66-.268.034.034 0 01-.002-.003l-.002-.001v-.001l-.002-.001-.002-.002-3.778-3.778A.945.945 0 015.39 8.332l2.166 2.166V1.444a.944.944 0 111.888 0v9.054l2.166-2.166a.945.945 0 011.336 1.336l-3.778 3.778s-.002 0-.002.002h-.001l-.001.002-.002.001-.002.002-.032.03a.94.94 0 01-.26.165h-.001-.001a.94.94 0 01-.366.074z"
></path>
<defs>
<linearGradient
id="paint0_linear_151_35913"
x1="8.5"
x2="8.5"
y1="0.5"
y2="17.5"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#5575FF"></stop>
<stop offset="1" stopColor="#8F59FC"></stop>
</linearGradient>
</defs>
</svg>
<span>Download Selected</span>
</Button>
<Button className="delete-selected-btn" disabled={selectedFiles.length == 0}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-trash"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="#FF4D4D"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M4 7l16 0" />
<path d="M10 11l0 6" />
<path d="M14 11l0 6" />
<path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12" />
<path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3" />
</svg>
<span>Delete Selected</span>
</Button>
</div>
</div> : null}
<div className="voicelab-list-box">
{generateVoiceList.loading ? (<GenerateLoader />) :
(Object.keys(generateVoiceList.data).length > 0 && generateVoiceList.data.generated_voices.length > 0) ?
generateVoiceList.data.generated_voices.map(
(voice, i) => (
<div className="voicelab-list-card" key={i}>
<div className="voicelab-list-info">
<div class="checkbox">
<label class="checkbox-wrapper" for={`voice-${i}`}>
<input
type="checkbox"
class="checkbox-input"
id={`voice-${i}`}
checked={selectedFiles.includes(voice)}
onChange={() => toggleCheckbox(voice)}
/>
<span class="checkbox-tile">
<span class="checkbox-label">{voice.voice.name}</span>
</span>
</label>
</div>
</div>
<div className="voicelab-list-action-btn-sec">
<div className="voicelab-list-created-date-sec">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-calendar-month"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="#787878"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M4 7a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12z" />
<path d="M16 3v4" />
<path d="M8 3v4" />
<path d="M4 11h16" />
<path d="M7 14h.013" />
<path d="M10.01 14h.005" />
<path d="M13.01 14h.005" />
<path d="M16.015 14h.005" />
<path d="M13.015 17h.005" />
<path d="M7.01 17h.005" />
<path d="M10.01 17h.005" />
</svg>
<span>{voice.updated_at_formatted}</span>
</div>
<Button className="voicelab-list-action-btn" disabled={generatedVoiceDelete.buttonDisable} onClick={() => { playAudio(voice.output) }}>
{isPlaying && audio?.src === voice.output ? (
<svg
width="25"
height="26"
viewBox="0 0 25 26"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<svg width="25" height="26" viewBox="0 0 25 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.9948 20.0042C10.0948 20.003 10.9939 19.1021 10.9927 18.0021L10.9823 8.00209C10.9812 6.90209 10.0802 6.00302 8.98022 6.00417C7.88022 6.00532 6.98116 6.90625 6.98231 8.00625L6.99272 18.0062C6.99387 19.1062 7.8948 20.0053 8.9948 20.0042ZM14.9823 7.99792L14.9927 17.9979C14.9939 19.0979 15.8948 19.997 16.9948 19.9958C18.0948 19.9947 18.9939 19.0937 18.9927 17.9937L18.9823 7.99376C18.9812 6.89376 18.0802 5.99469 16.9802 5.99584C15.8802 5.99698 14.9812 6.89792 14.9823 7.99792Z" fill="url(#paint0_linear_819_5485)" />
<defs>
<linearGradient id="paint0_linear_819_5485" x1="12.9802" y1="6" x2="12.9948" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#5575FF" />
<stop offset="1" stop-color="#8F59FC" />
</linearGradient>
</defs>
</svg>
</svg>
) : (
<svg
width="25"
height="26"
viewBox="0 0 25 26"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-player-play-filled"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path
d="M6 4v16a1 1 0 0 0 1.524 .852l13 -8a1 1 0 0 0 0 -1.704l-13 -8a1 1 0 0 0 -1.524 .852z"
stroke-width="0"
fill="#5575FF"
/>
</svg>
</svg>
)}
</Button>
<Button className="voicelab-list-action-btn" disabled={generatedVoiceDelete.buttonDisable} onClick={() => handleDeleteVoice(voice)}>
{(generatedVoiceDelete.buttonDisable && generatedVoiceDelete.data.generated_voice_unique_id == voice.unique_id) ? (
<ButtonLoader />
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-trash"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="#FF4D4D"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M4 7l16 0" />
<path d="M10 11l0 6" />
<path d="M14 11l0 6" />
<path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12" />
<path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3" />
</svg>
)}
</Button>
</div>
</div>
))
: (
<NoDataFound />
)}
</div>
{(Object.keys(generateVoiceList.data).length > 0 && generateVoiceList.data.generated_voices.length > 0) ?
<div className="pagination-sec">
<Pagination>
{[...Array(Math.ceil(generateVoiceList.data.total_generated_voices / 12)).keys()].map((page) => (
<Pagination.Item
key={page + 1}
active={page + 1 === currentPage}
onClick={() => handlePageChange(page + 1)}
>
{page + 1}
</Pagination.Item>
))}
</Pagination>
</div>
: null}
</div>
</Col>
</Row>
</Container>
</div>
<LandingFooterIndex />
</div>
</>
);
};
export default GeneratedVoiceListIndex;
Back to Directory
File Manager