feat: user search, group members management, and fixed canvases filtering
This commit is contained in:
@@ -36,6 +36,56 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Add Member Modal -->
|
||||
<div v-if="showAddMemberModal" class="fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-50 p-4" @click.self="showAddMemberModal = false">
|
||||
<div class="bg-slate-900 border border-slate-700 rounded-3xl p-8 w-full max-w-md shadow-2xl">
|
||||
<h2 class="text-2xl font-bold text-white mb-6 flex items-center gap-2">
|
||||
<span>👤</span> Добавить участника
|
||||
</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="text-xs font-bold text-slate-500 uppercase tracking-wider block mb-2">Поиск пользователя</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
@input="searchUsers"
|
||||
placeholder="Введите имя или email..."
|
||||
class="w-full px-4 py-3 bg-slate-800 border border-slate-700 rounded-xl text-white outline-none focus:border-blue-500 transition"
|
||||
/>
|
||||
<div v-if="searching" class="absolute right-4 top-3.5">
|
||||
<div class="animate-spin h-5 w-5 border-2 border-blue-500 border-t-transparent rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search Results -->
|
||||
<div v-if="searchResults.length > 0" class="max-h-60 overflow-y-auto bg-slate-800/50 rounded-xl border border-slate-700 divide-y divide-slate-700">
|
||||
<div v-for="u in searchResults" :key="u.id" class="p-3 flex items-center justify-between hover:bg-slate-700/50 transition">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-medium text-white">{{ u.username }}</span>
|
||||
<span class="text-[10px] text-slate-500">{{ u.email }}</span>
|
||||
</div>
|
||||
<button
|
||||
@click="addMember(u.id)"
|
||||
class="px-3 py-1 bg-blue-600 hover:bg-blue-500 text-white text-xs font-bold rounded-lg transition"
|
||||
>
|
||||
Выбрать
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="searchQuery.length >= 2" class="text-center py-4 text-slate-500 text-sm">
|
||||
Пользователи не найдены
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<button @click="showAddMemberModal = false" class="w-full py-3 bg-slate-800 hover:bg-slate-700 text-slate-300 rounded-xl font-bold transition">
|
||||
Закрыть
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -50,6 +100,58 @@ const auth = useAuth()
|
||||
const group = ref(null)
|
||||
const members = ref([])
|
||||
const showAddMemberModal = ref(false)
|
||||
const searchQuery = ref('')
|
||||
const searchResults = ref([])
|
||||
const searching = ref(false)
|
||||
|
||||
const searchUsers = async () => {
|
||||
if (searchQuery.value.length < 2) {
|
||||
searchResults.value = []
|
||||
return
|
||||
}
|
||||
searching.value = true
|
||||
try {
|
||||
const data = await $fetch('/api/users/search', {
|
||||
params: { q: searchQuery.value },
|
||||
headers: { Authorization: `Bearer ${auth.token.value}` }
|
||||
})
|
||||
searchResults.value = data.users || []
|
||||
} catch (e) {
|
||||
console.error('Search failed', e)
|
||||
} finally {
|
||||
searching.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const addMember = async (userId) => {
|
||||
try {
|
||||
await $fetch(`/api/groups/${route.params.id}/add-member`, {
|
||||
method: 'POST',
|
||||
body: { userId, role: 'member' },
|
||||
headers: { Authorization: `Bearer ${auth.token.value}` }
|
||||
})
|
||||
showAddMemberModal.value = false
|
||||
searchQuery.value = ''
|
||||
searchResults.value = []
|
||||
await fetchGroup()
|
||||
} catch (e) {
|
||||
alert(e.data?.message || 'Ошибка при добавлении')
|
||||
}
|
||||
}
|
||||
|
||||
const removeMember = async (userId) => {
|
||||
if (!confirm('Удалить участника из группы?')) return
|
||||
try {
|
||||
await $fetch(`/api/groups/${route.params.id}/members`, {
|
||||
method: 'DELETE',
|
||||
body: { userId },
|
||||
headers: { Authorization: `Bearer ${auth.token.value}` }
|
||||
})
|
||||
await fetchGroup()
|
||||
} catch (e) {
|
||||
alert('Ошибка при удалении')
|
||||
}
|
||||
}
|
||||
|
||||
const fetchGroup = async () => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user