Files
kedaimaster/src/components/ItemType.js
karyamanswasta b28c6ed0fe ok
2025-08-26 13:07:13 +07:00

222 lines
8.6 KiB
JavaScript

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,
onCreate,
blank,
name,
imageUrl,
selected,
rectangular,
}) {
const inputRef = useRef(null);
const [namee, setName] = useState(name);
const [selectedImage, setSelectedImage] = useState(null);
const [previewUrl, setPreviewUrl] = useState(imageUrl);
// Effect to update local state when name prop changes
useEffect(() => {
setName(name);
}, [name]);
useEffect(() => {
if (blank && inputRef.current) {
inputRef.current.focus();
}
}, [blank]);
useEffect(() => {
if (selectedImage) {
const reader = new FileReader();
reader.onloadend = () => {
onClick(reader.result, selectedImage);
};
reader.readAsDataURL(selectedImage);
} else {
setPreviewUrl(imageUrl);
}
}, [selectedImage, imageUrl]);
const handleImageChange = (e) => {
setSelectedImage(e.target.files[0]);
console.log(e.target.files[0]);
e.target.value = null; // This clears the input
};
const handleNameChange = (e) => {
setName(e.target.value);
};
const handleCreate = async () => {
if (!selectedImage) {
console.error("No image selected");
return;
}
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 (
<div
className={
styles[
namee
? "item-type"
: rectangular
? "item-type-rectangular"
: "item-type-nomargin"
]
}
style={{ zIndex: blank ? 301 : "inherit" }}
>
<div
onClick={
rectangular ? (blank ? null : () => onClick(iconImageUrl)) : onClick
}
className={styles["item-type-rect"]}
style={{
// 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'
}}
>
{iconImageUrl === 'uploads/assets/All.png' ? (
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="100%" height="100%" viewBox="0 0 800.000000 800.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.16, written by Peter Selinger 2001-2019
</metadata>
<g transform="translate(0.000000,800.000000) scale(0.100000,-0.100000)"
fill="currentColor" stroke="none">
<path d="M3708 7165 c-3 -4 -44 -10 -90 -15 -266 -28 -530 -91 -753 -180 -11
-4 -42 -16 -70 -26 -27 -9 -129 -57 -225 -106 -186 -94 -188 -95 -262 -145
-26 -18 -52 -33 -58 -33 -5 0 -24 -13 -42 -28 -18 -16 -53 -43 -78 -61 -124
-88 -157 -114 -217 -168 -87 -78 -244 -236 -318 -318 -56 -63 -84 -99 -166
-215 -18 -25 -47 -62 -66 -83 -18 -20 -33 -42 -33 -47 0 -6 -12 -29 -27 -53
-15 -23 -32 -49 -38 -59 -30 -49 -194 -380 -209 -423 -10 -27 -22 -59 -26 -70
-81 -203 -137 -426 -177 -700 -20 -137 -23 -692 -5 -830 24 -184 59 -380 73
-407 5 -10 9 -23 9 -30 0 -25 78 -266 130 -403 25 -65 193 -392 237 -460 171
-264 379 -510 591 -701 59 -52 114 -102 123 -110 9 -7 19 -14 23 -14 7 0 110
-75 173 -125 17 -14 52 -37 78 -51 26 -13 61 -35 79 -49 17 -13 42 -28 56 -34
14 -6 32 -15 40 -21 8 -5 67 -35 130 -66 63 -30 122 -59 130 -64 8 -4 33 -15
55 -23 22 -8 83 -31 135 -50 94 -36 219 -71 410 -117 51 -12 201 -37 305 -50
92 -12 651 -12 740 0 39 6 102 14 140 19 210 28 511 109 663 177 29 13 57 24
62 24 19 0 251 111 357 170 53 30 88 51 118 70 17 11 43 27 59 36 30 16 103
70 164 120 18 14 50 38 72 53 21 14 66 52 99 84 33 31 64 57 67 57 17 0 293
299 337 363 16 23 38 53 51 67 19 21 118 164 151 218 6 9 25 38 43 64 17 26
32 54 32 62 0 8 4 17 9 20 13 8 181 354 181 372 0 5 11 36 24 69 52 132 121
391 146 545 6 41 17 95 23 120 8 31 12 168 12 430 0 326 -3 402 -18 495 -10
61 -22 133 -27 160 -7 45 -22 107 -52 220 -6 22 -35 114 -65 205 -49 149 -97
255 -240 533 -17 35 -81 136 -145 231 -29 41 -149 203 -175 235 -39 47 -342
350 -383 384 -63 51 -297 222 -331 242 -19 11 -65 39 -104 62 -63 38 -193 104
-361 184 -89 42 -370 133 -519 167 -192 44 -230 51 -340 64 -109 12 -697 23
-707 13z m-553 -1586 c12 -23 15 -87 15 -359 l0 -332 -31 -29 -31 -29 -335 0
-335 0 -29 29 -29 29 0 334 1 333 26 30 26 30 326 5 c179 3 339 1 354 -4 15
-4 34 -21 42 -37z m1201 31 c50 -27 54 -57 54 -386 0 -251 -3 -310 -15 -334
-31 -61 -28 -60 -390 -60 -298 0 -332 2 -351 18 -42 34 -44 48 -44 382 0 347
1 354 56 383 31 16 658 13 690 -3z m1267 -31 c15 -27 17 -65 17 -359 l0 -328
-31 -31 -31 -31 -328 0 c-218 0 -337 4 -353 11 -53 24 -57 52 -57 390 0 327 3
354 47 375 23 11 660 22 693 11 14 -4 33 -21 43 -38z m-2504 -1203 c49 -26 51
-42 51 -389 0 -296 -2 -324 -19 -353 -30 -49 -65 -54 -386 -54 -274 0 -289 1
-325 21 -21 12 -43 32 -49 46 -7 16 -11 134 -11 350 l0 327 32 33 32 33 323 0
c261 0 329 -3 352 -14z m1237 -2 c52 -35 54 -49 54 -379 0 -348 -2 -360 -69
-394 -38 -20 -57 -21 -327 -21 -320 0 -355 5 -385 54 -17 29 -19 56 -19 356 1
251 4 330 14 349 27 49 39 50 384 51 283 0 326 -2 348 -16z m1233 2 c49 -26
51 -43 51 -386 0 -285 -2 -322 -17 -349 -33 -56 -61 -61 -384 -61 -271 0 -292
1 -329 20 -69 35 -70 40 -70 394 l0 316 36 40 36 40 325 0 c261 0 329 -3 352
-14z m-2475 -1226 c53 -20 56 -41 56 -389 0 -227 -3 -328 -12 -346 -24 -53
-40 -55 -387 -55 l-320 0 -36 31 -35 31 0 335 0 335 34 34 34 34 320 0 c180 0
332 -4 346 -10z m1243 -7 c50 -33 53 -57 53 -388 0 -254 -3 -311 -15 -335 -30
-58 -43 -60 -389 -60 -223 0 -323 3 -341 12 -53 24 -55 39 -55 394 l0 326 34
34 34 34 326 0 c291 0 330 -2 353 -17z m1227 7 c53 -20 56 -40 56 -396 l0
-326 -34 -34 -34 -34 -326 0 c-358 0 -360 0 -392 61 -21 42 -21 637 1 679 30
58 40 59 387 60 178 0 328 -4 342 -10z"/>
</g>
</svg>
) : (iconImageUrl && typeof iconImageUrl === 'string' && iconImageUrl.startsWith('icon:')) ? (
<div style={{width:'100%',height:'100%',display:'flex',alignItems:'center',justifyContent:'center'}}>
<LucideCategoryIcon name={namee} iconKey={(iconImageUrl || '').split(':')[1]} />
</div>
) : (
<img
src={previewUrl}
alt={namee}
className={styles["item-type-image"]}
/>
)}
{blank && rectangular && (
<div className={styles["item-type-image-container"]}>
<input
type="file"
accept=".png, .jpg, .jpeg"
className={styles["item-type-image-input"]}
onChange={handleImageChange}
id="image-input"
/>
</div>
)}
</div>
{!rectangular && !blank && (
<input
ref={inputRef}
className={`${styles["item-type-name"]} ${styles.noborder}`}
value={formatName(namee)}
onChange={handleNameChange}
disabled={true}
style={{
top: 'initial',
borderBottom: 'none',
color: selected ? '#2d2d2d' : '#333',
textTransform: 'capitalize'
}}
/>
)}
</div>
);
}
function LucideCategoryIcon({ name, iconKey }) {
const key = pickIconKey(name, iconKey);
const size = '56%';
switch (key) {
case 'coffee':
return <Coffee color={'currentColor'} size={size} strokeWidth={2} />;
case 'drink':
return <CupSoda color={'currentColor'} size={size} strokeWidth={2} />;
case 'dessert':
return <CakeSlice color={'currentColor'} size={size} strokeWidth={2} />;
case 'food':
return <Utensils color={'currentColor'} size={size} strokeWidth={2} />;
case 'all':
return <Grid2X2 color={'currentColor'} size={size} strokeWidth={2} />;
case 'plus':
return <Plus color={'currentColor'} size={size} strokeWidth={2} />;
default:
return <Utensils color={'currentColor'} size={size} strokeWidth={2} />;
}
}
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';
}