diff --git a/app/Http/Controllers/Transactions/PostchecksController.php b/app/Http/Controllers/Transactions/PostchecksController.php index d2e8b8e..9e617b5 100644 --- a/app/Http/Controllers/Transactions/PostchecksController.php +++ b/app/Http/Controllers/Transactions/PostchecksController.php @@ -34,16 +34,16 @@ class PostchecksController extends Controller 'pressure_high' => 'required|numeric|min:0', 'pressure_low' => 'nullable|numeric|min:0', 'cabin_temperature' => 'nullable|numeric', - 'cabin_temperature_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', + 'cabin_temperature_image' => 'nullable|image|mimes:jpeg,png,jpg|max:20480', 'ac_condition' => 'nullable|in:' . implode(',', Postcheck::getAcConditionOptions()), - 'ac_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', + 'ac_image' => 'nullable|image|mimes:jpeg,png,jpg|max:20480', 'blower_condition' => 'nullable|in:' . implode(',', Postcheck::getBlowerConditionOptions()), - 'blower_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', + 'blower_image' => 'nullable|image|mimes:jpeg,png,jpg|max:20480', 'evaporator_condition' => 'nullable|in:' . implode(',', Postcheck::getEvaporatorConditionOptions()), - 'evaporator_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', + 'evaporator_image' => 'nullable|image|mimes:jpeg,png,jpg|max:20480', 'compressor_condition' => 'nullable|in:' . implode(',', Postcheck::getCompressorConditionOptions()), 'postcheck_notes' => 'nullable|string', - 'front_image' => 'required|image|mimes:jpeg,png,jpg|max:2048', + 'front_image' => 'required|image|mimes:jpeg,png,jpg|max:20480', ]); $data = [ diff --git a/app/Http/Controllers/Transactions/PrechecksController.php b/app/Http/Controllers/Transactions/PrechecksController.php index e9d4c69..3b15fab 100644 --- a/app/Http/Controllers/Transactions/PrechecksController.php +++ b/app/Http/Controllers/Transactions/PrechecksController.php @@ -34,16 +34,16 @@ class PrechecksController extends Controller 'pressure_high' => 'required|numeric|min:0', 'pressure_low' => 'nullable|numeric|min:0', 'cabin_temperature' => 'nullable|numeric', - 'cabin_temperature_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', + 'cabin_temperature_image' => 'nullable|image|mimes:jpeg,png,jpg|max:20480', 'ac_condition' => 'nullable|in:' . implode(',', Precheck::getAcConditionOptions()), - 'ac_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', + 'ac_image' => 'nullable|image|mimes:jpeg,png,jpg|max:20480', 'blower_condition' => 'nullable|in:' . implode(',', Precheck::getBlowerConditionOptions()), - 'blower_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', + 'blower_image' => 'nullable|image|mimes:jpeg,png,jpg|max:20480', 'evaporator_condition' => 'nullable|in:' . implode(',', Precheck::getEvaporatorConditionOptions()), - 'evaporator_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', + 'evaporator_image' => 'nullable|image|mimes:jpeg,png,jpg|max:20480', 'compressor_condition' => 'nullable|in:' . implode(',', Precheck::getCompressorConditionOptions()), 'precheck_notes' => 'nullable|string', - 'front_image' => 'required|image|mimes:jpeg,png,jpg|max:2048', + 'front_image' => 'required|image|mimes:jpeg,png,jpg|max:20480', ]); $data = [ diff --git a/resources/views/transaction/postchecks.blade.php b/resources/views/transaction/postchecks.blade.php index 1076270..b5198fa 100644 --- a/resources/views/transaction/postchecks.blade.php +++ b/resources/views/transaction/postchecks.blade.php @@ -420,7 +420,7 @@
- Atau upload foto dari galeri: + Atau upload foto dari galeri (maksimal 20MB):
@@ -460,7 +460,7 @@
- Atau upload foto dari galeri: + Atau upload foto dari galeri (maksimal 20MB):
@@ -507,7 +507,7 @@
- Atau upload foto dari galeri: + Atau upload foto dari galeri (maksimal 20MB):
@@ -554,7 +554,7 @@
- Atau upload foto dari galeri: + Atau upload foto dari galeri (maksimal 20MB):
@@ -601,7 +601,7 @@
- Atau upload foto dari galeri: + Atau upload foto dari galeri (maksimal 20MB):
@@ -1086,13 +1086,7 @@ } try { - // Stop current stream - stopCamera(videoId); - - // Wait a bit before starting new camera - await new Promise(resolve => setTimeout(resolve, 100)); - - // Get current facing mode + // Get current facing mode before stopping const currentTracks = streams[videoId] ? streams[videoId].getVideoTracks() : []; let currentFacingMode = 'environment'; // default to back camera @@ -1106,16 +1100,75 @@ // Switch to opposite camera const newFacingMode = currentFacingMode === 'environment' ? 'user' : 'environment'; - const constraints = { - video: { - width: { min: 320, ideal: 640, max: 1280 }, - height: { min: 240, ideal: 480, max: 720 }, - aspectRatio: { ideal: 4/3 }, - facingMode: { ideal: newFacingMode } - } - }; + // Stop current stream + stopCamera(videoId); - const stream = await navigator.mediaDevices.getUserMedia(constraints); + // Wait a bit before starting new camera + await new Promise(resolve => setTimeout(resolve, 200)); + + // Try to get the specific camera + let stream; + + try { + // First try with specific facing mode + const constraints = { + video: { + width: { min: 320, ideal: 640, max: 1280 }, + height: { min: 240, ideal: 480, max: 720 }, + aspectRatio: { ideal: 4/3 }, + facingMode: { ideal: newFacingMode } + } + }; + + stream = await navigator.mediaDevices.getUserMedia(constraints); + } catch (err) { + console.log('Gagal dengan facingMode, mencoba dengan deviceId...'); + + // If facingMode fails, try to get available devices and switch + try { + const devices = await navigator.mediaDevices.enumerateDevices(); + const videoDevices = devices.filter(device => device.kind === 'videoinput'); + + if (videoDevices.length > 1) { + // Find current device index + const currentDevice = videoDevices.find(device => { + if (currentTracks.length > 0) { + return device.deviceId === currentTracks[0].getSettings().deviceId; + } + return false; + }); + + const currentIndex = currentDevice ? videoDevices.indexOf(currentDevice) : 0; + const nextIndex = (currentIndex + 1) % videoDevices.length; + const nextDevice = videoDevices[nextIndex]; + + console.log('Beralih dari device:', currentDevice?.label, 'ke:', nextDevice?.label); + + const deviceConstraints = { + video: { + deviceId: { exact: nextDevice.deviceId }, + width: { min: 320, ideal: 640, max: 1280 }, + height: { min: 240, ideal: 480, max: 720 }, + aspectRatio: { ideal: 4/3 } + } + }; + + stream = await navigator.mediaDevices.getUserMedia(deviceConstraints); + } else { + // Fallback to basic constraints + stream = await navigator.mediaDevices.getUserMedia({ + video: { + width: { min: 320, ideal: 640, max: 1280 }, + height: { min: 240, ideal: 480, max: 720 }, + aspectRatio: { ideal: 4/3 } + } + }); + } + } catch (deviceErr) { + console.error('Gagal beralih dengan deviceId:', deviceErr); + throw deviceErr; + } + } video.srcObject = stream; streams[videoId] = stream; @@ -1142,6 +1195,17 @@ console.log('Berhasil beralih ke kamera:', newFacingMode === 'environment' ? 'belakang' : 'depan'); + // Show success notification + Swal.fire({ + icon: 'success', + title: 'Kamera Berhasil Diganti', + text: `Berhasil beralih ke ${newFacingMode === 'environment' ? 'kamera belakang' : 'kamera depan'}`, + timer: 1500, + showConfirmButton: false, + toast: true, + position: 'top-end' + }); + } catch (err) { console.error('Gagal beralih kamera:', err); Swal.fire({ @@ -1204,12 +1268,12 @@ return; } - // Validasi ukuran file (max 2MB) - if (file.size > 2 * 1024 * 1024) { + // Validasi ukuran file (max 20MB) + if (file.size > 20 * 1024 * 1024) { Swal.fire({ icon: 'warning', title: 'Ukuran File Terlalu Besar', - text: 'Ukuran file maksimal 2MB', + text: 'Ukuran file maksimal 20MB', confirmButtonText: 'OK' }); return; diff --git a/resources/views/transaction/prechecks.blade.php b/resources/views/transaction/prechecks.blade.php index e9554cb..95c3a9f 100644 --- a/resources/views/transaction/prechecks.blade.php +++ b/resources/views/transaction/prechecks.blade.php @@ -420,7 +420,7 @@
- Atau upload foto dari galeri: + Atau upload foto dari galeri (maksimal 20MB):
@@ -460,7 +460,7 @@
- Atau upload foto dari galeri: + Atau upload foto dari galeri (maksimal 20MB):
@@ -507,7 +507,7 @@
- Atau upload foto dari galeri: + Atau upload foto dari galeri (maksimal 20MB):
@@ -554,7 +554,7 @@
- Atau upload foto dari galeri: + Atau upload foto dari galeri (maksimal 20MB):
@@ -601,7 +601,7 @@
- Atau upload foto dari galeri: + Atau upload foto dari galeri (maksimal 20MB):
@@ -1086,13 +1086,7 @@ } try { - // Stop current stream - stopCamera(videoId); - - // Wait a bit before starting new camera - await new Promise(resolve => setTimeout(resolve, 100)); - - // Get current facing mode + // Get current facing mode before stopping const currentTracks = streams[videoId] ? streams[videoId].getVideoTracks() : []; let currentFacingMode = 'environment'; // default to back camera @@ -1106,16 +1100,75 @@ // Switch to opposite camera const newFacingMode = currentFacingMode === 'environment' ? 'user' : 'environment'; - const constraints = { - video: { - width: { min: 320, ideal: 640, max: 1280 }, - height: { min: 240, ideal: 480, max: 720 }, - aspectRatio: { ideal: 4/3 }, - facingMode: { ideal: newFacingMode } - } - }; + // Stop current stream + stopCamera(videoId); - const stream = await navigator.mediaDevices.getUserMedia(constraints); + // Wait a bit before starting new camera + await new Promise(resolve => setTimeout(resolve, 200)); + + // Try to get the specific camera + let stream; + + try { + // First try with specific facing mode + const constraints = { + video: { + width: { min: 320, ideal: 640, max: 1280 }, + height: { min: 240, ideal: 480, max: 720 }, + aspectRatio: { ideal: 4/3 }, + facingMode: { ideal: newFacingMode } + } + }; + + stream = await navigator.mediaDevices.getUserMedia(constraints); + } catch (err) { + console.log('Gagal dengan facingMode, mencoba dengan deviceId...'); + + // If facingMode fails, try to get available devices and switch + try { + const devices = await navigator.mediaDevices.enumerateDevices(); + const videoDevices = devices.filter(device => device.kind === 'videoinput'); + + if (videoDevices.length > 1) { + // Find current device index + const currentDevice = videoDevices.find(device => { + if (currentTracks.length > 0) { + return device.deviceId === currentTracks[0].getSettings().deviceId; + } + return false; + }); + + const currentIndex = currentDevice ? videoDevices.indexOf(currentDevice) : 0; + const nextIndex = (currentIndex + 1) % videoDevices.length; + const nextDevice = videoDevices[nextIndex]; + + console.log('Beralih dari device:', currentDevice?.label, 'ke:', nextDevice?.label); + + const deviceConstraints = { + video: { + deviceId: { exact: nextDevice.deviceId }, + width: { min: 320, ideal: 640, max: 1280 }, + height: { min: 240, ideal: 480, max: 720 }, + aspectRatio: { ideal: 4/3 } + } + }; + + stream = await navigator.mediaDevices.getUserMedia(deviceConstraints); + } else { + // Fallback to basic constraints + stream = await navigator.mediaDevices.getUserMedia({ + video: { + width: { min: 320, ideal: 640, max: 1280 }, + height: { min: 240, ideal: 480, max: 720 }, + aspectRatio: { ideal: 4/3 } + } + }); + } + } catch (deviceErr) { + console.error('Gagal beralih dengan deviceId:', deviceErr); + throw deviceErr; + } + } video.srcObject = stream; streams[videoId] = stream; @@ -1142,6 +1195,17 @@ console.log('Berhasil beralih ke kamera:', newFacingMode === 'environment' ? 'belakang' : 'depan'); + // Show success notification + Swal.fire({ + icon: 'success', + title: 'Kamera Berhasil Diganti', + text: `Berhasil beralih ke ${newFacingMode === 'environment' ? 'kamera belakang' : 'kamera depan'}`, + timer: 1500, + showConfirmButton: false, + toast: true, + position: 'top-end' + }); + } catch (err) { console.error('Gagal beralih kamera:', err); Swal.fire({ @@ -1204,12 +1268,12 @@ return; } - // Validasi ukuran file (max 2MB) - if (file.size > 2 * 1024 * 1024) { + // Validasi ukuran file (max 20MB) + if (file.size > 20 * 1024 * 1024) { Swal.fire({ icon: 'warning', title: 'Ukuran File Terlalu Besar', - text: 'Ukuran file maksimal 2MB', + text: 'Ukuran file maksimal 20MB', confirmButtonText: 'OK' }); return;