import React, { useState, useEffect } from 'react' import ReactDOM from 'react-dom' import { UserPlus, Unlink, Check, Loader2, Clock, X } from 'lucide-react' import { useVacayStore } from '../../store/vacayStore' import { useAuthStore } from '../../store/authStore' import { useTranslation } from '../../i18n' import { useToast } from '../shared/Toast' import CustomSelect from '../shared/CustomSelect' import apiClient from '../../api/client' const PRESET_COLORS = [ '#6366f1', '#ec4899', '#14b8a6', '#8b5cf6', '#ef4444', '#3b82f6', '#22c55e', '#06b6d4', '#f43f5e', '#a855f7', '#10b981', '#0ea5e9', '#64748b', '#be185d', '#0d9488', ] export default function VacayPersons() { const { t } = useTranslation() const toast = useToast() const { users, pendingInvites, invite, cancelInvite, updateColor, selectedUserId, setSelectedUserId, isFused } = useVacayStore() const { user: currentUser } = useAuthStore() // Default selectedUserId to current user useEffect(() => { if (!selectedUserId && currentUser) setSelectedUserId(currentUser.id) }, [currentUser, selectedUserId]) const [showInvite, setShowInvite] = useState(false) const [showColorPicker, setShowColorPicker] = useState(false) const [colorEditUserId, setColorEditUserId] = useState(null) const [availableUsers, setAvailableUsers] = useState([]) const [selectedInviteUser, setSelectedInviteUser] = useState(null) const [inviting, setInviting] = useState(false) const loadAvailable = async () => { try { const data = await apiClient.get('/addons/vacay/available-users').then(r => r.data) setAvailableUsers(data.users) } catch { /* */ } } const handleInvite = async () => { if (!selectedInviteUser) return setInviting(true) try { await invite(selectedInviteUser) toast.success(t('vacay.inviteSent')) setShowInvite(false) setSelectedInviteUser(null) } catch (err) { toast.error(err.response?.data?.error || t('vacay.inviteError')) } finally { setInviting(false) } } const handleColorChange = async (color) => { await updateColor(color, colorEditUserId) setShowColorPicker(false) setColorEditUserId(null) } const editingUserColor = users.find(u => u.id === colorEditUserId)?.color || '#6366f1' return (
{t('vacay.persons')}
{users.map(u => { const isSelected = selectedUserId === u.id return (
{ if (isFused) setSelectedUserId(u.id) }} className="flex items-center gap-2 px-2.5 py-1.5 rounded-lg group transition-all" style={{ background: isSelected ? 'var(--bg-hover)' : 'transparent', border: isSelected ? '1px solid var(--border-primary)' : '1px solid transparent', cursor: isFused ? 'pointer' : 'default', }}>
) })} {/* Pending invites */} {pendingInvites.map(inv => (
{inv.username} ({t('vacay.pending')})
))}
{/* Invite Modal — Portal to body to avoid z-index issues */} {showInvite && ReactDOM.createPortal(
setShowInvite(false)}>
e.stopPropagation()}>

{t('vacay.inviteUser')}

{t('vacay.inviteHint')}

{availableUsers.length === 0 ? (

{t('vacay.noUsersAvailable')}

) : ( ({ value: u.id, label: `${u.username} (${u.email})` }))} placeholder={t('vacay.selectUser')} searchable /> )}
, document.body )} {/* Color Picker Modal — Portal to body */} {showColorPicker && ReactDOM.createPortal(
{ setShowColorPicker(false); setColorEditUserId(null) }}>
e.stopPropagation()}>

{t('vacay.changeColor')}

{PRESET_COLORS.map(c => (
, document.body )}
) }