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/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/ConfirmDeleteModal.vue b/resources/js/components/ConfirmDeleteModal.vue new file mode 100644 index 0000000..ffcca4e --- /dev/null +++ b/resources/js/components/ConfirmDeleteModal.vue @@ -0,0 +1,40 @@ + + + diff --git a/resources/js/components/CreateItemModal.vue b/resources/js/components/CreateItemModal.vue new file mode 100644 index 0000000..f2b2983 --- /dev/null +++ b/resources/js/components/CreateItemModal.vue @@ -0,0 +1,187 @@ + + + \ 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/components/KasirForm.vue b/resources/js/components/KasirForm.vue new file mode 100644 index 0000000..97aefbe --- /dev/null +++ b/resources/js/components/KasirForm.vue @@ -0,0 +1,93 @@ + + + + + + diff --git a/resources/js/components/KasirTransaksiList.vue b/resources/js/components/KasirTransaksiList.vue new file mode 100644 index 0000000..012b413 --- /dev/null +++ b/resources/js/components/KasirTransaksiList.vue @@ -0,0 +1,42 @@ + + + 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 8ecfacd..5f4a1ae 100644 --- a/resources/js/pages/InputProduk.vue +++ b/resources/js/pages/InputProduk.vue @@ -1,173 +1,137 @@ diff --git a/resources/js/pages/Kasir.vue b/resources/js/pages/Kasir.vue new file mode 100644 index 0000000..5aa9b2d --- /dev/null +++ b/resources/js/pages/Kasir.vue @@ -0,0 +1,40 @@ + + + diff --git a/resources/js/pages/Produk.vue b/resources/js/pages/Produk.vue index 566dce7..e57a268 100644 --- a/resources/js/pages/Produk.vue +++ b/resources/js/pages/Produk.vue @@ -1,5 +1,19 @@ @@ -128,38 +158,47 @@ import axios from "axios"; import mainLayout from "../layouts/mainLayout.vue"; import ProductCard from "../components/ProductCard.vue"; import searchbar from "../components/searchbar.vue"; +import CreateItemModal from "../components/CreateItemModal.vue"; +import ConfirmDeleteModal from "../components/ConfirmDeleteModal.vue"; const products = ref([]); const searchQuery = ref(""); const selectedCategory = ref("semua"); +const creatingItem = ref(false); +const deleting = ref(false); -// overlay state -const showOverlay = ref(false); const detail = ref({}); +const showOverlay = ref(false); const currentFotoIndex = ref(0); +// Buka modal item +const openItemModal = () => { + creatingItem.value = true; +}; +const closeItemModal = () => { + creatingItem.value = false; +}; + // 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); } }); -// Filter gabungan (kategori + search) +// Filter produk (kategori + search) const filteredProducts = computed(() => { let hasil = products.value; - // filter kategori if (selectedCategory.value !== "semua") { hasil = hasil.filter( (p) => p.kategori.toLowerCase() === selectedCategory.value ); } - // filter search if (searchQuery.value) { hasil = hasil.filter((p) => p.nama.toLowerCase().includes(searchQuery.value.toLowerCase()) @@ -169,33 +208,29 @@ const filteredProducts = computed(() => { return hasil; }); -// buka overlay -async function openOverlay(id) { - try { - const res = await axios.get(`http://127.0.0.1:8000/api/produk/${id}`); - detail.value = res.data; - currentFotoIndex.value = 0; // reset ke foto pertama +// Buka overlay detail +function openOverlay(id) { + const produk = products.value.find((p) => p.id === id); + if (produk) { + detail.value = produk; + currentFotoIndex.value = 0; showOverlay.value = true; - } catch (error) { - console.error("Gagal fetch detail produk:", error); } } -// tutup overlay +// Tutup overlay detail function closeOverlay() { showOverlay.value = false; - detail.value = {}; currentFotoIndex.value = 0; } -// foto navigation +// Navigasi foto function nextFoto() { if (detail.value.foto && detail.value.foto.length > 0) { currentFotoIndex.value = (currentFotoIndex.value + 1) % detail.value.foto.length; } } - function prevFoto() { if (detail.value.foto && detail.value.foto.length > 0) { currentFotoIndex.value = @@ -208,4 +243,18 @@ function prevFoto() { function formatNumber(num) { return new Intl.NumberFormat().format(num || 0); } + +// Hapus produk +async function deleteProduk() { + try { + await axios.delete(`/api/produk/${detail.value.id}`); + products.value = products.value.filter((p) => p.id !== detail.value.id); + deleting.value = false; + showOverlay.value = false; + alert("Produk berhasil dihapus!"); + } catch (err) { + console.error("Gagal hapus produk:", err); + alert("Gagal menghapus produk!"); + } +} diff --git a/resources/js/router/index.js b/resources/js/router/index.js index 8c4f90c..1856f73 100644 --- a/resources/js/router/index.js +++ b/resources/js/router/index.js @@ -3,6 +3,7 @@ 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' import InputProduk from '../pages/InputProduk.vue' @@ -32,6 +33,11 @@ const routes = [ name: 'Nampan', component: Tray }, + { + path: '/kasir', + name: 'Kasir', + component: Kasir + }, ] 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