leumas-private-shared
Version:
Private React JSX Package For Leumas Shared Components, Headers, Footers, Asides, Login Pages, API Key Manager and much more. Styles and everything reusable to avoid DRY code across all of our subdomains
239 lines (199 loc) • 9.1 kB
JSX
import React, { useState, useEffect } from 'react';
import {LeumasBaseStyle} from "../../styles/baseStyles"
import { FaPlay, FaVideo, FaCode, FaInfoCircle } from 'react-icons/fa';
import { MdHome } from 'react-icons/md';
import axios from "axios"
import Spinner2 from '../Loaders/Spinner2';
import { getItemById } from '../../helpers/LMS-WildCard-Helpers/UniversalCrud/UniversalCrudHelpers';
import { useAuthUser } from 'react-auth-kit';
import {sendIRSignalToPort} from "../../components/NPMDev/SerialPort/sendIRSignalToPort"
const ButtonCard = ({ buttonData , selectedPort}) => {
const [isModalOpen, setModalOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [modalContent, setModalContent] = useState('');
const auth = useAuthUser();
console.log("buttonData" , buttonData)
const handleButtonClick = (type) => {
switch(type) {
case 'audioBtn':
playAudio(buttonData.audioUrl);
break;
case 'videoBtn':
playVideo(buttonData.videoUrl);
break;
case 'smartHomeBtn':
controlSmartHomeDevice(buttonData.smartHomeDeviceId);
break;
case 'gptBtn':
runGPTCommand(buttonData.gptCommand);
break;
case 'actionBtn':
triggerServerAction(buttonData.serverAction);
break;
case 'codeBtn':
executeCode(buttonData.code);
break;
case 'IrBtn':
triggerIRSignal(buttonData.irSignalData , selectedPort);
break;
default:
console.warn("Unknown button type");
}
}
const playAudio = (audioUrl) => {
// Create a new audio object
const audio = new Audio(audioUrl);
// Event listener for when the audio has ended
audio.addEventListener("ended", () => {
console.log(`Finished playing audio from ${audioUrl}`);
});
// Play the audio
audio.play().catch(error => {
console.error(`Failed to play audio from ${audioUrl}`, error);
});
};
const playVideo = (videoUrl) => {
// Create a video element
const video = document.createElement("video");
video.setAttribute("controls", ""); // Add video controls
video.src = videoUrl;
// Create an overlay for the video to be center-aligned
const overlay = document.createElement("div");
overlay.style.position = "fixed";
overlay.style.top = "0";
overlay.style.right = "0";
overlay.style.bottom = "0";
overlay.style.left = "0";
overlay.style.background = "rgba(0,0,0,0.8)";
overlay.style.display = "flex";
overlay.style.alignItems = "center";
overlay.style.justifyContent = "center";
overlay.style.zIndex = "1000"; // to ensure it's on top of other elements
// Append video to overlay
overlay.appendChild(video);
// Append overlay to the body
document.body.appendChild(overlay);
// Play the video
video.play().catch(error => {
console.error(`Failed to play video from ${videoUrl}`, error);
});
// Remove the video overlay when video ends
video.addEventListener("ended", () => {
document.body.removeChild(overlay);
});
// Optionally, click outside of the video or on the video to close it
overlay.addEventListener("click", () => {
video.pause();
document.body.removeChild(overlay);
});
};
const controlSmartHomeDevice = (deviceId) => {
// Logic to control smart home device
console.log(`Controlling device with ID ${deviceId}`);
}
const runGPTCommand = async (gptCommand) => {
setIsLoading(true);
// Logic to run GPT command
console.log(`Running GPT command: ${gptCommand}`);
const messages = [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": gptCommand }
];
try {
const res = await axios.post(`${import.meta.env.VITE_REACT_APP_LEUMAS_AI_ENDPOINT}/openai/chatgpt/chat-completions/chat-completion`, {
model: "gpt-3.5-turbo",
messages: messages
});
if (res.data.choices && res.data.choices[0] && res.data.choices[0].message) {
setModalContent(res.data.choices[0].message.content);
setModalOpen(true);
}
} catch (error) {
console.error('Error making request to backend:', error);
setModalContent('Error fetching response from GPT-3.');
setModalOpen(true);
} finally {
setIsLoading(false)
}
}
const triggerServerAction = (serverAction) => {
// Logic to trigger a server action
console.log(`Triggering server action: ${serverAction}`);
}
const executeCode = (code) => {
// Logic to execute the provided code
// Be VERY cautious executing arbitrary code for security reasons
console.log(`Executing code: ${code}`);
}
const triggerIRSignal = async (irSignalData , selectedPort) => {
if (!selectedPort) {
console.error("No port selected!");
return;
}
getItemById("IRSignal", irSignalData, "LeumasAPI", auth()?.token).then(async (data) => {
console.log(data);
if (data && data.IRValue && selectedPort) { // ensure you have the data and a selected port
const response = await sendIRSignalToPort(selectedPort, data.IRValue);
if (response && response.success) {
console.log(response.message);
} else {
console.error("Failed to send IR signal");
}
}
});
}
const getIconForButtonType = (type) => {
switch(type) {
case 'audioBtn':
return <FaPlay size={24} />; // Adjust size as necessary
case 'videoBtn':
return <FaVideo size={24} />;
case 'codeBtn':
return <FaCode size={24} />;
case 'smartHomeBtn':
return <MdHome size={24} />;
case 'actionBtn' :
return <MdHome size={24} />;
case 'gptBtn' :
return <MdHome size={24} />;
case 'IrBtn' :
return <MdHome size={24} />;
// ... add other cases for other button types
default:
return null;
}
};
return (
<>
{isLoading ? <Spinner2 loading={true} /> : <div className={`${LeumasBaseStyle} max-w-[100px] max-h-[100px] min-h-[100px] relative group hover:shadow-xl hover:scale-110 border-glow`}
data-tooltip={buttonData.description || "Some default tooltip text"}>
<button className="w-full h-full relative" onClick={() => handleButtonClick(buttonData.buttonType)}>
<span className="absolute bottom-0 right-0 text-xs ">
{buttonData.buttonType}
</span>
<div className="absolute inset-0 flex items-center justify-center">
{getIconForButtonType(buttonData.buttonType)}
</div>
</button>
<button className="absolute bottom-0 left-0 text-xs p-1 bg-white bg-opacity-50 rounded-full hover:bg-opacity-100 transition-opacity duration-300"
onClick={() => { /* Handle the 'view details' logic here */ }}>
<FaInfoCircle />
</button>
{/* Tooltip styling */}
<div className="absolute bottom-full left-1/2 transform -translate-x-1/2 translate-y-2 px-2 py-1 bg-black text-white text-xs rounded shadow-lg opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none">
{buttonData.description}
</div>
{/* <div className='absolute top-0 right-0 w-full text-[8px] max-w-[50px]'>
<SerialPortSelector setSelectedPort={handlePortChange} />
</div> */}
</div> }
{isModalOpen && (
<div className=" p-6 rounded shadow-lg absolute bottom-0 left-0 max-w-sm bg-transparent z-50 bg-white text-black m-4 max-h-[250px] max-w-[400px] ">
<button onClick={() => setModalOpen(false)} className="absolute top-2 right-2">X</button>
<p>{modalContent}</p>
</div>
)}
</>
);
}
export default ButtonCard;