import axios from "axios"; import { useState } from "react"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Label } from "../ui/label"; import { Maximize2, Minimize2, Trash2Icon } from "lucide-react"; import { ActionType } from "@prisma/client"; import { boolean } from "zod"; const actionTypes = [ { "name": "Overwrite local file content", "value": ActionType.WRITE_TO_FILE, "inputs": [ { "type": "text", "label": "File path", "key": "file_path", "placeholder": "Enter local file path, relative or full." }, { "type": "text", "label": "File content", "key": "file_content", "placeholder": "Enter the text to write to the file." } ] }, { "name": "Append to local file", "value": ActionType.APPEND_TO_FILE, "inputs": [ { "type": "text", "label": "File path", "key": "file_path", "placeholder": "Enter local file path, relative or full." }, { "type": "text", "label": "File content", "key": "file_content", "placeholder": "Enter the text to append to the file." } ] }, { "name": "Cause a transformation on OBS scene item", "value": ActionType.OBS_TRANSFORM, "inputs": [] }, { "name": "Play an audio file locally", "value": ActionType.AUDIO_FILE, "inputs": [ { "type": "text", "label": "File path", "key": "file_path", "placeholder": "Enter local file path, relative or full." } ] }, { "name": "User gets a random TTS voice that is enabled", "value": ActionType.RANDOM_TTS_VOICE, "inputs": [] }, { "name": "User gets a specific TTS voice", "value": ActionType.SPECIFIC_TTS_VOICE, "inputs": [ { "type": "text", "label": "TTS Voice", "key": "tts_voice", "placeholder": "Name of an enabled TTS voice", } ] }, { "name": "Toggle OBS scene item visibility", "value": ActionType.TOGGLE_OBS_VISIBILITY, "inputs": [ { "type": "text", "label": "Scene Name", "key": "scene_name", "placeholder": "Name of the OBS scene" }, { "type": "text", "label": "Scene Item Name", "key": "scene_item_name", "placeholder": "Name of the OBS scene item / source" } ] }, { "name": "Set OBS scene item visibility", "value": ActionType.SPECIFIC_OBS_VISIBILITY, "inputs": [ { "type": "text", "label": "Scene Name", "key": "scene_name", "placeholder": "Name of the OBS scene" }, { "type": "text", "label": "Scene Item Name", "key": "scene_item_name", "placeholder": "Name of the OBS scene item / source" }, { "type": "text-values", "label": "Visible", "key": "obs_visible", "placeholder": "true for visible; false otherwise", "values": ["true", "false"] } ] }, { "name": "Set OBS scene item's index", "value": ActionType.SPECIFIC_OBS_INDEX, "inputs": [ { "type": "text", "label": "Scene Name", "key": "scene_name", "placeholder": "Name of the OBS scene" }, { "type": "text", "label": "Scene Item Name", "key": "scene_item_name", "placeholder": "Name of the OBS scene item / source" }, { "type": "number", "label": "Index", "key": "obs_index", "placeholder": "index, starting from 0." } ] }, { "name": "Sleep - do nothing", "value": ActionType.SLEEP, "inputs": [ { "type": "number", "label": "Sleep", "key": "sleep", "placeholder": "Time in milliseconds to do nothing", } ] }, { "name": "Nightbot - Play", "value": ActionType.NIGHTBOT_PLAY, "inputs": [ { "type": "oauth.nightbot.play", "label": "nightbot.play", "key": "nightbot_play", "placeholder": "", } ] }, { "name": "Nightbot - Pause", "value": ActionType.NIGHTBOT_PAUSE, "inputs": [ { "type": "oauth.nightbot.pause", "label": "nightbot.pause", "key": "nightbot_pause", "placeholder": "", } ] }, { "name": "Nightbot - Skip", "value": ActionType.NIGHTBOT_SKIP, "inputs": [ { "type": "oauth.nightbot.skip", "label": "nightbot.skip", "key": "nightbot_skip", "placeholder": "", } ] }, { "name": "Nightbot - Clear Playlist", "value": ActionType.NIGHTBOT_CLEAR_PLAYLIST, "inputs": [ { "type": "oauth.nightbot.clear_playlist", "label": "nightbot.clear_playlist", "key": "nightbot_clear_playlist", "placeholder": "", } ] }, { "name": "Nightbot - Clear Queue", "value": ActionType.NIGHTBOT_CLEAR_QUEUE, "inputs": [ { "type": "oauth.nightbot.clear_queue", "label": "nightbot.clear_queue", "key": "nightbot_clear_queue", "placeholder": "", } ] }, ] interface RedeemableAction { name: string type: string | undefined data: { [key: string]: string } edit?: boolean showEdit?: boolean isNew: boolean obsTransformations: { label: string, placeholder: string, description: string }[] connections: { name: string, type: string }[] adder: (name: string, type: ActionType, data: { [key: string]: string }) => void remover: (action: { name: string, type: string, data: any }) => void } const RedemptionAction = ({ name, type, data, edit, showEdit = true, isNew = false, obsTransformations = [], connections = [], adder, remover }: RedeemableAction) => { const [open, setOpen] = useState<{ [key: string]: boolean }>({ 'actions': false, 'oauth': false, 'oauth.nightbot': false, 'oauth.twitch': false }) const [actionName, setActionName] = useState(name) const [actionType, setActionType] = useState<{ name: string, value: ActionType, inputs: any[] } | undefined>(actionTypes.find(a => a.value == type?.toUpperCase())) const [actionData, setActionData] = useState<{ [key: string]: string }>(data) const [isEditable, setIsEditable] = useState(edit) const [isMinimized, setIsMinimized] = useState(!isNew) const [oldData, setOldData] = useState<{ n: string, t: ActionType | undefined, d: { [k: string]: string } } | undefined>(undefined) function Save(name: string, type: ActionType | undefined, data: { [key: string]: string }, isNew: boolean) { // TODO: validation if (!name) { return } console.log('typeeee', type) if (!type) { return } if (!data) { return } let info: any = { name, type } info = { ...info, ...data } if (isNew) { axios.post("/api/settings/redemptions/actions", info) .then(d => { adder(name, type, data) setActionName("") setActionType(undefined) setActionData({}) }) } else { axios.put("/api/settings/redemptions/actions", info) .then(d => { setIsEditable(false) }) } } function Cancel(data: { n: string, t: ActionType | undefined, d: { [k: string]: any } } | undefined) { if (!data) return setActionName(data.n) setActionType(actionTypes.find(a => a.value == data.t)) setActionData(data.d) setIsEditable(false) setOldData(undefined) } function Delete() { axios.delete("/api/settings/redemptions/actions?action_name=" + name) .then(d => { remover(d.data) }) } return (
{isMinimized &&
|| !isMinimized &&
setActionName(e.target.value)} value={actionName} readOnly={!isNew} /> {!isEditable && || isEditable && setOpen({ ...open, 'actions': !open['actions'] })}> No action found. {actionTypes.map((action) => ( { setActionType(actionTypes.find(v => v.name.toLowerCase() == value.toLowerCase())) setOpen({ ...open, 'actions': false }) }}> {action.name} ))} }
{actionType &&
{actionType.inputs.map(i => { if (i.type == "text") { return
setActionData(d => { let abc = { ...actionData } abc[i.key] = e.target.value; return abc })} readOnly={!isEditable} />
} else if (i.type == "number") { return
setActionData(d => { let abc = { ...actionData } const v = parseInt(e.target.value) if (e.target.value.length == 0) { abc[i.key] = "0" } else if (!Number.isNaN(v) && Number.isSafeInteger(v)) { abc[i.key] = v.toString() } else if (Number.isNaN(v)) { abc[i.key] = "0" } return abc })} readOnly={!isEditable} />
} else if (i.type == "text-values") { return
setActionData(d => { let abc = { ...actionData } abc[i.key] = i.values.map((v: string) => v.startsWith(e.target.value)).some((v: boolean) => v) ? e.target.value : abc[i.key] return abc })} readOnly={!isEditable} />
} else { return
{ const temp = { ...open }; temp[i.type] = !temp[i.type]; setOpen(temp) }}> No connection found. {connections.filter(c => !i.type.includes('.') || c.type == i.type.split('.')[1]) .map((connection) => ( { const connection = connections.find(v => v.name.toLowerCase() == value.toLowerCase()) if (!!connection) { setActionData({ 'oauth_name': connection.name, 'oauth_type' : connection.type }) } else setActionData({}) const temp = { ...open } temp[i.type] = false setOpen(temp) }}> {connection.name} ))}
} return
})}
} {actionType && actionType.value == ActionType.OBS_TRANSFORM &&
{obsTransformations.map(t =>
{ let c = { ...actionData } c[t.label] = e.target.value setActionData(c) }} readOnly={!isEditable} />
)}
}
{isEditable && } {isEditable && !isNew && } {showEdit && !isEditable && } {!isEditable && } {!isNew && }
}
); } export default RedemptionAction;