Curso Firebase / Firestore desde cero 💪 (Parte II)
Curso Firebase / Firestore desde cero 💪
Vue JS + Firebase + Vuetify [Práctica Calendario con Firestore]
Apuntes:
- Guía de Bluuweb sobre Vuetify & Firebase.
- Página de Vuetify.
- Crear nuevo proyecto Vue: $ vue create calendario.
- Seleccionar forma manual.
- Seleccionamos: Babel, Router y Vuex.
- En Use history mode for router? respondemos que si.
- Seleccionamos In package.json.
- En Save this as a preset for future projects? respondemos que no.
- Instalamos Vuetify con: $ vue add vuetify (Vuetify se debe instalar en un proyecto limpio, ya que en su proceso de instalación reemplaza algunos archivos).
- Seleccionamos la instalación por defecto.
- Ir a Firebase y crear un nuevo proyecto y lo nombramos vue-calendario.
- No habilitar Google Analytics para este proyecto.
- Seleccionar Database.
- Crear base de datos de Cloud Firestore.
- Seleccionamos comenzar en modo de prueba y dar siguiente y luego a listo.
- Ahora vamos a configuración del proyecto.
- Ir a Tus apps y seleccionamos web (</>).
- En sobrenombre de app le ponemos calendario.
- Por ahora no configuraremos Firebase Hosting.
- Dar clic en Registra app.
- Copiamos el SDK de Firebase y luego de ejecutar las dos siguientes instalaciones, pegarlos en src/main.js.
- Instalamos firebase ejecutando: $ npm i firebase.
- Ejecutar en terminal: $ npm i vue-textarea-autosize.
- src/main.js:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify';
import VueTextareaAutosize from "vue-textarea-autosize";
Vue.use(VueTextareaAutosize);
import firebase from "firebase/app";
import "firebase/firestore";
// Your web app's Firebase configuration
// Inicialmente decia: var firebaseConfig
const firebaseConfig = {
apiKey: "AIzaSyBIdgby5Goc_nhWH5t0BmvIfWi3bftZXno",
authDomain: "vue-calendario-dbef1.firebaseapp.com",
databaseURL: "https://vue-calendario-dbef1.firebaseio.com",
projectId: "vue-calendario-dbef1",
storageBucket: "vue-calendario-dbef1.appspot.com",
messagingSenderId: "536089541138",
appId: "1:536089541138:web:2e0fe3a7ee49573d8236cb"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
export const db = firebase.firestore();
Vue.config.productionTip = false
new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount('#app')
- Para levantar un servidor local ejecutamos en terminal: $ npm run serve.
- src/App.vue:
<template>
<v-row class="fill-height">
<v-col>
<v-sheet height="64">
<v-toolbar flat color="white">
<v-btn color="primary" dark class="mr-4" @click="dialog = true">
Agregar
</v-btn>
<v-btn outlined class="mr-4" @click="setToday">
Hoy
</v-btn>
<v-btn fab text small @click="prev">
<v-icon small>mdi-chevron-left</v-icon>
</v-btn>
<v-btn fab text small @click="next">
<v-icon small>mdi-chevron-right</v-icon>
</v-btn>
<v-toolbar-title>{{ title }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-menu bottom right>
<template v-slot:activator="{ on }">
<v-btn
outlined
v-on="on"
>
<span>{{ typeToLabel[type] }}</span>
<v-icon right>mdi-menu-down</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item @click="type = 'day'">
<v-list-item-title>Día</v-list-item-title>
</v-list-item>
<v-list-item @click="type = 'week'">
<v-list-item-title>Semana</v-list-item-title>
</v-list-item>
<v-list-item @click="type = 'month'">
<v-list-item-title>Mes</v-list-item-title>
</v-list-item>
<v-list-item @click="type = '4day'">
<v-list-item-title>4 días</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-toolbar>
</v-sheet>
<v-sheet height="600">
<v-calendar
ref="calendar"
v-model="focus"
color="primary"
:events="events"
:event-color="getEventColor"
:event-margin-bottom="3"
:now="today"
:type="type"
@click:event="showEvent"
@click:more="viewDay"
@click:date="viewDay"
@change="updateRange"
:weekdays="[1, 2, 3, 4, 5, 6, 0]"
locale="es"
:short-weekdays="false"
></v-calendar>
<!-- Modal Agregar Evento -->
<v-dialog v-model="dialog">
<v-card>
<v-container>
<v-form @submit.prevent="addEvent">
<v-text-field
type="text" label="Agregar Nombre" v-model="name">
</v-text-field>
<v-text-field
type="text" label="Agregar un Detalle" v-model="details">
</v-text-field>
<v-text-field
type="date" label="Inicio del evento" v-model="start">
</v-text-field>
<v-text-field
type="date" label="Fin del evento" v-model="end">
</v-text-field>
<v-text-field
type="color" label="Color del evento" v-model="color">
</v-text-field>
<v-btn type="submit" color="primary" class="mr-4"
@click.stop="dialog = false">Agregar</v-btn>
</v-form>
</v-container>
</v-card>
</v-dialog>
<v-menu
v-model="selectedOpen"
:close-on-content-click="false"
:activator="selectedElement"
offset-x
>
<v-card
color="grey lighten-4"
min-width="350px"
flat
>
<v-toolbar
:color="selectedEvent.color"
dark
>
<v-btn icon @click="deleteEvent(selectedEvent)">
<v-icon>mdi-delete</v-icon>
</v-btn>
<v-toolbar-title v-html="selectedEvent.name"></v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
<v-card-text>
<v-form v-if="currentlyEditing !== selectedEvent.id">
{{selectedEvent.name}} - {{selectedEvent.details}}
</v-form>
<v-form v-else>
<v-text-field
type="text" v-model="selectedEvent.name"
label="Editar Nombre">
</v-text-field>
<textarea-autosize
v-model="selectedEvent.details"
type="text"
style="width: 100%"
:min-height="100"
></textarea-autosize>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
text
color="secondary"
@click="selectedOpen = false"
>
Cancel
</v-btn>
<v-btn text v-if="currentlyEditing !== selectedEvent.id"
@click.prevent="editEvent(selectedEvent.id)">Editar</v-btn>
<v-btn text v-else @click.prevent="updateEvent(selectedEvent)">Guardar Cambios</v-btn>
</v-card-actions>
</v-card>
</v-menu>
</v-sheet>
</v-col>
</v-row>
</template>
<script>
import {db} from '../main'
export default {
data: () => ({
today: new Date().toISOString().substr(0,10),
focus: new Date().toISOString().substr(0,10),
type: 'month',
typeToLabel: {
month: 'Mes',
week: 'Week',
day: 'Day',
'4day': '4 Days',
},
start: null,
end: null,
selectedEvent: {},
selectedElement: null,
selectedOpen: false,
events: [],
name: null,
details: null,
color: '#1976D2',
dialog: false,
currentlyEditing: null
}),
computed: {
title () {
const { start, end } = this
if (!start || !end) {
return ''
}
const startMonth = this.monthFormatter(start)
const endMonth = this.monthFormatter(end)
const suffixMonth = startMonth === endMonth ? '' : endMonth
const startYear = start.year
const endYear = end.year
const suffixYear = startYear === endYear ? '' : endYear
const startDay = start.day + this.nth(start.day)
const endDay = end.day + this.nth(end.day)
switch (this.type) {
case 'month':
return `${startMonth} ${startYear}`
case 'week':
case '4day':
return `${startMonth} ${startDay} ${startYear} - ${suffixMonth} ${endDay} ${suffixYear}`
case 'day':
return `${startMonth} ${startDay} ${startYear}`
}
return ''
},
monthFormatter () {
return this.$refs.calendar.getFormatter({
timeZone: 'UTC', month: 'long',
})
},
},
mounted () {
this.$refs.calendar.checkChange();
},
created(){
this.getEvents();
},
methods: {
async updateEvent(ev){
try {
await db.collection('eventos').doc(ev.id).update({
name: ev.name,
details: ev.details
})
this.selectedOpen = false;
this.currentlyEditing = null;
} catch (error) {
console.log(error);
}
},
editEvent(id){
this.currentlyEditing = id
},
async deleteEvent(ev){
try {
await db.collection('eventos').doc(ev.id).delete();
this.selectedOpen = false;
this.getEvents();
} catch (error) {
console.log(error);
}
},
async addEvent(){
try {
if(this.name && this.start && this.end){
await db.collection('eventos').add({
name: this.name,
details: this.details,
start: this.start,
end: this.end,
color: this.color
})
this.getEvents();
this.name = null;
this.details = null;
this.start = null;
this.end = null;
this.color = '#1976D2';
}else{
console.log('Campos obligatorios');
}
} catch (error) {
console.log(error);
}
},
async getEvents(){
try {
const snapshot = await db.collection('eventos').get();
const events = [];
snapshot.forEach(doc => {
// console.log(doc.id);
let eventoData = doc.data();
eventoData.id = doc.id;
events.push(eventoData);
})
this.events = events;
} catch (error) {
console.log(error);
}
},
viewDay ({ date }) {
this.focus = date
this.type = 'day'
},
getEventColor (event) {
return event.color
},
setToday () {
this.focus = this.today
},
prev () {
this.$refs.calendar.prev()
},
next () {
this.$refs.calendar.next()
},
showEvent ({ nativeEvent, event }) {
const open = () => {
this.selectedEvent = event
this.selectedElement = nativeEvent.target
setTimeout(() => this.selectedOpen = true, 10)
}
if (this.selectedOpen) {
this.selectedOpen = false
setTimeout(open, 10)
} else {
open()
}
nativeEvent.stopPropagation()
},
updateRange ({ start, end }) {
// You could load events from an outside source (like database) now that we have the start and end dates on the calendar
this.start = start
this.end = end
},
nth (d) {
return d > 3 && d < 21
? 'th'
: ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'][d % 10]
},
},
}
</script>
- Ir a Database del proyecto en Firebase,
- Clic en iniciar colección.
- En ID de la colección: eventos.
- Escribir en campo name y en valor prueba.
- Presionamos guardar.
Comentarios
Publicar un comentario