Skip to content
Snippets Groups Projects
nodedetails.tsx 8.6 KiB
Newer Older
import React, { useEffect, useState } from "react";
import { DescriptiveReference, Node } from "../../common/graph/node";
import { NodeType } from "../../common/graph/nodetype";
import "./nodedetails.css";
import { NodeDataChangeRequest } from "../editor";
import ReferencesEditor from "./referenceseditor";
    idToObjectType: Map<number, NodeType>;
    onNodeDataChange: (
        requests: NodeDataChangeRequest[],
        createCheckpoint?: boolean
    ) => void;
    createCheckpoint: (description: string) => void;
    createCheckpoint,
    const [changed, setChanged] = useState(false);

    const getCollectiveValue = function <ValueType>(
        getter: (n: Node) => ValueType,
        defaultValue: ValueType
    ) {
        const referenceValue = getter(selectedNodes[0]);
        const differentValueFound = selectedNodes.some(
            (n: Node) => getter(n) !== referenceValue
        return differentValueFound ? defaultValue : referenceValue;
    };

    const handleDataChange = function <ValueType>(
        key: keyof NodeDataChangeRequest,
        value: ValueType
    ) {
        if (!changed) {
            setChanged(true);
        }

        Object.assign(referenceData, { [key]: value });
            // Generate changes for individual nodes if multiple nodes are selected
                const update = Object.fromEntries(
                    Object.entries(referenceData).filter(
                        ([k, v]) => v !== undefined
                    )
                );

                const defaults = {
                    name: node.name,
                    description: node.description,
                    video: node.video,
                    icon: node.icon,
                    banner: node.banner,
                    references: node.references,
                    type: node.type,
                    visibleAfter: node.visibleAfter,
                };
                return Object.assign({}, defaults, update, {
                    id: node.id,
                });
    const handleBlur = () => {
        if (changed) {
            createCheckpoint(`Modified ${selectedNodes.length} node(s) data.`);
            setChanged(false);
        }
    };

    const handleReferenceChange = (references: DescriptiveReference[]) => {
        // Save previous changes (only does anything on changed=true)
        handleBlur();

        // Register new changes
        handleDataChange("references", references);

        // Store immediately
        createCheckpoint(
            `Modified ${selectedNodes.length} node(s) references.`
        );
        setChanged(false);
    };

    useEffect(handleBlur, [selectedNodes]);

    if (selectedNodes.length == 0) {
        return <div id="nodedetails">No node selected.</div>;
    }

    const referenceData: NodeDataChangeRequest = {
        id: -1,
        name: getCollectiveValue((n) => n.name, undefined),
        description: getCollectiveValue((n) => n.description, undefined),
        video: getCollectiveValue((n) => n.video, undefined),
        icon: getCollectiveValue((n) => n.icon, undefined),
        banner: getCollectiveValue((n) => n.banner, undefined),
        references: getCollectiveValue((n) => n.references, undefined),
        type: getCollectiveValue((n) => n.type, undefined),
        visibleAfter: getCollectiveValue((n) => n.visibleAfter, undefined),
    };

        <div id="nodedetails" onBlur={handleBlur}>
                    <input
                        type="text"
                        id="node-name"
                        name="node-name"
                        placeholder="Enter name"
                        className="bottom-space"
                        value={referenceData.name ?? ""}
                            handleDataChange("name", event.target.value)
            {selectedNodes.length === 1 && (
                    <textarea
                        id="node-description"
                        name="node-description"
                        className="bottom-space"
                        placeholder={"Enter description"}
                        value={referenceData.description ?? ""}
                            handleDataChange("description", event.target.value)
                {referenceData.icon && (
                    <div>
                        <img
                            id="node-image-preview"
                            className="preview-image"
                            src={referenceData.icon}
                        />
                        <br />
                    </div>
                )}
                <input
                    type="text"
                    id="node-image"
                    name="node-image"
                    placeholder="Image URL"
                    className="bottom-space"
                    value={referenceData.icon ?? ""}
                    onChange={(event) =>
                        handleDataChange("icon", event.target.value)
                    }
                />
            </div>
            <div>
                {referenceData.banner && (
                    <div>
                        <img
                            id="node-image-preview"
                            className="preview-image"
                            src={referenceData.banner}
                        />
                        <br />
                    </div>
                )}
                <input
                    type="text"
                    id="node-detail-image"
                    name="node-detail-image"
                    placeholder="Image URL"
                    className="bottom-space"
                    value={referenceData.banner ?? ""}
                    onChange={(event) =>
                        handleDataChange("banner", event.target.value)
                    }
                />
            </div>
            <div>
                <select
                    id="node-type"
                    name="node-type"
                    className="bottom-space"
                    value={referenceData.type ? referenceData.type.id : ""}
                    onChange={(event) =>
                        handleDataChange(
                            "type",
                            idToObjectType.get(Number(event.target.value))
                        )
                    }
                >
                    <option className="empty-select-option" disabled></option>
                    {[...idToObjectType.values()].map((type) => (
                        <option key={type.id} value={type.id}>
                            {type.name}
                        </option>
                    ))}
                </select>
            </div>
            <div>
                <input
                    type="text"
                    placeholder="Video URL"
                    id="node-video"
                    name="node-video"
                    value={referenceData.video ?? ""}
                    onChange={(event) =>
                        handleDataChange("video", event.target.value)
                    }
                ></input>
            </div>
                <h4>Visible after date</h4>
                <DateVisibilityInput
                    date={referenceData.visibleAfter}
                    onDateChange={(date) =>
                        handleDataChange("visibleAfter", date)
            {selectedNodes.length === 1 && (
                <div>
                    <h4>References</h4>
                    <ReferencesEditor
                        references={referenceData.references ?? []}
                        onReferencesChange={handleReferenceChange}