77 lines
3.7 KiB
PHP
77 lines
3.7 KiB
PHP
@props(['members' => [], 'readonly' => false])
|
|
|
|
@php
|
|
$initial = collect(old('members_present') ? old('members', []) : (collect($members)->map(fn ($m) => [
|
|
'user_id' => $m->id,
|
|
'name' => $m->name,
|
|
'role' => $m->pivot->role,
|
|
])->all()))->map(fn ($m) => [
|
|
'user_id' => $m['user_id'] ?? '',
|
|
'name' => $m['name'] ?? ('User #' . ($m['user_id'] ?? '')),
|
|
'role' => $m['role'] ?? '',
|
|
])->values()->all();
|
|
$input = 'block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm';
|
|
@endphp
|
|
|
|
<!-- Team members -->
|
|
@if($readonly)
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Team members</label>
|
|
<p class="mt-1 text-sm text-gray-500">Only the submitter or an admin can change the team.</p>
|
|
<ul class="mt-2 space-y-1">
|
|
@forelse($initial as $m)
|
|
<li class="text-sm text-gray-900">{{ $m['name'] }} <span class="text-gray-500">- {{ $m['role'] }}</span></li>
|
|
@empty
|
|
<li class="text-sm text-gray-500">No team members.</li>
|
|
@endforelse
|
|
</ul>
|
|
</div>
|
|
@else
|
|
<div x-data="{
|
|
members: @js($initial),
|
|
q: '',
|
|
results: [],
|
|
timer: null,
|
|
search() {
|
|
clearTimeout(this.timer);
|
|
if (this.q.trim().length < 2) { this.results = []; return; }
|
|
this.timer = setTimeout(async () => {
|
|
const res = await fetch(@js(route('users.search')) + '?q=' + encodeURIComponent(this.q.trim()), { headers: { 'Accept': 'application/json' } });
|
|
this.results = res.ok ? (await res.json()).filter(u => !this.members.some(m => String(m.user_id) === String(u.id))) : [];
|
|
}, 300);
|
|
},
|
|
add(u) {
|
|
this.members.push({ user_id: u.id, name: u.name, role: '' });
|
|
this.q = ''; this.results = [];
|
|
}
|
|
}">
|
|
<input type="hidden" name="members_present" value="1">
|
|
<label class="block text-sm font-medium text-gray-700">Team members</label>
|
|
<div class="relative mt-2">
|
|
<input type="text" x-model="q" @input="search()" placeholder="Search users by name" autocomplete="off" class="{{ $input }}">
|
|
<ul x-show="results.length" x-cloak class="absolute z-10 mt-1 w-full bg-white border border-gray-200 rounded-md shadow-lg">
|
|
<template x-for="u in results" :key="u.id">
|
|
<li><button type="button" @click="add(u)" class="w-full text-left px-3 py-2 text-sm hover:bg-gray-50" x-text="u.name"></button></li>
|
|
</template>
|
|
</ul>
|
|
</div>
|
|
<div class="mt-3 space-y-3">
|
|
<template x-for="(member, i) in members" :key="member.user_id">
|
|
<div class="grid grid-cols-1 sm:grid-cols-12 gap-2 p-3 border border-gray-200 rounded-md items-center">
|
|
<input type="hidden" :name="`members[${i}][user_id]`" :value="member.user_id">
|
|
<input type="hidden" :name="`members[${i}][name]`" :value="member.name">
|
|
<span class="sm:col-span-4 text-sm text-gray-900" x-text="member.name"></span>
|
|
<input type="text" :name="`members[${i}][role]`" x-model="member.role" placeholder="Role (e.g. Designer)" maxlength="100" class="{{ $input }} sm:col-span-7">
|
|
<button type="button" @click="members.splice(i, 1)" class="sm:col-span-1 text-sm text-red-600 hover:text-red-800">Remove</button>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
@foreach($errors->get('members.*') as $messages)
|
|
<p class="mt-2 text-sm text-red-600">{{ $messages[0] }}</p>
|
|
@endforeach
|
|
@error('members')
|
|
<p class="mt-2 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
@endif
|