Files

316 lines
18 KiB
PHP

<div class="my-4">
<!-- Search/Filter Section -->
<form wire:submit.prevent="applySearch" class="mb-6">
<div class="flex flex-col md:flex-row md:space-x-12">
<div class="w-full md:w-2/4 md:flex-none space-y-4">
<div>
<x-jetstream.label for="search" value="{{ __('Keywords') }}" />
<x-jetstream.input :clearable="true" class="text-theme-primary placeholder-theme-light text-sm"
placeholder="{{ __('Search by name or location') }}" right-icon="search"
wire:model="searchInput" />
@error('search')
<div class="mb-3 text-sm text-red-700" role="alert">
{{ __($message) }}
</div>
@enderror
</div>
<div>
<x-jetstream.label for="filterType" value="{{ __('Select by interaction') }}" />
<x-select wire:model="filterTypeInput" multiselect placeholder="{{ __('All interactions') }}">
<x-select.option label="{{ __('Stars') }}" value="stars" />
<x-select.option label="{{ __('Bookmarks') }}" value="bookmarks" />
<x-select.option label="{{ __('Transactions') }}" value="transactions" />
<x-select.option label="{{ __('Conversations') }}" value="conversations" />
@if($showRoleColumn)
<x-select.option label="{{ __('Linked members') }}" value="linked" />
@endif
</x-select>
</div>
@if($showRoleColumn && count($availableRoles) > 0)
<div>
<x-jetstream.label for="filterRoleInput" value="{{ __(ucfirst(strtolower(getActiveProfileType())) . ' role') }}" />
<x-select wire:model="filterRoleInput" :clearable="true" placeholder="{{ __('Select role') }}">
<x-select.option label="{{ __('Any role') }}" value="any" />
@foreach($availableRoles as $roleKey => $roleLabel)
<x-select.option label="{{ $roleLabel }}" value="{{ $roleKey }}" />
@endforeach
</x-select>
</div>
@endif
</div>
</div>
<div class="mt-6 mb-6 md:mb-12 lg:mb-18">
<x-jetstream.secondary-button class="my-3" type="submit" wire:loading.attr="disabled" wire:target="applySearch">
<span wire:loading.remove wire:target="applySearch">{{ __('Search') }}</span>
<span wire:loading wire:target="applySearch">{{ __('Searching...') }}</span>
</x-jetstream.secondary-button>
<x-jetstream.secondary-button class="my-3 ml-4" wire:click.prevent="resetSearch" wire:loading.attr="disabled" wire:target="resetSearch">
{{ __('Clear all') }}
</x-jetstream.secondary-button>
</div>
</form>
<!-- General error section -->
@if (session('error'))
<div class="relative mt-6 rounded border border-red-400 bg-red-100 px-4 py-3 text-red-700" role="alert">
<strong class="font-bold">{{ __('Error') }}!</strong>
<span class="block sm:inline">{{ session('error') }}</span>
</div>
@endif
<!-- Results table -->
<div class="relative mb-6 mt-6">
<div wire:loading>
<span> {{ __('Loading...') }} </span>
</div>
</div>
<div class="bg-white shadow-sm rounded-lg" x-data="{
initScrollSync() {
if (this.$refs.topScroll && this.$refs.bottomScroll && this.$refs.table && this.$refs.topScrollContent) {
this.$refs.topScrollContent.style.width = this.$refs.table.scrollWidth + 'px';
}
}
}" x-init="setTimeout(() => initScrollSync(), 100)">
<!-- Top scrollbar -->
<div class="overflow-x-auto border-b border-gray-200" x-ref="topScroll" @scroll="$refs.bottomScroll.scrollLeft = $event.target.scrollLeft">
<div x-ref="topScrollContent" style="height: 20px;"></div>
</div>
<!-- Table with bottom scrollbar -->
<div class="overflow-x-auto" x-ref="bottomScroll" @scroll="$refs.topScroll.scrollLeft = $event.target.scrollLeft">
<table class="min-w-full divide-y divide-gray-200" id="contacts" x-ref="table">
<thead class="bg-gray-50">
<tr>
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 tracking-wider align-middle">
<button wire:click="sortBy('name')" class="uppercase flex items-center hover:text-gray-700 focus:outline-none">
{{ __('Contact') }}
@if($sortField === 'name')
<x-icon class="ml-1 h-4 w-4" name="{{ $sortAsc ? 'chevron-up' : 'chevron-down' }}" />
@endif
</button>
</th>
@if($showRoleColumn)
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 tracking-wider align-middle">
<button wire:click="sortBy('org_role')" class="uppercase flex items-center hover:text-gray-700 focus:outline-none">
{{ __('Role') }}
@if($sortField === 'org_role')
<x-icon class="ml-1 h-4 w-4" name="{{ $sortAsc ? 'chevron-up' : 'chevron-down' }}" />
@endif
</button>
</th>
@endif
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 tracking-wider align-middle">
<button wire:click="sortBy('has_star')" class="uppercase flex items-center hover:text-gray-700 focus:outline-none">
{{ __('Saved') }}
@if($sortField === 'has_star')
<x-icon class="ml-1 h-4 w-4" name="{{ $sortAsc ? 'chevron-up' : 'chevron-down' }}" />
@endif
</button>
</th>
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 tracking-wider align-middle">
<button wire:click="sortBy('transaction_count')" class="uppercase flex items-center hover:text-gray-700 focus:outline-none">
{{ __('Exchanges') }}
@if($sortField === 'transaction_count')
<x-icon class="ml-1 h-4 w-4" name="{{ $sortAsc ? 'chevron-up' : 'chevron-down' }}" />
@endif
</button>
</th>
<th class="px-3 py-3 text-right text-xs font-medium text-gray-500 tracking-wider align-middle hidden xl:table-cell">
<button wire:click="sortBy('last_interaction')" class="uppercase flex items-center justify-end ml-auto hover:text-gray-700 focus:outline-none">
{{ __('Last interaction') }}
@if($sortField === 'last_interaction')
<x-icon class="ml-1 h-4 w-4" name="{{ $sortAsc ? 'chevron-up' : 'chevron-down' }}" />
@endif
</button>
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
@if ($contacts && $contacts->count() > 0)
@foreach ($contacts as $contact)
<tr onclick="window.location='{{ url($contact['profile_path']) }}'"
class="cursor-pointer hover:bg-gray-50">
<td class="px-3 py-4 text-sm">
<div class="flex items-center">
<div class="flex-shrink-0">
<img alt="profile"
class="h-10 w-10 md:h-12 md:w-12 lg:h-16 lg:w-16 rounded-full profile-photo object-cover outline outline-1 outline-offset-0 outline-gray-600"
src="{{ Storage::url($contact['profile_photo']) }}" />
</div>
<div class="ml-3 min-w-0 flex-1">
<div class="text-sm font-medium text-gray-900 truncate">
{{ $contact['name'] }}
</div>
@if ($contact['full_name'] != $contact['name'])
<div class="text-xs text-gray-500 font-normal truncate">
{{ $contact['full_name'] }}
</div>
@endif
<div class="text-xs text-gray-500 font-normal truncate">
{{ $contact['location'] }}
</div>
@if($contact['profile_type_name'] === 'Organization')
<div class="text-xs font-normal mt-1">
<span class="bg-theme-brand px-1 text-gray-100">
{{ __('Organization') }}
</span>
</div>
@elseif($contact['profile_type_name'] === 'Bank')
<div class="text-xs font-normal mt-1">
<span class="bg-theme-brand px-1 text-gray-100">
{{ __('Bank') }}
</span>
</div>
@elseif($contact['profile_type_name'] === 'Admin')
<div class="text-xs font-normal mt-1">
<span class="bg-theme-brand px-1 text-gray-100">
{{ __('Admin') }}
</span>
</div>
@endif
</div>
</div>
</td>
@if($showRoleColumn)
<td class="px-3 py-4 text-sm text-gray-500" onclick="event.stopPropagation()">
@if(!empty($contact['org_role']))
<span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-700">
{{ $roleLabels[$contact['org_role']] ?? $contact['org_role'] }}
@if($authIsManager && str_ends_with($contact['org_role'], '-coordinator'))
<button type="button"
wire:click="confirmRemoveCoordinator({{ (int) $contact['profile_id'] }})"
class="ml-0.5 text-gray-400 hover:text-red-600 focus:outline-none"
title="{{ __('Remove coordinator') }}">
<x-icon name="x-circle" class="w-3.5 h-3.5" mini />
</button>
@endif
</span>
@else
<span class="text-gray-300">—</span>
@endif
</td>
@endif
<td class="px-3 py-4 text-sm text-gray-500">
<div class="flex justify-start items-center space-x-2">
@if ($contact['has_star'])
<x-icon class="h-5 w-5 text-yellow-500" name="star" solid
title="{{ __('Has stars') }}" />
@endif
@if ($contact['has_bookmark'])
<x-icon class="h-5 w-5 text-yellow-500" name="bookmark" solid
title="{{ __('Has bookmarks') }}" />
@endif
@if (!$contact['has_star'] && !$contact['has_bookmark'])
<span class="text-gray-300">—</span>
@endif
</div>
</td>
<td class="px-3 py-4 text-sm text-gray-500">
<div class="flex justify-start items-center space-x-3 text-xs">
@if ($contact['transaction_count'] > 0)
<span class="text-theme-primary font-medium">
<x-icon class="h-4 w-4 inline text-theme-primary" name="clock" />
{{ $contact['transaction_count'] }}
</span>
@endif
@if ($contact['message_count'] > 0)
<span class="text-theme-primary font-medium">
<x-icon class="h-4 w-4 inline text-theme-primary" name="chat-bubble-left-right" />
{{ $contact['message_count'] }}
</span>
@endif
</div>
</td>
<td class="px-3 py-4 whitespace-nowrap text-right text-sm text-gray-500 hidden xl:table-cell">
@if($contact['last_interaction'])
<div class="leading-tight">
<div>{{ \Carbon\Carbon::parse($contact['last_interaction'])->translatedFormat('d M') }}</div>
<div>{{ \Carbon\Carbon::parse($contact['last_interaction'])->translatedFormat('Y') }}</div>
</div>
@else
<span class="text-gray-300">—</span>
@endif
</td>
</tr>
@endforeach
@else
<tr>
<td colspan="{{ $showRoleColumn ? 5 : 4 }}" class="px-6 py-12 text-center text-gray-500">
<span wire:loading>
{{ __('One moment, collecting all your contacts...') }}
</span>
<span wire:loading.remove>
{{ __('No contacts found') }}
</span>
</td>
</tr>
@endif
</tbody>
</table>
</div><!-- end overflow-x-auto bottom scroll -->
<!-- Pagination -->
@if($contacts && $contacts->hasPages())
<div class="px-6 py-3 border-t border-gray-200">
{{ $contacts->links('livewire.long-paginator') }}
</div>
@endif
</div>
<!-- Results count and per-page selector -->
@if ($contacts && $contacts->total() > 0)
<div class="mt-4 flex items-center justify-between">
<div class="flex items-center">
<select class="w-20 cursor-pointer rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-primary-500 focus:outline-none focus:ring focus:ring-primary-500 sm:text-sm"
wire:model.live="perPage">
<option value="20">20</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
<span class="ml-2 text-sm text-gray-500">{{ __('per page') }}</span>
</div>
<div class="text-sm text-gray-500">
{{ trans_choice('messages.contacts_found', $contacts->total(), ['count' => $contacts->total()]) }}
</div>
</div>
@endif
<!-- Remove coordinator confirmation modal -->
<x-jetstream.dialog-modal wire:model="confirmingRemoveCoordinator">
<x-slot name="title">
{{ __('Remove coordinator') }}
</x-slot>
<x-slot name="content">
{{ __('Are you sure you want to remove :name as a coordinator?', ['name' => $removingProfileName]) }}
</x-slot>
<x-slot name="footer">
<x-jetstream.secondary-button wire:click="$set('confirmingRemoveCoordinator', false)" wire:loading.attr="disabled">
{{ __('Cancel') }}
</x-jetstream.secondary-button>
<x-jetstream.danger-button class="ml-3" wire:click="removeCoordinator" wire:loading.attr="disabled" wire:target="removeCoordinator">
<span wire:loading.remove wire:target="removeCoordinator">{{ __('Remove') }}</span>
<span wire:loading wire:target="removeCoordinator">{{ __('Removing...') }}</span>
</x-jetstream.danger-button>
</x-slot>
</x-jetstream.dialog-modal>
@push('scripts')
{{-- Scroll to top when clicking paginator --}}
<script>
document.addEventListener('scroll-to-top', event => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
</script>
@endpush
</div>