import { memo, useEffect, useMemo, useRef, useState } from "react"
import {
Checkbox, ColorPicker, Input,
InputNumber, Select, Collapse
} from "antd"
import { capitalize } from "../utils/common"
import Tools from "./constants/tools.js"
import { useActiveWidget } from "./activeWidgetContext.js"
import { Layouts } from "./constants/layouts.js"
import { DynamicRadioInputList } from "../components/inputs.js"
import { useFileUploadContext } from "../contexts/fileUploadContext.js"
import { AudioOutlined, FileImageOutlined, FileTextOutlined, VideoCameraOutlined } from "@ant-design/icons"
import { useWidgetContext } from "./context/widgetContext.js"
/**
*
* @param {boolean} isOpen
* @param {string} widgetType
* @param {object} attrs - widget attributes
*/
const CanvasToolBar = memo(({ isOpen, widgetType, }) => {
// const { activeWidgetAttrs } = useActiveWidget()
const {activeWidget} = useWidgetContext()
// console.log("active widget context: ", activeWidgetAttrs)
const [toolbarOpen, setToolbarOpen] = useState(isOpen)
const [toolbarAttrs, setToolbarAttrs] = useState({})
const focusedInputRef = useRef()
const [cursorPos, setCursorPos] = useState(0) // store cursor position for focused input so during remount if the cursor position goes to end we can use this
const [activeInputKey, setActiveInputKey] = useState(null)
const {uploadedAssets} = useFileUploadContext()
useEffect(() => {
const stateUpdatedCallback = () => {
setToolbarAttrs(activeWidget.getToolbarAttrs())
}
if (activeWidget){
activeWidget.stateChangeSubscriberCallback(stateUpdatedCallback)
// console.log("sytate update: ", activeWidget.getToolbarAttrs())
setToolbarAttrs(activeWidget.getToolbarAttrs())
}
}, [activeWidget, focusedInputRef, cursorPos]) // , activeWidget?.state
useEffect(() => {
setToolbarOpen(isOpen)
}, [isOpen])
useEffect(() => {
if (focusedInputRef.current?.input && activeInputKey) {
// this fixes the cursor going to the end issue during remount
focusedInputRef.current.setSelectionRange(cursorPos, cursorPos)
}
}, [toolbarAttrs, focusedInputRef, cursorPos])
// useEffect(() => {
// setToolbarAttrs(activeWidget.getToolbarAttrs())
// }, [])
const uploadItems = useMemo(() => {
const returnComponentBasedOnFileType = (file) => {
if (file.fileType === "image"){
return (
{file.name}
)
}else if (file.fileType === "video"){
return (
{file.name}
)
}else if (file.fileType === "audio"){
return (
)
}else{
return (
{file.name}
)
}
}
const uploadList = uploadedAssets.map((file, idx) => ({
value: file.name,
label: returnComponentBasedOnFileType(file),
fileType: file.fileType,
type: file.type,
// previewUrl: file.previewUrl,
}))
return uploadList
}, [uploadedAssets])
const handleInputFocus = (key, event) => {
const {value, target} = event
setActiveInputKey(key)
setCursorPos(target.selectionStart)
focusedInputRef.current = event.target
}
const handleInputBlur = () => {
setActiveInputKey(null);
focusedInputRef.current = null;
}
const handleChange = (value, callback) => {
if (callback) {
callback(value)
}
if (focusedInputRef.current?.input) {
setCursorPos(focusedInputRef.current.input.selectionStart)
}else{
setCursorPos(0)
}
}
function getUploadFileFromName(name){
return uploadedAssets.find(val => val.name === name)
}
const renderUploadDropDown = (val, filter) => {
let uploadOptions = [...uploadItems]
if (filter){
uploadOptions = uploadOptions.filter((value, idx) => filter.includes(value.type))
}
return (
)
}
const renderLayoutManager = (val) => {
return (
)
}
const renderCustomTool = (val) => {
return (
// NOTE: custom components must accept value and onChange
handleChange(value, val.onChange)}>
)
}
const renderTool = (keyName, val) => {
return (
<>
{val.tool === Tools.INPUT && (
handleInputFocus(val.label, event)}
onBlur={handleInputBlur}
ref={activeInputKey === val.label ? focusedInputRef : null}
value={val.value}
onChange={(e) => handleChange(e.target.value, val.onChange)}
/>
)}
{val.tool === Tools.NUMBER_INPUT && (
handleInputFocus(val.label, event)}
onBlur={handleInputBlur}
ref={activeInputKey === val.label ? focusedInputRef : null}
onChange={(value) => handleChange(value, val.onChange)}
/>
)}
{val.tool === Tools.COLOR_PICKER && (
handleChange(value.toHexString(), val.onChange)}
/>
)}
{val.tool === Tools.SELECT_DROPDOWN && (
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
onChange={(value) => handleChange(value, val.onChange)}
/>
)}
{val.tool === Tools.CHECK_BUTTON && (
handleChange(e.target.checked, val.onChange)}
>{val.label}
)}
{val.tool === Tools.INPUT_RADIO_LIST && (
// FIXME: problem with maximum recursion error
handleChange({ inputs, selectedRadio }, val.onChange)}
/>
)}
{
val.tool === Tools.LAYOUT_MANAGER && (
renderLayoutManager(val)
)
}
{
val.tool === Tools.UPLOADED_LIST && (
renderUploadDropDown(val, val?.toolProps?.filterOptions || null)
)
}
{
val.tool === Tools.CUSTOM && (
renderCustomTool(val)
)
}
>
)
}
const renderToolbar = (obj, parentKey = "", toolCount=0) => {
// console.log("obj: ", obj)
const keys = []
return Object.entries(obj).map(([key, val], i) => {
const keyName = parentKey ? `${parentKey}.${key}` : key
// console.log("obj2: ", key, val)
// Highlight outer labels in blue for first-level keys
const isFirstLevel = parentKey === ""
const outerLabelClass = isFirstLevel
? "tw-text-sm tw-text-black tw-font-medium"
: "tw-text-sm"
if (!val?.label){
return null
}
// Render tool widgets
if (typeof val === "object" && val.tool) {
if (isFirstLevel && keys.length < 3) keys.push(keyName)
if (isFirstLevel){
return (
{renderTool(keyName, val)}
)
}
else
return (
{val.label}
{renderTool(keyName, val)}
)
}
// Handle nested objects and horizontal display for inner elements
if (typeof val === "object") {
const containerClass = val.display === "horizontal"
? "tw-flex tw-flex-row tw-flex-wrap tw-content-start tw-gap-4"
: "tw-flex tw-flex-col tw-gap-2"
if (isFirstLevel && keys.length < 3) keys.push(keyName)
if (isFirstLevel){
return (
{renderToolbar(val, keyName, toolCount+1)}
)
}else{
return (
{/* Outer label highlighted in blue for first-level */}
{val.label}
{renderToolbar(val, keyName, toolCount+1)}
)
}
}
return null
})
}
return (
{capitalize(`${activeWidget?.getDisplayName() || ""}`).replace(/_/g, " ")}
{renderToolbar(toolbarAttrs || {})}
)
})
export default CanvasToolBar