mediacms/frontend/src/static/js/components/BulkActionChangeOwnerModal.tsx
Markos Gogoulos 870274e676 fix
2025-10-18 16:29:42 +03:00

180 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import './BulkActionChangeOwnerModal.scss';
import { translateString } from '../utils/helpers/';
interface User {
name: string;
username: string;
}
interface BulkActionChangeOwnerModalProps {
isOpen: boolean;
selectedMediaIds: string[];
onCancel: () => void;
onSuccess: (message: string) => void;
onError: (message: string) => void;
csrfToken: string;
}
export const BulkActionChangeOwnerModal: React.FC<BulkActionChangeOwnerModalProps> = ({
isOpen,
selectedMediaIds,
onCancel,
onSuccess,
onError,
csrfToken,
}) => {
const [searchTerm, setSearchTerm] = useState('');
const [searchResults, setSearchResults] = useState<User[]>([]);
const [selectedUser, setSelectedUser] = useState<User | null>(null);
const [isProcessing, setIsProcessing] = useState(false);
const [searchTimeout, setSearchTimeout] = useState<NodeJS.Timeout | null>(null);
useEffect(() => {
if (!isOpen) {
// Reset state when modal closes
setSearchTerm('');
setSearchResults([]);
setSelectedUser(null);
}
}, [isOpen]);
const searchUsers = async (name: string) => {
if (!name.trim()) {
setSearchResults([]);
return;
}
try {
const response = await fetch(`/api/v1/users?name=${encodeURIComponent(name)}`);
if (!response.ok) {
throw new Error(translateString('Failed to search users'));
}
const data = await response.json();
setSearchResults(data.results || data);
} catch (error) {
console.error('Error searching users:', error);
}
};
const handleSearchChange = (value: string) => {
setSearchTerm(value);
// Clear previous timeout
if (searchTimeout) {
clearTimeout(searchTimeout);
}
// Set new timeout for debounced search
const timeout = setTimeout(() => {
searchUsers(value);
}, 300);
setSearchTimeout(timeout);
};
const handleUserSelect = (user: User) => {
setSelectedUser(user);
setSearchTerm(user.name + ' - ' + user.username);
setSearchResults([]);
};
const handleSubmit = async () => {
if (!selectedUser) {
onError(translateString('Please select a user'));
return;
}
setIsProcessing(true);
try {
const response = await fetch('/api/v1/media/user/bulk_actions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken,
},
body: JSON.stringify({
action: 'change_owner',
media_ids: selectedMediaIds,
owner: selectedUser.username,
}),
});
if (!response.ok) {
throw new Error(translateString('Failed to change owner'));
}
const data = await response.json();
onSuccess(data.detail || translateString('Successfully changed owner'));
onCancel();
} catch (error) {
console.error('Error changing owner:', error);
onError(translateString('Failed to change owner. Please try again.'));
} finally {
setIsProcessing(false);
}
};
if (!isOpen) return null;
return (
<div className="change-owner-modal-overlay">
<div className="change-owner-modal">
<div className="change-owner-modal-header">
<h2>{translateString('Select Owner')}</h2>
<button className="change-owner-modal-close" onClick={onCancel}>
×
</button>
</div>
<div className="change-owner-modal-content">
<div className="search-box-wrapper">
<div className="search-box">
<input
type="text"
placeholder={translateString('Search for user...')}
value={searchTerm}
onChange={(e) => handleSearchChange(e.target.value)}
/>
</div>
{searchResults.length > 0 && (
<div className="search-results">
{searchResults.slice(0, 10).map((user) => (
<div
key={user.username}
className="search-result-item"
onClick={() => handleUserSelect(user)}
>
{user.name} - {user.username}
</div>
))}
</div>
)}
</div>
{selectedUser && (
<div className="selected-user">
<span>{translateString('Selected')}: {selectedUser.name} - {selectedUser.username}</span>
</div>
)}
</div>
<div className="change-owner-modal-footer">
<button className="change-owner-btn change-owner-btn-cancel" onClick={onCancel} disabled={isProcessing}>
{translateString('Cancel')}
</button>
<button
className="change-owner-btn change-owner-btn-submit"
onClick={handleSubmit}
disabled={isProcessing || !selectedUser}
>
{isProcessing ? translateString('Processing...') : translateString('Submit')}
</button>
</div>
</div>
</div>
);
};