Add considering table
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
parent
b8d02c43f8
commit
65a4b82fe5
@ -557,3 +557,214 @@ td {
|
|||||||
min-width: unset;
|
min-width: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Sortable column header ── */
|
||||||
|
.sortable-th {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortable-th:hover {
|
||||||
|
background: var(--color-background);
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-icon {
|
||||||
|
opacity: 0.6;
|
||||||
|
font-size: 0.8em;
|
||||||
|
margin-inline-start: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Consideration panel ── */
|
||||||
|
.consideration-panel {
|
||||||
|
background: var(--color-background-secondary);
|
||||||
|
border: 1px solid var(--color-warning, #e8a838);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consideration-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
background: rgba(232, 168, 56, 0.1);
|
||||||
|
border-bottom: 1px solid var(--color-warning, #e8a838);
|
||||||
|
}
|
||||||
|
|
||||||
|
.consideration-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.consideration-count {
|
||||||
|
color: var(--color-warning, #e8a838);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-consideration-toggle {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--color-warning, #e8a838);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 0.25rem 0.75rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--color-text);
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-consideration-toggle:hover {
|
||||||
|
background: rgba(232, 168, 56, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.consideration-list {
|
||||||
|
padding: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consideration-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
background: var(--color-background);
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.consideration-item-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consideration-phone {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-remove-consideration {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--color-danger);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--color-danger);
|
||||||
|
padding: 0.2rem 0.6rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-remove-consideration:hover {
|
||||||
|
background: var(--color-danger);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consideration-item-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.4rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-consideration-invite,
|
||||||
|
.btn-consideration-decline {
|
||||||
|
padding: 0.25rem 0.75rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: opacity 0.15s, box-shadow 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-consideration-invite {
|
||||||
|
background: var(--color-success, #38a169);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-consideration-invite:hover {
|
||||||
|
opacity: 0.85;
|
||||||
|
box-shadow: 0 2px 6px rgba(56, 161, 105, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-consideration-decline {
|
||||||
|
background: var(--color-danger, #e53e3e);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-consideration-decline:hover {
|
||||||
|
opacity: 0.85;
|
||||||
|
box-shadow: 0 2px 6px rgba(229, 62, 62, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Sticky action bar ── */
|
||||||
|
.sticky-action-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
background: var(--color-background-secondary);
|
||||||
|
border-top: 2px solid var(--color-primary);
|
||||||
|
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.2);
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-selection-count {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-action-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-consideration {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 38px;
|
||||||
|
padding: 0 1rem;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: background 0.2s ease;
|
||||||
|
background: var(--color-warning, #e8a838);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-consideration:hover {
|
||||||
|
background: #cf8f20;
|
||||||
|
box-shadow: 0 2px 8px rgba(232, 168, 56, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.sticky-action-bar {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-action-buttons {
|
||||||
|
justify-content: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-action-buttons > * {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -49,7 +49,13 @@ const he = {
|
|||||||
selectGuestsFirst: 'בחר אורחים לשליחת הזמנה',
|
selectGuestsFirst: 'בחר אורחים לשליחת הזמנה',
|
||||||
deleteSelected: '🗑️ מחק נבחרים',
|
deleteSelected: '🗑️ מחק נבחרים',
|
||||||
confirmDeleteSelected: 'האם אתה בטוח שברצונך למחוק {count} אורחים?',
|
confirmDeleteSelected: 'האם אתה בטוח שברצונך למחוק {count} אורחים?',
|
||||||
failedToDeleteSelected: 'נכשל במחיקת האורחים הנבחרים'
|
failedToDeleteSelected: 'נכשל במחיקת האורחים הנבחרים',
|
||||||
|
addToConsideration: '📋 הוסף לשיקול',
|
||||||
|
considerationList: 'רשימת שיקול',
|
||||||
|
removeFromConsideration: 'הסר',
|
||||||
|
sortByName: 'מיין לפי שם',
|
||||||
|
inviteGuest: '✅ מזמין',
|
||||||
|
notInviteGuest: '❌ לא מזמין'
|
||||||
}
|
}
|
||||||
|
|
||||||
function GuestList({ eventId, onBack, onShowMembers }) {
|
function GuestList({ eventId, onBack, onShowMembers }) {
|
||||||
@ -72,6 +78,12 @@ function GuestList({ eventId, onBack, onShowMembers }) {
|
|||||||
const [itemsPerPage, setItemsPerPage] = useState(25)
|
const [itemsPerPage, setItemsPerPage] = useState(25)
|
||||||
const [showWhatsAppModal, setShowWhatsAppModal] = useState(false)
|
const [showWhatsAppModal, setShowWhatsAppModal] = useState(false)
|
||||||
const [eventData, setEventData] = useState({})
|
const [eventData, setEventData] = useState({})
|
||||||
|
const [sortOrder, setSortOrder] = useState(() => {
|
||||||
|
const saved = localStorage.getItem(`guestSortOrder_${eventId}`)
|
||||||
|
return saved && ['asc', 'desc', 'none'].includes(saved) ? saved : 'none'
|
||||||
|
}) // 'none' | 'asc' | 'desc'
|
||||||
|
const [considerationIds, setConsiderationIds] = useState(new Set())
|
||||||
|
const [showConsiderationPanel, setShowConsiderationPanel] = useState(true)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadGuests()
|
loadGuests()
|
||||||
@ -171,6 +183,39 @@ function GuestList({ eventId, onBack, onShowMembers }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleAddToConsideration = () => {
|
||||||
|
setConsiderationIds(prev => new Set([...prev, ...selectedGuestIds]))
|
||||||
|
setSelectedGuestIds(new Set())
|
||||||
|
setShowConsiderationPanel(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRemoveFromConsideration = (guestId) => {
|
||||||
|
setConsiderationIds(prev => {
|
||||||
|
const next = new Set(prev)
|
||||||
|
next.delete(guestId)
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleConsiderationDecision = async (guestId, invite) => {
|
||||||
|
if (invite) {
|
||||||
|
try {
|
||||||
|
await updateGuest(eventId, guestId, { rsvp_status: 'invited' })
|
||||||
|
setGuests(prev => prev.map(g => g.id === guestId ? { ...g, rsvp_status: 'invited' } : g))
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to update guest:', err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
await deleteGuest(eventId, guestId)
|
||||||
|
setGuests(prev => prev.filter(g => g.id !== guestId))
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to delete guest:', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleRemoveFromConsideration(guestId)
|
||||||
|
}
|
||||||
|
|
||||||
const handleDeleteSelected = async () => {
|
const handleDeleteSelected = async () => {
|
||||||
if (selectedGuestIds.size === 0) return
|
if (selectedGuestIds.size === 0) return
|
||||||
if (!window.confirm(he.confirmDeleteSelected.replace('{count}', selectedGuestIds.size))) return
|
if (!window.confirm(he.confirmDeleteSelected.replace('{count}', selectedGuestIds.size))) return
|
||||||
@ -201,10 +246,11 @@ function GuestList({ eventId, onBack, onShowMembers }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const toggleSelectAll = () => {
|
const toggleSelectAll = () => {
|
||||||
if (selectedGuestIds.size === filteredGuests.length) {
|
const paged = itemsPerPage === 'all' ? sortedGuests : sortedGuests.slice(0, itemsPerPage)
|
||||||
|
if (selectedGuestIds.size === paged.length && paged.length > 0) {
|
||||||
setSelectedGuestIds(new Set())
|
setSelectedGuestIds(new Set())
|
||||||
} else {
|
} else {
|
||||||
setSelectedGuestIds(new Set(filteredGuests.map(g => g.id)))
|
setSelectedGuestIds(new Set(paged.map(g => g.id)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,6 +299,16 @@ function GuestList({ eventId, onBack, onShowMembers }) {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const sortedGuests = sortOrder === 'none'
|
||||||
|
? filteredGuests
|
||||||
|
: [...filteredGuests].sort((a, b) => {
|
||||||
|
const nameA = `${a.first_name || ''} ${a.last_name || ''}`.toLowerCase()
|
||||||
|
const nameB = `${b.first_name || ''} ${b.last_name || ''}`.toLowerCase()
|
||||||
|
return sortOrder === 'asc'
|
||||||
|
? nameA.localeCompare(nameB, 'he')
|
||||||
|
: nameB.localeCompare(nameA, 'he')
|
||||||
|
})
|
||||||
|
|
||||||
const stats = {
|
const stats = {
|
||||||
total: guests.length,
|
total: guests.length,
|
||||||
confirmed: guests.filter(g => g.rsvp_status === 'confirmed').length,
|
confirmed: guests.filter(g => g.rsvp_status === 'confirmed').length,
|
||||||
@ -344,7 +400,7 @@ function GuestList({ eventId, onBack, onShowMembers }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="guest-list-container">
|
<div className="guest-list-container" style={selectedGuestIds.size > 0 ? { paddingBottom: '80px' } : {}}>
|
||||||
<div className="guest-list-header">
|
<div className="guest-list-header">
|
||||||
{/* ── Row 1: back + title ── */}
|
{/* ── Row 1: back + title ── */}
|
||||||
<div className="guest-list-header-top">
|
<div className="guest-list-header-top">
|
||||||
@ -372,23 +428,6 @@ function GuestList({ eventId, onBack, onShowMembers }) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="btn-group btn-group-primary">
|
<div className="btn-group btn-group-primary">
|
||||||
{selectedGuestIds.size > 0 && (
|
|
||||||
<>
|
|
||||||
<button
|
|
||||||
className="btn-delete-selected"
|
|
||||||
onClick={handleDeleteSelected}
|
|
||||||
>
|
|
||||||
{he.deleteSelected} ({selectedGuestIds.size})
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="btn-whatsapp"
|
|
||||||
onClick={() => setShowWhatsAppModal(true)}
|
|
||||||
title={he.selectGuestsFirst}
|
|
||||||
>
|
|
||||||
{he.sendWhatsApp} ({selectedGuestIds.size})
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<button className="btn-add-guest" onClick={() => {
|
<button className="btn-add-guest" onClick={() => {
|
||||||
setEditingGuest(null)
|
setEditingGuest(null)
|
||||||
setShowGuestForm(true)
|
setShowGuestForm(true)
|
||||||
@ -420,15 +459,44 @@ function GuestList({ eventId, onBack, onShowMembers }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedGuestIds.size > 0 && (
|
<SearchFilter eventId={eventId} onSearch={setSearchFilters} />
|
||||||
<div className="selection-bar">
|
|
||||||
<span className="selection-text">
|
{considerationIds.size > 0 && (
|
||||||
{he.selectedCount.replace('{count}', selectedGuestIds.size)}
|
<div className="consideration-panel">
|
||||||
</span>
|
<div className="consideration-header">
|
||||||
|
<h3>📋 {he.considerationList} <span className="consideration-count">({considerationIds.size})</span></h3>
|
||||||
|
<button className="btn-consideration-toggle" onClick={() => setShowConsiderationPanel(p => !p)}>
|
||||||
|
{showConsiderationPanel ? '▲ הסתר' : '▼ הצג'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{showConsiderationPanel && (
|
||||||
|
<div className="consideration-list">
|
||||||
|
{guests.filter(g => considerationIds.has(g.id)).map(guest => (
|
||||||
|
<div key={guest.id} className="consideration-item">
|
||||||
|
<div className="consideration-item-info">
|
||||||
|
<strong>{guest.first_name} {guest.last_name}</strong>
|
||||||
|
{guest.phone_number && <span className="consideration-phone">{guest.phone_number}</span>}
|
||||||
|
</div>
|
||||||
|
<div className="consideration-item-actions">
|
||||||
|
<button
|
||||||
|
className="btn-consideration-invite"
|
||||||
|
onClick={() => handleConsiderationDecision(guest.id, true)}
|
||||||
|
>
|
||||||
|
{he.inviteGuest}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn-consideration-decline"
|
||||||
|
onClick={() => handleConsiderationDecision(guest.id, false)}
|
||||||
|
>
|
||||||
|
{he.notInviteGuest}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<SearchFilter eventId={eventId} onSearch={setSearchFilters} />
|
|
||||||
|
|
||||||
<div className="pagination-controls">
|
<div className="pagination-controls">
|
||||||
<label htmlFor="items-per-page">הצג אורחים:</label>
|
<label htmlFor="items-per-page">הצג אורחים:</label>
|
||||||
@ -440,7 +508,7 @@ function GuestList({ eventId, onBack, onShowMembers }) {
|
|||||||
<option value="25">25</option>
|
<option value="25">25</option>
|
||||||
<option value="50">50</option>
|
<option value="50">50</option>
|
||||||
<option value="100">100</option>
|
<option value="100">100</option>
|
||||||
<option value="all">הכל ({filteredGuests.length})</option>
|
<option value="all">הכל ({sortedGuests.length})</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -470,12 +538,18 @@ function GuestList({ eventId, onBack, onShowMembers }) {
|
|||||||
<th className="checkbox-cell">
|
<th className="checkbox-cell">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={selectedGuestIds.size === (itemsPerPage === 'all' ? filteredGuests : filteredGuests.slice(0, itemsPerPage)).length && (itemsPerPage === 'all' ? filteredGuests : filteredGuests.slice(0, itemsPerPage)).length > 0}
|
checked={selectedGuestIds.size === (itemsPerPage === 'all' ? sortedGuests : sortedGuests.slice(0, itemsPerPage)).length && (itemsPerPage === 'all' ? sortedGuests : sortedGuests.slice(0, itemsPerPage)).length > 0}
|
||||||
onChange={toggleSelectAll}
|
onChange={toggleSelectAll}
|
||||||
title={he.selectAll}
|
title={he.selectAll}
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th>{he.name}</th>
|
<th className="sortable-th" onClick={() => setSortOrder(o => {
|
||||||
|
const next = o === 'asc' ? 'desc' : o === 'desc' ? 'none' : 'asc'
|
||||||
|
localStorage.setItem(`guestSortOrder_${eventId}`, next)
|
||||||
|
return next
|
||||||
|
})} title={he.sortByName}>
|
||||||
|
{he.name} <span className="sort-icon">{sortOrder === 'asc' ? '↑' : sortOrder === 'desc' ? '↓' : '⇅'}</span>
|
||||||
|
</th>
|
||||||
<th>{he.phone}</th>
|
<th>{he.phone}</th>
|
||||||
<th>{he.email}</th>
|
<th>{he.email}</th>
|
||||||
<th>{he.rsvpStatus}</th>
|
<th>{he.rsvpStatus}</th>
|
||||||
@ -485,7 +559,7 @@ function GuestList({ eventId, onBack, onShowMembers }) {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{(itemsPerPage === 'all' ? filteredGuests : filteredGuests.slice(0, itemsPerPage)).map(guest => (
|
{(itemsPerPage === 'all' ? sortedGuests : sortedGuests.slice(0, itemsPerPage)).map(guest => (
|
||||||
<tr key={guest.id} className={selectedGuestIds.has(guest.id) ? 'selected' : ''}>
|
<tr key={guest.id} className={selectedGuestIds.has(guest.id) ? 'selected' : ''}>
|
||||||
<td className="checkbox-cell">
|
<td className="checkbox-cell">
|
||||||
<input
|
<input
|
||||||
@ -545,11 +619,31 @@ function GuestList({ eventId, onBack, onShowMembers }) {
|
|||||||
isOpen={showWhatsAppModal}
|
isOpen={showWhatsAppModal}
|
||||||
onClose={() => setShowWhatsAppModal(false)}
|
onClose={() => setShowWhatsAppModal(false)}
|
||||||
selectedGuests={Array.from(selectedGuestIds).map(id =>
|
selectedGuests={Array.from(selectedGuestIds).map(id =>
|
||||||
filteredGuests.find(g => g.id === id)
|
guests.find(g => g.id === id)
|
||||||
).filter(Boolean)}
|
).filter(Boolean)}
|
||||||
eventData={eventData}
|
eventData={eventData}
|
||||||
onSend={handleSendWhatsApp}
|
onSend={handleSendWhatsApp}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Sticky action bar — always visible when guests are selected */}
|
||||||
|
{selectedGuestIds.size > 0 && (
|
||||||
|
<div className="sticky-action-bar">
|
||||||
|
<span className="sticky-selection-count">
|
||||||
|
{he.selectedCount.replace('{count}', selectedGuestIds.size)}
|
||||||
|
</span>
|
||||||
|
<div className="sticky-action-buttons">
|
||||||
|
<button className="btn-consideration" onClick={handleAddToConsideration}>
|
||||||
|
{he.addToConsideration}
|
||||||
|
</button>
|
||||||
|
<button className="btn-whatsapp" onClick={() => setShowWhatsAppModal(true)}>
|
||||||
|
💬 {he.sendWhatsApp}
|
||||||
|
</button>
|
||||||
|
<button className="btn-delete-selected" onClick={handleDeleteSelected}>
|
||||||
|
{he.deleteSelected}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user