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 ? (
-
) : (
-
- {isBeingEdit ? "Simpan" : "Buat"}
+
+ {isBeingEdit ? 'Simpan' : 'Buat'}
- ))}
+ )
+ )}
{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
+
+
index === 0 ? null : moveItemTypeUp(itemTypeId)}
+ disabled={index === 0}
+ aria-label="Naikkan kategori"
>
-
-
-
moveItemTypeDown(itemTypeId)} // Move onClick here for the whole div
+
+
+
index === indexTotal - 1 ? null : moveItemTypeDown(itemTypeId)}
+ disabled={index === indexTotal - 1}
+ aria-label="Turunkan kategori"
>
-
-
-
-
+
+
-
-
-
- >
+
+
+
)}
}
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' ?
-

- :
- }
+ ) : (iconImageUrl && typeof iconImageUrl === 'string' && iconImageUrl.startsWith('icon:')) ? (
+
+
+
+ ) : (
+

+ )}
{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 &&
-