From 12192c536d0009c1bb643353eb50a3b970623cf3 Mon Sep 17 00:00:00 2001 From: Timoti313 Date: Thu, 28 Aug 2025 14:07:56 +0700 Subject: [PATCH 1/5] [feat Kasir, KasirForm, KasirTransaksiList] --- resources/js/components/KasirForm.vue | 83 +++++++++++++++++++ .../js/components/KasirTransaksiList.vue | 33 ++++++++ resources/js/pages/Kasir.vue | 31 +++++++ resources/js/router/index.js | 7 ++ 4 files changed, 154 insertions(+) create mode 100644 resources/js/components/KasirForm.vue create mode 100644 resources/js/components/KasirTransaksiList.vue create mode 100644 resources/js/pages/Kasir.vue diff --git a/resources/js/components/KasirForm.vue b/resources/js/components/KasirForm.vue new file mode 100644 index 0000000..066a5ca --- /dev/null +++ b/resources/js/components/KasirForm.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/resources/js/components/KasirTransaksiList.vue b/resources/js/components/KasirTransaksiList.vue new file mode 100644 index 0000000..0301fff --- /dev/null +++ b/resources/js/components/KasirTransaksiList.vue @@ -0,0 +1,33 @@ + + + diff --git a/resources/js/pages/Kasir.vue b/resources/js/pages/Kasir.vue new file mode 100644 index 0000000..0b27fe4 --- /dev/null +++ b/resources/js/pages/Kasir.vue @@ -0,0 +1,31 @@ + + + diff --git a/resources/js/router/index.js b/resources/js/router/index.js index f7e4dec..f5eaa5d 100644 --- a/resources/js/router/index.js +++ b/resources/js/router/index.js @@ -3,6 +3,8 @@ import Home from '../pages/Home.vue' import Produk from '../pages/Produk.vue' import Brankas from '../pages/Brankas.vue' import Tray from '../pages/Tray.vue' +import Kasir from '../pages/Kasir.vue' + const routes = [ @@ -26,6 +28,11 @@ const routes = [ name: 'Nampan', component: Tray }, + { + path: '/kasir', + name: 'Kasir', + component: Kasir + }, ] From eebabfd9192085f459e2f4964e6a6cdf1101dbc0 Mon Sep 17 00:00:00 2001 From: Baghaztra Date: Thu, 28 Aug 2025 15:13:19 +0700 Subject: [PATCH 2/5] [update] Input produk --- .env.example | 65 +++++++ resources/js/components/DropdownNav.vue | 48 ----- resources/js/components/Header.vue | 2 +- resources/js/pages/InputProduk.vue | 245 ++++++++++-------------- resources/js/pages/Produk.vue | 8 +- routes/web.php | 2 +- 6 files changed, 169 insertions(+), 201 deletions(-) create mode 100644 .env.example delete mode 100644 resources/js/components/DropdownNav.vue diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b7edfb1 --- /dev/null +++ b/.env.example @@ -0,0 +1,65 @@ +APP_NAME=Laravel +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_URL=http://localhost + +APP_LOCALE=en +APP_FALLBACK_LOCALE=en +APP_FAKER_LOCALE=en_US + +APP_MAINTENANCE_DRIVER=file +# APP_MAINTENANCE_STORE=database + +PHP_CLI_SERVER_WORKERS=4 + +BCRYPT_ROUNDS=12 + +LOG_CHANNEL=stack +LOG_STACK=single +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=sqlite +# DB_HOST=127.0.0.1 +# DB_PORT=3306 +# DB_DATABASE=laravel +# DB_USERNAME=root +# DB_PASSWORD= + +SESSION_DRIVER=database +SESSION_LIFETIME=120 +SESSION_ENCRYPT=false +SESSION_PATH=/ +SESSION_DOMAIN=null + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=database + +CACHE_STORE=database +# CACHE_PREFIX= + +MEMCACHED_HOST=127.0.0.1 + +REDIS_CLIENT=phpredis +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=log +MAIL_SCHEME=null +MAIL_HOST=127.0.0.1 +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_FROM_ADDRESS="hello@example.com" +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false + +VITE_APP_NAME="${APP_NAME}" \ No newline at end of file diff --git a/resources/js/components/DropdownNav.vue b/resources/js/components/DropdownNav.vue deleted file mode 100644 index 629ff4a..0000000 --- a/resources/js/components/DropdownNav.vue +++ /dev/null @@ -1,48 +0,0 @@ - - - diff --git a/resources/js/components/Header.vue b/resources/js/components/Header.vue index 174bc14..d8b59ae 100644 --- a/resources/js/components/Header.vue +++ b/resources/js/components/Header.vue @@ -45,7 +45,7 @@ const toggleDropdown = () => {
  • {{ sub.label }} diff --git a/resources/js/pages/InputProduk.vue b/resources/js/pages/InputProduk.vue index 8ecfacd..f92a062 100644 --- a/resources/js/pages/InputProduk.vue +++ b/resources/js/pages/InputProduk.vue @@ -2,162 +2,115 @@

    Produk Baru

    - +
    - +
    - +
    - +
    - +
    - +
    - -
    -
    - -
    -
    - - -
    -
    - - +
    -
    - +
    +
    + + +
    +
    + + +
    - +
    - +
    -
    +
    - + -
    - + -
    + 'cursor-not-allowed opacity-50': uploadLoading + }">
    - -
    +
    - +
    - + +
    -

    +

    - - - - - + + +

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

    - - +
    {{ uploadError }}
    + +
    + + + +
    @@ -191,15 +144,17 @@ const uploadedImages = ref([]); const isDragging = ref(false); const uploadError = ref(''); const fileInput = ref(null); -const userId = ref(1); // Sesuaikan dengan user yang login +// TODO: Logika autentikasi user +const userId = ref(1); const isFormValid = computed(() => { - return form.value.nama && - form.value.kategori && - form.value.berat > 0 && - form.value.kadar > 0 && - form.value.harga_per_gram > 0 && - form.value.harga_jual > 0; + return form.value.nama && + form.value.kategori && + form.value.berat > 0 && + form.value.kadar > 0 && + form.value.harga_per_gram > 0 && + form.value.harga_jual > 0 && + uploadedImages.value.length > 0; }); const calculateHargaJual = () => { @@ -220,7 +175,6 @@ const loadExistingPhotos = async () => { if (error.response?.status !== 404) { console.error('Error loading existing photos:', error); } - // 404 is expected when no photos exist yet } }; @@ -238,64 +192,61 @@ const handleFileSelect = (event) => { 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 = ''; - - // Validate file count + if (uploadedImages.value.length + files.length > 6) { uploadError.value = 'Maksimal 6 foto yang dapat diupload'; return; } - - // Validate file types and sizes + const validFiles = files.filter(file => { const isValidType = ['image/jpeg', 'image/jpg', 'image/png'].includes(file.type); - const isValidSize = file.size <= 2 * 1024 * 1024; // 2MB - + 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); formData.append('id_user', userId.value); - + const response = await axios.post('/api/foto/upload', formData, { headers: { 'Content-Type': 'multipart/form-data', }, }); - + uploadedImages.value.push(response.data); } - - // Clear file input + if (fileInput.value) { fileInput.value.value = ''; } - + } catch (error) { console.error('Upload error:', error); uploadError.value = error.response?.data?.message || 'Gagal mengupload foto'; @@ -315,21 +266,20 @@ const removeImage = async (imageId) => { } }; -const submitForm = async () => { +const submitForm = async (addItem) => { if (!isFormValid.value) { alert('Mohon lengkapi semua field yang diperlukan'); return; } - + loading.value = true; - + try { const response = await axios.post('/api/produk', { ...form.value, id_user: userId.value }); - - // Reset form + form.value = { nama: '', kategori: '', @@ -338,19 +288,22 @@ const submitForm = async () => { harga_per_gram: 0, harga_jual: 0, }; - + uploadedImages.value = []; uploadError.value = ''; - + if (fileInput.value) { fileInput.value.value = ''; } - - alert('Produk berhasil disimpan!'); - + + if (addItem) { + alert('Produk berhasil ditambahkan. Silakan tambahkan produk lainnya.'); + } else { + window.location.href = '/produk?message=Produk berhasil disimpan'; + } } catch (error) { console.error('Submit error:', error); - + if (error.response?.data?.errors) { const errors = Object.values(error.response.data.errors).flat(); alert('Error: ' + errors.join(', ')); @@ -371,14 +324,12 @@ const resetPhotos = async () => { } }; -// Load existing photos on component mount +const back = () => { + resetPhotos(); + window.history.back(); +}; + onMounted(() => { loadExistingPhotos(); }); - -// Clean up photos if user leaves without saving -onUnmounted(() => { - // Optional: You might want to clean up temporary photos here - // resetPhotos(); -}); diff --git a/resources/js/pages/Produk.vue b/resources/js/pages/Produk.vue index 566dce7..7104636 100644 --- a/resources/js/pages/Produk.vue +++ b/resources/js/pages/Produk.vue @@ -24,9 +24,9 @@
    - +
    @@ -141,7 +141,7 @@ const currentFotoIndex = ref(0); // Fetch data awal onMounted(async () => { try { - const res = await axios.get("http://127.0.0.1:8000/api/produk"); + const res = await axios.get("/api/produk"); products.value = res.data; } catch (error) { console.error("Gagal ambil data produk:", error); @@ -172,7 +172,7 @@ const filteredProducts = computed(() => { // buka overlay async function openOverlay(id) { try { - const res = await axios.get(`http://127.0.0.1:8000/api/produk/${id}`); + const res = await axios.get(`/api/produk/${id}`); detail.value = res.data; currentFotoIndex.value = 0; // reset ke foto pertama showOverlay.value = true; diff --git a/routes/web.php b/routes/web.php index fcdea34..ac3aef3 100644 --- a/routes/web.php +++ b/routes/web.php @@ -30,4 +30,4 @@ Route::prefix('api')->group(function () { // Frontend SPA Route::get('/{any}', function () { return view('app'); -})->where('any', '.*'); +})->where('any', '^(?!storage|api).*$'); \ No newline at end of file From 1d6bee91e123d002a227ffa2a5a8b1fa205d679c Mon Sep 17 00:00:00 2001 From: Timoti313 Date: Thu, 28 Aug 2025 16:20:58 +0700 Subject: [PATCH 3/5] [update Kasir, KasirForm, KasirTransaksiList] Error Data transaksi tidak tampil --- resources/js/components/KasirForm.vue | 40 ++++++++++++------- .../js/components/KasirTransaksiList.vue | 13 +++++- resources/js/pages/Kasir.vue | 27 ++++++++----- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/resources/js/components/KasirForm.vue b/resources/js/components/KasirForm.vue index 066a5ca..97aefbe 100644 --- a/resources/js/components/KasirForm.vue +++ b/resources/js/components/KasirForm.vue @@ -2,25 +2,33 @@
    -
    - - +
    +
    + + +
    +
    + + +
    -
    -
    - -
    - Total: - Rp{{ total.toLocaleString() }},- -
    - - +
    +
    + Total: + + Rp{{ total.toLocaleString() }},- + +
    -
    @@ -24,10 +24,19 @@ diff --git a/resources/js/pages/Kasir.vue b/resources/js/pages/Kasir.vue index 0b27fe4..5aa9b2d 100644 --- a/resources/js/pages/Kasir.vue +++ b/resources/js/pages/Kasir.vue @@ -8,24 +8,33 @@
    - +
    +}) + +const lihatDetail = (trx) => { + alert(`Detail transaksi: ${trx.kode}`) +} + From 8046360f6ecfee7d1ed67018979458775e6e8adc Mon Sep 17 00:00:00 2001 From: Baghaztra Date: Thu, 28 Aug 2025 22:45:11 +0700 Subject: [PATCH 4/5] [feat] create item --- app/Http/Controllers/ItemController.php | 5 +- resources/css/app.css | 8 +- resources/js/App.vue | 2 +- resources/js/components/CreateItemModal.vue | 187 ++++++++++++++++++++ resources/js/components/Modal.vue | 96 ++++++++++ resources/js/pages/InputProduk.vue | 73 +++++++- 6 files changed, 355 insertions(+), 16 deletions(-) create mode 100644 resources/js/components/CreateItemModal.vue create mode 100644 resources/js/components/Modal.vue diff --git a/app/Http/Controllers/ItemController.php b/app/Http/Controllers/ItemController.php index 652d867..399e5e0 100644 --- a/app/Http/Controllers/ItemController.php +++ b/app/Http/Controllers/ItemController.php @@ -23,11 +23,10 @@ class ItemController extends Controller public function store(Request $request) { $validated = $request->validate([ - 'id_produk' => 'required|in:produks.id', - 'id_nampan' => 'nullable|in:nampans.id' + 'id_produk' => 'required', + 'id_nampan' => 'nullable' ],[ 'id_produk' => 'Id produk tidak valid.', - 'id_nampan' => 'Id nampan tidak valid' ]); $item = Item::create($validated); diff --git a/resources/css/app.css b/resources/css/app.css index 56784c1..513731f 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -5,12 +5,6 @@ @source '../**/*.blade.php'; @source '../**/*.js'; -@import url('https://fonts.googleapis.com/css2?family=Platypi:wght@400;500;600;700&display=swap'); - -html, body { - font-family: "Platypi", sans-serif; -} - @theme { --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; @@ -20,5 +14,5 @@ html, body { --color-A: #F8F0E5; --color-B: #EADBC8; --color-C: #DAC0A3; - --color-D: #0F2C59; + --color-D: #024768; } diff --git a/resources/js/App.vue b/resources/js/App.vue index 2631a6c..2271c86 100644 --- a/resources/js/App.vue +++ b/resources/js/App.vue @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/resources/js/components/CreateItemModal.vue b/resources/js/components/CreateItemModal.vue new file mode 100644 index 0000000..1ab7592 --- /dev/null +++ b/resources/js/components/CreateItemModal.vue @@ -0,0 +1,187 @@ + + + \ No newline at end of file diff --git a/resources/js/components/Modal.vue b/resources/js/components/Modal.vue new file mode 100644 index 0000000..de1fa83 --- /dev/null +++ b/resources/js/components/Modal.vue @@ -0,0 +1,96 @@ + + + + + \ No newline at end of file diff --git a/resources/js/pages/InputProduk.vue b/resources/js/pages/InputProduk.vue index f92a062..c9164b8 100644 --- a/resources/js/pages/InputProduk.vue +++ b/resources/js/pages/InputProduk.vue @@ -1,5 +1,15 @@