Browse Source

Implementa edição de associados

master
Guilherme Capanema 6 years ago
parent
commit
f9396f0211
11 changed files with 487 additions and 261 deletions
  1. +103
    -0
      app/Http/Livewire/Collaborators/Associates/Edit.php
  2. +3
    -1
      resources/lang/pt-BR.json
  3. +3
    -0
      resources/lang/pt-BR/associates.php
  4. +1
    -0
      resources/svg/breadcrumb-separator.svg
  5. +1
    -245
      resources/views/livewire/associates/auth/register/individual.blade.php
  6. +245
    -0
      resources/views/livewire/associates/partials/forms/individual.blade.php
  7. +52
    -0
      resources/views/livewire/collaborators/associates/edit.blade.php
  8. +22
    -13
      resources/views/livewire/collaborators/associates/index.blade.php
  9. +25
    -2
      resources/views/livewire/collaborators/associates/show.blade.php
  10. +4
    -0
      routes/web.php
  11. +28
    -0
      tests/Feature/Collaborators/Associates/EditTest.php

+ 103
- 0
app/Http/Livewire/Collaborators/Associates/Edit.php View File

@ -0,0 +1,103 @@
<?php
namespace App\Http\Livewire\Collaborators\Associates;
use App\Associate;
use Carbon\Carbon;
use Illuminate\Validation\Rule;
use Livewire\Component;
class Edit extends Component
{
/** @var string */
public $name;
/** @var string */
public $birthday;
/** @var array */
public $document;
/** @var array */
public $address;
/** @var array */
public $profile;
/** @var string */
public $email;
/** @var string */
public $discussion;
/** @var int */
public $contribution;
/** \App\Associate */
public $associate;
public function mount(Associate $associate)
{
$this->associate = $associate;
$this->name = $associate->name;
$this->birthday = $associate->birthday->format('d/m/Y');
$this->document = $associate->document;
$this->address = $associate->address;
$this->profile = $associate->profile;
$this->email = $associate->email;
$this->discussion = $associate->discussion;
$this->contribution = $associate->contribution;
}
public function save()
{
$this->validate([
'address.city' => ['required', 'string'],
'address.complement' => ['nullable', 'string'],
'address.country' => ['required', 'string'],
'address.neighbourhood' => ['required', 'string'],
'address.number' => ['required', 'string'],
'address.postcode' => ['required', 'string'],
'address.state' => ['required', 'string'],
'address.street' => ['required', 'string'],
'birthday' => ['required', 'date_format:d/m/Y'],
'contribution' => ['required', 'numeric'],
'discussion' => ['required', 'string', 'in:all,daily,occasional'],
'document.number' => ['required', 'string'],
'document.type' => ['required', 'string', 'in:cpf,identity,passport'],
'email' => ['required', 'email', Rule::unique('associates')->ignore($this->associate->id)],
'name' => ['required'],
'profile.bike_activities' => ['nullable', 'string'],
'profile.bike_use' => ['nullable', 'string'],
'profile.comments' => ['nullable', 'string'],
'profile.expectation' => ['nullable', 'string'],
'profile.gender' => ['required', 'string', 'in:male,female,other'],
'profile.occupation' => ['required', 'string'],
'profile.org_participation' => ['nullable', 'string'],
'profile.phone' => ['required', 'string'],
'profile.scholarity' => ['required', 'string', 'in:primary-school,high-school,bachelor,master,phd'],
'profile.secondary_emails' => ['nullable', 'string'],
'profile.social' => ['nullable', 'string'],
'profile.ucb_comments' => ['nullable', 'string'],
'profile.website' => ['nullable', 'string'],
]);
$this->associate->update([
'address' => $this->address,
'birthday' => Carbon::createFromFormat('d/m/Y', $this->birthday),
'contribution' => $this->contribution,
'discussion' => $this->discussion,
'document' => $this->document,
'email' => $this->email,
'name' => $this->name,
'profile' => $this->profile,
]);
session()->flash('notify-saved');
}
public function render()
{
return view('livewire.collaborators.associates.edit');
}
}

+ 3
- 1
resources/lang/pt-BR.json View File

@ -1,5 +1,7 @@
{ {
"Search:": "Buscar:", "Search:": "Buscar:",
"Show": "Mostrar", "Show": "Mostrar",
"entries": "registros"
"entries": "registros",
"Save": "Salvar",
"Saved": "Salvo"
} }

+ 3
- 0
resources/lang/pt-BR/associates.php View File

@ -2,6 +2,9 @@
return [ return [
'model' => 'Associados', 'model' => 'Associados',
'index' => 'Índice',
'show' => 'Dados do associado',
'edit' => 'Editar associado',
'attributes' => [ 'attributes' => [
'category' => 'Categoria', 'category' => 'Categoria',
'nature' => 'Natureza', 'nature' => 'Natureza',


+ 1
- 0
resources/svg/breadcrumb-separator.svg View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"/></svg>

+ 1
- 245
resources/views/livewire/associates/auth/register/individual.blade.php View File

@ -18,250 +18,7 @@
<form wire:submit.prevent="register" class="max-w-7xl mx-auto"> <form wire:submit.prevent="register" class="max-w-7xl mx-auto">
<div class="flex flex-wrap pt-8 border-t border-gray-200 mt-8">
<div class="lg:pr-6 w-full lg:w-1/3">
<h2 class="text-2xl font-medium">
Informações pessoais
</h2>
<p class="text-gray-400 mt-2">
Conte-nos um pouco sobre você.
</p>
</div>
<div class="lg:pl-6 w-full lg:w-2/3">
<div class="px-4 py-8 bg-white shadow sm:rounded-lg sm:px-10 space-y-6">
<x-input.group label="{{ __('associates.attributes.name') }}" for="name" :error="$errors->first('name')">
<x-input.text wire:model.lazy="name" id="name" :state="$errors->has('name') ? false : null" required autofocus />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.birthday') }}" for="birthday" :error="$errors->first('birthday')">
<x-input.text wire:model.lazy="birthday" id="birthday" mask="date" placeholder="dd/mm/yyyy" :state="$errors->has('birthday') ? false : null" required />
</x-input.group>
<x-input.radio-group label="{{ __('associates.attributes.profile.gender') }}" :inline="true" :error="$errors->first('profile.gender')">
<x-input.radio wire:model.lazy="profile.gender" name="profile-gender" label="Homem" value="male" :state="$errors->has('profile.gender') ? false : null" required />
<x-input.radio wire:model.lazy="profile.gender" name="profile-gender" label="Mulher" value="female" :state="$errors->has('profile.gender') ? false : null" required />
<x-input.radio wire:model.lazy="profile.gender" name="profile-gender" label="Outro" value="other" :state="$errors->has('profile.gender') ? false : null" required />
</x-input-radio-group>
<div class="flex flex-wrap -mx-2">
<x-input.group class="px-2 w-full lg:w-1/2 mt-6 lg:mt-0" label="{{ __('associates.attributes.document.type') }}" for="document-type" :error="$errors->first('document.type')">
<x-input.select wire:model.lazy="document.type" id="document-type">
<option value="cpf">CPF</option>
<option value="identity">Carteira de Identidade</option>
<option value="passport">Passaporte</option>
</x-input.select>
</x-input.group>
<x-input.group class="px-2 w-full lg:w-1/2 mt-6 lg:mt-0" label="{{ __('associates.attributes.document.number') }}" for="document-number" :error="$errors->first('document.number')">
<x-input.text wire:model.lazy="document.number" id="document-number" :state="$errors->has('document.number') ? false : null" required />
</x-input.group>
</div>
<x-input.group label="{{ __('associates.attributes.profile.occupation') }}" for="profile-occupation" :error="$errors->first('profile.occupation')">
<x-input.text wire:model.lazy="profile.occupation" id="profile-occupation" placeholder="Profissão ou ocupação principal" :state="$errors->has('profile.occupation') ? false : null" required />
</x-input.group>
<x-input.radio-group label="{{ __('associates.attributes.profile.scholarity') }}" :error="$errors->first('profile.scholarity')">
<x-input.radio wire:model.lazy="profile.scholarity" name="profile-scholarity" label="Ensino fundamental" value="primary-school" :state="$errors->has('profile.scholarity') ? false : null" required />
<x-input.radio wire:model.lazy="profile.scholarity" name="profile-scholarity" label="Ensino médio" value="high-school" :state="$errors->has('profile.scholarity') ? false : null" required />
<x-input.radio wire:model.lazy="profile.scholarity" name="profile-scholarity" label="Graduação" value="bachelor" :state="$errors->has('profile.scholarity') ? false : null" required />
<x-input.radio wire:model.lazy="profile.scholarity" name="profile-scholarity" label="Mestrado" value="master" :state="$errors->has('profile.scholarity') ? false : null" required />
<x-input.radio wire:model.lazy="profile.scholarity" name="profile-scholarity" label="Doutorado" value="phd" :state="$errors->has('profile.scholarity') ? false : null" required />
</x-input.radio-group>
</div>
</div>
</div>
<div class="flex flex-wrap pt-8 border-t border-gray-200 mt-8">
<div class="lg:pr-6 w-full lg:w-1/3">
<h2 class="text-2xl font-medium">
Dados de contato
</h2>
<p class="text-gray-400 mt-2">
Endereço e meios de comunicação digitais.
</p>
</div>
<div class="lg:pl-6 w-full lg:w-2/3">
<div class="px-4 py-8 bg-white shadow sm:rounded-lg sm:px-10 space-y-6">
<div x-data="{}" class="flex flex-wrap -mx-2">
<x-input.group class="px-2 w-full lg:w-1/2" label="{{ __('associates.attributes.address.country') }}" for="address-country" :error="$errors->first('address.country')">
<x-input.select wire:model="address.country" @input="document.getElementById('address-postcode').dispatchEvent(new Event('refreshMask', {detail: {mask: null}}))" id="address-country" :state="$errors->has('address.country') ? false : null" required>
@foreach (\App\Country::all() as $country)
<option value="{{ $country->code }}">{{ __('countries.' . $country->code) }}</option>
@endforeach
</x-input.select>
</x-input.group>
@if ($address['country'] === 'BR')
<x-input.group class="px-2 w-full lg:w-1/2" label="{{ __('associates.attributes.address.postcode') }}" for="address-postcode-masked" :error="$errors->first('address.postcode')">
<x-input.text wire:model.lazy="address.postcode" id="address-postcode-masked" mask="postcode" :state="$errors->has('address.postcode') ? false : null" required />
</x-input.group>
@else
<x-input.group class="px-2 w-full lg:w-1/2" label="{{ __('associates.attributes.address.postcode') }}" for="address-postcode" :error="$errors->first('address.postcode')">
<x-input.text wire:model.lazy="address.postcode" id="address-postcode" :state="$errors->has('address.postcode') ? false : null" required />
</x-input.group>
@endif
</div>
<x-input.group label="{{ __('associates.attributes.address.street') }}" for="address-street" :error="$errors->first('address.street')">
<x-input.text wire:model.lazy="address.street" wire:target="address.postcode" wire:loading.attr="disabled" id="address-street" :state="$errors->has('address.street') ? false : null" required />
</x-input.group>
<div class="flex flex-wrap -mx-2">
<x-input.group x-data="{}" class="px-2 w-full lg:w-1/4 mt-6 lg:mt-0" label="{{ __('associates.attributes.address.number') }}" for="address-number" :error="$errors->first('address.number')">
<x-input.text wire:model.lazy="address.number" @address-autofilled.window="$refs.addressNumber.focus()" x-ref="addressNumber" id="address-number" :state="$errors->has('address.number') ? false : null" required />
</x-input.group>
<x-input.group class="px-2 w-full lg:w-1/4" label="{{ __('associates.attributes.address.complement') }}" for="address-complement" :error="$errors->first('address.complement')">
<x-input.text wire:model.lazy="address.complement" id="address-complement" :state="$errors->has('address.complement') ? false : null" />
</x-input.group>
<x-input.group class="px-2 w-full lg:w-1/2 mt-6 lg:mt-0" label="{{ __('associates.attributes.address.neighbourhood') }}" for="address-neighbourhood" :error="$errors->first('address.neighbourhood')">
<x-input.text wire:model.lazy="address.neighbourhood" wire:target="address.postcode" wire:loading.attr="disabled" id="address-neighbourhood" :state="$errors->has('address.neighbourhood') ? false : null" required />
</x-input.group>
</div>
<div class="flex flex-wrap -mx-2">
<x-input.group class="px-2 w-full lg:w-1/2" label="{{ __('associates.attributes.address.city') }}" for="address-city" :error="$errors->first('address.city')">
<x-input.text wire:model.lazy="address.city" wire:target="address.postcode" wire:loading.attr="disabled" id="address-city" :state="$errors->has('address.city') ? false : null" required />
</x-input.group>
<x-input.group class="px-2 w-full lg:w-1/2 mt-6 lg:mt-0" label="{{ __('associates.attributes.address.state') }}" for="address-state" :error="$errors->first('address.state')">
<x-input.text wire:model.lazy="address.state" wire:target="address.postcode" wire:loading.attr="disabled" id="address-state" :state="$errors->has('address.state') ? false : null" required />
</x-input.group>
</div>
<x-input.group label="{{ __('associates.attributes.profile.phone') }}" for="profile-phone" :error="$errors->first('profile.phone')">
<x-input.text wire:model.lazy="profile.phone" id="profile-phone" mask="phone" :state="$errors->has('profile.phone') ? false : null" required />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.email') }}" for="email" :error="$errors->first('email')">
<x-input.email wire:model.lazy="email" id="email" :state="$errors->has('email') ? false : null" required />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.secondary_emails') }}" for="profile-secondary_emails" :error="$errors->first('profile.secondary_emails')">
<x-input.textarea wire:model.lazy="profile.secondary_emails" id="profile-secondary_emails" :state="$errors->has('profile.secondary_emails') ? false : null" />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.website') }}" for="profile-website" :error="$errors->first('profile.website')">
<x-input.text wire:model.lazy="profile.website" id="profile-website" :state="$errors->has('profile.website') ? false : null" />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.social') }}" for="profile-social" :error="$errors->first('profile.social')">
<x-input.text wire:model.lazy="profile.social" id="profile-social" :state="$errors->has('profile.social') ? false : null" />
</x-input.group>
</div>
</div>
</div>
<div class="flex flex-wrap pt-8 border-t border-gray-200 mt-8">
<div class="lg:pr-6 w-full lg:w-1/3">
<h2 class="text-2xl font-medium">
Dados de contato
</h2>
<p class="text-gray-400 mt-2">
Endereço e meios de comunicação digitais.
</p>
</div>
<div class="lg:pl-6 w-full lg:w-2/3">
<div class="px-4 py-8 bg-white shadow sm:rounded-lg sm:px-10 space-y-6">
<x-input.radio-group label="{{ __('associates.attributes.discussion') }}" :error="$errors->first('discussion')">
<x-input.radio wire:model.lazy="discussion" name="discussion" label="Participar da discussão (todos os e-mails)" value="all" :state="$errors->has('discussion') ? false : null" required />
<x-input.radio wire:model.lazy="discussion" name="discussion" label="Compilação da discussão (1 e-mail por dia)" value="daily" :state="$errors->has('discussion') ? false : null" required />
<x-input.radio wire:model.lazy="discussion" name="discussion" label="Notificações ocasionais da diretoria" value="occasional" :state="$errors->has('discussion') ? false : null" required />
</x-input.radio-group>
<x-input.group label="{{ __('associates.attributes.profile.expectation') }}" for="profile-expectation" :error="$errors->first('profile.expectation')">
<x-input.textarea wire:model.lazy="profile.expectation" id="profile-expectation" placeholder="O que você espera que UCB consiga ou faça: atuação, conquistas, pautas (descreva brevemente)?" :state="$errors->has('profile.expectation') ? false : null" />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.bike_use') }}" for="profile-bike_use" :error="$errors->first('profile.bike_use')">
<x-input.textarea wire:model.lazy="profile.bike_use" id="profile-bike_use" placeholder="Por quê e para quê usa a bicicleta? Descreva brevemente" :state="$errors->has('profile.bike_use') ? false : null" />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.org_participation') }}" for="profile-org_participation" :error="$errors->first('profile.org_participation')">
<x-input.textarea wire:model.lazy="profile.bike_use" id="profile-bike_use" placeholder="Você participa em associações ou coletivos de ciclistas que promovem a bicicleta? Quais? " :state="$errors->has('profile.bike_use') ? false : null" />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.bike_activities') }}" for="profile-bike_activities" :error="$errors->first('profile.bike_activities')">
<x-input.textarea wire:model.lazy="profile.bike_use" id="profile-bike_use" placeholder="Realiza atividades ou participa para promover a bicicleta (descreva brevemente)?" :state="$errors->has('profile.bike_use') ? false : null" />
</x-input.group>
<x-input.radio-group
x-data="{ custom_contribution: false }"
@click="custom_contribution = false"
label="{{ __('associates.attributes.contribution') }}"
for="contribution"
:error="$errors->first('contribution')"
>
<x-input.radio wire:model.lazy="contribution" name="contribution" label="Não desejo contribuir" value="0" :state="$errors->has('contribution') ? false : null" required />
<x-input.radio wire:model.lazy="contribution" name="contribution" label="R$ 15,00" value="15" :state="$errors->has('contribution') ? false : null" required />
<x-input.radio wire:model.lazy="contribution" name="contribution" label="R$ 30,00" value="30" :state="$errors->has('contribution') ? false : null" required />
<x-input.radio wire:model.lazy="contribution" name="contribution" label="R$ 60,00" value="60" :state="$errors->has('contribution') ? false : null" required />
<x-input.radio wire:model.lazy="contribution" name="contribution" label="R$ 120,00" value="120" :state="$errors->has('contribution') ? false : null" required />
<x-input.radio
name="contribution"
@click="
$event.stopPropagation();
custom_contribution = true;
$nextTick(() => { $refs.customContributionInput.focus() });
"
:state="$errors->has('contribution') ? false : null"
required
>
<span class="text-sm">Outro</span>
<x-input.text
wire:model.lazy="contribution"
x-ref="customContributionInput"
@click="$event.stopPropagation();"
x-show="custom_contribution"
id="contribution-other"
mask="currency"
:state="$errors->has('contribution') ? false : null"
/>
</x-input.radio>
</x-input.radio-group>
</div>
</div>
</div>
@include('livewire.associates.partials.forms.individual')
<div class="flex flex-wrap pt-8 border-t border-gray-200 mt-8"> <div class="flex flex-wrap pt-8 border-t border-gray-200 mt-8">
@ -296,7 +53,6 @@
</button> </button>
</span> </span>
</div> </div>
</form> </form>
</div> </div>

+ 245
- 0
resources/views/livewire/associates/partials/forms/individual.blade.php View File

@ -0,0 +1,245 @@
<div class="flex flex-wrap pt-8 border-t border-gray-200 mt-8">
<div class="lg:pr-6 w-full lg:w-1/3">
<h2 class="text-2xl font-medium">
Informações pessoais
</h2>
<p class="text-gray-400 mt-2">
Conte-nos um pouco sobre você.
</p>
</div>
<div class="lg:pl-6 w-full lg:w-2/3">
<div class="px-4 py-8 bg-white shadow sm:rounded-lg sm:px-10 space-y-6">
<x-input.group label="{{ __('associates.attributes.name') }}" for="name" :error="$errors->first('name')">
<x-input.text wire:model.lazy="name" id="name" :state="$errors->has('name') ? false : null" required autofocus />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.birthday') }}" for="birthday" :error="$errors->first('birthday')">
<x-input.text wire:model.lazy="birthday" id="birthday" mask="date" placeholder="dd/mm/yyyy" :state="$errors->has('birthday') ? false : null" required />
</x-input.group>
<x-input.radio-group label="{{ __('associates.attributes.profile.gender') }}" :inline="true" :error="$errors->first('profile.gender')">
<x-input.radio wire:model.lazy="profile.gender" name="profile-gender" label="Homem" value="male" :state="$errors->has('profile.gender') ? false : null" required />
<x-input.radio wire:model.lazy="profile.gender" name="profile-gender" label="Mulher" value="female" :state="$errors->has('profile.gender') ? false : null" required />
<x-input.radio wire:model.lazy="profile.gender" name="profile-gender" label="Outro" value="other" :state="$errors->has('profile.gender') ? false : null" required />
</x-input-radio-group>
<div class="flex flex-wrap -mx-2">
<x-input.group class="px-2 w-full lg:w-1/2 mt-6 lg:mt-0" label="{{ __('associates.attributes.document.type') }}" for="document-type" :error="$errors->first('document.type')">
<x-input.select wire:model.lazy="document.type" id="document-type">
<option value="cpf">CPF</option>
<option value="identity">Carteira de Identidade</option>
<option value="passport">Passaporte</option>
</x-input.select>
</x-input.group>
<x-input.group class="px-2 w-full lg:w-1/2 mt-6 lg:mt-0" label="{{ __('associates.attributes.document.number') }}" for="document-number" :error="$errors->first('document.number')">
<x-input.text wire:model.lazy="document.number" id="document-number" :state="$errors->has('document.number') ? false : null" required />
</x-input.group>
</div>
<x-input.group label="{{ __('associates.attributes.profile.occupation') }}" for="profile-occupation" :error="$errors->first('profile.occupation')">
<x-input.text wire:model.lazy="profile.occupation" id="profile-occupation" placeholder="Profissão ou ocupação principal" :state="$errors->has('profile.occupation') ? false : null" required />
</x-input.group>
<x-input.radio-group label="{{ __('associates.attributes.profile.scholarity') }}" :error="$errors->first('profile.scholarity')">
<x-input.radio wire:model.lazy="profile.scholarity" name="profile-scholarity" label="Ensino fundamental" value="primary-school" :state="$errors->has('profile.scholarity') ? false : null" required />
<x-input.radio wire:model.lazy="profile.scholarity" name="profile-scholarity" label="Ensino médio" value="high-school" :state="$errors->has('profile.scholarity') ? false : null" required />
<x-input.radio wire:model.lazy="profile.scholarity" name="profile-scholarity" label="Graduação" value="bachelor" :state="$errors->has('profile.scholarity') ? false : null" required />
<x-input.radio wire:model.lazy="profile.scholarity" name="profile-scholarity" label="Mestrado" value="master" :state="$errors->has('profile.scholarity') ? false : null" required />
<x-input.radio wire:model.lazy="profile.scholarity" name="profile-scholarity" label="Doutorado" value="phd" :state="$errors->has('profile.scholarity') ? false : null" required />
</x-input.radio-group>
</div>
</div>
</div>
<div class="flex flex-wrap pt-8 border-t border-gray-200 mt-8">
<div class="lg:pr-6 w-full lg:w-1/3">
<h2 class="text-2xl font-medium">
Dados de contato
</h2>
<p class="text-gray-400 mt-2">
Endereço e meios de comunicação digitais.
</p>
</div>
<div class="lg:pl-6 w-full lg:w-2/3">
<div class="px-4 py-8 bg-white shadow sm:rounded-lg sm:px-10 space-y-6">
<div x-data="{}" class="flex flex-wrap -mx-2">
<x-input.group class="px-2 w-full lg:w-1/2" label="{{ __('associates.attributes.address.country') }}" for="address-country" :error="$errors->first('address.country')">
<x-input.select wire:model="address.country" @input="document.getElementById('address-postcode').dispatchEvent(new Event('refreshMask', {detail: {mask: null}}))" id="address-country" :state="$errors->has('address.country') ? false : null" required>
@foreach (\App\Country::all() as $country)
<option value="{{ $country->code }}">{{ __('countries.' . $country->code) }}</option>
@endforeach
</x-input.select>
</x-input.group>
@if ($address['country'] === 'BR')
<x-input.group class="px-2 w-full lg:w-1/2" label="{{ __('associates.attributes.address.postcode') }}" for="address-postcode-masked" :error="$errors->first('address.postcode')">
<x-input.text wire:model.lazy="address.postcode" id="address-postcode-masked" mask="postcode" :state="$errors->has('address.postcode') ? false : null" required />
</x-input.group>
@else
<x-input.group class="px-2 w-full lg:w-1/2" label="{{ __('associates.attributes.address.postcode') }}" for="address-postcode" :error="$errors->first('address.postcode')">
<x-input.text wire:model.lazy="address.postcode" id="address-postcode" :state="$errors->has('address.postcode') ? false : null" required />
</x-input.group>
@endif
</div>
<x-input.group label="{{ __('associates.attributes.address.street') }}" for="address-street" :error="$errors->first('address.street')">
<x-input.text wire:model.lazy="address.street" wire:target="address.postcode" wire:loading.attr="disabled" id="address-street" :state="$errors->has('address.street') ? false : null" required />
</x-input.group>
<div class="flex flex-wrap -mx-2">
<x-input.group x-data="{}" class="px-2 w-full lg:w-1/4 mt-6 lg:mt-0" label="{{ __('associates.attributes.address.number') }}" for="address-number" :error="$errors->first('address.number')">
<x-input.text wire:model.lazy="address.number" @address-autofilled.window="$refs.addressNumber.focus()" x-ref="addressNumber" id="address-number" :state="$errors->has('address.number') ? false : null" required />
</x-input.group>
<x-input.group class="px-2 w-full lg:w-1/4" label="{{ __('associates.attributes.address.complement') }}" for="address-complement" :error="$errors->first('address.complement')">
<x-input.text wire:model.lazy="address.complement" id="address-complement" :state="$errors->has('address.complement') ? false : null" />
</x-input.group>
<x-input.group class="px-2 w-full lg:w-1/2 mt-6 lg:mt-0" label="{{ __('associates.attributes.address.neighbourhood') }}" for="address-neighbourhood" :error="$errors->first('address.neighbourhood')">
<x-input.text wire:model.lazy="address.neighbourhood" wire:target="address.postcode" wire:loading.attr="disabled" id="address-neighbourhood" :state="$errors->has('address.neighbourhood') ? false : null" required />
</x-input.group>
</div>
<div class="flex flex-wrap -mx-2">
<x-input.group class="px-2 w-full lg:w-1/2" label="{{ __('associates.attributes.address.city') }}" for="address-city" :error="$errors->first('address.city')">
<x-input.text wire:model.lazy="address.city" wire:target="address.postcode" wire:loading.attr="disabled" id="address-city" :state="$errors->has('address.city') ? false : null" required />
</x-input.group>
<x-input.group class="px-2 w-full lg:w-1/2 mt-6 lg:mt-0" label="{{ __('associates.attributes.address.state') }}" for="address-state" :error="$errors->first('address.state')">
<x-input.text wire:model.lazy="address.state" wire:target="address.postcode" wire:loading.attr="disabled" id="address-state" :state="$errors->has('address.state') ? false : null" required />
</x-input.group>
</div>
<x-input.group label="{{ __('associates.attributes.profile.phone') }}" for="profile-phone" :error="$errors->first('profile.phone')">
<x-input.text wire:model.lazy="profile.phone" id="profile-phone" mask="phone" :state="$errors->has('profile.phone') ? false : null" required />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.email') }}" for="email" :error="$errors->first('email')">
<x-input.email wire:model.lazy="email" id="email" :state="$errors->has('email') ? false : null" required />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.secondary_emails') }}" for="profile-secondary_emails" :error="$errors->first('profile.secondary_emails')">
<x-input.textarea wire:model.lazy="profile.secondary_emails" id="profile-secondary_emails" :state="$errors->has('profile.secondary_emails') ? false : null" />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.website') }}" for="profile-website" :error="$errors->first('profile.website')">
<x-input.text wire:model.lazy="profile.website" id="profile-website" :state="$errors->has('profile.website') ? false : null" />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.social') }}" for="profile-social" :error="$errors->first('profile.social')">
<x-input.text wire:model.lazy="profile.social" id="profile-social" :state="$errors->has('profile.social') ? false : null" />
</x-input.group>
</div>
</div>
</div>
<div class="flex flex-wrap pt-8 border-t border-gray-200 mt-8">
<div class="lg:pr-6 w-full lg:w-1/3">
<h2 class="text-2xl font-medium">
Dados de contato
</h2>
<p class="text-gray-400 mt-2">
Endereço e meios de comunicação digitais.
</p>
</div>
<div class="lg:pl-6 w-full lg:w-2/3">
<div class="px-4 py-8 bg-white shadow sm:rounded-lg sm:px-10 space-y-6">
<x-input.radio-group label="{{ __('associates.attributes.discussion') }}" :error="$errors->first('discussion')">
<x-input.radio wire:model.lazy="discussion" name="discussion" label="Participar da discussão (todos os e-mails)" value="all" :state="$errors->has('discussion') ? false : null" required />
<x-input.radio wire:model.lazy="discussion" name="discussion" label="Compilação da discussão (1 e-mail por dia)" value="daily" :state="$errors->has('discussion') ? false : null" required />
<x-input.radio wire:model.lazy="discussion" name="discussion" label="Notificações ocasionais da diretoria" value="occasional" :state="$errors->has('discussion') ? false : null" required />
</x-input.radio-group>
<x-input.group label="{{ __('associates.attributes.profile.expectation') }}" for="profile-expectation" :error="$errors->first('profile.expectation')">
<x-input.textarea wire:model.lazy="profile.expectation" id="profile-expectation" placeholder="O que você espera que UCB consiga ou faça: atuação, conquistas, pautas (descreva brevemente)?" :state="$errors->has('profile.expectation') ? false : null" />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.bike_use') }}" for="profile-bike_use" :error="$errors->first('profile.bike_use')">
<x-input.textarea wire:model.lazy="profile.bike_use" id="profile-bike_use" placeholder="Por quê e para quê usa a bicicleta? Descreva brevemente" :state="$errors->has('profile.bike_use') ? false : null" />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.org_participation') }}" for="profile-org_participation" :error="$errors->first('profile.org_participation')">
<x-input.textarea wire:model.lazy="profile.org_participation" id="profile-org_participation" placeholder="Você participa em associações ou coletivos de ciclistas que promovem a bicicleta? Quais? " :state="$errors->has('profile.org_participation') ? false : null" />
</x-input.group>
<x-input.group label="{{ __('associates.attributes.profile.bike_activities') }}" for="profile-bike_activities" :error="$errors->first('profile.bike_activities')">
<x-input.textarea wire:model.lazy="profile.bike_activities" id="profile-bike_activities" placeholder="Realiza atividades ou participa para promover a bicicleta (descreva brevemente)?" :state="$errors->has('profile.bike_activities') ? false : null" />
</x-input.group>
<x-input.radio-group
x-data="{ custom_contribution: false }"
@click="custom_contribution = false"
label="{{ __('associates.attributes.contribution') }}"
for="contribution"
:error="$errors->first('contribution')"
>
<x-input.radio wire:model.lazy="contribution" name="contribution" label="Não desejo contribuir" value="0" :state="$errors->has('contribution') ? false : null" required />
<x-input.radio wire:model.lazy="contribution" name="contribution" label="R$ 15,00" value="15" :state="$errors->has('contribution') ? false : null" required />
<x-input.radio wire:model.lazy="contribution" name="contribution" label="R$ 30,00" value="30" :state="$errors->has('contribution') ? false : null" required />
<x-input.radio wire:model.lazy="contribution" name="contribution" label="R$ 60,00" value="60" :state="$errors->has('contribution') ? false : null" required />
<x-input.radio wire:model.lazy="contribution" name="contribution" label="R$ 120,00" value="120" :state="$errors->has('contribution') ? false : null" required />
<x-input.radio
name="contribution"
@click="
$event.stopPropagation();
custom_contribution = true;
$nextTick(() => { $refs.customContributionInput.focus() });
"
:state="$errors->has('contribution') ? false : null"
required
>
<span class="text-sm">Outro</span>
<x-input.text
wire:model.lazy="contribution"
x-ref="customContributionInput"
@click="$event.stopPropagation();"
x-show="custom_contribution"
id="contribution-other"
mask="currency"
:state="$errors->has('contribution') ? false : null"
/>
</x-input.radio>
</x-input.radio-group>
</div>
</div>
</div>

+ 52
- 0
resources/views/livewire/collaborators/associates/edit.blade.php View File

@ -0,0 +1,52 @@
<div class="pt-2 pb-6">
<nav class="text-black font-bold" aria-label="Breadcrumb">
<ol class="list-none p-0 inline-flex">
<li class="flex items-center">
<span>
{{ __('associates.model') }}
</span>
@svg('breadcrumb-separator', 'fill-current w-3 h-3 mx-3')
</li>
<li class="flex items-center">
<a href="{{ route('collaborators.associates.index') }}">
{{ __('associates.index') }}
</a>
@svg('breadcrumb-separator', 'fill-current w-3 h-3 mx-3')
</li>
<li>
<a href="{{ route('collaborators.associates.edit', compact('associate')) }}" class="text-gray-500" aria-current="page">
{{ __('associates.edit') }}
</a>
</li>
</ol>
</nav>
<form wire:submit.prevent="save" class="max-w-7xl mx-auto mt-6">
@include('livewire.associates.partials.forms.individual')
<div class="flex items-center justify-end space-x-4 pt-12">
@if (session()->has('notify-saved'))
<span
x-data="{ open: true }"
x-init="setTimeout(() => { open = false }, 2500)"
x-show.transition.duration.1000ms="open"
class="text-gray-500"
>
{{ __('Saved') }}
</span>
@endif
<span class="block w-full lg:w-auto rounded-md shadow-sm">
<button type="submit" class="flex justify-center w-full px-16 py-2 text-sm font-medium text-white bg-green-600 border border-transparent rounded-md hover:bg-green-500 focus:outline-none focus:border-green-700 focus:shadow-outline-green active:bg-green-700 transition duration-150 ease-in-out">
{{ __('Save') }}
</button>
</span>
</div>
</form>
</div>

+ 22
- 13
resources/views/livewire/collaborators/associates/index.blade.php View File

@ -1,10 +1,22 @@
<div>
<h1 class="text-3xl font-bold">
{{ __('associates.model') }}
</h1>
<div class="flex items-center justify-between px-4 py-4 sm:px-6">
<div class="pt-2 pb-6">
<nav class="text-black font-bold" aria-label="Breadcrumb">
<ol class="list-none p-0 inline-flex">
<li class="flex items-center">
<span>
{{ __('associates.model') }}
</span>
@svg('breadcrumb-separator', 'fill-current w-3 h-3 mx-3')
</li>
<li>
<a href="{{ route('collaborators.associates.index') }}" class="text-gray-500" aria-current="page">
{{ __('associates.index') }}
</a>
</li>
</ol>
</nav>
<div class="flex items-center justify-between mt-4 py-4">
<label class="flex items-center"> <label class="flex items-center">
@ -109,7 +121,8 @@
</td> </td>
<td class="px-6 py-4 whitespace-no-wrap text-right border-b border-gray-200 text-sm leading-5 font-medium"> <td class="px-6 py-4 whitespace-no-wrap text-right border-b border-gray-200 text-sm leading-5 font-medium">
<a href="#" class="text-indigo-600 hover:text-indigo-900">Edit
<a href="{{ route('collaborators.associates.edit', compact('associate')) }}" class="text-indigo-600 hover:text-indigo-900">
{{ __('Edit') }}
</a> </a>
</td> </td>
@ -117,12 +130,8 @@
@endforeach @endforeach
</tbody> </tbody>
</table> </table>
{{ $associates->links() }}
</div> </div>
</div> </div>
</div> </div>
<div class="mt-4">
{{ $associates->links() }}
</div>
</div> </div>

+ 25
- 2
resources/views/livewire/collaborators/associates/show.blade.php View File

@ -1,5 +1,28 @@
<div>
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
<div class="pt-2 pb-6">
<nav class="text-black font-bold" aria-label="Breadcrumb">
<ol class="list-none p-0 inline-flex">
<li class="flex items-center">
<span>
{{ __('associates.model') }}
</span>
@svg('breadcrumb-separator', 'fill-current w-3 h-3 mx-3')
</li>
<li class="flex items-center">
<a href="{{ route('collaborators.associates.index') }}">
{{ __('associates.index') }}
</a>
@svg('breadcrumb-separator', 'fill-current w-3 h-3 mx-3')
</li>
<li>
<a href="{{ route('collaborators.associates.show', compact('associate')) }}" class="text-gray-500" aria-current="page">
{{ __('associates.show') }}
</a>
</li>
</ol>
</nav>
<div class="bg-white shadow overflow-hidden sm:rounded-lg mt-6">
<div class="flex items-center px-4 py-5 border-b border-gray-200 sm:px-6"> <div class="flex items-center px-4 py-5 border-b border-gray-200 sm:px-6">


+ 4
- 0
routes/web.php View File

@ -47,6 +47,10 @@ Route::prefix('admin')->name('collaborators.')->group(function () {
Route::livewire('associates/{associate}', 'collaborators.associates.show') Route::livewire('associates/{associate}', 'collaborators.associates.show')
->layout('layouts.collaborators') ->layout('layouts.collaborators')
->name('associates.show'); ->name('associates.show');
Route::livewire('associates/{associate}/edit', 'collaborators.associates.edit')
->layout('layouts.collaborators')
->name('associates.edit');
}); });
}); });


+ 28
- 0
tests/Feature/Collaborators/Associates/EditTest.php View File

@ -0,0 +1,28 @@
<?php
namespace Tests\Feature\Collaborators\Associates;
use App\Associate;
use App\Collaborator;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Livewire\Livewire;
use Tests\TestCase;
class EditTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function a_collaborator_can_view_edit_page()
{
$collaborator = factory(Collaborator::class)->create();
$this->be($collaborator, 'collaborators');
$associate = factory(Associate::class)->create();
$this->get(route('collaborators.associates.edit', compact('associate')))
->assertSuccessful()
->assertSeeLivewire('collaborators.associates.edit');
}
}