Update ClientPortal.tsx
This commit is contained in:
@@ -141,18 +141,42 @@ export const ClientPortal: React.FC<ClientPortalProps> = ({
|
||||
setIsTyping(false);
|
||||
};
|
||||
|
||||
const submitTicket = (e: React.FormEvent) => {
|
||||
const submitTicket = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsUploading(true);
|
||||
const attachments: Attachment[] = [];
|
||||
if (ticketFiles) {
|
||||
|
||||
if (ticketFiles && ticketFiles.length > 0) {
|
||||
for (let i = 0; i < ticketFiles.length; i++) {
|
||||
const file = ticketFiles[i];
|
||||
attachments.push({
|
||||
id: `att-${Date.now()}-${i}`,
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
url: URL.createObjectURL(file) // Note: This is client-side only URL for preview, real implementation would upload here too or later
|
||||
});
|
||||
|
||||
// Validation check before upload
|
||||
const maxSize = (settings.features.maxFileSizeMb || 5) * 1024 * 1024;
|
||||
if (file.size > maxSize) {
|
||||
showToast(`File ${file.name} troppo grande. Max ${settings.features.maxFileSizeMb}MB`, 'error');
|
||||
continue;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/upload', { method: 'POST', body: formData });
|
||||
if(res.ok) {
|
||||
const data = await res.json();
|
||||
attachments.push({
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
url: data.url,
|
||||
type: data.type
|
||||
});
|
||||
} else {
|
||||
showToast(`Errore caricamento ${file.name}`, 'error');
|
||||
}
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
showToast(`Errore di rete caricamento ${file.name}`, 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +191,7 @@ export const ClientPortal: React.FC<ClientPortalProps> = ({
|
||||
|
||||
setTicketForm({ subject: '', description: '', queue: queues.length > 0 ? queues[0].name : 'General' });
|
||||
setTicketFiles(null);
|
||||
setIsUploading(false);
|
||||
setActiveView('dashboard');
|
||||
};
|
||||
|
||||
@@ -390,6 +415,20 @@ export const ClientPortal: React.FC<ClientPortalProps> = ({
|
||||
</div>
|
||||
<div className="p-6 space-y-6">
|
||||
<div className="bg-gray-50 p-4 rounded-lg">{selectedTicket.description}</div>
|
||||
|
||||
{selectedTicket.attachments && selectedTicket.attachments.length > 0 && (
|
||||
<div className="bg-blue-50/50 p-4 rounded-lg border border-blue-100">
|
||||
<h3 className="text-xs font-bold text-blue-800 uppercase mb-2 flex items-center"><Paperclip className="w-3 h-3 mr-1"/> Allegati Iniziali</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{selectedTicket.attachments.map(att => (
|
||||
<a key={att.id} href={att.url} target="_blank" rel="noopener noreferrer" className="flex items-center text-xs bg-white border border-blue-200 text-blue-600 px-3 py-2 rounded-lg hover:bg-blue-50 transition">
|
||||
<FileText className="w-3 h-3 mr-2 text-blue-400" /> {att.name}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-4">
|
||||
<h3 className="font-bold text-gray-700">Messaggi</h3>
|
||||
{selectedTicket.messages.map(m => (
|
||||
@@ -440,12 +479,22 @@ export const ClientPortal: React.FC<ClientPortalProps> = ({
|
||||
<form onSubmit={submitTicket} className="space-y-4">
|
||||
<input type="text" placeholder="Oggetto" className="w-full border p-3 rounded-lg" value={ticketForm.subject} onChange={e => setTicketForm({...ticketForm, subject: e.target.value})} required />
|
||||
<textarea placeholder="Descrizione" rows={5} className="w-full border p-3 rounded-lg" value={ticketForm.description} onChange={e => setTicketForm({...ticketForm, description: e.target.value})} required />
|
||||
<select className="w-full border p-3 rounded-lg" value={ticketForm.queue} onChange={e => setTicketForm({...ticketForm, queue: e.target.value})}>
|
||||
{queues.map(q => <option key={q.id} value={q.name}>{q.name}</option>)}
|
||||
</select>
|
||||
{/* Create Ticket attachment (mock for now as backend requires form data or separate upload) */}
|
||||
{/* For simplicity in this demo, omitting file upload on creation to keep code lean, or would need same async upload logic */}
|
||||
<button type="submit" className="w-full bg-brand-600 text-white py-3 rounded-lg font-bold">Crea Ticket</button>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<select className="w-full border p-3 rounded-lg bg-white" value={ticketForm.queue} onChange={e => setTicketForm({...ticketForm, queue: e.target.value})}>
|
||||
{queues.map(q => <option key={q.id} value={q.name}>{q.name}</option>)}
|
||||
</select>
|
||||
<div className="relative">
|
||||
<label className={`flex items-center justify-center w-full border p-3 rounded-lg cursor-pointer hover:bg-gray-50 ${isUploading ? 'opacity-50 pointer-events-none' : ''}`}>
|
||||
{isUploading ? <Loader2 className="w-5 h-5 animate-spin text-brand-600" /> : <Paperclip className="w-5 h-5 text-gray-500 mr-2" />}
|
||||
<span className="text-gray-500 text-sm">{ticketFiles && ticketFiles.length > 0 ? `${ticketFiles.length} file selezionati` : 'Allega file'}</span>
|
||||
<input type="file" className="hidden" multiple onChange={(e) => setTicketFiles(e.target.files)} />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" disabled={isUploading} className="w-full bg-brand-600 text-white py-3 rounded-lg font-bold hover:bg-brand-700 disabled:opacity-70 flex items-center justify-center">
|
||||
{isUploading ? <Loader2 className="w-5 h-5 animate-spin mr-2" /> : null}
|
||||
{isUploading ? 'Caricamento in corso...' : 'Crea Ticket'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user