Created
June 4, 2018 20:40
-
-
Save iErik/2863f6b1952c75a85ff1404b4d1f733e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<c-card | |
:title="accountName ? `Exclusivo de ${accountName}` : ''"> | |
<c-toggle | |
class="input" | |
v-if="!data.id" | |
:labels="{ checked: 'Ativa', unchecked: 'Inativa'}" | |
:value="data.status" | |
height="30" | |
width="80" | |
sync | |
@input="v => data.status = v" | |
slot="action" /> | |
<c-form | |
autocomplete="new-password" | |
id="perk" | |
class="new-perk-form" | |
@submit.prevent> | |
<c-title size="3">Informações</c-title> | |
<div class="half -left"> | |
<!-- name required --> | |
<c-input | |
required | |
name="nome" | |
v-model="data.name" | |
v-validate="'required'" | |
label="Nome do parceiro" | |
:feedback-show="errors.has('nome')" | |
:feedback-message="errors.first('nome')" /> | |
<!-- colors --> | |
<c-input | |
type="color" | |
name="cor" | |
required | |
v-model="data.colors.primary" | |
v-validate="'required'" | |
:feedback-show="errors.has('cor')" | |
:feedback-message="errors.first('cor')" | |
label="Cor" /> | |
<!-- logo --> | |
<div class="inline"> | |
<c-input | |
type="file" | |
file-accept="image/*" | |
:file-label="computedFileLabel" | |
v-model="data.logo" | |
@change.native="e => previewLogo(e, 'logoSrc')" | |
label="Logo (5:4, mín. de 100:80)" | |
/> | |
<c-button | |
:disabled="!logoSrc" | |
:popover-label="`<img style='height: 100%; width: 100px; object-fit: contain' src='${logoSrc}' />`" | |
alternative | |
type="button" | |
size="lg" | |
icon="file-preview"> | |
Preview | |
</c-button> | |
</div> | |
<!-- logo --> | |
<div class="inline"> | |
<c-input | |
type="file" | |
file-accept="image/png" | |
:file-label="computedNegativeFileLabel" | |
v-model="data.logo_negative" | |
@change.native="e => previewLogo(e, 'negativeLogoSrc')" | |
label="Logo negativo (5:4, mín. de 100:80, PNG transparente)" | |
/> | |
<c-button | |
:disabled="!negativeLogoSrc" | |
:popover-label="` | |
<div style='background-color: ${data.colors.primary}'> | |
<img | |
style=' | |
background-color: transparent; | |
height: 100%; width: 100px; | |
object-fit: contain;' | |
src='${negativeLogoSrc}' | |
/> | |
</div> | |
`" | |
alternative | |
type="button" | |
size="lg" | |
icon="file-preview"> | |
Preview | |
</c-button> | |
</div> | |
<c-input | |
name="cnpj" | |
v-model="data.cnpj" | |
:value="data.cnpj" | |
@input="cnpj => data.cnpj = cnpj.replace(/\D/g, '')" | |
:mask="['##.###.###/####-##']" | |
label="CNPJ" | |
/> | |
</div> | |
<div class="half"> | |
<!-- is_main --> | |
<c-toggle | |
form-label="Principal" | |
:labels="{ checked: 'É principal', unchecked: 'Não é principal'}" | |
:value="!!data.is_main" | |
@input="v => data.is_main = +v" | |
width="140" /> | |
<!-- description required --> | |
<c-input | |
text-area | |
maxlength="200" | |
required | |
v-model="data.description" | |
name="sobre" | |
v-validate="'required|max:200'" | |
:feedback-show="errors.has('sobre')" | |
:feedback-message="errors.first('sobre')" | |
:label="`Sobre o parceiro (${computedDescriptionLength})`" /> | |
<!-- observation --> | |
<c-input | |
text-area | |
maxlength="140" | |
name="observacoes" | |
v-validate="'max:140'" | |
rows="4" | |
:feedback-show="errors.has('observacoes')" | |
:feedback-message="errors.first('observacoes')" | |
v-model="data.observation" | |
:label="`Observações (${computedObservationLength})`" /> | |
<!-- categories (Array de ids) --> | |
<c-select | |
:options="availableCategories" | |
:multiple="true" | |
:disabled="isFetchingCategories" | |
label="label" | |
track-by="value" | |
required | |
:feedback-show="!data.categories.length" | |
:feedback-message="'O campo categorias é obrigatório.'" | |
:value="computedCategories" | |
@input="v => updateCategories(v)" | |
form-label="Categorias" /> | |
</div> | |
<c-title size="3">Contato</c-title> | |
<div class="half -left"> | |
<!-- contact.name --> | |
<c-input | |
label="Nome" | |
required | |
name="nomeContato" | |
v-validate="'required'" | |
:feedback-show="errors.has('nomeContato')" | |
:feedback-message="errors.first('nomeContato')" | |
v-model="data.contact.name" /> | |
<!-- contact.phone --> | |
<c-input | |
label="Telefone" | |
placeholder="(DDD) + Número" | |
:mask="['(##) ####-####', '(##) ####-#####']" | |
v-model="data.contact.phone" /> | |
<!-- contact.email --> | |
<c-input | |
label="Email" | |
type="email" | |
v-validate="'email'" | |
name="emailContato" | |
:feedback-show="errors.has('emailContato')" | |
:feedback-message="errors.first('emailContato')" | |
v-model="data.contact.email" /> | |
</div> | |
<!-- contract --> | |
<div class="half"> | |
<c-input | |
type="file" | |
v-model="data.contract" | |
file-label="Escolher arquivo" | |
label="Importar contrato" /> | |
</div> | |
</c-form> | |
<c-form @submit.prevent class="new-perk-form"> | |
<!-- address (Array de objetos) --> | |
<c-title size="3">Endereço</c-title> | |
<section class="manual-address"> | |
<input type="hidden" :value="newAddress.id" /> | |
<!-- code required --> | |
<c-input | |
label="CEP" | |
:mask="['#####-###']" | |
type="text" | |
name="cep" | |
@keyup="fillAddress" | |
v-validate="newAddress.code ? 'required' : ''" | |
:required="!!newAddress.code" | |
:feedback-show="errors.has('cep')" | |
:feedback-message="errors.first('cep')" | |
v-model="newAddress.code" /> | |
<div class="inline"> | |
<!-- street required --> | |
<c-input | |
label="Endereço" | |
type="text" | |
name="endereço" | |
v-validate="newAddress.code ? 'required' : ''" | |
:required="!!newAddress.code" | |
:feedback-show="errors.has('endereço')" | |
:feedback-message="errors.first('endereço')" | |
v-model="newAddress.street" /> | |
<!-- number required --> | |
<c-input | |
label="Número" | |
type="text" | |
name="numero" | |
v-validate="newAddress.code ? 'required' : ''" | |
:required="!!newAddress.code" | |
:feedback-show="errors.has('numero')" | |
:feedback-message="errors.first('numero')" | |
v-model="newAddress.number" /> | |
</div> | |
<div class="inline"> | |
<!-- complement --> | |
<c-input | |
label="Complemento" | |
type="text" | |
v-model="newAddress.complement" /> | |
<!-- lat --> | |
<c-input | |
label="Latitude" | |
type="text" | |
v-model="newAddress.latitude" /> | |
<!-- long --> | |
<c-input | |
label="Longitude" | |
type="text" | |
v-model="newAddress.longitude" /> | |
</div> | |
<!-- neighborhood required --> | |
<c-input | |
label="Bairro" | |
type="text" | |
name="bairro" | |
v-validate="newAddress.code ? 'required' : ''" | |
:required="!!newAddress.code" | |
:feedback-show="errors.has('bairro')" | |
:feedback-message="errors.first('bairro')" | |
v-model="newAddress.neighborhood" /> | |
<div class="inline"> | |
<!-- state required --> | |
<c-input | |
label="Estado" | |
type="text" | |
name="estado" | |
v-validate="newAddress.code ? 'required' : ''" | |
:required="!!newAddress.code" | |
:feedback-show="errors.has('estado')" | |
:feedback-message="errors.first('estado')" | |
v-model="newAddress.state" /> | |
<!-- city --> | |
<c-input | |
label="Cidade" | |
type="text" | |
name="cidade" | |
v-validate="newAddress.code ? 'required' : ''" | |
:required="!!newAddress.code" | |
:feedback-show="errors.has('cidade')" | |
:feedback-message="errors.first('cidade')" | |
v-model="newAddress.city" /> | |
</div> | |
<c-button | |
icon="plus" | |
:disabled="isNewAddressInvalid" | |
@click="saveAddress"> | |
<template v-if="data.address.length">Adicionar à lista ({{data.address.length}})</template> | |
<template v-else>Adicionar outro</template> | |
</c-button> | |
</section> | |
<c-table v-if="data.address.length" | |
@select="v => selectedAddress = v" | |
:cols="addressCols" | |
:rows="data.address"> | |
<template | |
slot="row" | |
slot-scope="{ row, index }"> | |
<td class="c-table-cell -content c-table-text">{{ row.street }}</td> | |
<td class="c-table-cell -content c-table-text">{{ row.number }}</td> | |
<td class="c-table-cell -content c-table-text">{{ row.complement }}</td> | |
<td class="c-table-cell -content c-table-text">{{ row.neighborhood }}</td> | |
<td class="c-table-cell -content c-table-text">{{ row.state }}</td> | |
<td class="c-table-cell -content c-table-text">{{ row.city }}</td> | |
<td class="c-table-cell -content c-table-text"> | |
<c-button alternative size="lg" icon="pencil" | |
@click="editAddress(row, index)" | |
popover-label="Editar" /> | |
<c-button alternative size="lg" icon="trash" | |
@click="removeAddress(index)" | |
popover-label="Apagar" /> | |
</td> | |
</template> | |
</c-table> | |
<c-button | |
alternative | |
@click="$router.push({ name: 'Parceiro', params: $route.params })" | |
formname="perk" | |
slot="actions" | |
type="reset"> | |
Cancelar | |
</c-button> | |
<c-button | |
slot="actions" | |
:disabled="!data.categories.length || isProcessing || isFormInvalid" | |
@click="emitSubmit" | |
formname="perk" | |
icon="floppy-disk" | |
type="button"> | |
Salvar | |
</c-button> | |
</c-form> | |
</c-card> | |
</template> | |
<script> | |
import { validate } from 'vue-convenia-util' | |
import * as types from '@store/types' | |
import cep from 'cep-promise' | |
const ADDRESS_TEMPLATE = { | |
id: '', | |
code: '', | |
street: '', | |
number: '', | |
complement: '', | |
latitude: '', | |
longitude: '', | |
neighborhood: '', | |
state: '', | |
city: '' | |
} | |
const PERK_TEMPLATE = { | |
id: null, | |
name: '', | |
is_main: false, | |
logo: '', | |
cnpj: '', | |
logo_negative: '', | |
description: '', | |
categories: [], | |
notify: false, | |
colors: { | |
primary: '' | |
}, | |
contact: { | |
name: '', | |
phone: '', | |
email: '' | |
}, | |
address: [], | |
status: true | |
} | |
const checkFields = (names) => function () { | |
const checkField = (name) => this.fields[name] && this.fields[name].invalid | |
const checked = names.some(checkField) | |
return checked | |
} | |
export default { | |
props: { | |
currentPerk: { | |
type: Object, | |
default: () => {} | |
}, | |
availableCategories: { | |
type: Array, | |
default: () => [] | |
}, | |
isFetchingCategories: Boolean, | |
isProcessing: Boolean, | |
accountName: String | |
}, | |
data () { | |
return { | |
logoSrc: '', | |
negativeLogoSrc: '', | |
newAddress: { ...ADDRESS_TEMPLATE }, | |
selectedAddress: '', | |
addressCols: [ | |
{ label: 'Endereço' }, | |
{ label: 'Número' }, | |
{ label: 'Comp.' }, | |
{ label: 'Bairro' }, | |
{ label: 'Estado' }, | |
{ label: 'Cidade' }, | |
{ label: 'Ações' } | |
], | |
data: this.currentPerk && Object.keys(this.currentPerk).length ? { | |
...PERK_TEMPLATE, | |
...this.currentPerk, | |
colors: { | |
...PERK_TEMPLATE.colors, | |
...this.currentPerk.colors | |
}, | |
contact: { | |
...PERK_TEMPLATE.contact, | |
...this.currentPerk.contact | |
}, | |
address: [ | |
...PERK_TEMPLATE.address, | |
...this.currentPerk.address | |
], | |
categories: [ | |
...PERK_TEMPLATE.categories, | |
...this.currentPerk.categories | |
] | |
} : { | |
...PERK_TEMPLATE, | |
colors: { ...PERK_TEMPLATE.colors }, | |
contact: { ...PERK_TEMPLATE.contact }, | |
address: [ ...PERK_TEMPLATE.address ], | |
categories: [ ...PERK_TEMPLATE.categories ] | |
} | |
} | |
}, | |
computed: { | |
computedDescriptionLength () { | |
return 200 - (this.data.description ? this.data.description.length : 0) | |
}, | |
computedObservationLength () { | |
return 140 - (this.data.observation ? this.data.observation.length : 0) | |
}, | |
computedCategories () { | |
return this.data.categories.map(it => { | |
return { | |
label: it.name, | |
value: it.id | |
} | |
}) | |
}, | |
computedFileLabel () { | |
if (validate.is(this.data.logo, 'String') && this.data.logo.length > 1) { | |
this.logoSrc = this.data.logo | |
return 'Trocar foto' | |
} | |
return 'Escolher foto' | |
}, | |
computedNegativeFileLabel () { | |
if (validate.is(this.data.logo_negative, 'String') && this.data.logo_negative.length > 1) { | |
this.negativeLogoSrc = this.data.logo_negative | |
return 'Trocar foto' | |
} | |
return 'Escolher foto' | |
}, | |
isInformationInvalid: checkFields(['nome', 'sobre', 'observacoes', 'cor']), | |
isContactInvalid: checkFields(['nomeContato', 'emailContato']), | |
isNewAddressInvalid () { | |
// return this.hasAddress ? false : ['cep', 'endereço', 'numero', 'bairro', 'estado', 'cidade'].some(field => this.fields[field].invalid) | |
return false | |
}, | |
isFormInvalid () { | |
return this.isInformationInvalid || this.isContactInvalid || this.isNewAddressInvalid | |
}, | |
hasAddress () { | |
return this.data.address.length >= 1 | |
} | |
}, | |
methods: { | |
updateCategories (categories) { | |
this.data.categories = categories.map(it => { | |
return { | |
name: it.label, | |
id: it.value | |
} | |
}) | |
}, | |
async emitSubmit () { | |
const result = await this.$validator.validateAll() | |
const action = this.$route.params.perkId ? 'update' : 'create' | |
const isMain = this.data.is_main ? 1 : 0 | |
const status = this.data.status ? 1 : 0 | |
const payload = { ...this.data, is_main: isMain, status } | |
if (action === 'update' && !(payload.logo instanceof File)) { | |
delete payload.logo | |
} | |
if (action === 'update' && !(payload.logo_negative instanceof File)) { | |
delete payload.logo_negative | |
} | |
payload.categories = payload.categories.map(it => it.id) | |
if (result) { | |
if (this.newAddress.code && !this.isNewAddressInvalid) { | |
payload.address.push(this.newAddress) | |
} | |
this.$emit(action, payload) | |
} else this.$store.dispatch(types.NOTIFICATIONS_INCLUDE, Error('Verifique os campos preenchidos.')) | |
}, | |
previewLogo (event, src) { | |
const input = event.target | |
if (input.files && input.files[0]) { | |
const reader = new FileReader() | |
reader.onload = e => { | |
this[src] = e.target.result | |
} | |
reader.readAsDataURL(input.files[0]) | |
} | |
}, | |
async fillAddress () { | |
if (this.newAddress.code.length <= 8) return | |
const response = await cep(this.newAddress.code.replace('-', '')) | |
this.newAddress = { ...this.newAddress, ...response } | |
this.$nextTick(() => { | |
['endereço', 'bairro', 'estado', 'cidade'].forEach(field => { | |
this.$validator.validate(field) | |
}) | |
}) | |
}, | |
editAddress (data, index) { | |
this.newAddress = { ...data } | |
this.data.address.splice(index, 1) | |
this.$nextTick(() => { | |
['cep', 'endereço', 'numero', 'bairro', 'estado', 'cidade'].forEach(field => { | |
this.$validator.validate(field) | |
}) | |
}) | |
}, | |
removeAddress (index) { | |
this.data.address.splice(index, 1) | |
this.clearAddressValidator() | |
}, | |
saveAddress () { | |
this.data.address.push({ ...this.newAddress }) | |
this.clearAddressValidator() | |
this.newAddress = { ...ADDRESS_TEMPLATE } | |
}, | |
clearAddressValidator () { | |
['cep', 'endereço', 'numero', 'bairro', 'estado', 'cidade'].forEach(key => { | |
this.$validator.flag(key, { | |
dirty: false, | |
invalid: true, | |
pending: false, | |
pristine: true, | |
required: true, | |
touched: false, | |
untouched: true, | |
valid: false, | |
validated: false | |
}) | |
}) | |
} | |
} | |
} | |
</script> | |
<style lang="scss"> | |
.new-perk-form { | |
display: flex; | |
flex-flow: row wrap; | |
& > .half { | |
flex: 0 50%; | |
padding-left: inner-base(); | |
&.-left { | |
padding-left: 0; | |
padding-right: inner-base(); | |
} | |
& > .c-input, | |
& > .c-toggle, | |
& > .c-select, | |
& > .inline { | |
margin-bottom: inner-base(); | |
} | |
& > .c-select + .c-input { | |
position: relative; | |
top: -2px; | |
} | |
@include medium-down { | |
flex: 0 100%; | |
padding-left: 0; | |
&.-left { | |
padding-right: 0; | |
} | |
} | |
& > .inline { | |
display: flex; | |
flex-flow: row wrap; | |
align-items: flex-end; | |
.c-input { | |
flex: 1; | |
.input-label { | |
overflow: hidden; | |
} | |
} | |
.c-button { | |
flex: 0 100px; | |
margin-left: inner-base(); | |
& > .c-popover { | |
z-index: 3; | |
} | |
} | |
} | |
} | |
& > .c-title, | |
& > .manual-address, | |
& > .actions { | |
flex: 0 100%; | |
width: 100%; | |
} | |
} | |
.manual-address { | |
& > .inline { | |
display: flex; | |
flex-flow: row wrap; | |
& > .c-input { | |
flex: 1; | |
margin-left: inner-base(); | |
&:first-child { margin-left: 0; } | |
} | |
} | |
& > .inline, | |
& > .c-input { | |
margin-bottom: inner-base(); | |
} | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment