fix(clipboard): corrigir erro de permissao de escrita e adicionar botao copiar nome
continuous-integration/webhook Deploy concluído (VPS4)
continuous-integration/webhook Deploy concluído (VPS4)
This commit is contained in:
@@ -59,6 +59,14 @@ function GtoDetailModal({ isOpen, onClose, gto, onUpdated }) {
|
||||
}
|
||||
}, [selectedImage]);
|
||||
|
||||
const getExtension = (filename) => {
|
||||
if (!filename) return 'jpg';
|
||||
const parts = filename.split('.');
|
||||
if (parts.length < 2) return 'jpg';
|
||||
const ext = parts[parts.length - 1].toLowerCase();
|
||||
return ext === 'jpeg' ? 'jpg' : ext;
|
||||
};
|
||||
|
||||
const handleDownload = async (img) => {
|
||||
try {
|
||||
const url = img.filename?.startsWith('http')
|
||||
@@ -67,10 +75,11 @@ function GtoDetailModal({ isOpen, onClose, gto, onUpdated }) {
|
||||
const response = await fetch(url);
|
||||
const blob = await response.blob();
|
||||
|
||||
const ext = getExtension(img.filename);
|
||||
const pName = (img.patient_name || 'paciente').trim().replace(/[\/\\:*?"<>|]/g, '').replace(/\s+/g, '_');
|
||||
const obs = (img.remark || '').trim().replace(/[\/\\:*?"<>|]/g, '').replace(/\s+/g, '_');
|
||||
|
||||
const fileName = obs ? `${pName}-${obs}.jpg` : `${pName}.jpg`;
|
||||
const fileName = obs ? `${pName}-${obs}.${ext}` : `${pName}.${ext}`;
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
@@ -84,10 +93,16 @@ function GtoDetailModal({ isOpen, onClose, gto, onUpdated }) {
|
||||
}
|
||||
};
|
||||
|
||||
const handleCopy = (img) => {
|
||||
const handleCopyImage = async (img) => {
|
||||
const url = img.filename?.startsWith('http')
|
||||
? img.filename
|
||||
: `/uploads/${img.filename}`;
|
||||
|
||||
try {
|
||||
showToast('Processando cópia da imagem...', 'info');
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
'image/png': new Promise((resolve, reject) => {
|
||||
const imageObj = new Image();
|
||||
imageObj.crossOrigin = 'anonymous';
|
||||
imageObj.onload = () => {
|
||||
@@ -97,24 +112,42 @@ function GtoDetailModal({ isOpen, onClose, gto, onUpdated }) {
|
||||
canvas.height = imageObj.naturalHeight;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(imageObj, 0, 0);
|
||||
canvas.toBlob(async (blob) => {
|
||||
try {
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({ 'image/png': blob })
|
||||
]);
|
||||
showToast('Imagem copiada para a área de transferência!', 'success');
|
||||
} catch (err) {
|
||||
showToast('Erro ao copiar imagem para área de transferência.', 'error');
|
||||
console.error(err);
|
||||
canvas.toBlob((blob) => {
|
||||
if (blob) {
|
||||
resolve(blob);
|
||||
} else {
|
||||
reject(new Error('Erro ao converter imagem em blob'));
|
||||
}
|
||||
}, 'image/png');
|
||||
} catch (e) {
|
||||
showToast('Erro ao processar imagem para cópia.', 'error');
|
||||
console.error(e);
|
||||
reject(e);
|
||||
}
|
||||
};
|
||||
imageObj.onerror = () => showToast('Erro ao carregar imagem para cópia.', 'error');
|
||||
imageObj.onerror = () => reject(new Error('Erro ao carregar a imagem'));
|
||||
imageObj.src = url;
|
||||
})
|
||||
})
|
||||
]);
|
||||
showToast('Imagem copiada para a área de transferência!', 'success');
|
||||
} catch (err) {
|
||||
showToast('Erro ao copiar imagem. Certifique-se de que a página está focada.', 'error');
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCopyFilename = async (img) => {
|
||||
try {
|
||||
const ext = getExtension(img.filename);
|
||||
const pName = (img.patient_name || 'paciente').trim().replace(/[\/\\:*?"<>|]/g, '').replace(/\s+/g, '_');
|
||||
const obs = (img.remark || '').trim().replace(/[\/\\:*?"<>|]/g, '').replace(/\s+/g, '_');
|
||||
|
||||
const fileName = obs ? `${pName}-${obs}.${ext}` : `${pName}.${ext}`;
|
||||
|
||||
await navigator.clipboard.writeText(fileName);
|
||||
showToast('Nome do arquivo copiado para a área de transferência!', 'success');
|
||||
} catch (err) {
|
||||
showToast('Erro ao copiar nome do arquivo.', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const saveImageRemark = async () => {
|
||||
@@ -329,22 +362,30 @@ function GtoDetailModal({ isOpen, onClose, gto, onUpdated }) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 12, width: '100%' }}>
|
||||
<div style={{ display: 'flex', gap: 12, width: '100%', flexWrap: 'wrap' }}>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary"
|
||||
onClick={() => handleDownload(selectedImage)}
|
||||
style={{ flex: 1, height: 46, fontSize: '0.95rem', fontWeight: 600, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8 }}
|
||||
style={{ flex: 1, minWidth: 140, height: 46, fontSize: '0.95rem', fontWeight: 600, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8 }}
|
||||
>
|
||||
💾 Baixar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary"
|
||||
onClick={() => handleCopy(selectedImage)}
|
||||
style={{ flex: 1, height: 46, fontSize: '0.95rem', fontWeight: 600, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8 }}
|
||||
onClick={() => handleCopyImage(selectedImage)}
|
||||
style={{ flex: 1, minWidth: 140, height: 46, fontSize: '0.95rem', fontWeight: 600, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8 }}
|
||||
>
|
||||
📋 Copiar para Área de Transferência
|
||||
🖼️ Copiar Imagem
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary"
|
||||
onClick={() => handleCopyFilename(selectedImage)}
|
||||
style={{ flex: 1, minWidth: 140, height: 46, fontSize: '0.95rem', fontWeight: 600, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8 }}
|
||||
>
|
||||
📋 Copiar Nome
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -246,8 +246,14 @@ export default function ImageDetailsPage() {
|
||||
img.src = url;
|
||||
};
|
||||
|
||||
const copyImageToClipboard = () => {
|
||||
const copyImageToClipboard = async () => {
|
||||
const url = imageUrl;
|
||||
|
||||
try {
|
||||
showToast('Processando cópia da imagem...', 'info');
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
'image/png': new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.onload = () => {
|
||||
@@ -267,26 +273,27 @@ export default function ImageDetailsPage() {
|
||||
ctx.scale(fH ? -1 : 1, fV ? -1 : 1);
|
||||
ctx.rotate(rad);
|
||||
ctx.drawImage(img, -w / 2, -h / 2);
|
||||
canvas.toBlob(async (blob) => {
|
||||
try {
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
'image/png': blob
|
||||
canvas.toBlob((blob) => {
|
||||
if (blob) {
|
||||
resolve(blob);
|
||||
} else {
|
||||
reject(new Error('Erro ao converter canvas em blob'));
|
||||
}
|
||||
}, 'image/png');
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
};
|
||||
img.onerror = () => reject(new Error('Erro ao carregar imagem para cópia.'));
|
||||
img.src = url;
|
||||
})
|
||||
})
|
||||
]);
|
||||
showToast('Imagem copiada para a área de transferência!', 'success');
|
||||
} catch (err) {
|
||||
showToast('Erro ao copiar imagem para clipboard.', 'error');
|
||||
showToast('Erro ao copiar imagem. Certifique-se de que a página está focada.', 'error');
|
||||
console.error(err);
|
||||
}
|
||||
}, 'image/png');
|
||||
} catch (e) {
|
||||
showToast('Erro ao processar imagem para cópia.', 'error');
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
img.onerror = () => showToast('Erro ao carregar imagem para cópia.', 'error');
|
||||
img.src = url;
|
||||
};
|
||||
|
||||
const markGtoSent = async (gtoId, sent) => {
|
||||
|
||||
Reference in New Issue
Block a user