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 @@
+
+
+
+
+
+
+
+
+
![]()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Format: JPG, JPEG, PNG (Max: 2MB per file, Max: {{ maxPhotos }} foto)
+
+ {{ uploadError }}
+
+
+
+
+
+
+
+
+
Ambil Foto
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 {