Commit 0d7614a6 authored by void's avatar void 💬
Browse files

hacer que TomarPosicionForm use Form

hubo que implementar field.type: 'select' y field.value
parent b2f2f1e8
......@@ -51,6 +51,7 @@ html
--gray: #c7c7c7
--darkgray: #8f8f8f
--verydarkgray: #555
--red: red
color: var(--foreground)
background: var(--background)
......@@ -159,12 +160,19 @@ a
color: var(--accent)
.error
background: red
padding: 15px
color: var(--background)
color: var(--red)
padding: .5em
font-weight: bold
a
color: var(--background)
.input-error
color: var(--red)
font-size: .8em
.container
padding: 0 20px
.inline-nav
display: flex
a
......
......@@ -9,10 +9,11 @@
width: 100%
text-align: left
max-width: 600px
margin: 15px auto
margin: .2em auto
margin-top: .5em
label
display: block
input, textarea, select
input, textarea, select, button
width: 100%
margin: 0
margin-top: 5px
......
<template>
<form @submit.prevent="onSubmit">
<template v-for="field in fields">
<field v-if="field.type === 'submit'">
<div class="error" v-if="error">
{{ error }}
</div>
<custom-button :loading="loading" class="primary">
{{ field.content }}
</custom-button>
</field>
<field v-else>
<span
class="input-error"
v-if="errors[field.name]"
v-for="error in errors[field.name]"
>
{{ error }}
</span>
<textarea
v-if="field.type === 'textarea'"
:name="field.name"
autocomplete="off"
:placeholder="field.placeholder"
:required="field.required"
:minlength="field.minLength"
>
{{ field.value }}
</textarea
>
<select
v-else-if="field.type === 'select'"
:name="field.name"
autocomplete="off"
:required="field.required"
>
<option
v-for="option in field.options"
:value="option.value"
:disabled="option.disabled"
:selected="field.value === option.value"
>
{{ option.content }}
</option>
</select>
<input
v-else
:type="field.type"
:name="field.name"
autocomplete="off"
:placeholder="field.placeholder"
:required="field.required"
:minlength="field.minLength"
:value="field.value"
/>
</field>
</template>
</form>
</template>
<script>
import Field from '@/components/Field'
import CustomButton from '@/components/Button'
import { grabValues } from '@/utils'
export default {
name: 'Form',
components: { Field, CustomButton },
props: ['fields', 'handleSubmit', 'parseError'],
data() {
return {
error: null,
errors: {},
loading: false,
}
},
methods: {
async onSubmit(event) {
this.error = null
this.errors = {}
this.loading = true
const values = grabValues(event)
try {
await this.handleSubmit(values)
} catch (error) {
if (typeof error === 'string') this.error = this.parseError(error)
else this.errors = error
}
this.loading = false
},
},
}
</script>
<style scoped>
.error {
padding-bottom: 0.3em;
}
</style>
<template>
<form @submit.prevent="tomarPosicion">
<div>
<h3>
<template v-if="posicionPrevia">
cambiar posición
......@@ -8,84 +8,61 @@
tomar posición
</template>
</h3>
<p class="error" v-if="error">{{ error }}</p>
<field>
<label for="estado">estado</label>
<!-- hay que abolirlo :P -->
<select name="estado" id="estado" v-model="estado" required>
<option value="compromiso">Me comprometo</option>
<option value="a_favor">A favor</option>
<option value="en_contra">En contra</option>
<option value="bloqueo">BLOQUEO!</option>
<option value="indiferente">Indiferente</option>
</select>
</field>
<field>
<label for="comentario">
comentario (opcional)
</label>
<textarea id="comentario" v-model="comentario" autocomplete="off" />
</field>
<custom-button :loading="loading" class="primary" :class="{ done }">
<span class="ghost">
crear posición
</span>
<span class="texto">
crear posición
</span>
<span class="done">
listo!
</span>
</custom-button>
</form>
<custom-form
:fields="fields"
:handleSubmit="handleSubmit"
:parseError="parseError"
/>
</div>
</template>
<script>
import Field from '@/components/Field'
import CustomButton from '@/components/Button'
import CustomForm from '@/components/Form'
export default {
name: 'TomarPosicionForm',
props: ['consensoId', 'posicionPrevia', 'barcaId'],
components: { Field, CustomButton },
data() {
let posicion = {
estado: 'indiferencia',
comentario: '',
}
if (this.posicionPrevia) {
posicion = {
estado: this.posicionPrevia.estado,
comentario: this.posicionPrevia.comentario,
}
}
return {
...posicion,
loading: false,
done: false,
error: null,
}
components: { CustomForm },
computed: {
fields() {
return [
{
name: 'estado',
required: true,
type: 'select',
value: this.posicionPrevia ? this.posicionPrevia.estado : '',
options: [
{ value: '', content: 'Elegí una posición', disabled: true },
{ value: 'compromiso', content: 'Me comprometo' },
{ value: 'a_favor', content: 'A favor' },
{ value: 'en_contra', content: 'En contra' },
{ value: 'bloqueo', content: 'BLOQUEO!' },
{ value: 'indiferente', content: 'Indiferente' },
],
},
{
name: 'comentario',
type: 'textarea',
placeholder: 'descripción (opcional)',
value: this.posicionPrevia && this.posicionPrevia.comentario,
},
{
type: 'submit',
content: this.posicionPrevia ? 'cambiar posición' : 'tomar posición',
},
]
},
},
methods: {
tomarPosicion(event) {
const { consensoId, barcaId, estado, comentario } = this
const posicion = { estado, comentario }
this.loading = true
this.error = null
this.$store
.dispatch('crearPosicion', {
barcaId,
consensoId,
posicion,
})
.then(() => {
this.done = true
setTimeout(() => (this.done = false), 1200)
})
.catch(error => (this.error = error))
.finally(() => (this.loading = false))
handleSubmit(posicion) {
const { consensoId, barcaId } = this
return this.$store.dispatch('crearPosicion', {
barcaId,
consensoId,
posicion,
})
},
parseError: error => error,
},
}
</script>
......@@ -93,21 +70,4 @@ export default {
<style lang="sass" scoped>
h3
margin: 0.5em auto
.error
background: red
padding: 15px
color: var(--background)
button
.done, .texto
position: absolute
.done
transition: .25s opacity
opacity: 0
.ghost
color: transparent
&.done
.done
opacity: 1
.texto
opacity: 0
</style>
<template>
<form @submit.prevent="crearBarca">
<div class="container">
<h1>Crear barca!</h1>
<span class="error" v-if="errors.nombre" v-for="error in errors.nombre">{{
error
}}</span>
<input type="text" name="nombre" placeholder="Nombre" autocomplete="off" />
<span
class="error"
v-if="errors.descripcion"
v-for="error in errors.descripcion"
>{{ error }}</span
>
<textarea placeholder="Descripción" name="descripcion" autocomplete="off" />
<custom-button :loading="loading" class="primary">
Crear barca
</custom-button>
</form>
<custom-form
:fields="fields"
:handleSubmit="handleSubmit"
:parseError="parseError"
/>
</div>
</template>
<script>
import CustomButton from '@/components/Button'
import CustomForm from '@/components/Form'
export default {
name: 'CrearBarcaView',
components: { CustomButton },
components: { CustomForm },
data() {
return {
loading: false,
errors: {},
fields: [
{ name: 'nombre', placeholder: 'Nombre', required: true, type: 'text' },
{
name: 'descripcion',
placeholder: 'Descripción',
required: true,
type: 'textarea',
},
{ type: 'submit', content: 'Crear barca' },
],
}
},
methods: {
crearBarca(event) {
const [nombre, descripcion] = [
event.target.nombre.value,
event.target.descripcion.value,
]
this.loading = true
this.errors = {}
this.$store
.dispatch('crearBarca', {
nombre,
descripcion,
})
handleSubmit(barcaData) {
return this.$store
.dispatch('crearBarca', barcaData)
.then(barca => this.$router.push(`/barcas/${barca.id}`))
.catch(errors => (this.errors = errors))
.finally(() => (this.loading = false))
},
parseError: error => error, // probablemente no pase ningun error generico
},
}
</script>
<template>
<form @submit.prevent="crearConsenso">
<h1>Crear propuesta</h1>
<span class="error" v-if="errors.titulo" v-for="error in errors.titulo">{{
error
}}</span>
<input
type="text"
placeholder="Titulo de la propuesta"
name="titulo"
autocomplete="off"
required
/>
<span class="error" v-if="errors.texto" v-for="error in errors.texto">{{
error
}}</span>
<textarea
name="texto"
placeholder="Descripción..."
autocomplete="off"
required
<div class="container">
<h1>Crear consenso</h1>
<custom-form
:fields="fields"
:handleSubmit="handleSubmit"
:parseError="parseError"
/>
<custom-button :loading="loading" class="primary">
Crear propuesta
</custom-button>
</form>
</div>
</template>
<script>
import CustomButton from '@/components/Button'
import { grabValues } from '@/utils'
import CustomForm from '@/components/Form'
export default {
name: 'CrearConsensoView',
data() {
return {
errors: {},
loading: false,
fields: [
{
name: 'titulo',
placeholder: 'Titulo de la propuesta',
required: true,
type: 'text',
},
{
name: 'texto',
placeholder: 'Descripción',
required: true,
type: 'textarea',
},
{ type: 'submit', content: 'Crear propuesta' },
],
}
},
components: {
CustomButton,
CustomForm,
},
computed: {
barcaId() {
......@@ -50,29 +42,14 @@ export default {
},
},
methods: {
crearConsenso(event) {
const consenso = grabValues(event)
this.loading = true
this.errors = {}
this.$store
handleSubmit(consenso) {
return this.$store
.dispatch('crearConsenso', { consenso, barcaId: this.barcaId })
.then(consenso =>
this.$router.push(`/barcas/${this.barcaId}/consensos/${consenso.id}`),
)
.catch(errors => [console.error(errors), (this.errors = errors)])
.finally(() => (this.loading = false))
},
parseError: error => error, // probablemente no pase ningun error generico
},
}
</script>
<style scoped>
.error {
color: red;
}
.crear-consenso {
margin: 0 0.5em;
text-align: center;
}
</style>
<template>
<div class="crear-cuenta">
<form @submit.prevent="crearCuenta">
<h1>Creando cuenta...</h1>
<field>
<label for="nick">
Tu nickname
<span class="error" v-if="errors.nick" v-for="error in errors.nick">{{
error
}}</span>
</label>
<input
type="text"
id="nick"
v-model="nick"
autocomplete="off"
required
/>
</field>
<field>
<label for="email">
Tu email
<span
class="error"
v-if="errors.email"
v-for="error in errors.email"
>{{ error }}</span
>
</label>
<input
type="email"
id="email"
v-model="email"
autocomplete="off"
required
/>
</field>
<field>
<label for="password">
Tu contraseña
<span
class="error"
v-if="errors.password"
v-for="error in errors.password"
>{{ error }}</span
>
</label>
<input
type="password"
id="password"
minlength="8"
v-model="password"
autocomplete="off"
required
/>
</field>
<!-- TODO: confirmar contraseñas? -->
<custom-button :loading="loading" class="primary"
>Crear cuenta</custom-button
>
</form>
<div class="container">
<h1>Creando cuenta...</h1>
<custom-form
:fields="fields"
:handleSubmit="handleSubmit"
:parseError="parseError"
/>
</div>
</template>
<script>
import Field from '@/components/Field'
import CustomButton from '@/components/Button'
import CustomForm from '@/components/Form'
export default {
name: 'CrearCuentaView',
data() {
return {
nick: '',
email: '',
password: '',
errors: {},
loading: false,
fields: [
{ name: 'nick', placeholder: 'Nickname', required: true, type: 'text' },
{
name: 'email',
placeholder: 'Dirección de e-mail',
required: true,
type: 'email',
},
{
name: 'password',
placeholder: 'Contraseña',
required: true,
minLength: 8,
type: 'password',
},
{ type: 'submit', content: 'Crear cuenta' },
],
}
},
components: {
Field,
CustomButton,
CustomForm,
},
methods: {
crearCuenta(event) {
const { nick, email, password } = this
const userData = { nick, email, password }
this.loading = true
this.errors = {}
this.$store
handleSubmit(userData) {
return this.$store
.dispatch('crearCuenta', userData)
.then(res => this.$router.replace('/'))
.catch(errors => (this.errors = errors))
.finally(() => (this.loading = false))
},
parseError: error => error, // probablemente no pase ningun error generico
},
}
</script>
<style scoped>
.error {
color: red;
}
.crear-cuenta {