import React, { Component, createRef } from "react"; import PropTypes from "prop-types"; import DialogContainer from "../../hubs/src/react-components/dialog-container"; import { fetchReticulumAuthenticated } from "../../hubs/src/utils/phoenix-utils"; function parseTSVInt(value) { const intVal = parseInt(value); return isNaN(intVal) ? undefined : intVal; } function parseTSVBool(value) { return value.toLowerCase().trim() === "true" } export default class RoomManagementDialog extends Component { static propTypes = { onClose: PropTypes.func, closable: PropTypes.bool }; static defaultProps = { closable: true }; constructor(props) { super(props); this.fileInputRef = createRef(); } onSubmit = async () => { const tsv = await this.fileInputRef.current.files[0].text() const lines = tsv.split("\n"); lines.shift(); const newLines = []; const header = ["Room Id", "Room Name", "Room Description", "Scene Id", "Group Order", "Room Order", "Room Size", "Spawn and Move Media", "Spawn Camera", "Spawn Drawing", "Pin Objects", "Public"]; newLines.push(header.join("\t")); for (const line of lines) { let [id, name, description, scene_id, group_order, room_order, room_size, spawn_and_move_media, spawn_camera, spawn_drawing, pin_objects, allow_promotion] = line.split("\t"); const roomParams = { hub: { name, description, scene_id: scene_id || undefined, user_data: { group_order: parseTSVInt(group_order), room_order: parseTSVInt(room_order) }, member_permissions: { spawn_and_move_media: parseTSVBool(spawn_and_move_media), spawn_camera: parseTSVBool(spawn_camera), spawn_drawing: parseTSVBool(spawn_drawing), pin_objects: parseTSVBool(pin_objects) }, room_size: parseTSVInt(room_size), allow_promotion: parseTSVBool(allow_promotion) } }; let new_id = id; if (id) { await fetchReticulumAuthenticated(`/api/v1/hubs/${id}`, "PATCH", roomParams); } else { const res = await fetchReticulumAuthenticated(`/api/v1/hubs`, "POST", roomParams); new_id = res.hub_id; } const newLine = [new_id, name, description, scene_id, group_order, room_order, room_size, spawn_and_move_media, spawn_camera, spawn_drawing, pin_objects, allow_promotion]; newLines.push(newLine.join("\t")); await new Promise(resolve => setTimeout(resolve, 2500)); } const newTsv = newLines.join("\n"); const blob = new Blob([newTsv], { type: "text/tsv" }); const downloadEl = document.createElement("a"); downloadEl.download = "room-list.tsv"; downloadEl.href = URL.createObjectURL(blob); downloadEl.click(); this.props.onClose(); }; onDownloadRoomList = async () => { const rooms = await fetchReticulumAuthenticated("/api/v1/media/search?source=rooms&filter=public"); const lines = []; const header = ["Room Id", "Room Name", "Room Description", "Scene Id", "Group Order", "Room Order", "Room Size", "Spawn and Move Media", "Spawn Camera", "Spawn Drawing", "Pin Objects", "Public"]; lines.push(header.join("\t")); for (let { id, name, description, scene_id, user_data, room_size, allow_promotion } of rooms.entries) { const groupOrder = user_data && user_data.group_order; const roomOrder = user_data && user_data.room_order; const line = [id, name || "", description || "", scene_id || "", groupOrder || "", roomOrder || "", room_size || "", "false", "false", "false", "false", allow_promotion || "true"]; lines.push(line.join("\t")); } const tsv = lines.join("\n"); const blob = new Blob([tsv], { type: "text/tsv" }); const downloadEl = document.createElement("a"); downloadEl.download = "room-list.tsv"; downloadEl.href = URL.createObjectURL(blob); downloadEl.click(); }; render() { return ( <DialogContainer title="Room Management" {...this.props}> <form onSubmit={this.onSubmit}> <label htmlFor="room-management-file">Room List (.tsv)</label> <input id="room-management-file" type="file" accept=".tsv" multiple={false} ref={this.fileInputRef} /> <button type="submit">Update Rooms</button> <button type="button" onClick={this.onDownloadRoomList}>Download Room List</button> </form> </DialogContainer> ); } }