fix handle upload file on page precheck and postcheck

This commit is contained in:
2025-07-11 14:55:11 +07:00
parent 748ac8a77e
commit e3956ae0e4
5 changed files with 352 additions and 114 deletions

View File

@@ -151,6 +151,16 @@
min-height: 80px;
}
.file-input-hidden {
display: none;
}
.file-info {
margin-top: 5px;
font-size: 12px;
color: #6c757d;
}
/* Mobile Responsive */
@media (max-width: 768px) {
.container {
@@ -275,7 +285,7 @@
<a href="/" class="btn btn-warning btn-sm">
Kembali
</a>
<form action="{{ route('postchecks.store', $transaction->id) }}" method="POST" id="postcheckForm">
<form action="{{ route('postchecks.store', $transaction->id) }}" method="POST" id="postcheckForm" enctype="multipart/form-data">
@csrf
<input type="hidden" name="transaction_id" value="{{ $transaction->id }}">
@@ -332,13 +342,12 @@
</div>
</div>
<!-- Foto Depan -->
<div class="section-header">
<h5><i class="fas fa-camera"></i> Foto Depan Kendaraan <span class="text-danger">*</span></h5>
</div>
<div class="form-group">
<input type="hidden" id="front_image" name="front_image" required>
<input type="file" id="front_image" name="front_image" accept="image/*" class="file-input-hidden" required>
<div class="camera-container">
<video id="front_camera" autoplay playsinline class="camera-video"></video>
<canvas id="front_canvas" style="display: none;"></canvas>
@@ -372,7 +381,7 @@
<div class="col-md-6">
<div class="form-group">
<label for="cabin_temperature_image">Foto Suhu Kabin</label>
<input type="hidden" id="cabin_temperature_image" name="cabin_temperature_image">
<input type="file" id="cabin_temperature_image" name="cabin_temperature_image" accept="image/*" class="file-input-hidden">
<div class="camera-container">
<video id="cabin_camera" autoplay playsinline class="camera-video"></video>
<canvas id="cabin_canvas" style="display: none;"></canvas>
@@ -413,23 +422,23 @@
<div class="col-md-6">
<div class="form-group">
<label for="ac_image">Foto AC</label>
<input type="hidden" id="ac_image" name="ac_image">
<input type="file" id="ac_image" name="ac_image" accept="image/*" class="file-input-hidden">
<div class="camera-container">
<video id="ac_camera" autoplay playsinline class="camera-video"></video>
<canvas id="ac_canvas" style="display: none;"></canvas>
<div class="camera-controls">
<button type="button" class="btn btn-primary btn-sm" onclick="startCamera('ac_camera')">
<i class="fas fa-camera"></i> Buka Kamera
</button>
<button type="button" class="btn btn-success btn-sm" onclick="capturePhoto('ac_camera', 'ac_canvas', 'ac_image', 'ac_preview')">
<i class="fas fa-camera-retro"></i> Ambil Foto
</button>
</div>
<div class="mt-2">
<small class="text-muted">Atau upload foto dari galeri:</small>
<input type="file" class="form-control-file mt-1" accept="image/*" onchange="handleFileUpload(this, 'ac_image', 'ac_preview')">
</div>
<div id="ac_preview" class="photo-preview"></div>
<div class="camera-controls">
<button type="button" class="btn btn-primary btn-sm" onclick="startCamera('ac_camera')">
<i class="fas fa-camera"></i> Buka Kamera
</button>
<button type="button" class="btn btn-success btn-sm" onclick="capturePhoto('ac_camera', 'ac_canvas', 'ac_image', 'ac_preview')">
<i class="fas fa-camera-retro"></i> Ambil Foto
</button>
</div>
<div class="mt-2">
<small class="text-muted">Atau upload foto dari galeri:</small>
<input type="file" class="form-control-file mt-1" accept="image/*" onchange="handleFileUpload(this, 'ac_image', 'ac_preview')">
</div>
<div id="ac_preview" class="photo-preview"></div>
</div>
</div>
</div>
@@ -454,23 +463,23 @@
<div class="col-md-6">
<div class="form-group">
<label for="blower_image">Foto Blower</label>
<input type="hidden" id="blower_image" name="blower_image">
<input type="file" id="blower_image" name="blower_image" accept="image/*" class="file-input-hidden">
<div class="camera-container">
<video id="blower_camera" autoplay playsinline class="camera-video"></video>
<canvas id="blower_canvas" style="display: none;"></canvas>
<div class="camera-controls">
<button type="button" class="btn btn-primary btn-sm" onclick="startCamera('blower_camera')">
<i class="fas fa-camera"></i> Buka Kamera
</button>
<button type="button" class="btn btn-success btn-sm" onclick="capturePhoto('blower_camera', 'blower_canvas', 'blower_image', 'blower_preview')">
<i class="fas fa-camera-retro"></i> Ambil Foto
</button>
</div>
<div class="mt-2">
<small class="text-muted">Atau upload foto dari galeri:</small>
<input type="file" class="form-control-file mt-1" accept="image/*" onchange="handleFileUpload(this, 'blower_image', 'blower_preview')">
</div>
<div id="blower_preview" class="photo-preview"></div>
<div class="camera-controls">
<button type="button" class="btn btn-primary btn-sm" onclick="startCamera('blower_camera')">
<i class="fas fa-camera"></i> Buka Kamera
</button>
<button type="button" class="btn btn-success btn-sm" onclick="capturePhoto('blower_camera', 'blower_canvas', 'blower_image', 'blower_preview')">
<i class="fas fa-camera-retro"></i> Ambil Foto
</button>
</div>
<div class="mt-2">
<small class="text-muted">Atau upload foto dari galeri:</small>
<input type="file" class="form-control-file mt-1" accept="image/*" onchange="handleFileUpload(this, 'blower_image', 'blower_preview')">
</div>
<div id="blower_preview" class="photo-preview"></div>
</div>
</div>
</div>
@@ -495,23 +504,23 @@
<div class="col-md-6">
<div class="form-group">
<label for="evaporator_image">Foto Evaporator</label>
<input type="hidden" id="evaporator_image" name="evaporator_image">
<input type="file" id="evaporator_image" name="evaporator_image" accept="image/*" class="file-input-hidden">
<div class="camera-container">
<video id="evaporator_camera" autoplay playsinline class="camera-video"></video>
<canvas id="evaporator_canvas" style="display: none;"></canvas>
<div class="camera-controls">
<button type="button" class="btn btn-primary btn-sm" onclick="startCamera('evaporator_camera')">
<i class="fas fa-camera"></i> Buka Kamera
</button>
<button type="button" class="btn btn-success btn-sm" onclick="capturePhoto('evaporator_camera', 'evaporator_canvas', 'evaporator_image', 'evaporator_preview')">
<i class="fas fa-camera-retro"></i> Ambil Foto
</button>
</div>
<div class="mt-2">
<small class="text-muted">Atau upload foto dari galeri:</small>
<input type="file" class="form-control-file mt-1" accept="image/*" onchange="handleFileUpload(this, 'evaporator_image', 'evaporator_preview')">
</div>
<div id="evaporator_preview" class="photo-preview"></div>
<div class="camera-controls">
<button type="button" class="btn btn-primary btn-sm" onclick="startCamera('evaporator_camera')">
<i class="fas fa-camera"></i> Buka Kamera
</button>
<button type="button" class="btn btn-success btn-sm" onclick="capturePhoto('evaporator_camera', 'evaporator_canvas', 'evaporator_image', 'evaporator_preview')">
<i class="fas fa-camera-retro"></i> Ambil Foto
</button>
</div>
<div class="mt-2">
<small class="text-muted">Atau upload foto dari galeri:</small>
<input type="file" class="form-control-file mt-1" accept="image/*" onchange="handleFileUpload(this, 'evaporator_image', 'evaporator_preview')">
</div>
<div id="evaporator_preview" class="photo-preview"></div>
</div>
</div>
</div>
@@ -580,8 +589,6 @@ function logout(event){
})
}
// Fallback untuk browser lama
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
@@ -671,11 +678,11 @@ async function startCamera(videoId) {
}
}
// Capture photo
// Capture photo and convert to file
function capturePhoto(videoId, canvasId, inputId, previewId) {
const video = document.getElementById(videoId);
const canvas = document.getElementById(canvasId);
const input = document.getElementById(inputId);
const fileInput = document.getElementById(inputId);
const preview = document.getElementById(previewId);
if (!video.srcObject) {
@@ -695,23 +702,37 @@ function capturePhoto(videoId, canvasId, inputId, previewId) {
canvas.height = video.videoHeight;
context.drawImage(video, 0, 0, canvas.width, canvas.height);
const imageData = canvas.toDataURL('image/jpeg', 0.8);
input.value = imageData;
// Convert canvas ke File object
canvas.toBlob(function(blob) {
// Buat File object
const file = new File([blob], `photo_${Date.now()}.jpg`, {
type: 'image/jpeg',
lastModified: Date.now()
});
// Assign ke file input
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files;
// Preview
const url = URL.createObjectURL(blob);
preview.innerHTML = `
<img src="${url}" style="max-width: 200px; max-height: 150px; border-radius: 8px; border: 3px solid #059669; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
<div class="mt-2">
<small class="text-success"><i class="fas fa-check"></i> Foto berhasil diambil</small>
<br>
<small class="text-muted">Ukuran: ${(file.size / 1024).toFixed(1)} KB</small>
</div>
`;
}, 'image/jpeg', 0.8);
preview.innerHTML = `
<img src="${imageData}" style="max-width: 200px; max-height: 150px; border-radius: 8px; border: 3px solid #059669; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
<div class="mt-2">
<small class="text-success"><i class="fas fa-check"></i> Foto berhasil diambil</small>
</div>
`;
} catch (err) {
alert('Gagal mengambil foto: ' + err.message);
}
}
// Handle file upload
// Handle file upload from gallery
function handleFileUpload(input, inputId, previewId) {
const file = input.files[0];
if (!file) return;
@@ -721,20 +742,29 @@ function handleFileUpload(input, inputId, previewId) {
return;
}
const reader = new FileReader();
reader.onload = function(e) {
const imageData = e.target.result;
document.getElementById(inputId).value = imageData;
const preview = document.getElementById(previewId);
preview.innerHTML = `
<img src="${imageData}" style="max-width: 200px; max-height: 150px; border-radius: 8px; border: 3px solid #059669; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
<div class="mt-2">
<small class="text-success"><i class="fas fa-check"></i> Foto berhasil diupload</small>
</div>
`;
};
reader.readAsDataURL(file);
// Validasi ukuran file (max 2MB)
if (file.size > 2 * 1024 * 1024) {
alert('Ukuran file maksimal 2MB');
return;
}
// Assign ke file input yang sesuai
const targetInput = document.getElementById(inputId);
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
targetInput.files = dataTransfer.files;
// Preview
const url = URL.createObjectURL(file);
const preview = document.getElementById(previewId);
preview.innerHTML = `
<img src="${url}" style="max-width: 200px; max-height: 150px; border-radius: 8px; border: 3px solid #059669; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
<div class="mt-2">
<small class="text-success"><i class="fas fa-check"></i> Foto berhasil diupload</small>
<br>
<small class="text-muted">Ukuran: ${(file.size / 1024).toFixed(1)} KB</small>
</div>
`;
}
// Stop all cameras when page is unloaded
@@ -751,11 +781,23 @@ document.getElementById('postcheckForm').addEventListener('submit', function(e)
requiredFields.forEach(fieldId => {
const field = document.getElementById(fieldId);
if (!field.value.trim()) {
field.classList.add('is-invalid');
isValid = false;
if (field.type === 'file') {
// Validasi file input
if (!field.files || field.files.length === 0) {
field.classList.add('is-invalid');
isValid = false;
} else {
field.classList.remove('is-invalid');
}
} else {
field.classList.remove('is-invalid');
// Validasi input biasa
if (!field.value.trim()) {
field.classList.add('is-invalid');
isValid = false;
} else {
field.classList.remove('is-invalid');
}
}
});