var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _AddNewAppForm_favoriteToAdd;
import React, { useEffect } from "react";
import storeActions from "../stores/StoreActions";
import { FinsembleDialogTextInput } from "../../../../legacyControls/FinsembleDialogTextInput";
import { FinsembleDialogButton } from "../../../../legacyControls/FinsembleDialogButton";
import "../../../../../assets/css/dialogs.css";
import { isValidURL } from "../../../../shared/validateURL";
import { addProtocolToValidURL } from "../../../../shared/addProtocolToValidURL";
import { FEAGlobals } from "../../../../../../common/Globals";
import { useFavorites } from "../../../../../hooks/useFavorites";
const FORM_DEFAULTS = {
    name: "",
    tags: "",
    url: "",
};
const VALIDATION_DEFAULTS = {
    name: true,
    url: true,
};
const INVALID_NAME_MSG = "Name cannot be empty or be a duplicate of an existing component.";
let INVALID_URL_MSG = "URL must be valid (e.g., http://www.google.com). Only http and https protocols are supported.";
/**
 * A function component with no UI which is responsible for registering an app as a favorite.
 *
 * @param props the props for this component
 * @returns
 */
const UseFavoritesBridge = (props) => {
    // Get the useFavorites hook
    const { addFavorite } = useFavorites();
    // Because addFavorites invokes a dispatch, it must be launched from
    // useEffect
    useEffect(() => {
        // Only add the favorite if there is a favorite to add
        if (!!props.favorite) {
            // It is not necessary to check to see if this
            addFavorite(props.favorite);
        }
    }, []);
    // There is no markup for this component; it will be rendered only once
    return React.createElement(React.Fragment, null);
};
/**
 * A component that has a form to accept new app properties
 * like name, url and tags, validates user input then saves it
 * to persistent store. Showing or hiding this component is up to
 * parent component.
 * @example <AddNewAppForm onDone={this.someHandlerFunction}></AddNewAppForm>
 */
class AddNewAppForm extends React.Component {
    constructor(props) {
        super(props);
        // This private member represents a descriptor of the new app to created ONLY if
        // the new app should be a favorite (this happens when the "Favorites" folder is
        // the active folder in the advanced app launcher)
        _AddNewAppForm_favoriteToAdd.set(this, undefined);
        this.state = {
            // if you do not do this, FORM_DEFAULTS gets mutated by setState later on.
            form: Object.assign({}, FORM_DEFAULTS),
            validation: Object.assign({}, VALIDATION_DEFAULTS),
            // changed to true after the user submits (if they submit bad information). This gives updated information on keypress.
            validateOnInputChange: false,
        };
        this.onSubmit = this.onSubmit.bind(this);
        this.onClear = this.onClear.bind(this);
        this.onCancel = this.onCancel.bind(this);
        this.done = this.done.bind(this);
        this.onURLChanged = this.onURLChanged.bind(this);
        this.onAppNameChanged = this.onAppNameChanged.bind(this);
        this.onKeyDown = this.onKeyDown.bind(this);
        this.addNewApp = this.addNewApp.bind(this);
        this.addNewAppCallback = this.addNewAppCallback.bind(this);
    }
    /**
     * Calls the storeActions.addApp() method
     * to save the new app in store.
     */
    onSubmit() {
        this.fixURL();
        this.fixName();
        let validName = this.validateName(this.state.form.name);
        let validURL = this.validateURL(this.state.form.url);
        if (!validName || !validURL) {
            this.setState({
                validation: {
                    url: validURL,
                    name: validName,
                },
                validateOnInputChange: true,
            });
            return;
        }
        this.setState({
            validation: Object.assign({}, VALIDATION_DEFAULTS),
            validateOnInputChange: false,
        });
        let formData = this.state.form;
        if (this.props.beforeAddComponent) {
            if (typeof this.props.beforeAddComponent !== "function") {
                FEAGlobals.FSBL.Clients.Logger.system.error("beforeAddComponent provided to Advanced App Launcher does not appear to be a function, skipping");
            }
            else {
                formData = this.props.beforeAddComponent(formData);
            }
        }
        this.addNewApp(formData, this.addNewAppCallback);
    }
    addNewAppCallback(error) {
        // Notify parent if no errors
        if (error) {
            FEAGlobals.FSBL.Clients.Logger.system.error(error);
            this.setState({
                validation: {
                    name: false,
                    url: true,
                },
            });
        }
        else {
            this.done();
        }
    }
    addNewApp(form, cb) {
        if (this.props.customAddComponent) {
            if (typeof this.props.customAddComponent === "function") {
                this.props.customAddComponent(form, cb);
                return;
            }
            else {
                FEAGlobals.FSBL.Clients.Logger.system.error("Custom Add Component parameter provided to Advanced App Launcher does not appear to be a function, falling back to default add");
            }
        }
        const { name, url, tags } = form;
        if (name && url) {
            storeActions.addApp({
                name,
                url,
                tags: tags ? tags.split(",") : [],
                appID: name,
                type: "unknown",
                canDelete: true,
            }, (err) => {
                // This is the callback after an app has been added
                // Set the private member #favoriteToAdd to be undefined
                __classPrivateFieldSet(this, _AddNewAppForm_favoriteToAdd, undefined, "f");
                // Determine the active folder
                const activeFolder = storeActions.getActiveFolder().name;
                // If the active folder is "Favorites", then favorite the new app
                if ("Favorites" === activeFolder) {
                    __classPrivateFieldSet(this, _AddNewAppForm_favoriteToAdd, {
                        id: name,
                        category: "Application",
                        name,
                        icon: undefined,
                    }, "f");
                }
                cb(err);
            });
        }
    }
    /**
     * Clears all form inputs
     */
    onClear() {
        //document.getElementById("new-app").reset();
        this.setState({
            form: Object.assign({}, FORM_DEFAULTS),
        });
    }
    /**
     * Just cancel and do not add the app
     */
    onCancel() {
        this.done();
    }
    /**
     * Calls the passed onDone property to let the parent component
     * know that we finished processing user's request (submit/cancel)
     */
    done() {
        if (this.props.onDone && typeof this.props.onDone === "function") {
            this.props.onDone();
        }
        this.onClear();
    }
    /**
     * When the url changes, validate it (after submit), or set state.
     * @param {keyboardEvent} e
     */
    onURLChanged(e) {
        let { form, validation } = this.state;
        if (!form) {
            form = {};
        }
        form.url = e.target.value;
        if (this.state.validateOnInputChange) {
            validation.url = this.validateURL(form.url);
        }
        this.setState({
            form,
        });
    }
    /**
     * When the name changes, validate it (after submit), or set state.
     * @param {keyboardEvent} e
     */
    onAppNameChanged(e) {
        let { form, validation } = this.state;
        if (!form) {
            form = {};
        }
        form.name = e.target.value;
        if (this.state.validateOnInputChange) {
            validation.name = this.validateName(form.name);
        }
        this.setState({
            form,
        });
    }
    /**
     * Attempt to make a URL object, if successful the provided URL is valid.
     * If the URL constructor determines the provided string to be invalid it throws a TypeError.
     *
     * @param {string} url
     * @return boolean
     */
    validateURL(url) {
        if (!url) {
            return false;
        }
        if (this.props.customURLValidation) {
            if (typeof this.props.customURLValidation === "function") {
                const [result, message] = this.props.customURLValidation(url);
                if (typeof result !== "boolean") {
                    FEAGlobals.FSBL.Clients.Logger.system.error("Custom URL Validation routine does not return a boolean, falling back to default validation");
                }
                else {
                    if (message) {
                        INVALID_URL_MSG = message;
                    }
                    return result;
                }
            }
            else {
                FEAGlobals.FSBL.Clients.Logger.system.error("Custom url validation provided to Advanced App Launcher does not appear to be a function, falling back to default validation");
            }
        }
        return isValidURL(url);
    }
    /**
     * When the url changes, validate it (after submit), or set state.
     * @param {string} name
     */
    validateName(name) {
        if (typeof name !== "string") {
            return false;
        }
        return name !== "" || /^[0-9a-zA-Z_.-\s]+$/.test(name);
    }
    /**
     * Allows user to skip the protocol. Puts one in there if they don't have it.
     */
    fixURL() {
        let { form } = this.state;
        if (!form) {
            form = {};
        }
        if (typeof form.url === "string") {
            form.url = addProtocolToValidURL(form === null || form === void 0 ? void 0 : form.url);
        }
        this.setState({ form });
    }
    /**
     * Removes empty spaces from beginning and end of line
     */
    fixName() {
        var _a;
        let { form } = this.state;
        if (!form) {
            form = {};
        }
        form.name = (_a = form.name) === null || _a === void 0 ? void 0 : _a.trim();
        this.setState({ form });
    }
    /**
     * Hotkey handler
     * Escape clears the form and hides it.
     * Enter submits.
     * @param {} e
     */
    onKeyDown(e) {
        if (e.detail.key === "Escape") {
            this.onClear();
            this.done();
        }
        if (e.detail.key === "Enter") {
            this.onSubmit();
        }
    }
    // Listen for esc/enter
    componentDidMount() {
        document.addEventListener("portal:keydown", this.onKeyDown);
    }
    // remove listen for esc/enter
    componentWillUnmount() {
        document.removeEventListener("portal:keydown", this.onKeyDown);
    }
    render() {
        return (React.createElement("div", { className: "add-app-form controls-wrapper" },
            React.createElement("form", { id: "new-app" },
                React.createElement(FinsembleDialogTextInput, { inputLabel: "Name", onInputChange: this.onAppNameChanged, placeholder: "Name", autoFocus: true, value: this.state.form.name }),
                !this.state.validation.name && React.createElement("div", { className: "input-error" }, INVALID_NAME_MSG),
                React.createElement(FinsembleDialogTextInput, { inputLabel: "URL", onInputChange: this.onURLChanged, placeholder: "URL", value: this.state.form.url }),
                !this.state.validation.url && React.createElement("div", { className: "input-error" }, INVALID_URL_MSG),
                React.createElement("div", { className: "button-wrapper" },
                    React.createElement(FinsembleDialogButton, { className: "fsbl-button-neutral", onClick: this.onClear }, "Clear"),
                    React.createElement(FinsembleDialogButton, { className: "fsbl-button-neutral", onClick: this.onCancel }, "Cancel"),
                    React.createElement(FinsembleDialogButton, { className: "fsbl-button-affirmative", onClick: this.onSubmit }, "Confirm"))),
            !!__classPrivateFieldGet(this, _AddNewAppForm_favoriteToAdd, "f") && React.createElement(UseFavoritesBridge, { favorite: __classPrivateFieldGet(this, _AddNewAppForm_favoriteToAdd, "f") })));
    }
}
_AddNewAppForm_favoriteToAdd = new WeakMap();
export default AddNewAppForm;
//# sourceMappingURL=AddNewAppForm.js.map