From 884975181c3722374a918a85bb5da9dbde5daa80 Mon Sep 17 00:00:00 2001 From: Baghaztra Date: Mon, 27 Oct 2025 20:02:02 +0700 Subject: [PATCH] [Update] Ubah dimensi kamera menjadi 1x1 --- package-lock.json | 2 +- resources/js/components/PhotoUploader.vue | 443 ++++++++++++++++++++++ resources/js/pages/EditProduk.vue | 350 +---------------- resources/js/pages/InputProduk.vue | 212 +---------- 4 files changed, 453 insertions(+), 554 deletions(-) create mode 100644 resources/js/components/PhotoUploader.vue diff --git a/package-lock.json b/package-lock.json index d06a6c5..2318044 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "html", + "name": "Kasir", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/resources/js/components/PhotoUploader.vue b/resources/js/components/PhotoUploader.vue new file mode 100644 index 0000000..26d8b0b --- /dev/null +++ b/resources/js/components/PhotoUploader.vue @@ -0,0 +1,443 @@ + + + diff --git a/resources/js/pages/EditProduk.vue b/resources/js/pages/EditProduk.vue index 60575bd..c605337 100644 --- a/resources/js/pages/EditProduk.vue +++ b/resources/js/pages/EditProduk.vue @@ -77,191 +77,7 @@
- - -
- -
-
- - -
-
- - -
-
-
-
- - - -
-
- - - - -
-

-
-
- - -
- - -
-
-
- - - -

- Format: JPG, JPEG, PNG (Max: 2MB per file, Max: 6 foto) -

- -
- {{ uploadError }} -
+
@@ -281,43 +97,6 @@ - - -
- - -
-
- - -
- - -
-
-
@@ -329,6 +108,7 @@ import mainLayout from "../layouts/mainLayout.vue"; import InputField from "../components/InputField.vue"; import InputSelect from "../components/InputSelect.vue"; import CreateItemModal from "../components/CreateItemModal.vue"; +import PhotoUploader from "../components/PhotoUploader.vue"; const route = useRoute(); const router = useRouter(); @@ -347,15 +127,6 @@ const form = ref({ const category = ref([]); const uploadedImages = ref([]); const loading = ref(false); -const uploadLoading = ref(false); -const uploadError = ref(""); -const isDragging = ref(false); -const fileInput = ref(null); -const showUploadMenu = ref(false); -const showCamera = ref(false); -const video = ref(null); -const canvas = ref(null); -let stream = null; const openItemModal = ref(false); const editedProduct = ref(null); @@ -423,122 +194,11 @@ const loadFoto = async () => { uploadedImages.value = response.data; } catch (error) { console.error("Error loading photos:", error); - uploadError.value = "Gagal memuat foto"; } }; -const toggleUploadMenu = () => { - if (!uploadLoading.value && uploadedImages.value.length < 6) { - showUploadMenu.value = !showUploadMenu.value; - } -}; - -const triggerFileUpload = () => { - showUploadMenu.value = false; - fileInput.value?.click(); -}; - -const handleFileSelect = (e) => { - const files = Array.from(e.target.files); - uploadFiles(files); -}; - -const handleDrop = (e) => { - e.preventDefault(); - isDragging.value = false; - if (uploadLoading.value || uploadedImages.value.length >= 6) return; - const files = Array.from(e.dataTransfer.files); - uploadFiles(files); -}; - -const uploadFiles = async (files) => { - uploadError.value = ''; - if (uploadedImages.value.length + files.length > 6) { - uploadError.value = 'Maksimal 6 foto yang dapat diupload'; - return; - } - const validFiles = files.filter(file => { - const isValidType = ['image/jpeg', 'image/jpg', 'image/png'].includes(file.type); - const isValidSize = file.size <= 2 * 1024 * 1024; - if (!isValidType) { - uploadError.value = 'Format file harus JPG, JPEG, atau PNG'; - return false; - } - if (!isValidSize) { - uploadError.value = 'Ukuran file maksimal 2MB'; - return false; - } - return true; - }); - if (validFiles.length === 0) return; - uploadLoading.value = true; - try { - for (const file of validFiles) { - const formData = new FormData(); - formData.append('foto', file); - const response = await axios.post('/api/foto', formData, { - headers: { - Authorization: `Bearer ${localStorage.getItem("token")}`, - 'Content-Type': 'multipart/form-data', - }, - }); - uploadedImages.value.push(response.data); - } - if (fileInput.value) { - fileInput.value.value = ''; - } - } catch (error) { - console.error('Upload error:', error); - uploadError.value = error.response?.data?.message || 'Gagal mengupload foto'; - } finally { - uploadLoading.value = false; - } -}; - -const removeImage = async (id) => { - try { - await axios.delete(`/api/foto/${id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem("token")}`, - }, - }); - uploadedImages.value = uploadedImages.value.filter((i) => i.id !== id); - } catch { - uploadError.value = "Gagal menghapus foto"; - } -}; - -const openCameraModal = async () => { - showUploadMenu.value = false; - showCamera.value = true; - try { - stream = await navigator.mediaDevices.getUserMedia({ video: true }); - video.value.srcObject = stream; - } catch (err) { - console.error("Gagal akses kamera:", err); - alert("Tidak bisa mengakses kamera, cek izin browser!"); - closeCamera(); - } -}; - -const closeCamera = () => { - showCamera.value = false; - if (stream) { - stream.getTracks().forEach(track => track.stop()); - stream = null; - } -}; - -const capturePhoto = () => { - const ctx = canvas.value.getContext("2d"); - canvas.value.width = video.value.videoWidth; - canvas.value.height = video.value.videoHeight; - ctx.drawImage(video.value, 0, 0); - canvas.value.toBlob(async (blob) => { - if (!blob) return; - await uploadFiles([new File([blob], "camera_photo.png", { type: "image/png" })]); - closeCamera(); - }, "image/png"); +const handleUploadError = (error) => { + console.error('Upload error:', error); }; const submitForm = async () => { @@ -552,7 +212,7 @@ const submitForm = async () => { router.push("/produk?message=Produk berhasil diperbarui"); } catch (err) { console.error("Submit error:", err); - uploadError.value = err.response?.data?.message || "Gagal menyimpan produk"; + alert(err.response?.data?.message || "Gagal menyimpan produk"); } finally { loading.value = false; } diff --git a/resources/js/pages/InputProduk.vue b/resources/js/pages/InputProduk.vue index de159a8..1117285 100644 --- a/resources/js/pages/InputProduk.vue +++ b/resources/js/pages/InputProduk.vue @@ -50,87 +50,7 @@
- - -
- -
-
- - -
-
- - -
-
-
-
- - - -
-
- - - - - -
-

-
-
- - -
- - - -
-
-
- - - - -

Format: JPG, JPEG, PNG (Max: 2MB per file, Max: 6 foto)

-
- {{ uploadError }} -
+
@@ -147,9 +67,6 @@ - -
-
@@ -172,6 +89,7 @@ import mainLayout from "../layouts/mainLayout.vue"; import InputField from "../components/InputField.vue"; import InputSelect from "../components/InputSelect.vue"; import CreateItemModal from "../components/CreateItemModal.vue"; +import PhotoUploader from "../components/PhotoUploader.vue"; const router = useRouter(); @@ -184,23 +102,12 @@ const form = ref({ harga_jual: null, }); const category = ref([]); -const showUploadMenu = ref(false); -const fileInput = ref(null); const loading = ref(false); -const uploadLoading = ref(false); const uploadedImages = ref([]); -const isDragging = ref(false); -const uploadError = ref(''); const errors = ref({}); const openItemModal = ref(false); const createdProduct = ref(null); -// Camera states -const showCamera = ref(false); -const video = ref(null); -const canvas = ref(null); -let stream = null; - // Formatted values for harga_per_gram and harga_jual const hargaPerGramFormatted = ref(""); const hargaJualFormatted = ref(""); @@ -303,119 +210,11 @@ const loadFoto = async () => { uploadedImages.value = response.data; } catch (e) { console.error(e); - uploadError.value = "Gagal memuat foto"; } }; -const toggleUploadMenu = () => { - if (!uploadLoading.value && uploadedImages.value.length < 6) { - showUploadMenu.value = !showUploadMenu.value; - } -}; - -const triggerFileUpload = () => { - showUploadMenu.value = false; - fileInput.value?.click(); -}; - -const handleFileSelect = (event) => { - const files = Array.from(event.target.files); - uploadFiles(files); -}; - -const handleDrop = (event) => { - event.preventDefault(); - isDragging.value = false; - if (uploadLoading.value || uploadedImages.value.length >= 6) return; - const files = Array.from(event.dataTransfer.files); - uploadFiles(files); -}; - -const uploadFiles = async (files) => { - uploadError.value = ''; - if (uploadedImages.value.length + files.length > 6) { - uploadError.value = 'Maksimal 6 foto yang dapat diupload'; - return; - } - const validFiles = files.filter((file) => { - const isValidType = ['image/jpeg', 'image/jpg', 'image/png'].includes(file.type); - const isValidSize = file.size <= 2 * 1024 * 1024; - if (!isValidType) { - uploadError.value = 'Format file harus JPG, JPEG, atau PNG'; - return false; - } - if (!isValidSize) { - uploadError.value = 'Ukuran file maksimal 2MB'; - return false; - } - return true; - }); - if (validFiles.length === 0) return; - uploadLoading.value = true; - try { - for (const file of validFiles) { - const formData = new FormData(); - formData.append('foto', file); - const response = await axios.post('/api/foto', formData, { - headers: { - Authorization: `Bearer ${localStorage.getItem("token")}`, - 'Content-Type': 'multipart/form-data', - }, - }); - uploadedImages.value.push(response.data); - } - if (fileInput.value) fileInput.value.value = ''; - } catch (error) { - console.error('Upload error:', error); - uploadError.value = error.response?.data?.message || 'Gagal mengupload foto'; - } finally { - uploadLoading.value = false; - } -}; - -const removeImage = async (id) => { - try { - await axios.delete(`/api/foto/${id}`, { - headers: { Authorization: `Bearer ${localStorage.getItem("token")}` }, - }); - uploadedImages.value = uploadedImages.value.filter((i) => i.id !== id); - } catch { - uploadError.value = "Gagal menghapus foto"; - } -}; - -// CAMERA FUNCTIONS -const openCameraModal = async () => { - showUploadMenu.value = false; - showCamera.value = true; - try { - stream = await navigator.mediaDevices.getUserMedia({ video: true }); - video.value.srcObject = stream; - } catch (err) { - console.error("Gagal akses kamera:", err); - alert("Tidak bisa mengakses kamera, cek izin browser!"); - closeCamera(); - } -}; - -const closeCamera = () => { - showCamera.value = false; - if (stream) { - stream.getTracks().forEach((track) => track.stop()); - stream = null; - } -}; - -const capturePhoto = () => { - const ctx = canvas.value.getContext("2d"); - canvas.value.width = video.value.videoWidth; - canvas.value.height = video.value.videoHeight; - ctx.drawImage(video.value, 0, 0); - canvas.value.toBlob(async (blob) => { - if (!blob) return; - await uploadFiles([new File([blob], "camera_photo.png", { type: "image/png" })]); - closeCamera(); - }, "image/png"); +const handleUploadError = (error) => { + console.error('Upload error:', error); }; const submitForm = async (addItem) => { @@ -446,9 +245,6 @@ const submitForm = async (addItem) => { hargaPerGramFormatted.value = ""; hargaJualFormatted.value = ""; uploadedImages.value = []; - uploadError.value = ''; - showUploadMenu.value = false; - if (fileInput.value) fileInput.value.value = ''; if (addItem) { openCreateItemModal(createdProductData); } else {