diff --git a/note/detailUI.md b/note/detailUI.md new file mode 100644 index 0000000..72efab6 --- /dev/null +++ b/note/detailUI.md @@ -0,0 +1,58 @@ +**Overlay/Status** +- Loader Overlay: layar penuh dengan spinner `ThreeDots` dan pesan `screenMessag +e`; muncul saat `loading` true. +- Grayscale State: seluruh konten `div.Cafe` menjadi abu-abu saat `isExceededDea +dline` true (kelas `grayscale`). +- Modal Pesan: “Kafe sedang tidak tersedia” dapat muncul via `setModal("message" +, ...)` ketika `isExceededDeadline` dari socket; modalnya dikelola global (di lu +ar file ini). + +**Header** +- Bar Atas “Menu”: judul “Menu”, info toko (nama, gambar), profil user, opsi log +out, akses pegawai, table code. +- Edit Mode Toggle: kontrol untuk mengaktifkan/menonaktifkan mode edit kategori/ +item (prop `isEditMode` + `setIsEditMode`). + +**Branding/Watermark** +- Dev Watermark (atas): `div.Watermark` kecil hanya tampil jika `API_BASE_URL` b +ukan domain resmi prod/dev (indikator environment). +- Footer Watermark: komponen `` di bagian paling bawah halaman. + +**Music** +- Music Player: widget pemutar/antrian lagu dengan dukungan Spotify; menampilkan + status login Spotify (`isSpotifyNeedLogin`) dan antrian (`queue`), interaksi vi +a `socket`. + +**Kategori (ItemTypeLister)** +- Daftar Kategori: list tipe menu (nama + gambar tipe, visibilitas). +- Filter Kategori: memilih 1 kategori untuk menyaring tampilan item (`filterId`) +. +- Edit Kategori: saat `isEditMode` aktif, bisa memilih tipe yang sedang diedit ( +`beingEditedType`) dan mengubah urutan tipe (via kontrol di ItemLister). + +**Daftar Item per Kategori (ItemLister x N)** +- Section per Kategori: render berulang untuk setiap tipe yang lolos filter. Men +ampilkan: + - Judul/nama kategori dan gambar (bila ada). + - Daftar item dalam kategori (nama, harga, promo, deskripsi, gambar, visibilit +as). +- Aksi Item: + - Tambah item: tombol/form untuk membuat item (owner/akses yang berwenang). + - Ubah item: edit nama, harga, promo, deskripsi, gambar. +- Reorder Kategori: panah/aksi “naik/turun” pada section untuk memindahkan posis +i kategori (memanggil `moveItemType*`). +- Raw Mode: jika tidak edit dan filter spesifik aktif, `raw` true untuk gaya tam +pilan ringkas. + +**Sticky Bar (Keranjang & Transaksi)** +- Tombol Cart (kiri, utama): muncul jika bukan edit mode dan (user login atau ke +ranjang > 0). + - Menampilkan jumlah item (dengan “+” jika ada transaksi terakhir), total harg +a “Rp{totalPrice}” atau teks “Open bill” (jika `lastTransaction.payment_type == +'paylater'`). + - Posisi: sticky di bawah (offset bottom ~40px), lebar responsif. +- Tombol Transactions (kanan, kecil): hanya muncul jika user login; navigasi ke +riwayat transaksi. + + +material list, material \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 24ae32f..ce6ead7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,12 +14,14 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "apexcharts": "^5.3.4", "caniuse-lite": "^1.0.30001690", "crypto-js": "^4.2.0", "dayjs": "^1.11.13", "html-to-image": "^1.11.11", "html2canvas": "^1.4.1", "jsqr": "^1.4.0", + "lucide-react": "^0.541.0", "qr-scanner": "^1.4.2", "qrcode.react": "^3.1.0", "react": "^18.3.1", @@ -3905,171 +3907,6 @@ "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", "license": "MIT" }, - "node_modules/@mui/core-downloads-tracker": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.1.tgz", - "integrity": "sha512-+mIK1Z0BhOaQ0vCgOkT1mSrIpEHLo338h4/duuL4TBLXPvUMit732mnwJY3W40Avy30HdeSfwUAAGRkKmwRaEQ==", - "license": "MIT", - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - } - }, - "node_modules/@mui/material": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.1.tgz", - "integrity": "sha512-Xf6Shbo03YmcBedZMwSpEFOwpYDtU7tC+rhAHTrA9FHk0FpsDqiQ9jUa1j/9s3HLs7KWb5mDcGnlwdh9Q9KAag==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.28.2", - "@mui/core-downloads-tracker": "^7.3.1", - "@mui/system": "^7.3.1", - "@mui/types": "^7.4.5", - "@mui/utils": "^7.3.1", - "@popperjs/core": "^2.11.8", - "@types/react-transition-group": "^4.4.12", - "clsx": "^2.1.1", - "csstype": "^3.1.3", - "prop-types": "^15.8.1", - "react-is": "^19.1.1", - "react-transition-group": "^4.4.5" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^7.3.1", - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@mui/material-pigment-css": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/private-theming": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.1.tgz", - "integrity": "sha512-WU3YLkKXii/x8ZEKnrLKsPwplCVE11yZxUvlaaZSIzCcI3x2OdFC8eMlNy74hVeUsYQvzzX1Es/k4ARPlFvpPQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.28.2", - "@mui/utils": "^7.3.1", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/styled-engine": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.1.tgz", - "integrity": "sha512-Nqo6OHjvJpXJ1+9TekTE//+8RybgPQUKwns2Lh0sq+8rJOUSUKS3KALv4InSOdHhIM9Mdi8/L7LTF1/Ky6D6TQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.28.2", - "@emotion/cache": "^11.14.0", - "@emotion/serialize": "^1.3.3", - "@emotion/sheet": "^1.4.0", - "csstype": "^3.1.3", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.4.1", - "@emotion/styled": "^11.3.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - } - } - }, - "node_modules/@mui/system": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.1.tgz", - "integrity": "sha512-mIidecvcNVpNJMdPDmCeoSL5zshKBbYPcphjuh6ZMjhybhqhZ4mX6k9zmIWh6XOXcqRQMg5KrcjnO0QstrNj3w==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.28.2", - "@mui/private-theming": "^7.3.1", - "@mui/styled-engine": "^7.3.1", - "@mui/types": "^7.4.5", - "@mui/utils": "^7.3.1", - "clsx": "^2.1.1", - "csstype": "^3.1.3", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, "node_modules/@mui/types": { "version": "7.4.5", "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.5.tgz", @@ -4638,7 +4475,6 @@ "resolved": "https://registry.npmjs.org/@svgdotjs/svg.draggable.js/-/svg.draggable.js-3.0.6.tgz", "integrity": "sha512-7iJFm9lL3C40HQcqzEfezK2l+dW2CpoVY3b77KQGqc8GXWa6LhhmX5Ckv7alQfUXBuZbjpICZ+Dvq1czlGx7gA==", "license": "MIT", - "peer": true, "peerDependencies": { "@svgdotjs/svg.js": "^3.2.4" } @@ -4648,7 +4484,6 @@ "resolved": "https://registry.npmjs.org/@svgdotjs/svg.filter.js/-/svg.filter.js-3.0.9.tgz", "integrity": "sha512-/69XMRCDoam2HgC4ldHIaDgeQf1ViHIsa0Ld4uWgiXtZ+E24DWHe/9Ib6kbNiZ7WRIdlVokUDR1Fg0kjIpkfbw==", "license": "MIT", - "peer": true, "dependencies": { "@svgdotjs/svg.js": "^3.2.4" }, @@ -4661,7 +4496,6 @@ "resolved": "https://registry.npmjs.org/@svgdotjs/svg.js/-/svg.js-3.2.4.tgz", "integrity": "sha512-BjJ/7vWNowlX3Z8O4ywT58DqbNRyYlkk6Yz/D13aB7hGmfQTvGX4Tkgtm/ApYlu9M7lCQi15xUEidqMUmdMYwg==", "license": "MIT", - "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/Fuzzyma" @@ -4672,7 +4506,6 @@ "resolved": "https://registry.npmjs.org/@svgdotjs/svg.resize.js/-/svg.resize.js-2.0.5.tgz", "integrity": "sha512-4heRW4B1QrJeENfi7326lUPYBCevj78FJs8kfeDxn5st0IYPIRXoTtOSYvTzFWgaWWXd3YCDE6ao4fmv91RthA==", "license": "MIT", - "peer": true, "engines": { "node": ">= 14.18" }, @@ -4686,7 +4519,6 @@ "resolved": "https://registry.npmjs.org/@svgdotjs/svg.select.js/-/svg.select.js-4.0.3.tgz", "integrity": "sha512-qkMgso1sd2hXKd1FZ1weO7ANq12sNmQJeGDjs46QwDVsxSRcHmvWKL2NDF7Yimpwf3sl5esOLkPqtV2bQ3v/Jg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 14.18" }, @@ -4924,26 +4756,6 @@ "tslib": "^2.8.0" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", @@ -5976,8 +5788,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz", "integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@zxing/browser": { "version": "0.0.7", @@ -6315,7 +6126,6 @@ "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-5.3.4.tgz", "integrity": "sha512-N0gNh8uLu/BN8N+BCphNK+gZAoSoUtDDn1jFGB+3+EMcv8s6vajuP3W0g4dMLTRp6chFkjMmQK3uD8pz4ISmLA==", "license": "SEE LICENSE IN LICENSE", - "peer": true, "dependencies": { "@svgdotjs/svg.draggable.js": "^3.0.4", "@svgdotjs/svg.filter.js": "^3.0.8", @@ -15199,6 +15009,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.541.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.541.0.tgz", + "integrity": "sha512-s0Vircsu5WaGv2KoJZ5+SoxiAJ3UXV5KqEM3eIFDHaHkcLIFdIWgXtZ412+Gh02UsdS7Was+jvEpBvPCWQISlg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", @@ -20825,20 +20644,6 @@ "is-typedarray": "^1.0.0" } }, - "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", diff --git a/package.json b/package.json index fe2433e..7563a92 100644 --- a/package.json +++ b/package.json @@ -10,12 +10,14 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "apexcharts": "^5.3.4", "caniuse-lite": "^1.0.30001690", "crypto-js": "^4.2.0", "dayjs": "^1.11.13", "html-to-image": "^1.11.11", "html2canvas": "^1.4.1", "jsqr": "^1.4.0", + "lucide-react": "^0.541.0", "qr-scanner": "^1.4.2", "qrcode.react": "^3.1.0", "react": "^18.3.1", diff --git a/src/App.css b/src/App.css index 00861f4..04ebe4c 100644 --- a/src/App.css +++ b/src/App.css @@ -1,6 +1,14 @@ @import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Aboreto&family=Rubik+Doodle+Shadow&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@200;300;400;500;600;700;800&ital,wght@0,200..800;1,200..800&display=swap"); +:root { + --brand-primary: #73a585; /* general brand (e.g., music player) */ + --brand-sage: #6B8F71; /* sage green for active category */ + --brand-sage-50: #F0F6F2; /* very light hover bg */ + --brand-sage-100: #E9F3ED; /* light hover bg */ + --brand-sage-hover: #7FAE7D; /* hover for filled buttons */ + --brand-sage-muted: #CFD8D3; /* disabled button */ +} html, body { scrollbar-width: none; /* Firefox */ @@ -54,6 +62,8 @@ body { color: white; } +/* removed two-column layout; reverted to single column */ + .App-link { color: #61dafb; } diff --git a/src/components/Header.js b/src/components/Header.js index 141419f..f2c3cf3 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -4,6 +4,7 @@ import { useLocation } from "react-router-dom"; import { useNavigationHelpers } from "../helpers/navigationHelpers"; import Switch from "react-switch"; +// Restore original gradient background for header container when shopName exists const HeaderBarbackground = styled.div` ${({ shopName }) => shopName && @@ -19,7 +20,7 @@ const HeaderBar = styled.div` display: flex; justify-content: space-between; align-items: center; - padding: 20px 15px; + padding: 12px 14px; color: black; background-color: #ffffff; z-index: 200; @@ -33,30 +34,15 @@ const HeaderBar = styled.div` const Title = styled.h2` margin: 0; font-family: "Plus Jakarta Sans", sans-serif; - font-weight: 500; + font-weight: 600; font-style: normal; font-size:${(props) => (props.HeaderSize)}; - color: rgba(88, 55, 50, 1); - text-transform: uppercase; + color: rgba(45, 45, 45, 1); `; -const ProfileName = styled.h2` - position: absolute; - font-family: "Plus Jakarta Sans", sans-serif; - font-weight: 500; - font-style: normal; - font-size: 30px; - z-index: 199; - overflow: hidden; - white-space: nowrap; - animation: ${(props) => { - if (props.animate === "grow") return gg; - if (props.animate === "shrink") return ss; - return nn; - }} - 0.5s forwards; - text-align: left; -`; +// SubTitle removed per redesign (no subtitle below cafe name) + +// Deprecated the animated ProfileName in favor of a cleaner layout const nn = keyframes` 0% { @@ -103,22 +89,17 @@ const ss = keyframes` } `; -const ProfileImage = styled.img` - position: relative; - width: 60px; - height: 60px; - border-radius: 50%; - object-fit: contain; - cursor: pointer; - z-index: 199; - animation: ${(props) => { - if (props.animate === "grow") return g; - if (props.animate === "shrink") return s; - return "none"; - }} - 0.5s forwards; +const CafeAvatar = styled.img` + width: clamp(32px, 5vw, 56px); + height: clamp(32px, 5vw, 56px); + border-radius: 8px; + object-fit: cover; + background: #f2f2f2; + margin-left: 8px; /* extra left padding so it’s not too tight */ `; +// User initial avatar removed; only cafe image is shown on the left + const g = keyframes` 0% { top: 0px; @@ -149,62 +130,43 @@ const s = keyframes` } `; +/* Replace bubble-like animation with subtle fade/slide */ const grow = keyframes` - 0% { - right: 12px; - width: 60px; - height: 60px; - border-top-left-radius: 50%; - border-bottom-left-radius: 50%; - } - 100% { - right: 28px; - width: 300px; - border-top-left-radius: 15px; - border-bottom-left-radius: 15px; - } + 0% { opacity: 0; transform: translateY(-6px) scale(0.98); } + 100% { opacity: 1; transform: translateY(0) scale(1); } `; const shrink = keyframes` - 0% { - right: 12px; - width: 300px; - height: auto; - border-radius: 20px; - } - 100% { - right: 28px; - width: 60px; - height: 60px; - border-radius: 50%; - } + 0% { opacity: 1; transform: translateY(0) scale(1); } + 100% { opacity: 0; transform: translateY(-6px) scale(0.98); } `; const Rectangle = styled.div` - overflow-y: hidden; + overflow-y: auto; position: absolute; - top: 39px; - right: 12px; - width: 200px; - max-height: 87vh; /* or another appropriate value */ + top: calc(100% + 8px); + right: 0; + width: 240px; + max-height: 75vh; background-color: white; z-index: 198; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); - animation: ${(props) => (props.animate === "grow" ? grow : shrink)} 0.5s - forwards; - padding: 10px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); + border: 1px solid #f0f0f0; + border-radius: 12px; + animation: ${(props) => (props.animate === "grow" ? grow : shrink)} 0.2s forwards; + padding: 10px 12px; box-sizing: border-box; overflow-x: hidden; font-size: 14px; color: #393939; + backdrop-filter: blur(2px); `; const ChildContainer = styled.div` display: flex; flex-direction: column; justify-content: flex-start; - align-items: flex-end; - flex-wrap: wrap; - padding-top: 70px; + align-items: stretch; + flex-wrap: nowrap; `; const ChildWrapper = styled.div` @@ -213,25 +175,88 @@ const ChildWrapper = styled.div` width: 100%; `; const Child = styled.div` - width: 100%; - height: 36px; - font-family: "Plus Jakarta Sans", sans-serif; - font-weight: 500; - font-style: normal; - + width: 100%; + min-height: 36px; + font-family: "Plus Jakarta Sans", sans-serif; + font-weight: 500; + font-style: normal; + padding: ${(props) => (props.hasChildren ? '8px 0 4px' : '8px 4px')}; ${(props) => props.hasChildren ? ` - margin-top: 14px; - border-top: 0.5px solid #a5a5a5; + margin-top: 10px; + border-top: 0.5px solid #e9e9e9; height: auto; ` : ` display: flex; align-items: center; + justify-content: space-between; + cursor: pointer; `} `; +const LeftGroup = styled.div` + display: flex; + align-items: center; + gap: 10px; +`; + +const CenterGroup = styled.div` + flex: 1; + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; /* so clicks pass through center when needed */ +`; + +const CafeInfo = styled.div` + display: flex; + flex-direction: column; + justify-content: center; +`; + +const RightGroup = styled.div` + display: flex; + align-items: center; + gap: 10px; +`; + +const CategoryLabel = styled.div` + font-family: "Plus Jakarta Sans", sans-serif; + font-size: 12px; + font-weight: 700; + color: #6B8F71; + text-transform: uppercase; + letter-spacing: 0.04em; + padding: 6px 2px; + pointer-events: none; +`; + +const HamburgerButton = styled.button` + width: clamp(32px, 4.5vw, 52px); + height: clamp(32px, 4.5vw, 52px); + border-radius: 8px; + border: 1px solid #e5e5e5; + background: #ffffff; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + & > svg { + width: 60%; + height: 60%; + } +`; + +const HamburgerIcon = () => ( + + + + + +); + const Header = ({ HeaderText, @@ -261,10 +286,10 @@ const Header = ({ const [guestSideOf, setGuestSideOf] = useState(null); const location = useLocation(); - const handleImageClick = () => { + const toggleMenu = () => { if (showRectangle) { setAnimate("shrink"); - setTimeout(() => setShowRectangle(false), 500); + setTimeout(() => setShowRectangle(false), 200); } else { setAnimate("grow"); setShowRectangle(true); @@ -274,15 +299,14 @@ const Header = ({ const handleClickOutside = (event) => { if (rectangleRef.current && !rectangleRef.current.contains(event.target)) { setAnimate("shrink"); - setTimeout(() => setShowRectangle(false), 500); - rectangleRef.current.style.overflow = "hidden"; + setTimeout(() => setShowRectangle(false), 200); } }; const handleScroll = () => { if (showRectangle) { setAnimate("shrink"); - setTimeout(() => setShowRectangle(false), 500); + setTimeout(() => setShowRectangle(false), 200); } }; @@ -321,38 +345,48 @@ const Header = ({ // Otherwise, use the possessive function return `${cafeName}'s menu`; }; - return ( + + const formatCafeName = (name) => { + if (!name) return name; + return name + .toLowerCase() + .replace(/\b\w/g, (c) => c.toUpperCase()); + }; + return ( - - - {shopName == null - ? HeaderText == null - ? "kedaimaster" - : HeaderText - : shopName} - -
- - - {showProfile && user.username !== undefined ? user.username : "guest"} - - {showRectangle && ( - - + + + + + + + {formatCafeName( + shopName == null + ? HeaderText == null + ? "kedaimaster" + : HeaderText + : shopName + )} + + + + + + + + {showRectangle && ( + + {guestSideOfClerk && guestSideOfClerk.clerkUsername && ( this is the guest side of {guestSideOfClerk.clerkUsername} )} {user.username !== undefined && ( - setModal("edit_account")}> - Kelola akun - + Kelola akun )} {user.roleId == 0 && ( setModal('create_coupon', {})}>Buat Voucher)} @@ -364,9 +398,9 @@ const Header = ({ user.roleId === 1 && ( <> - - {shopName} - + + {formatCafeName(shopName)} + Mode pengembangan   - Konfigurasi + Konfigurasi setModal("welcome_config")}> Desain kafe @@ -393,7 +427,7 @@ const Header = ({ - Kasir + Kasir setModal("create_clerk")}> + Tambah @@ -420,7 +454,7 @@ const Header = ({ user.cafeId == shopId && user.roleId === 2 && ( - {shopName} + {formatCafeName(shopName)} Mode pengembangan  @@ -435,7 +469,7 @@ const Header = ({ - Konfigurasi + Konfigurasi setModal("welcome_config")}> Desain kafe @@ -478,11 +512,12 @@ const Header = ({ {user.username !== undefined && ( Logout )} - - - )} -
-
+ + + )} + + + ); }; diff --git a/src/components/Item.js b/src/components/Item.js index fe3b53f..7d48540 100644 --- a/src/components/Item.js +++ b/src/components/Item.js @@ -74,6 +74,11 @@ const Item = ({ } }; + const formatCurrency = (value) => { + const num = Number(value) || 0; + return num.toLocaleString('id-ID'); + }; + const handlePriceChange = (event) => { setItemPrice(event.target.value); }; @@ -93,23 +98,17 @@ const Item = ({
{!forInvoice && ( - //
{ - currentTarget.onerror = null; // prevents looping + currentTarget.onerror = null; currentTarget.src = "https://png.pngtree.com/png-vector/20221125/ourmid/pngtree-no-image-available-icon-flatvector-illustration-pic-design-profile-vector-png-image_40966566.jpg"; }} alt={itemName} - style={{ - filter: !isAvailable ? "grayscale(100%)" : "none", - }} + style={{ filter: !isAvailable ? "grayscale(100%)" : "none" }} className={styles.imageContainer} /> - //
)}
{forInvoice && @@ -141,168 +140,63 @@ const Item = ({ onChange={handleNameChange} disabled={!blank && !isBeingEdit} /> */} -

- {itemName} -

+
+

{itemName}

+ {!forInvoice && ( +
+ {promoPrice && promoPrice != 0 && promoPrice != '' ? ( + <> +
+ Promo {(((initialPrice - promoPrice) / initialPrice) * 100).toFixed(0)}% +
+
+ Rp {formatCurrency(promoPrice)} + Rp {formatCurrency(initialPrice)} +
+ + ) : ( + Rp {formatCurrency(initialPrice)} + )} +
+ )} +
{forInvoice && ( <>

x

{itemQty}

)} + {!forInvoice && ( - // - -
- {promoPrice && promoPrice != 0 && promoPrice != '' ? - <> -
- Promo {(((initialPrice - promoPrice) / initialPrice) * 100).toFixed(0)}% -
- -
- {promoPrice} - {initialPrice} -
- - : - <> - -
- {initialPrice} -
- - } -
- )} - - {!forInvoice && - (!isBeingEdit && itemQty != 0 ? ( + !isBeingEdit && itemQty > 0 ? (
- - - - {!blank && !isBeingEdit ? ( -

{itemQty}

- ) : ( - - )} - - - +
+ + {!blank && !isBeingEdit ? ( + {itemQty} + ) : ( + + )} + +
) : !blank && !isBeingEdit ? (
-
) : (
-
- ))} + ) + )} {forInvoice && ( -

Rp {itemQty * (promoPrice > 0? promoPrice : itemPrice)}

+

Rp {formatCurrency(itemQty * (promoPrice > 0 ? promoPrice : itemPrice))}

)}
{forCart && ( @@ -316,18 +210,11 @@ const Item = ({ )} */}
- {itemDescription && itemDescription != 'undefined' && itemDescription?.length && + {itemDescription && itemDescription != 'undefined' && itemDescription?.length ? (
-

{itemDescription}

+

{itemDescription}

- } + ) : null}
); }; diff --git a/src/components/Item.module.css b/src/components/Item.module.css index c72de7f..0a74e5f 100644 --- a/src/components/Item.module.css +++ b/src/components/Item.module.css @@ -6,19 +6,20 @@ .item { display: flex; - align-items: stretch; + align-items: center; justify-content: space-between; - padding-left: 5px; - margin-top: 5px; - margin-bottom: 5px; - color: rgba(88, 55, 50, 1); - font-size: 32px; - box-sizing: border-box; /* Include padding and border in the element's total width */ - width: 100%; /* Ensure the item does not exceed the parent's width */ - overflow: hidden; /* Prevent internal overflow */ - padding-top: 10px; - margin-bottom: 5px; + width: 100%; + gap: 10px; + padding: 8px 10px; + margin: 6px 0; + border: 1px solid #e3ece6; + border-radius: 12px; + background: var(--brand-sage-50, #F0F6F2); + box-shadow: 0 1px 3px rgba(0,0,0,0.03); + box-sizing: border-box; + transition: box-shadow 0.2s ease, border-color 0.2s ease, background-color 0.2s ease; } +.item:hover { box-shadow: 0 4px 10px rgba(0,0,0,0.08); border-color: #d9e6de; } .item:not(.itemInvoice) { /* border-top: 2px solid #00000017; */ @@ -50,9 +51,9 @@ .imageContainer { position: relative; - width: 26vw; - height: 26vw; - border-radius: 12px; + width: clamp(68px, 18vw, 96px); + height: clamp(68px, 18vw, 96px); + border-radius: 10px; object-fit: cover; } @@ -84,11 +85,15 @@ .itemDetails { display: flex; flex-direction: column; - justify-content: space-between; - margin-left: 10px; - margin-right: 10px; - flex-grow: 1; + justify-content: center; + align-items: stretch; + gap: 6px; + margin-left: 6px; + margin-right: 6px; + flex: 1; + min-width: 0; } +.infoRow { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; } .itemInvoiceDetails { display: flex; @@ -127,17 +132,7 @@ font-weight: 500; } -.itemPrice { - font-family: "Plus Jakarta Sans", sans-serif; - font-style: normal; - font-weight: 600; - width: calc(100% - 15px); /* Adjust the width to prevent overflow */ - font-size: 3.3vw; - /* margin-bottom: 35px; */ - margin-left: 5px; - color: #3a3a3a; - background-color: transparent; -} +.itemPrice { display: none; } .itemPriceInvoice { font-family: "Plus Jakarta Sans", sans-serif; @@ -153,11 +148,9 @@ .itemQty { display: flex; align-items: center; - font-size: 0.9rem; - margin-left: 5px; - color: #a8c7a9; - fill: #a8c7a9; - height: 40px; + justify-content: flex-end; + gap: 8px; + min-height: 32px; } .itemQtyValue { @@ -183,19 +176,21 @@ } .addButton { - background-color: #ffffff; - border: 2px solid #a8c7a9; - /* border: none; */ - display: inline-block; - font-size: 14px; - font-weight: 600; - cursor: pointer; - width: 87px; - height: 32px; - margin-left: 5px; - margin-top: 5px; - border-radius: 20px; + background-color: var(--brand-sage, #6B8F71); + border: 1px solid var(--brand-sage, #6B8F71); + color: #ffffff; + display: inline-block; + font-size: 13px; + font-weight: 600; + cursor: pointer; + min-width: 84px; + height: 34px; + padding: 0 14px; + border-radius: 10px; /* square rounded corner */ + box-shadow: 0 1px 2px rgba(0,0,0,0.08); } +.addButton:hover { background-color: var(--brand-sage-hover, #7FAE7D); border-color: var(--brand-sage-hover, #7FAE7D); } +.addButton:disabled { background-color: var(--brand-sage-muted, #CFD8D3); border-color: var(--brand-sage-muted, #CFD8D3); cursor: default; } .grayscale { filter: grayscale(100%); } @@ -204,9 +199,8 @@ color: gray; } .plusNegative { - width: 35px; - height: 35px; - margin: 2.5px 0 -0.5px 0px; + width: 30px; + height: 30px; } .plusNegative2 { @@ -224,6 +218,91 @@ margin-right: 10px; } +/* New elements for clean cafe item card */ +.title { + font-family: "Plus Jakarta Sans", sans-serif; + font-weight: 600; + font-size: 16px; + color: #2d2d2d; + margin: 0 0 2px 0; + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + -webkit-line-clamp: 2; + text-transform: capitalize; + text-align: left; + flex: 1; min-width: 0; +} + +/* Responsive type scale for title and price */ +@media (min-width: 600px) { + .title { font-size: 17px; } + .priceNow { font-size: 15px; } +} +@media (min-width: 992px) { + .title { font-size: 18px; } + .priceNow { font-size: 16px; } +} +.desc { + color: #5f5f5f; + font-size: 12px; + line-height: 1.25; + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + -webkit-line-clamp: 2; +} +.priceRow { display: inline-flex; align-items: center; gap: 8px; } +.promoBadge { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 2px 8px; + height: 20px; + border-radius: 999px; + background: linear-gradient(to right, #e52535, #fe6d78); + color: #fff; + font-size: 11px; + font-weight: 700; +} +.priceNow { + color: #1c1d1d; + font-weight: 700; + font-size: 14px; + white-space: nowrap; +} +.priceOld { + color: #727272; + font-size: 12px; + text-decoration: line-through; + white-space: nowrap; +} +.qtyGroup { + display: inline-flex; + align-items: center; + border: 1px solid #e6e6e6; + border-radius: 10px; /* square rounded corners */ + height: 32px; + overflow: hidden; +} +.qtyBtn { + width: 34px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + background: #fff; + color: var(--brand-sage, #6B8F71); + border: none; +} +.qtyBtn:hover { background: var(--brand-sage-50, #F0F6F2); } +.qtyVal { + min-width: 28px; + text-align: center; + font-weight: 700; + color: #2d2d2d; +} + .itemInvoice .itemDetails { flex-direction: row; justify-content: space-between; diff --git a/src/components/ItemLister.js b/src/components/ItemLister.js index 39560ba..5dc15f9 100644 --- a/src/components/ItemLister.js +++ b/src/components/ItemLister.js @@ -17,6 +17,7 @@ import { import ItemType from "./ItemType.js"; import { createItemType, updateItemDeletionStatus } from "../helpers/itemHelper.js"; import ItemConfig from "./ItemConfig.js" +import { ArrowUp, ArrowDown, Pencil } from 'lucide-react'; const ItemLister = ({ index, @@ -618,87 +619,31 @@ const ItemLister = ({ disabled={!isEdit} /> {isEditMode && !isEdit && ( - <> -
moveItemTypeUp(itemTypeId)} // Move onClick here for the whole div +
+
-
moveItemTypeDown(itemTypeId)} // Move onClick here for the whole div + + +
- -
+ +
- - + + +
)} } diff --git a/src/components/ItemLister.module.css b/src/components/ItemLister.module.css index a71335f..1adf89e 100644 --- a/src/components/ItemLister.module.css +++ b/src/components/ItemLister.module.css @@ -85,6 +85,33 @@ justify-content: space-between; } +.titleActions { + display: inline-flex; + align-items: center; + gap: 6px; +} + +.iconBtn { + width: 32px; + height: 32px; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid #e6e6e6; + background: #ffffff; + color: #2d2d2d; + border-radius: 8px; /* square rounded */ + cursor: pointer; +} +.iconBtn:disabled { + opacity: 0.5; + cursor: default; +} +.iconBtn:hover:not(:disabled) { + background: var(--brand-sage-50, #F0F6F2); + border-color: var(--brand-sage, #6B8F71); +} + .title { background-color: transparent; font-family: "Plus Jakarta Sans", sans-serif; @@ -224,4 +251,4 @@ font-size: 6vw; color: black; text-align: left; -} \ No newline at end of file +} diff --git a/src/components/ItemType.js b/src/components/ItemType.js index bb931f7..3770708 100644 --- a/src/components/ItemType.js +++ b/src/components/ItemType.js @@ -1,5 +1,6 @@ import React, { useRef, useEffect, useState } from "react"; import styles from "./ItemType.module.css"; +import { Coffee, CupSoda, CakeSlice, Utensils, Grid2X2, Plus } from 'lucide-react'; export default function ItemType({ onClick, @@ -57,6 +58,15 @@ export default function ItemType({ onCreate(namee, selectedImage); }; + const formatName = (val) => { + if (!val || typeof val !== 'string') return val; + return val + .toLowerCase() + .replace(/\b\w/g, (c) => c.toUpperCase()); + }; + + const iconImageUrl = imageUrl === 'uploads/assets/All.png' ? 'icon:all' : imageUrl; + return (
onClick(imageUrl)) : onClick + rectangular ? (blank ? null : () => onClick(iconImageUrl)) : onClick } className={styles["item-type-rect"]} style={{ - top: selected ? "-10px" : "initial", + // Remove lift-up effect; only color changes when selected + backgroundColor: selected ? 'var(--brand-sage, #6B8F71)' : '#ffffff', + border: selected ? '1px solid var(--brand-sage, #6B8F71)' : '1px solid #e6e6e6', + color: selected ? '#ffffff' : '#4a6b5a' }} > - {imageUrl != 'uploads/assets/All.png' ? - {namee} - : Created by potrace 1.16, written by Peter Selinger 2001-2019 + fill="currentColor" stroke="none"> - } + ) : (iconImageUrl && typeof iconImageUrl === 'string' && iconImageUrl.startsWith('icon:')) ? ( +
+ +
+ ) : ( + {namee} + )} {blank && rectangular && (
)}
); } + +function LucideCategoryIcon({ name, iconKey }) { + const key = pickIconKey(name, iconKey); + const size = '56%'; + switch (key) { + case 'coffee': + return ; + case 'drink': + return ; + case 'dessert': + return ; + case 'food': + return ; + case 'all': + return ; + case 'plus': + return ; + default: + return ; + } +} + +function pickIconKey(name, iconKey) { + const n = (name || '').toLowerCase(); + if (iconKey === 'plus') return 'plus'; + if (iconKey === 'all') return 'all'; + if (/(kopi|coffee|espresso|latte|americano|kapal|brew)/.test(n)) return 'coffee'; + if (/(teh|tea|drink|minum|soda|juice|jus|milk|susu|lemon)/.test(n)) return 'drink'; + if (/(dessert|cake|kue|manis|ice|es krim|ice-cream)/.test(n)) return 'dessert'; + if (/(food|makan|snack|cemilan|nasi|mie|noodle|soup|sup|ayam|daging|ikan|roti|sandwich|burger|pizza)/.test(n)) return 'food'; + return 'food'; +} diff --git a/src/components/ItemType.module.css b/src/components/ItemType.module.css index edd7836..f3cd906 100644 --- a/src/components/ItemType.module.css +++ b/src/components/ItemType.module.css @@ -1,7 +1,7 @@ .item-type { - width: calc(25vw - 20px); - height: calc(30vw - 20px); - margin: 1px 10px 0px; + width: auto; + height: auto; + margin: 0 4px; /* tighter spacing between tiles */ overflow: visible; text-align: center; align-items: center; @@ -34,24 +34,33 @@ } .item-type-rect { position: relative; - height: 13vw; - width: 13vw; + height: clamp(48px, 9vw, 80px); + width: clamp(48px, 9vw, 80px); object-fit: cover; - border-radius: 15px; + border-radius: 12px; background-color: #fff; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); + display: flex; + align-items: center; + justify-content: center; +} + +.item-type-rect:hover { + background-color: var(--brand-sage-100, #E9F3ED); + border-color: var(--brand-sage, #6B8F71); } .item-type-name { font-family: "Plus Jakarta Sans", sans-serif; font-weight: 500; font-style: normal; - font-size: 14px; + font-size: 12px; color: #333; - width: calc(25vw - 30px); + width: auto; text-align: center; background-color: transparent; - position: relative; /* Needed for positioning the button */ + position: relative; + margin-top: 6px; /* keep label spacing constant; avoid jumping */ } .item-type-image { diff --git a/src/components/ItemTypeLister.css b/src/components/ItemTypeLister.css index a0692e0..e4a47ce 100644 --- a/src/components/ItemTypeLister.css +++ b/src/components/ItemTypeLister.css @@ -1,11 +1,23 @@ +/* New clean, intuitive category bar */ .item-type-lister { - width: 100vw; + width: 100%; overflow-x: auto; white-space: nowrap; - padding: 3px 0px; - margin-bottom: -5px; + padding: 2px 0px; /* tighter top/bottom padding */ } +.category-bar { + display: flex; + align-items: center; + gap: 8px; + overflow-x: auto; + padding: 8px 12px 4px; + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} +.category-bar::-webkit-scrollbar { display: none; } + +/* Legacy horizontal tile list container (used for tile UI) */ .item-type-list { display: inline-flex; -ms-overflow-style: none; /* IE and Edge */ @@ -13,11 +25,44 @@ overflow-y: hidden; } -.item-type { - display: inline-block; - margin-right: 20px; - /* Space between items */ +.category-chip { + flex: 0 0 auto; + display: inline-flex; + align-items: center; + gap: 8px; + height: 36px; + padding: 0 14px; + border-radius: 999px; + border: 1px solid #e6e6e6; + background: #ffffff; + color: #2d2d2d; + font-family: "Plus Jakarta Sans", sans-serif; + font-weight: 500; + font-size: 14px; + cursor: pointer; + user-select: none; } +.category-chip:hover { border-color: #d0d0d0; } +.category-chip.selected { + background: #73a585; + color: #ffffff; + border-color: #73a585; +} + +.category-chip .chip-icon { + width: 18px; + height: 18px; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.add-item-chip { + background: #f4f7f5; + border-color: #dfe7e2; + color: #4a6b5a; +} +.add-item-chip:hover { background: #eaf1ed; } .rect-creator { width: 100vw; height: 100vh; @@ -55,13 +100,4 @@ bottom: 0; align-self: center; /* Center the button horizontally */ } -.item-type-name { - font-family: "Plus Jakarta Sans", sans-serif; - font-style: normal; - height: 20vw; - font-size: 1.5rem; - font-weight: 500; - color: black; - text-transform: capitalize; - z-index: 301; -} +/* Legacy styles kept for ItemType grid if needed elsewhere */ diff --git a/src/components/ItemTypeLister.js b/src/components/ItemTypeLister.js index 996fc43..8ede325 100644 --- a/src/components/ItemTypeLister.js +++ b/src/components/ItemTypeLister.js @@ -2,7 +2,7 @@ import React, { useState, useRef, useEffect } from "react"; import smoothScroll from "smooth-scroll-into-view-if-needed"; import "./ItemTypeLister.css"; import ItemType from "./ItemType"; -import { createItem, createItemType } from "../helpers/itemHelper.js"; +import { createItem } from "../helpers/itemHelper.js"; import { getImageUrl } from "../helpers/itemHelper"; import ItemLister from "./ItemLister"; @@ -22,24 +22,6 @@ const ItemTypeLister = ({ const newItemDivRef = useRef(null); const [items, setItems] = useState([]); - const [itemTypeName, setItemTypeName] = useState(""); - const handleCreateItem = (name, price, selectedImage, previewUrl, description, promoPrice) => { - console.log(previewUrl); - const newItem = { - itemId: items.length + 1, - name, - price, - selectedImage, - image: previewUrl, - availability: true, - description, - promoPrice - }; - - // Update the items state with the new item - setItems((prevItems) => [...prevItems, newItem]); - }; - // Effect to handle changes to isAddingNewItem useEffect(() => { if (isAddingNewItem && newItemDivRef.current) { @@ -67,90 +49,63 @@ const ItemTypeLister = ({ document.body.style.overflow = !isAddingNewItem ? "hidden" : "auto"; }; - async function handleCreate(name, selectedImage) { - createItemType(shopId, name, selectedImage); - } + // Removed legacy image upload logic used by the old tile view + + const canManage = user && (user.user_id == shopOwnerId || user.cafeId == shopId); - const [selectedImage, setSelectedImage] = useState(null); - const [previewUrl, setPreviewUrl] = useState(""); - const [imageUrl, setImaguUrl] = useState(""); - - useEffect(() => { - // if (selectedImage) { - // const reader = new FileReader(); - // reader.onloadend = () => { - // setPreviewUrl(reader.result); - // }; - // reader.readAsDataURL(selectedImage); - // } else { - // setPreviewUrl(getImageUrl(imageUrl)); - setPreviewUrl(selectedImage); - // } - }, [selectedImage, imageUrl]); - const handleImageChange = (e) => { - setSelectedImage(e); + const formatName = (name) => { + if (!name) return name; + return name + .toLowerCase() + .replace(/\b\w/g, (c) => c.toUpperCase()); }; + return ( -
-
- {isEditMode && - !isAddingNewItem && - user && ( - user.user_id == shopOwnerId || user.cafeId == shopId) && ( - - )} - {user &&( - user.user_id == shopOwnerId || user.cafeId == shopId) && - isAddingNewItem && ( - <> - createItem(shopId, name, price, selectedImage, itemTypeId, description, promoPrice)} - beingEditedType={beingEditedType} - setBeingEditedType={setBeingEditedType} - alwaysEdit={true} - handleUnEdit={toggleAddNewItem} - /> - - )} +
+
+ {isEditMode && !isAddingNewItem && canManage && ( + + )} + + {canManage && isAddingNewItem && ( + createItem(shopId, name, price, selectedImage, itemTypeId, description, promoPrice)} + beingEditedType={beingEditedType} + setBeingEditedType={setBeingEditedType} + alwaysEdit={true} + handleUnEdit={toggleAddNewItem} + /> + )} + {itemTypes && itemTypes.length > 0 && ( onFilterChange(0)} - imageUrl={"uploads/assets/All.png"} + imageUrl={"icon:all"} + selected={filterId === 0} /> )} - {itemTypes && - itemTypes.map( - (itemType) => - ( - itemType.itemList.length > 0 || (user && (user.user_id == shopOwnerId || user.cafeId == shopId))) && ( - onFilterChange(itemType.itemTypeId)} - selected={filterId === itemType.itemTypeId} - /> - ) - )} + + {itemTypes && itemTypes.map((itemType) => ( + onFilterChange(itemType.itemTypeId)} + selected={filterId === itemType.itemTypeId} + /> + ))}
); diff --git a/src/pages/CafePage.js b/src/pages/CafePage.js index eebdc97..3f501e3 100644 --- a/src/pages/CafePage.js +++ b/src/pages/CafePage.js @@ -55,6 +55,7 @@ function CafePage({ const [searchParams] = useSearchParams(); const token = searchParams.get("token"); const { shopIdentifier, tableCode } = useParams(); + // Send params to parent immediately (original behavior) sendParam({ shopIdentifier, tableCode }); const { @@ -319,7 +320,7 @@ function CafePage({ /> ))} {!isEditMode && (user.username || cartItemsLength > 0) && -
+
{(lastTransaction != null || cartItemsLength > 0) &&
{lastTransaction != null && '+'}{cartItemsLength} item
@@ -338,7 +339,7 @@ function CafePage({
} {user.username && -
0 ? '6px' : '0px' }}> +
0) ? '6px' : '0px' }}>