// frontend/src/modals/bellcloud/devices/AddDeviceUserModal.jsx // Search and add an app user to a device's user_list. import { useState, useEffect, useRef, useCallback } from 'react' import api from '@/lib/api' import Modal from '@/components/ui/Modal' import Button from '@/components/ui/Button' import Spinner from '@/components/ui/Spinner' // ─── User row ───────────────────────────────────────────────────────────────── function UserRow({ user, onAdd, adding }) { const initials = (user.display_name || user.email || '?').charAt(0).toUpperCase() return (
{/* Avatar */}
{user.photo_url ? ( ) : initials}
{/* Info */}

{user.display_name || '—'}

{user.email && (

{user.email}

)}
{/* Add button */}
) } // ─── AddDeviceUserModal ─────────────────────────────────────────────────────── export default function AddDeviceUserModal({ open, deviceId, existingUserIds = [], onClose, onAdded }) { const [query, setQuery] = useState('') const [results, setResults] = useState([]) const [loading, setLoading] = useState(false) const [adding, setAdding] = useState(null) const [error, setError] = useState('') const debounceRef = useRef(null) const inputRef = useRef(null) // Reset on open useEffect(() => { if (!open) return setQuery('') setResults([]) setError('') setAdding(null) setTimeout(() => inputRef.current?.focus(), 80) }, [open]) const search = useCallback(async (q) => { setLoading(true) setError('') try { const data = await api.get(`/devices/${deviceId}/user-search?q=${encodeURIComponent(q)}`) // Filter out users already on the device const existing = new Set(existingUserIds) setResults((data.results || []).filter(u => !existing.has(u.id))) } catch (err) { setError(err.message || 'Search failed.') setResults([]) } finally { setLoading(false) } }, [deviceId, existingUserIds]) const handleInput = (e) => { const val = e.target.value setQuery(val) clearTimeout(debounceRef.current) debounceRef.current = setTimeout(() => search(val), 280) } // Load all users on open (empty query) useEffect(() => { if (open && deviceId) search('') }, [open, deviceId, search]) const handleAdd = async (user) => { setAdding(user.id) setError('') try { await api.post(`/devices/${deviceId}/user-list`, { user_id: user.id }) onAdded(user) // Remove from results so it disappears immediately setResults(prev => prev.filter(u => u.id !== user.id)) } catch (err) { setError(err.message || 'Failed to add user.') } finally { setAdding(null) } } return (
{/* Search */} {error && (
{error}
)} {/* Results */}
{loading ? (
) : results.length === 0 ? (
{query ? 'No users found matching your search.' : 'All users already added or no users exist.'}
) : ( results.map(user => ( )) )}
{/* Footer */}
) }