2025-08-11 15:52:41 +05:30

1226 lines
63 KiB
JavaScript

"use client"
import MasterLayout from "@/masterLayout/MasterLayout";
import { useRouter, useSearchParams } from "next/navigation";
import { Suspense, useEffect, useState } from "react";
import client from "@auth";
import classNames from "classnames";
import Link from "next/link";
import PageLoader from "@/components/common-component/PageLoader";
import PageNoData from "@/components/common-component/PageNoData";
import Breadcrumb from "@/components/Breadcrumb";
import { Icon } from "@iconify/react";
import axios from "axios";
import { Baseurl } from "@utils/BaseUrl.utils";
const DineInInner = () => {
const router = useRouter();
const searchParams = useSearchParams();
const roomName = decodeURIComponent(searchParams.get("roomname") || "");
const FloorName = decodeURIComponent(searchParams.get("floor") || "");
const [tables, setTables] = useState([]);
const [showModalTable, setShowModalTable] = useState(false);
const [showModal, setShowModal] = useState(false);
const [isEditMode, setIsEditMode] = useState(false);
const [selectedFloorId, setSelectedFloorId] = useState(null);
const [selectedTable, setSelectedTable] = useState(null);
const [seatCount, setSeatCount] = useState(1);
const [error, setError] = useState('');
const [loading, setLoading] = useState(true)
const [formData, setFormData] = useState({
tablename: "",
minimumoccupancy: "",
totalcapacity: "",
description: "",
enable: 0,
});
const [errors, setErrors] = useState({});
const [deleteConfirm, setDeleteConfirm] = useState({ show: false, id: null, isDeleted: null });
const [restaruntBranch, setRestaruntBranch] = useState("")
const [floorData, setFloorData] = useState(null);
const [roomData, setRoomData] = useState(null);
const [selectedFloor, setSelectedFloor] = useState("");
const [selectedRoom, setSelectedRoom] = useState("");
// Floor
const [showFloorModal, setShowFloorModal] = useState(false);
const [isFloorEditMode, setIsFloorEditMode] = useState(false);
// const [selectedFloorId, setSelectedFloorId] = useState(null);
const [floorFormData, setFloorFormData] = useState({
floorname: "",
description: "",
});
const [floorErrors, setFloorErrors] = useState({});
const [floorDeleteConfirm, setFloorDeleteConfirm] = useState({ show: false, id: null, isDeleted: null });
// Room
const [showRoomModal, setShowRoomModal] = useState(false);
const [editRoomMode, setEditRoomMode] = useState(false);
const [editingRoomId, setEditingRoomId] = useState(null);
const [roomFormData, setRoomFormData] = useState({
roomname: "",
description: "",
});
const [roomErrors, setRoomErrors] = useState({});
const [roomDeleteConfirm, setRoomDeleteConfirm] = useState({ show: false, id: null, isDeleted: null });
useEffect(() => {
const restarunt = localStorage.getItem("restaurantbranch")
setRestaruntBranch(restarunt)
}, [])
useEffect(() => {
const isLogin = JSON.parse(localStorage.getItem("isLogin"));
if (!isLogin) {
router.push(`/admin?restaurantbranch=${restaruntBranch}`);
}
}, [router]);
// Get floor data when branch is ready
useEffect(() => {
if (restaruntBranch) {
getFloor();
}
}, [restaruntBranch]);
const getFloor = async () => {
try {
const res = await client.get(
`/Dine360 Floor?fields=["*"]&limit_page_length=100&filters=[["restaurantbranch","=","${restaruntBranch}"]]`
);
const floors = res?.data?.data || [];
setFloorData(floors);
if (floors.length > 0) {
setSelectedFloor(floors[0].name);
setSelectedRoom(null);
getRoomData(floors[0].name);
} else {
setSelectedFloor(null);
setRoomData([]);
setTables([]);
}
} catch (error) {
console.error("Error fetching floor data:", error);
}
};
const getRoomData = async (floorName) => {
try {
const res = await client.get(
`/Dine360 Room?fields=["*"]&limit_page_length=100&filters=[["floor","=","${floorName}"]]`
);
const rooms = res?.data?.data || [];
setRoomData(rooms);
if (rooms.length > 0) {
setSelectedRoom(rooms[0].name);
getTableData(rooms[0].name);
} else {
setSelectedRoom(null); // clear selection if no rooms
setTables([]); // clear table data
}
} catch (error) {
console.error("Error fetching room data:", error);
}
};
const getTableData = async (roomName) => {
try {
setLoading(true)
const tableRes = await client.get(`/Dine360%20Table?fields=[\"*\"]&limit_page_length=100&filters=[["room","=","${roomName}"]]`);
console.log("tableRes", tableRes);
setTables(tableRes.data.data);
setLoading(false)
} catch (error) {
console.error("Error fetching data:", error);
setLoading(false)
}
}
// floor start
const handleFloorChange = (e) => {
const { name, value } = e.target;
setFloorFormData((prev) => ({ ...prev, [name]: value }));
};
const handleFloorSubmit = async (e) => {
e.preventDefault();
const newErrors = {};
Object.entries(floorFormData).forEach(([key, value]) => {
if (!value.trim()) newErrors[key] = `${key} is required`;
});
setFloorErrors(newErrors);
if (Object.keys(newErrors).length > 0) return;
const body = {
// ...(isFloorEditMode && { name: selectedFloorId }), // only adds `name` if editing
floorname: floorFormData?.floorname,
description: floorFormData?.description,
restaurantbranch: restaruntBranch
};
try {
if (isFloorEditMode) {
await client.put(`/Dine360 Floor/${selectedFloorId}`, body);
} else {
await client.post(`/Dine360 Floor`, body);
}
getFloor();
resetFloorForm();
} catch (error) {
if (
error?.response?.data?.exception?.includes("DuplicateEntryError") ||
error?.response?.data?.message?.includes("Duplicate entry")
) {
alert("Floor with this name already exists. Please use a different name.");
} else if (
error?.response?.data?.exception?.includes("UniqueValidationError") ||
error?.response?.data?.message?.includes("UniqueValidationError entry")
) {
alert("Floor with this name already exists. Please use a different name.");
} else {
alert("An error occurred. Please try again.");
}
}
};
const resetFloorForm = () => {
setFloorFormData({
floorname: "", description: "",
});
setShowFloorModal(false);
setIsFloorEditMode(false);
setSelectedFloorId(null);
setFloorErrors({});
};
const handleFloorEdit = (floor) => {
setIsFloorEditMode(true);
setSelectedFloorId(floor.name);
setFloorFormData({
floorname: floor.floorname || "",
description: floor.description || "",
});
setShowFloorModal(true);
};
const handleFloorDelete = async () => {
try {
const body = {
isdeleted: floorDeleteConfirm?.isDeleted == 0 ? 1 : 0
}
await client.put(`/Dine360 Floor/${floorDeleteConfirm.id}`, body);
setFloorDeleteConfirm({ show: false, id: null, isDeleted: null });
getFloor();
} catch (error) {
if (
error?.response?.data?.exception?.includes("DuplicateEntryError") ||
error?.response?.data?.message?.includes("Duplicate entry")
) {
alert("Floor with this name already exists. Please use a different name.");
} else if (error?.response?.data?.exception?.includes("LinkExistsError") ||
error?.response?.data?.message?.includes("LinkExistsError")) {
alert(" Cannot delete or cancel because Dine360 Floor three is linked with Dine360 Room ");
}
}
};
// floor end
// Room Start
const handleRoomChange = (e) => {
const { name, value } = e.target;
setRoomFormData((prev) => ({ ...prev, [name]: value }));
};
const handleRoomSubmit = async (e) => {
e.preventDefault();
const newErrors = {};
Object.entries(roomFormData).forEach(([key, value]) => {
if (!value.trim()) newErrors[key] = `${key} is required`;
});
setRoomErrors(newErrors);
if (Object.keys(newErrors).length > 0) return;
const body = {
roomname: roomFormData.roomname,
description: roomFormData.description,
floor: selectedFloor,
restaurantbranch: restaruntBranch
};
try {
if (editRoomMode) {
await client.put(`/Dine360 Room/${editingRoomId}`, body);
} else {
await client.post(`/Dine360 Room`, body);
}
getRoomData(selectedFloor);
resetRoomForm();
} catch (error) {
console.error("❌ Submission error:", error);
}
};
const handleRoomEdit = (room) => {
setRoomFormData({
roomname: room.roomname || "",
description: room.description || "",
// branch: room.branch || "",
});
setEditingRoomId(room.name);
setEditRoomMode(true);
setShowRoomModal(true);
};
const handleRoomDelete = async () => {
try {
const body = {
isdeleted: roomDeleteConfirm?.isDeleted == 0 ? 1 : 0
}
await client.put(`/Dine360 Room/${roomDeleteConfirm?.id}`, body);
setRoomDeleteConfirm({ show: false, id: null, isDeleted: null });
getRoomData(selectedFloor);
} catch (error) {
if (
error?.response?.data?.exception?.includes("DuplicateEntryError") ||
error?.response?.data?.message?.includes("Duplicate entry")
) {
alert("Floor with this name already exists. Please use a different name.");
} else if (error?.response?.data?.exception?.includes("LinkExistsError") ||
error?.response?.data?.message?.includes("LinkExistsError")) {
alert(" Cannot delete or cancel because Dine360 Floor three is linked with Dine360 Room fsrf65ahb5");
}
}
};
const resetRoomForm = () => {
setRoomFormData({ roomname: "", description: "", });
setRoomErrors({});
setEditRoomMode(false);
setEditingRoomId(null);
setShowRoomModal(false);
};
// Room End
console.log("selectedFloor", selectedFloor)
const handleTableClick = (table) => {
setSelectedTable(table);
setSeatCount(1);
setError('');
setShowModalTable(true);
};
const handleSeatChange = (e) => {
const value = parseInt(e.target.value);
if (value > selectedTable?.totalcapacity) {
setError(`Maximum capacity is ${selectedTable?.totalcapacity} seats`);
} else {
setError('');
}
setSeatCount(value);
};
const handleSeatSubmit = () => {
if (
selectedTable &&
seatCount > 0 &&
seatCount <= selectedTable?.totalcapacity
) {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // month is 0-based
const day = String(now.getDate()).padStart(2, '0');
const hour = String(now.getHours()).padStart(2, '0');
const minute = String(now.getMinutes()).padStart(2, '0');
const second = String(now.getSeconds()).padStart(2, '0');
const formattedTime = `${year}-${month}-${day} ${hour}:${minute}:${second}`;
console.log(formattedTime);
// Push the route with formatted timestamp
router.push(
`/admin/pos/menu-items?restaurantbranch=${restaruntBranch}&table=${encodeURIComponent(selectedTable.name)}&seats=${seatCount}&time=${encodeURIComponent(formattedTime)}`
);
}
};
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
};
const handleSubmit = async (e) => {
e.preventDefault();
const newErrors = {};
Object.entries(formData).forEach(([key, value]) => {
if (!String(value).trim()) {
newErrors[key] = `${key} is required`;
}
});
setErrors(newErrors);
if (Object.keys(newErrors).length > 0) return;
const Body = {
tablename: formData?.tablename,
minimumoccupancy: formData?.minimumoccupancy,
totalcapacity: formData?.totalcapacity,
description: formData?.description,
room: selectedRoom,
floor: selectedFloor,
status: "Available",
restaurantbranch: restaruntBranch
}
try {
if (isEditMode) {
await client.put(`/Dine360 Table/${selectedFloorId}`, Body);
} else {
const createTable = await client.post(`/Dine360 Table`, Body);
if (formData.enable == 1) {
const tableName = createTable?.data?.data?.name;
const RestaurantBranch = createTable?.data?.data?.restaurantbranch;
const AutoCreateBody = {
name: tableName,
restaurantbranch: RestaurantBranch,
enabled: formData.enable, // Uncomment if needed
};
try {
await axios.post(`${Baseurl}/Add-Table-To-Day`, AutoCreateBody);
} catch (apiError) {
console.error("Error while auto-creating table for the day:", apiError);
alert("Table created, but failed to assign it to the day.");
}
}
}
getTableData(selectedRoom);
resetForm();
} catch (error) {
if (
error?.response?.data?.exception?.includes("DuplicateEntryError") ||
error?.response?.data?.message?.includes("Duplicate entry")
) {
alert("Floor with this name already exists. Please use a different name.");
} else {
alert("An error occurred. Please try again.");
}
}
};
const resetForm = () => {
setFormData({
tablename: "",
minimumoccupancy: "",
totalcapacity: "",
// branch: "",
description: "",
enable: 0,
});
setShowModal(false);
setIsEditMode(false);
setSelectedFloorId(null);
setErrors({});
};
const handleEdit = (table) => {
setIsEditMode(true);
setSelectedFloorId(table.name);
setFormData({
tablename: table.tablename || "",
minimumoccupancy: table.minimumoccupancy || "",
totalcapacity: table.totalcapacity || "",
description: table.description || "",
// branch: room.branch || "",
});
setShowModal(true);
};
const handleDelete = async () => {
try {
const body = {
isdeleted: deleteConfirm?.isDeleted == 0 ? 1 : 0
}
await client.put(`/Dine360 Table/${deleteConfirm.id}`, body);
setDeleteConfirm({ show: false, id: null, isDeleted: null });
getTableData(selectedRoom);
} catch (error) {
console.error("Delete error:", error);
}
};
return (
<>
<div className="container " style={{ marginBottom: "100px" }}>
<div className="row mb-3" style={{ position: "sticky", top: "150px", zIndex: "1" }}>
{/* Floor & Room Wrapper Row */}
<div className="row mb-3">
{/* Floor Section */}
<div className="col-12 col-md-6 mb-3">
<div className="d-flex flex-wrap gap-2 align-items-start justify-content-center">
{/* Add Floor Card */}
<div
className="card shadow-sm bg-light border-0 text-center cursor-pointer d-flex align-items-center justify-content-center"
style={{ width: "60px", height: "40px", borderRadius: "12px" }}
onClick={() => setShowFloorModal(true)}
>
<Icon icon="lucide:plus" className="text-lg" />
</div>
{/* Floor Cards */}
{floorData?.map((floor) => (
<div
key={floor.name}
className={`card shadow-sm position-relative cursor-pointer border-2 px-2 py-1 ${selectedFloor === floor.name ? "bg-theme text-white" : "border-light"}`}
style={{ width: "auto", minWidth: "120px", maxWidth: "200px", borderRadius: "12px", height: "40px" }}
onClick={() => {
setSelectedFloor(floor.name);
getRoomData(floor.name);
}}
>
<div className="card-body px-3 py-1 d-flex gap-2 align-items-center justify-content-center" >
{
floor?.isdeleted == 1 && (<Icon icon="mdi:block-helper" style={{ color: "red" }} />)
}
<span
className="text-truncate text-sm fw-semibold w-100"
title={floor.floorname}
>
{floor.floorname}
</span>
</div>
{/* Dropdown */}
<div className="position-absolute" style={{ top: "4px", right: "4px", zIndex: 2 }}>
<div className="dropdown">
<button
className="btn px-1 py-1 d-flex align-items-center text-primary-light"
type="button"
data-bs-toggle="dropdown"
>
<Icon icon="entypo:dots-three-vertical" />
</button>
<ul className="dropdown-menu">
<li>
<Link className="dropdown-item px-16 py-8 d-flex align-items-center gap-2 rounded text-secondary-light bg-hover-neutral-200 text-hover-neutral-900" href="#" onClick={(e) => {
e.preventDefault();
handleFloorEdit(floor);
}}>
<Icon icon="lucide:edit" /> Edit
</Link>
</li>
<li>
<Link className="dropdown-item px-16 py-8 d-flex align-items-center gap-2 rounded text-secondary-light bg-hover-neutral-200 text-hover-neutral-900" href="#" onClick={(e) => {
e.preventDefault();
setFloorDeleteConfirm({ show: true, id: floor.name, isDeleted: floor.isdeleted });
}}>
{floor.isdeleted === 1 ? (
<>
<Icon icon="mdi:restore" /> Restore
</>
) : (
<>
<Icon icon="fluent:delete-24-regular" /> Delete
</>
)}
</Link>
</li>
</ul>
</div>
</div>
</div>
))}
</div>
</div>
{/* Room Section */}
<div className="col-12 col-md-6">
<div className="d-flex flex-wrap gap-2 align-items-start justify-content-center">
{/* Add Room Card */}
<div
className="card shadow-sm bg-light border-0 text-center cursor-pointer d-flex align-items-center justify-content-center"
style={{ width: "60px", height: "40px", borderRadius: "12px" }}
onClick={() => setShowRoomModal(true)}
>
<div className="text-theme">
<Icon icon="lucide:plus" className="text-lg mb-1" />
</div>
</div>
{/* Room Cards */}
{roomData?.map((room) => (
<div
key={room.name}
className={`card shadow-sm position-relative cursor-pointer border-2 ${selectedRoom === room.name && "bg-theme text-white"}`}
style={{ width: "auto", minWidth: "120px", maxWidth: "200px", height: "40px", borderRadius: "12px" }}
onClick={() => {
setSelectedRoom(room.name);
getTableData(room.name);
}}
>
<div className="card-body px-3 py-1 d-flex gap-2 align-items-center">
{
room?.isdeleted == 1 && (<Icon icon="mdi:block-helper" style={{ color: "red" }} />)
}
<span
className="text-truncatew-100 text-sm fw-semibold"
title={room.roomname}
>
{room.roomname}
</span>
</div>
{/* Dropdown */}
<div className="position-absolute" style={{ top: "3px", right: "3px", zIndex: 1 }}>
<div className="dropdown">
<button
className="btn px-1 py-1 d-flex align-items-center text-primary-light"
type="button"
data-bs-toggle="dropdown"
>
<Icon icon="entypo:dots-three-vertical" />
</button>
<ul className="dropdown-menu">
<li>
<Link className="dropdown-item px-16 py-8 d-flex align-items-center gap-2 rounded text-secondary-light bg-hover-neutral-200 text-hover-neutral-900" href="#" onClick={(e) => {
e.preventDefault();
handleRoomEdit(room);
}}>
<Icon icon="lucide:edit" /> Edit
</Link>
</li>
<li>
<Link className="dropdown-item px-16 py-8 d-flex align-items-center gap-2 rounded text-secondary-light bg-hover-neutral-200 text-hover-neutral-900" href="#" onClick={(e) => {
e.preventDefault();
setRoomDeleteConfirm({ show: true, id: room.name, isDeleted: room.isdeleted });
}}>
{room.isdeleted === 1 ? (
<>
<Icon icon="mdi:restore" /> Restore
</>
) : (
<>
<Icon icon="fluent:delete-24-regular" /> Delete
</>
)}
</Link>
</li>
</ul>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</div>
<div className='row gy-3 gx-3 '>
{/* <div className="d-flex justify-content-end align-items-center ">
<h6 className="mb-0">Table</h6>
<button
type="button"
className="btn btn-bg-theme radius-8 px-20 py-11"
onClick={() => setShowModal(true)}
>
Create
</button>
</div> */}
{loading ? (
<PageLoader />
) : tables.length === 0 ? (
<div className="col-xxl-2 col-lg-3 col-md-4 col-6 mb-4 d-flex justify-content-center align-items-center">
<div
className="card cursor-pointer shadow-sm bg-light border-0 d-flex align-items-center justify-content-center"
style={{ width: "150px", height: "150px", borderRadius: "12px" }}
onClick={() => setShowModal(true)}
>
<div className="text-center">
<div
className="d-flex align-items-center justify-content-center rounded-circle bg-theme bg-opacity-10 text-white mx-auto mb-2"
style={{ width: "48px", height: "48px" }}
>
<Icon icon="lucide:plus" className="text-xl" />
</div>
<small className="text-black">Add New</small>
</div>
</div>
</div>
) : (
<>
<div className="col-xxl-2 col-lg-3 col-md-4 col-6 mb-4 d-flex justify-content-center align-items-center">
<div
className="card cursor-pointer shadow-sm bg-light border-0 d-flex align-items-center justify-content-center"
style={{ width: "150px", height: "150px", borderRadius: "12px" }}
onClick={() => setShowModal(true)}
>
<div className="text-center">
<div
className="d-flex align-items-center justify-content-center rounded-circle bg-theme bg-opacity-10 text-white mx-auto mb-2"
style={{ width: "48px", height: "48px" }}
>
<Icon icon="lucide:plus" className="text-xl" />
</div>
<small className="text-black">Add New</small>
</div>
</div>
</div>
{tables.map((table) => (
<div className="col-xxl-2 col-lg-3 col-md-4 col-6 mb-4 text-center" key={table.name}>
<div className="d-inline-block">
<div
className={` `} >
<div className=" p-0 ">
{/* Top-right action buttons */}
<div
// onClick={() => handleTableClick(table)}
>
<div style={{ position: 'relative', paddingTop: "20px", width: "150px" }}>
<img
src={`/assets/images/seat/${(() => {
if (table?.totalcapacity <= 2) return 'seating-24.png';
if (table?.totalcapacity <= 4) return 'seating-25.png';
if (table?.totalcapacity <= 6) return 'seating-26.png';
if (table?.totalcapacity <= 8) return 'seating-27.png';
if (table?.totalcapacity <= 10) return 'seating-28.png';
return 'default.png'; // fallback image
})()}`}
alt="table"
className={classNames(
'w-100 h-100 object-fit-cover radius-8',
{ 'grayscale': table.status === 'booked' }
)}
/>
{
table?.isdeleted == 1 && (<Icon icon="mdi:block-helper" style={{
color: "red", position: "absolute", top: "28%",
left: "15%", zIndex: 1
}} />)
}
<h6
className={`position-absolute text-xs translate-middle text-white fw-bold text-center d-flex align-items-center justify-content-center ${table?.status === "Available" ? "bg-success-500" : table?.status === "Booked" ? "bg-warning-500" : "bg-secondary-500"}`}
style={{
pointerEvents: "none",
top: "55%",
left: "50%",
width: "50px",
height: "50px",
borderRadius: "50%",
}}
>
{table?.tablename}
</h6>
<div className="position-absolute " style={{ zIndex: 1, top: "25%", right: "10%" }}>
<div className='dropdown'>
<button
className='btn px-1 py-1 d-flex align-items-center text-primary-light'
type='button'
data-bs-toggle='dropdown'
aria-expanded='false'
>
<Icon icon='entypo:dots-three-vertical' className='menu-icon text-dark' />
</button>
<ul className='dropdown-menu'>
<li>
<Link
href="#"
className='dropdown-item px-16 py-8 d-flex align-items-center gap-2 rounded text-secondary-light bg-hover-neutral-200 text-hover-neutral-900'
onClick={(e) => {
e.preventDefault();
handleEdit(table)
}}
>
<Icon icon='lucide:edit' className='menu-icon' />
Edit
</Link>
</li>
<li>
<Link
href="#"
className='dropdown-item px-16 py-8 d-flex align-items-center gap-2 rounded text-secondary-light bg-hover-neutral-200 text-hover-neutral-900'
onClick={(e) => {
e.preventDefault();
setDeleteConfirm({ show: true, id: table.name, isDeleted: table.isdeleted })
}}
>
{table.isdeleted === 1 ? (
<>
<Icon icon="mdi:restore" /> Restore
</>
) : (
<>
<Icon icon="fluent:delete-24-regular" /> Delete
</>
)}
</Link>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
))}
</>
)
}
</div>
</div>
{/* floor create/update start */}
{showFloorModal && (
<div className="modal fade show" style={{ display: "block", backgroundColor: "rgba(0,0,0,0.5)" }}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-header border-0 pb-0">
<h6 className="modal-title text-lg">
{isFloorEditMode ? "Edit Floor" : "Create Floor"}
</h6>
<button type="button" className="btn-close" onClick={resetFloorForm}></button>
</div>
<div className="modal-body">
<form onSubmit={handleFloorSubmit}>
<div className="mb-3">
<label className="form-label">Floor Name</label>
<input
type="text"
className={`form-control ${floorErrors.floorname ? "is-invalid" : ""}`}
name="floorname"
value={floorFormData.floorname}
onChange={handleFloorChange}
/>
{floorErrors.floorname && (
<div className="invalid-feedback">{floorErrors.floorname}</div>
)}
</div>
<div className="mb-3">
<label className="form-label">Description</label>
<textarea
className={`form-control ${floorErrors.description ? "is-invalid" : ""}`}
name="description"
value={floorFormData.description}
onChange={handleFloorChange}
rows="3"
></textarea>
{floorErrors.description && (
<div className="invalid-feedback">{floorErrors.description}</div>
)}
</div>
<div className="d-flex justify-content-end">
<button type="submit" className="btn btn-bg-theme">
{isFloorEditMode ? "Update" : "Submit"}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
)}
{/* Floor create/update end */}
{/* Floor Delete Start */}
{floorDeleteConfirm.show && (
<div className="modal fade show" style={{ display: "block", backgroundColor: "rgba(0,0,0,0.5)" }}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-body">
<div className="d-flex justify-content-between mb-1">
<h6 className="text-lg mb-0">
{floorDeleteConfirm?.isDeleted === 0 ? "Confirm to Delete" : "Confirm to Restore"}
</h6>
<button
type="button"
className="btn-close"
onClick={() => setFloorDeleteConfirm({ show: false, id: null, isDeleted: null })}
></button>
</div>
<p className="m-0">
{floorDeleteConfirm?.isDeleted === 0
? "Are you sure you want to set this floor as Delete?"
: "Are you sure you want to set this floor as Restore?"}
</p>
<div className="d-flex justify-content-end gap-2 mt-1 ">
<button
className="btn btn-outline-danger px-14 py-6 text-sm"
onClick={() => setFloorDeleteConfirm({ show: false, id: null, isDeleted: null })}
>
Cancel
</button>
<button className="btn btn-danger px-14 py-6 text-sm" onClick={handleFloorDelete}>
{floorDeleteConfirm?.isDeleted === 0 ? "Delete" : "Restore"}
</button>
</div>
</div>
</div>
</div>
</div>
)}
{/* Floor Delete End */}
{/* Room start */}
{/* Modal */}
{showRoomModal && (
<div className="modal fade show" style={{ display: "block", backgroundColor: "rgba(0,0,0,0.5)" }}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-header border-0 pb-0">
<h6 className="modal-title text-lg">{editRoomMode ? "Edit Room" : "Create Room"}</h6>
<button
type="button"
className="btn-close"
onClick={resetRoomForm}
></button>
</div>
<div className="modal-body">
<form onSubmit={handleRoomSubmit}>
<div className="mb-3">
<label className="form-label">Room Name</label>
<input
type="text"
className={`form-control ${roomErrors.roomname ? "is-invalid" : ""}`}
name="roomname"
value={roomFormData.roomname}
onChange={handleRoomChange}
/>
{roomErrors.roomname && (
<div className="invalid-feedback">{roomErrors.roomname}</div>
)}
</div>
<div className="mb-3">
<label className="form-label">Description</label>
<textarea
className={`form-control ${roomErrors.description ? "is-invalid" : ""}`}
name="description"
value={roomFormData.description}
onChange={handleRoomChange}
rows="3"
></textarea>
{roomErrors.description && (
<div className="invalid-feedback">{roomErrors.description}</div>
)}
</div>
<div className="d-flex justify-content-end">
<button type="submit" className="btn btn-bg-theme">
{editRoomMode ? "Update" : "Submit"}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
)}
{/* Delete Confirmation Modal */}
{roomDeleteConfirm.show && (
<div className="modal fade show" style={{ display: "block", backgroundColor: "rgba(0,0,0,0.5)" }}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-body">
<div className="d-flex justify-content-between mb-1">
<h6 className="text-lg mb-0">
{roomDeleteConfirm?.isDeleted === 0 ? "Confirm to Delete" : "Confirm to Restore"}
</h6>
<button
type="button"
className="btn-close"
onClick={() => setRoomDeleteConfirm({ show: false, id: null, isDeleted: null })}
></button>
</div>
<p className="mb-0">
{roomDeleteConfirm?.isDeleted === 0
? "Are you sure you want to set this room as Delete?"
: "Are you sure you want to set this room as Restore?"}</p>
<div className="d-flex justify-content-end gap-2 mt-1">
<button
className="btn btn-outline-danger-600 px-14 py-6 text-sm"
onClick={() => setRoomDeleteConfirm({ show: false, id: null, isDeleted: null })}
>
Cancel
</button>
<button className="btn btn-danger px-14 py-6 text-sm" onClick={handleRoomDelete}>
{roomDeleteConfirm?.isDeleted === 0 ? "Delete" : "Restore"}
</button>
</div>
</div>
</div>
</div>
</div>
)}
{/* room end */}
{/* Seat Count Modal */}
{showModalTable && (
<div className="modal fade show" style={{ display: 'block', backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-header border-0 pb-0">
<h6 className="modal-title text-lg">Enter Seat Count</h6>
<button type="button" className="btn-close" onClick={() => setShowModalTable(false)}></button>
</div>
<div className="modal-body">
<div className="mb-3">
<label htmlFor="seatCount" className="form-label">Number of Seats</label>
<input
type="number"
className={`form-control ${error ? 'is-invalid' : ''}`}
id="seatCount"
max={selectedTable?.totalcapacity}
value={seatCount || ''} // 👈 fallback if seatCount is undefined or NaN
onChange={handleSeatChange}
/>
{error ? (
<div className="invalid-feedback">
{error}
</div>
) : (
<small >
Maximum capacity: {selectedTable?.totalcapacity}
</small>
)}
</div>
</div>
<div className="modal-footer border-0 pt-0">
<button type="button" className="btn btn-sm btn-outline-danger" onClick={() => setShowModalTable(false)}>Cancel</button>
<button type="button" className="btn btn-sm btn-danger-500" onClick={handleSeatSubmit}>Proceed to Menu</button>
</div>
</div>
</div>
</div>
)}
{/* Modal */}
{showModal && (
<div className="modal fade show" style={{ display: "block", backgroundColor: "rgba(0,0,0,0.5)" }}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-header border-0 pb-0">
<h6 className="modal-title text-lg">{isEditMode ? "Edit Table" : "Create Table"}</h6>
<button
type="button"
className="btn-close"
onClick={resetForm}
></button>
</div>
<div className="modal-body">
<form onSubmit={handleSubmit}>
<div className="mb-3">
<label className="form-label">Table Name</label>
<input
type="text"
className={`form-control ${errors.tablename ? "is-invalid" : ""}`}
name="tablename"
value={formData.tablename || ""}
onChange={handleChange}
/>
{errors.tablename && (
<div className="invalid-feedback">{errors.tablename}</div>
)}
</div>
<div className="mb-3">
<label className="form-label">Minimum Occupancy</label>
<input
type="number"
className={`form-control ${errors.minimumoccupancy ? "is-invalid" : ""}`}
name="minimumoccupancy"
value={formData.minimumoccupancy || ""}
onChange={handleChange}
/>
{errors.minimumoccupancy && (
<div className="invalid-feedback">{errors.minimumoccupancy}</div>
)}
</div>
<div className="mb-3">
<label className="form-label">Total Capacity</label>
<input
type="number"
className={`form-control ${errors.totalcapacity ? "is-invalid" : ""}`}
name="totalcapacity"
value={formData.totalcapacity || ""}
onChange={handleChange}
/>
{errors.totalcapacity && (
<div className="invalid-feedback">{errors.totalcapacity}</div>
)}
</div>
<div className="mb-3">
<label className="form-label">Description</label>
<textarea
className={`form-control ${errors.description ? "is-invalid" : ""}`}
name="description"
value={formData.description || ""}
onChange={handleChange}
rows="3"
></textarea>
{errors.description && (
<div className="invalid-feedback">{errors.description}</div>
)}
</div>
{/* <div className="mb-3">
<label className="form-label">Branch</label>
<select
className={`form-select ${errors.branch ? "is-invalid" : ""}`}
name="branch"
value={formData.branch}
onChange={handleChange}
>
<option value="">Select Branch</option>
{branchData.map((branch) => (
<option key={branch.name} value={branch.name}>
{branch.branch}
</option>
))}
</select>
{errors.branch && (
<div className="invalid-feedback">{errors.branch}</div>
)}
</div> */}
{
!isEditMode && (
<div className="mb-3 form-check d-flex align-items-center gap-2">
<input
type="checkbox"
className="form-check-input"
id="enableTable"
name="enable"
checked={formData.enable === 1}
onChange={(e) =>
setFormData({
...formData,
enable: e.target.checked ? 1 : 0,
})
}
/>
<label className="form-check-label" htmlFor="enableTable">
Auto Generate Day table creation
</label>
</div>
)
}
<div className="d-flex justify-content-end">
<button type="submit" className="btn btn-bg-theme">
{isEditMode ? "Update" : "Submit"}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
)}
{/* Delete Confirmation Modal */}
{deleteConfirm.show && (
<div className="modal fade show" style={{ display: "block", backgroundColor: "rgba(0,0,0,0.5)" }}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-body">
<div className="d-flex justify-content-between mb-1">
<h6 className="text-lg mb-0">
{deleteConfirm?.isDeleted === 0 ? "Confirm to Delete" : "Confirm to Restore"}
</h6>
<button
type="button"
className="btn-close"
onClick={() => setDeleteConfirm({ show: false, id: null, isDeleted: null })}
></button>
</div>
<p className="m-0">
{deleteConfirm?.isDeleted === 0
? "Are you sure you want to set this table as Delete?"
: "Are you sure you want to set this table as Restore?"}
</p>
<div className="d-flex justify-content-end gap-2 mt-1">
<button
className="btn btn-outline-danger px-14 py-6 text-sm"
onClick={() => setDeleteConfirm({ show: false, id: null, isDeleted: null })}
>
Cancel
</button>
<button className="btn btn-danger px-14 py-6 text-sm" onClick={handleDelete}>
{deleteConfirm?.isDeleted === 0 ? "Delete" : "Restore"}
</button>
</div>
</div>
</div>
</div>
</div>
)}
</>
);
};
const DineIn = (() => {
return (
<MasterLayout>
{/* Breadcrumb */}
<Breadcrumb title='Table' />
<Suspense fallback={<PageLoader />}>
<DineInInner />
</Suspense>
</MasterLayout>
)
})
export default DineIn;