115 lines
4.6 KiB
TypeScript
115 lines
4.6 KiB
TypeScript
import { useState } from "preact/compat";
|
|
import { MenuItem } from "./types";
|
|
|
|
const CATEGORIES = [
|
|
{ value: 'appetizer', label: 'Appetizer' },
|
|
{ value: 'main_course', label: 'Main Course' },
|
|
{ value: 'dessert', label: 'Dessert' },
|
|
{ value: 'beverages', label: 'Beverages' },
|
|
{ value: 'snack', label: 'Snack' },
|
|
];
|
|
|
|
const emptyItem = (): MenuItem => ({ name: '', price: 0, category: '', description: '' });
|
|
|
|
interface MenuItemsModalProps {
|
|
selected: Array<MenuItem>;
|
|
onSave: (items: Array<MenuItem>) => void;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export default function MenuItemsModal({ selected, onSave, onClose }: MenuItemsModalProps) {
|
|
const [items, setItems] = useState<Array<MenuItem>>(selected.length > 0 ? selected : [emptyItem()]);
|
|
|
|
function onChange(idx: number, field: keyof MenuItem, value: string) {
|
|
setItems(prev => prev.map((item, i) =>
|
|
i === idx ? { ...item, [field]: field === 'price' ? parseInt(value) || 0 : value } : item
|
|
));
|
|
}
|
|
|
|
function onAdd() {
|
|
setItems(prev => [...prev, emptyItem()]);
|
|
}
|
|
|
|
function onDelete(idx: number) {
|
|
setItems(prev => prev.filter((_, i) => i !== idx));
|
|
}
|
|
|
|
function handleSave() {
|
|
const valid = items.filter(item => item.name.trim() !== '');
|
|
onSave(valid);
|
|
}
|
|
|
|
return (
|
|
<div className="amenities-overlay" onClick={onClose}>
|
|
<div className="amenities-modal" style={{ maxWidth: 680 }} onClick={e => e.stopPropagation()}>
|
|
<div className="amenities-modal-header">
|
|
<span>Restaurant Menu</span>
|
|
<button className="amenities-close-btn" onClick={onClose}>✕</button>
|
|
</div>
|
|
|
|
<div className="amenities-modal-body">
|
|
{items.map((item, idx) => (
|
|
<div key={idx} className="menu-item-row">
|
|
<div className="menu-item-fields">
|
|
<div className="menu-item-field">
|
|
<span className="menu-item-label">Name <span style={{ color: '#ed4245' }}>*</span></span>
|
|
<input
|
|
className="bg-primary text-sm menu-item-input"
|
|
type="text"
|
|
value={item.name}
|
|
onInput={e => onChange(idx, 'name', (e.target as HTMLInputElement).value)}
|
|
placeholder="e.g. Nasi Goreng"
|
|
/>
|
|
</div>
|
|
<div className="menu-item-field" style={{ flex: '0 0 120px' }}>
|
|
<span className="menu-item-label">Price (IDR)</span>
|
|
<input
|
|
className="bg-primary text-sm menu-item-input"
|
|
type="number"
|
|
min={0}
|
|
value={item.price}
|
|
onInput={e => onChange(idx, 'price', (e.target as HTMLInputElement).value)}
|
|
/>
|
|
</div>
|
|
<div className="menu-item-field" style={{ flex: '0 0 140px' }}>
|
|
<span className="menu-item-label">Category</span>
|
|
<select
|
|
className="bg-primary text-sm menu-item-input"
|
|
value={item.category}
|
|
onChange={e => onChange(idx, 'category', (e.target as HTMLSelectElement).value)}
|
|
>
|
|
<option value="">—</option>
|
|
{CATEGORIES.map(c => (
|
|
<option key={c.value} value={c.value}>{c.label}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<div className="menu-item-field" style={{ flex: '1 1 180px' }}>
|
|
<span className="menu-item-label">Description</span>
|
|
<input
|
|
className="bg-primary text-sm menu-item-input"
|
|
type="text"
|
|
value={item.description}
|
|
onInput={e => onChange(idx, 'description', (e.target as HTMLInputElement).value)}
|
|
placeholder="Optional"
|
|
/>
|
|
</div>
|
|
<button className="menu-item-delete-btn" onClick={() => onDelete(idx)}>✕</button>
|
|
</div>
|
|
</div>
|
|
))}
|
|
<button type="button" className="amenities-trigger-btn" onClick={onAdd}>+ Add Item</button>
|
|
</div>
|
|
|
|
<div className="amenities-modal-footer">
|
|
<span className="text-sm" style={{ opacity: 0.6 }}>{items.filter(i => i.name.trim()).length} item(s)</span>
|
|
<div style={{ display: 'flex', gap: 8 }}>
|
|
<button className="amenities-cancel-btn" onClick={onClose}>Cancel</button>
|
|
<button className="amenities-save-btn" onClick={handleSave}>Save</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|