# Formulario con componentes

# Componentes

# BaseInput.vue

# template

<template>
  <div class="container formulario">
    <div class="mb-3">
      <label class="form-label">{{ label }}</label>
      <input
        type="text"
        class="form-control"
        :placeholder="label"
        :value="modelValue"
        @input="$emit('update:modelValue', $event.target.value)"
      />
    </div>
  </div>
</template>

# script

<script>
export default {
  props: {
    label: {
      type: String,
      default: "",
    },
    modelValue: {
      type: [String, Number],
      default: "",
    },
  },
};
</script>

Views > Pagina.vue

<base-input
  v-model="obra.author" 
  type="text" 
  label="Autor"/>
import BaseInput from "../components/formulario/BaseInput.vue";
BaseInput

# BaseInputDate.vue

# template

<template>
  <div class="container">
    <div class="mb-3">
      <label class="form-label">{{ label }}</label>
      <input
        type="date"
        class="form-control"
        :placeholder="label"
        :value="modelValue"
        @input="$emit('update:modelValue', $event.target.value)"
      />
    </div>
  </div>
</template>

# script

<script>
export default {
  props: {
    label: {
      type: String,
      default: "",
    },
    modelValue: {
      type: [Date],
      default: "",
    },
  },
};
</script>

# BaseTextArea.vue

# template

  <template>
  <div class="container">
    <div class="mb-3">
      <label class="form-label">{{ label }}</label>
      <textarea
        type="text"
        class="form-control"
        :placeholder="label"
        :value="modelValue"
        @input="$emit('update:modelValue', $event.target.value)"
        rows="3"
      ></textarea>
    </div>
  </div>
</template>

# script

<script>
export default {
  props: {
    label: {
      type: String,
      default: "",
    },
    modelValue: {
      type: [String, Number],
      default: "",
    },
  },
};
</script>

# BaseSelect.vue

# template

<template>
  <div class="container">
    <div class="mb-3">
      <label class="form-label">{{ label }}</label>
      <select 
        class="form-select" 
        :value="modelValue"
        v-bind="{
          ...$attrs,
          onChange: ($event)=> {$emit('update:modelValue', $event.target.value)}
          }"
          >
        <option
          v-for="opcion in opciones"
          :value="opcion"
          :key="opcion"
          :selected="opcion === modelValue"
        >
          {{ opcion }}
        </option>
      </select>
    </div>
  </div>
</template>

# script

<script>
export default {
  props: {
    opciones: {
      type: Array,
      required: true,
    },
    label: {
      type: String,
      default: "",
    },
    modelValue: {
      type: [String, Number],
      default: "",
    },
  },
};
</script>

# BaseCheckBox.vue

# template

<template>
  <div class="container formulario">
    <div class="mb-3">
      <div class="form-check">
        <input
          class="form-check-input"
          type="checkbox"
          :checked="modelValue"
          @change="$emit('update:modelValue', $event.target.checked)"
        />
        <label 
          class="form-check-label" for="flexCheckDefault"
          v-if="label"
          >
          {{ label }}
        </label>
      </div>
    </div>
  </div>
</template>

# script

<script>
export default {
  props: {
    label: {
      type: String,
      default: ''
    },
    modelValue: {
      type: Boolean,
      default: false
    }
  }
}
</script>

# BaseRadioButton.vue

# template

<template>
  <div class="container formulario">
    <div class="mb-3">
      <div class="form-check">
        <input
          class="form-check-input"
          type="radio"
          :checked="modelValue === value"
          @change="$emit('update:modelValue', value)"
          v-bind="$attrs"
        />
        <label 
          class="form-check-label" for="flexCheckDefault"
          v-if="label"
          >
          {{ label }}
        </label>
      </div>
    </div>
  </div>
</template>

# script

<script>
export default {
  props: {
    label: {
      type: String,
      default: ''
    },
    modelValue: {
      type: [String, Number],
      default: ''
    }, 
    value: {
      type: [String, Number],
      required: true
    }
  }
}
</script>

# Firebase Vista > View

# Firebase Formulario.vue

# template formulario

<div class="container my-4">
  <form>
    <base-input
      v-model="obra.author" 
      type="text" 
      label="Autor"/>
    <base-input
      v-model="obra.title" 
      type="text" 
      label="Título"/>
    <base-input-date 
      v-model="obra.date" 
      type="date" 
      label="Fecha" />
    <base-text-area 
      v-model="obra.synopsis" 
      type="text" 
      label="Descripción" />
    <base-input 
      v-model="obra.link" 
      type="text" 
      label="Enlace" />
    <base-input 
      v-model="obra.photo" 
      type="text" 
      label="Imagen" />
    <base-seleccion
      v-model="obra.categoria"
      :opciones="categorias"
      label="Selecciona una categoría"
    />
    <base-check-box 
      v-model="obra.pelicula" 
      label="Película"/>
    <base-check-box 
      v-model="obra.comic" 
      label="Cómic" />
    <base-radio-button
      v-model="obra.editorial"
      :value="0"
      label="DC Cómic"
    />
    <base-radio-button 
      v-model="obra.editorial" 
      :value="1" label="Marvel" />

    <div class="input-group my-3">
      <input type="file" @change="buscarImagen($event)" />
    </div>

    <div class="mt-3">
      <button
        v-show="this.editar === true"
        @click.prevent="actualizarDato(id)"
        class="btn btn-primary"
      >
        Actualizar
      </button>
      <button
        v-show="this.editar === false"
        @click.prevent="agregarDato()"
        class="btn btn-primary"
      >
        Guardar
      </button>
      <div class="mt-4">
        <img :src="datoImagen" />
      </div>
    </div>
  </form>
</div>

# template formulario

Importaciones de componentes

import Navbar from "@/components/Navbar.vue";
import BaseInput from "../components/formulario/BaseInput.vue";
import BaseInputDate from "../components/formulario/BaseInputDate.vue";
import BaseTextArea from "../components/formulario/BaseTextArea.vue";
import BaseSeleccion from "../components/formulario/BaseSeleccion.vue";
import BaseCheckBox from "../components/formulario/BaseCheckBox.vue";
import BaseRadioButton from "../components/formulario/BaseRadioButton.vue";

componentes:

BaseInput,
BaseInputDate,
BaseTextArea,
BaseSeleccion,
BaseCheckBox,
BaseRadioButton

data:

categorias: [
      "Los Vengadores",
      "Los Cuatro Fantásticos",
      "Guardianes de la Galaxia",
      "Superhéroe",
    ],
obra: {
      id: "",
      title: "",
      author: "",
      date: "",
      synopsis: "",
      link: "",
      photo: "",
      categoria: '',
      editorial: '',
      pelicula: '',
      comic: '',
    },

metodos:

categoria: this.obra.categoria,
editorial: this.obra.editorial,
pelicula: this.obra.pelicula,
comic: this.obra.comic,

# script completo

<script>
import Navbar from "@/components/Navbar.vue";
import BaseInput from "../components/formulario/BaseInput.vue";
import BaseInputDate from "../components/formulario/BaseInputDate.vue";
import BaseTextArea from "../components/formulario/BaseTextArea.vue";
import BaseSeleccion from "../components/formulario/BaseSeleccion.vue";
import BaseCheckBox from "../components/formulario/BaseCheckBox.vue";
import BaseRadioButton from "../components/formulario/BaseRadioButton.vue";
import {
  collection,
  getDocs,
  addDoc,
  deleteDoc,
  doc,
  getDoc,
  updateDoc,
} from "firebase/firestore";
import { db, storage } from "../main";
import firebase from "firebase/compat/app";
import router from "../router/index";

export default {
  name: "About",
  components: {
    Navbar,
    BaseInput,
    BaseInputDate,
    BaseTextArea,
    BaseSeleccion,
    BaseCheckBox,
    BaseRadioButton,
  },
  data() {
    return {
      file: null,
      datoImagen: null,
      error: null,
      editar: false,
      loading: false,

      categorias: [
        "Los Vengadores",
        "Los Cuatro Fantásticos",
        "Guardianes de la Galaxia",
        "Superhéroe",
      ],

      obras: [],
      obra: {
        id: "",
        title: "",
        author: "",
        date: "",
        synopsis: "",
        link: "",
        photo: "",
        categoria: '',
        editorial: '',
        pelicula: '',
        comic: '',
      },
    };
  },
  methods: {
    async obtenerDatos() {
      const querySnapshot = await getDocs(collection(db, "obras"));
      querySnapshot.forEach((doc) => {
        let obra = doc.data();
        obra.id = doc.id;
        this.obras.push(obra);
        console.log(obra);
      });
    },
    // DELETE / ELIMINAR / BORRAR
    async eliminarDato(id) {
      await deleteDoc(doc(db, "obras", id));
      router.go("/");
    },
    // GET BY ID / OBTENER POR ID
    async obtenerDatoID(id) {
      const docRef = doc(db, "obras", id);
      const docSnap = await getDoc(docRef);
      if (docSnap.exists()) {
        this.obra = docSnap.data();
        this.obra.id = docSnap.id;
      } else {
        console.log("¡No existe el documento!");
      }
    },

    // BUSCAR IMAGEN
    buscarImagen(event) {
      const tipoArchivo = event.target.files[0].type;
      if (tipoArchivo === "image/jpeg" || tipoArchivo === "image/png") {
        this.file = event.target.files[0];
        this.error = null;
      } else {
        this.error = "Archivo no válido";
        this.file = null;
        return;
      }
      const reader = new FileReader();
      reader.readAsDataURL(this.file);
      reader.onload = (e) => {
        this.datoImagen = e.target.result;
      };
    },
    // SUBIR IMAGEN STORAGE
    async agregarDato() {
      try {
        this.loading = true;
        var storageRef = firebase.storage().ref();
        await storageRef.child("imagenes").child(this.file.name).put(this.file);
        const urlDescarga = await storageRef
          .child("imagenes")
          .child(this.file.name)
          .getDownloadURL();
        await addDoc(collection(db, "obras"), {
          title: this.obra.title,
          author: this.obra.author,
          date: this.obra.date,
          synopsis: this.obra.synopsis,
          link: this.obra.link,
          categoria: this.obra.categoria,
          editorial: this.obra.editorial,
          pelicula: this.obra.pelicula,
          comic: this.obra.comic,
          photo: urlDescarga,
        });
        this.error = "Imagen subida con éxito";
        this.file = null;
      } catch (error) {
        console.log(error);
      } finally {
        router.push("/");
        this.loading = false;
      }
    },

    // MÉTODO actualizarDato
    async actualizarDato() {
      try {
        this.loading = true;
        var storageRef = firebase.storage().ref();
        await storageRef.child("imagenes").child(this.file.name).put(this.file);
        const urlDescarga = await storageRef
          .child("imagenes")
          .child(this.file.name)
          .getDownloadURL();
        const elemento = doc(db, "obras", this.obra.id);
        await updateDoc(elemento, {
          title: this.obra.title,
          author: this.obra.author,
          date: this.obra.date,
          synopsis: this.obra.synopsis,
          link: this.obra.link,
          categoria: this.obra.categoria,
          editorial: this.obra.editorial,
          pelicula: this.obra.pelicula,
          comic: this.obra.comic,
          photo: urlDescarga,
        });
        this.error = "Imagen subida con éxito";
        this.file = null;
      } catch (error) {
        console.log(error);
      } finally {
        router.push("/");
        this.loading = false;
      }
    },
  },
  mounted() {
    this.obtenerDatos();
  },
};
</script>

# Axios Vista > View

# Axios Formulario.vue

# template

<template>
  <BaseInput
    v-model="producto.nombre"
    type="text"
    label="Nombre"
  />
   <BaseTextarea
    v-model="producto.descripcion"
    type="text"
    label="Descripción"
  />
    <BaseSelect
    v-model="producto.categoria"
    :opciones="categorias"
    label="Selecciona una categoría"
  />
  <base-checkbox 
    v-model="producto.extras.pelicula" 
    label="Película"
    />
  <base-checkbox 
    v-model="producto.extras.comic" 
    label="Cómic"
    />
  <base-radio
  v-model="producto.editorial"
  :value="0"
  label="DC Cómic"
  />
  <base-radio
  v-model="producto.editorial"
  :value="1"
  label="Marvel"
  />
   {{ producto }}
</template>

# script

<script>
import BaseInput from "../components/BaseInput.vue"
import BaseTextarea from "../components/BaseTextarea.vue"
import BaseSelect from "../components/BaseSelect.vue"
import BaseCheckbox from "../components/BaseCheckbox.vue"
export default {
  name: 'Formulario',
  components: {
    BaseInput,
    BaseTextarea,
    BaseSelect,
    BaseCheckbox
  },
  data () {
    return {
      categorias: [
        'Los Vengadores',
        'Los Cuatro Fantásticos',
        'Guardianes de la Galaxia',
        'Superhéroe'
      ],
      producto: {
        categoria: '',
        nombre: '',
        descripcion: '',
        editorial: 0,
        extras: {
          pelicula: false,
          comic: false
        }
      }
    }
  }
}
</script>