<template>
    <component :is="tag" @click="call" :class="buttonClass">
        <span v-if="promise && runIcon">
            <i :class="runIcon"></i>
        </span>
        <span v-else-if="icon" class="icon">
            <i :class="icon"></i>
        </span>
        <span v-if="$slots.default"><slot name="default"/></span>
    </component>
</template>
<script>
import Model from '../model'

/**
 * Button that can be used to call API requests on provided url
 */
export default {
    emit: ['start', 'done'],

    props: {
        //! Component tag, by default, `button`
        tag: { type: String, default: 'a'},
        //! Button icon
        icon: String,
        //! Data or model instance to send
        data: Object,
        //! Action method, by default, `POST`
        method: { type: String, default: 'POST'},
        //! Action url
        url: String,
        //! Extra request options
        fetchOptions: {type: Object, default: () => {return {}}},
        //! Component class while action is running
        runClass: String,
        //! Icon class while action is running
        runIcon: String,
    },

    computed: {
        //! Input data as model instance
        item() {
            return this.data instanceof Model ? this.data
                        : new Model(this.data)
        },

        //! Computed button class
        buttonClass() {
            return this.promise ? this.runClass : ''
        }
    },

    data() {
        return {
            promise: false
        }
    },

    methods: {
        call() {
            if(this.promise || !this.url)
                return
            const options = Model.getOptions({
                ...this.fetchOptions,
                method: this.method,
                body: JSON.stringify(this.item.data),
            })
            this.promise = fetch(this.url, options).then(data => {
                const response = data.json();
                this.promise = null;
                this.$emit('done', response)
                return response
            }, data => { this.promise = null; return data })
            return this.promise
        },
    },
}
</script>
