1. Floor plan module floor, room and table management updated in single page
2. day reservation ui updated
13914
public/assets/css/lib/bootstrap.min.css
vendored
@ -13248,9 +13248,13 @@ select option {
|
||||
|
||||
/* Gradient Tab Css End */
|
||||
/* Focus Tab Css Start */
|
||||
.focus-tab .nav-link{
|
||||
border: 1px solid var(--theme-color);
|
||||
}
|
||||
|
||||
.focus-tab .nav-link.active {
|
||||
background-color: var(--primary-50);
|
||||
color: var(--primary-600);
|
||||
background-color: var(--theme-color);
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* Focus Tab Css End */
|
||||
|
||||
BIN
public/assets/images/day/fri.webp
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
public/assets/images/day/mon.webp
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
public/assets/images/day/sat.webp
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
public/assets/images/day/sun.webp
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
public/assets/images/day/thu.webp
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/assets/images/day/tue.webp
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/assets/images/day/wed.webp
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
1164
src/app/admin/(floor-plan-update)/floor-plan/page.jsx
Normal file
@ -19,19 +19,17 @@ const FloorSectionPageInner = () => {
|
||||
// const restaurantbranch = params?.restaurantbranch;
|
||||
// const RestaruntBranch = restaurantbranch
|
||||
// const floorName = decodeURIComponent(params.name);
|
||||
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const [editingRoomId, setEditingRoomId] = useState(null);
|
||||
const [roomData, setRoomData] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [formData, setFormData] = useState({
|
||||
const [showRoomModal, setShowRoomModal] = useState(false);
|
||||
const [editRoomMode, setEditRoomMode] = useState(false);
|
||||
const [editingRoomId, setEditingRoomId] = useState(null);
|
||||
const [roomFormData, setRoomFormData] = useState({
|
||||
roomname: "",
|
||||
description: "",
|
||||
});
|
||||
const [errors, setErrors] = useState({});
|
||||
const [deleteConfirm, setDeleteConfirm] = useState({ show: false, id: null });
|
||||
const [roomErrors, setRoomErrors] = useState({});
|
||||
const [roomDeleteConfirm, setRoomDeleteConfirm] = useState({ show: false, id: null });
|
||||
|
||||
const [restaruntBranch, setRestaruntBranch] = useState("")
|
||||
|
||||
@ -57,70 +55,68 @@ const FloorSectionPageInner = () => {
|
||||
const getRoomData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const roomRes = await client.get(
|
||||
`/Dine360%20Room?fields=["*"]&limit_page_length=100&filters=[["floor","=","${floorName}"]]`
|
||||
);
|
||||
setRoomData(roomRes?.data?.data || []);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
setError(error?.message || "Failed to fetch floor data");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleChange = (e) => {
|
||||
const handleRoomChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prev) => ({ ...prev, [name]: value }));
|
||||
setRoomFormData((prev) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
const handleRoomSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const newErrors = {};
|
||||
Object.entries(formData).forEach(([key, value]) => {
|
||||
if (!value.trim()) newErrors[key] = `${key} is required`;
|
||||
});
|
||||
setErrors(newErrors);
|
||||
setRoomErrors(newErrors);
|
||||
if (Object.keys(newErrors).length > 0) return;
|
||||
|
||||
const body = {
|
||||
roomname: formData.roomname,
|
||||
description: formData.description,
|
||||
roomname: roomFormData.roomname,
|
||||
description: roomFormData.description,
|
||||
floor: floorName,
|
||||
restaurantbranch: restaruntBranch
|
||||
};
|
||||
|
||||
try {
|
||||
if (editMode) {
|
||||
if (editRoomMode) {
|
||||
await client.put(`/Dine360 Room/${editingRoomId}`, body);
|
||||
} else {
|
||||
await client.post(`/Dine360 Room`, body);
|
||||
}
|
||||
getRoomData();
|
||||
resetForm();
|
||||
resetRoomForm();
|
||||
} catch (error) {
|
||||
console.error("❌ Submission error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEdit = (room) => {
|
||||
setFormData({
|
||||
setRoomFormData({
|
||||
roomname: room.roomname || "",
|
||||
description: room.description || "",
|
||||
// branch: room.branch || "",
|
||||
});
|
||||
setEditingRoomId(room.name);
|
||||
setEditMode(true);
|
||||
setShowModal(true);
|
||||
setEditRoomMode(true);
|
||||
setShowRoomModal(true);
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
const handleRoomDelete = async () => {
|
||||
try {
|
||||
await client.delete(`/Dine360 Room/${deleteConfirm?.id}`);
|
||||
setDeleteConfirm({ show: false, id: null });
|
||||
await client.delete(`/Dine360 Room/${roomDeleteConfirm?.id}`);
|
||||
setRoomDeleteConfirm({ show: false, id: null });
|
||||
getRoomData();
|
||||
} catch (error) {
|
||||
if (
|
||||
@ -135,12 +131,12 @@ const FloorSectionPageInner = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
setFormData({ roomname: "", description: "", });
|
||||
setErrors({});
|
||||
setEditMode(false);
|
||||
const resetRoomForm = () => {
|
||||
setRoomFormData({ roomname: "", description: "", });
|
||||
setRoomErrors({});
|
||||
setEditRoomMode(false);
|
||||
setEditingRoomId(null);
|
||||
setShowModal(false);
|
||||
setShowRoomModal(false);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -153,7 +149,7 @@ const FloorSectionPageInner = () => {
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-bg-theme radius-8 px-20 py-11"
|
||||
onClick={() => setShowModal(true)}
|
||||
onClick={() => setShowRoomModal(true)}
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
@ -201,7 +197,7 @@ const FloorSectionPageInner = () => {
|
||||
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: room.name })
|
||||
setRoomDeleteConfirm({ show: true, id: room.name })
|
||||
}}
|
||||
> <Icon
|
||||
icon='fluent:delete-24-regular'
|
||||
@ -222,7 +218,7 @@ const FloorSectionPageInner = () => {
|
||||
</button>
|
||||
<button
|
||||
className="remove-item-btn bg-danger-focus bg-hover-danger-200 text-danger-600 fw-medium w-40-px h-40-px d-flex justify-content-center align-items-center rounded-circle"
|
||||
onClick={() => setDeleteConfirm({ show: true, id: room.name })}
|
||||
onClick={() => setRoomDeleteConfirm({ show: true, id: room.name })}
|
||||
>
|
||||
<Icon
|
||||
icon='fluent:delete-24-regular'
|
||||
@ -247,45 +243,45 @@ const FloorSectionPageInner = () => {
|
||||
</div>
|
||||
|
||||
{/* Modal */}
|
||||
{showModal && (
|
||||
{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">{editMode ? "Edit Room" : "Create Room"}</h6>
|
||||
<h6 className="modal-title text-lg">{editRoomMode ? "Edit Room" : "Create Room"}</h6>
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
onClick={resetForm}
|
||||
onClick={resetRoomForm}
|
||||
></button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<form onSubmit={handleRoomSubmit}>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Room Name</label>
|
||||
<input
|
||||
type="text"
|
||||
className={`form-control ${errors.roomname ? "is-invalid" : ""}`}
|
||||
className={`form-control ${roomErrors.roomname ? "is-invalid" : ""}`}
|
||||
name="roomname"
|
||||
value={formData.roomname}
|
||||
onChange={handleChange}
|
||||
value={roomFormData.roomname}
|
||||
onChange={handleRoomChange}
|
||||
/>
|
||||
{errors.roomname && (
|
||||
<div className="invalid-feedback">{errors.roomname}</div>
|
||||
{roomErrors.roomname && (
|
||||
<div className="invalid-feedback">{roomErrors.roomname}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Description</label>
|
||||
<textarea
|
||||
className={`form-control ${errors.description ? "is-invalid" : ""}`}
|
||||
className={`form-control ${roomErrors.description ? "is-invalid" : ""}`}
|
||||
name="description"
|
||||
value={formData.description}
|
||||
onChange={handleChange}
|
||||
value={roomFormData.description}
|
||||
onChange={handleRoomChange}
|
||||
rows="3"
|
||||
></textarea>
|
||||
{errors.description && (
|
||||
<div className="invalid-feedback">{errors.description}</div>
|
||||
{roomErrors.description && (
|
||||
<div className="invalid-feedback">{roomErrors.description}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -293,7 +289,7 @@ const FloorSectionPageInner = () => {
|
||||
|
||||
<div className="d-flex justify-content-end">
|
||||
<button type="submit" className="btn btn-bg-theme">
|
||||
{editMode ? "Update" : "Submit"}
|
||||
{editRoomMode ? "Update" : "Submit"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@ -304,7 +300,7 @@ const FloorSectionPageInner = () => {
|
||||
)}
|
||||
|
||||
{/* Delete Confirmation Modal */}
|
||||
{deleteConfirm.show && (
|
||||
{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">
|
||||
@ -315,18 +311,18 @@ const FloorSectionPageInner = () => {
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
onClick={() => setDeleteConfirm({ show: false, id: null })}
|
||||
onClick={() => setRoomDeleteConfirm({ show: false, id: null })}
|
||||
></button>
|
||||
</div>
|
||||
<p className="mb-0">Are you sure you want to delete this Room?</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={() => setDeleteConfirm({ show: false, id: null })}
|
||||
onClick={() => setRoomDeleteConfirm({ show: false, id: null })}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button className="btn btn-danger px-14 py-6 text-sm" onClick={handleDelete}>
|
||||
<button className="btn btn-danger px-14 py-6 text-sm" onClick={handleRoomDelete}>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -9,6 +9,7 @@ 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 { Baseurl, ImageBase } from "@utils/BaseUrl.utils";
|
||||
|
||||
const SidesPageInner = () => {
|
||||
const router = useRouter();
|
||||
@ -148,16 +149,22 @@ const SidesPageInner = () => {
|
||||
form.append("doctype", doctype);
|
||||
form.append("docname", docname);
|
||||
|
||||
const res = await fetch("https://dev.dine360.ca/api/method/upload_file", {
|
||||
const res = await fetch(`${ImageBase}/api/method/upload_file`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Authorization": "token 482beca79d9c005:b8778f51fcca82b",
|
||||
// ❌ Don't set Content-Type when using FormData — let the browser set it
|
||||
},
|
||||
body: form,
|
||||
});
|
||||
|
||||
const result = await res.json();
|
||||
|
||||
if (!result.message?.file_url) throw new Error("Upload failed");
|
||||
return result.message.file_url;
|
||||
};
|
||||
|
||||
|
||||
const handleEdit = (room) => {
|
||||
setFormData({
|
||||
sidename: room.sidename || "",
|
||||
|
||||
@ -95,13 +95,13 @@ const DayReservationMainComponent = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="container-fluid" style={{ marginBottom: "100px" }}>
|
||||
<div className='card h-100 p-0 radius-12'>
|
||||
<div className='card-body p-3 p-lg-5 p-lg-40'>
|
||||
<div className='d-flex justify-content-between align-items-center mb-3'>
|
||||
<div>
|
||||
<div className="container" style={{ marginBottom: "100px" }}>
|
||||
<div className=' h-100 p-0 radius-12'>
|
||||
<div className='p-3 '>
|
||||
<div className='d-flex justify-content-end align-items-center mb-3'>
|
||||
{/* <div>
|
||||
<h6 className="mb-0 text-lg">Day Reservation</h6>
|
||||
</div>
|
||||
</div> */}
|
||||
<button className="btn btn-bg-theme" onClick={() => {
|
||||
setFormData({ day: "" });
|
||||
setFormError("");
|
||||
@ -120,21 +120,33 @@ const DayReservationMainComponent = () => {
|
||||
const gradientClass = gradientClasses[index % gradientClasses.length];
|
||||
return (
|
||||
<div className="col-xxl-3 col-lg-4 col-sm-6 cursor-pointer" key={days.name}>
|
||||
<div className={`card p-3 shadow-2 radius-8 h-100 bg-theme border border-white`}>
|
||||
<div className="card-body d-flex justify-content-between align-items-center p-0">
|
||||
|
||||
<div className="card p-3 shadow-2 radius-8 h-100 border border-white position-relative">
|
||||
<div className="card-body d-flex justify-content-center align-items-center p-0 ">
|
||||
|
||||
{/* Day Image Link */}
|
||||
<Link
|
||||
href={`/admin/day-reservation-enable-table?restaurantbranch=${restaruntBranch}&name=${days?.name}&day=${encodeURIComponent(days?.day)}`}
|
||||
>
|
||||
<h6 className="text-lg m-0">{days.day}</h6>
|
||||
<img
|
||||
src={`/assets/images/day/${days.day.slice(0, 3).toLowerCase()}.webp`}
|
||||
alt={days.day}
|
||||
style={{ width: "200px" }}
|
||||
/>
|
||||
</Link>
|
||||
|
||||
{/* Delete Button Top-Right */}
|
||||
<button
|
||||
className="remove-item-btn bg-danger-focus bg-hover-danger-200 text-danger-600 fw-medium w-40-px h-40-px d-flex justify-content-center align-items-center rounded-circle"
|
||||
className="remove-item-btn bg-danger-focus bg-hover-danger-200 text-danger-600 fw-medium w-40-px h-40-px d-flex justify-content-center align-items-center rounded-circle position-absolute"
|
||||
style={{ top: "8px", right: "8px" }}
|
||||
onClick={() => setDeleteConfirm({ show: true, id: days.name })}
|
||||
>
|
||||
<Icon icon='fluent:delete-24-regular' className='menu-icon' />
|
||||
<Icon icon="fluent:delete-24-regular" className="menu-icon" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
})
|
||||
|
||||
@ -219,15 +219,15 @@ const DayReservationTableEnableInner = () => {
|
||||
<PageNoData />
|
||||
) : (
|
||||
<>
|
||||
<div className="container-fluid" style={{ marginBottom: "100px" }}>
|
||||
<div className='card h-100 p-0 radius-12'>
|
||||
<div className='card-body p-3 p-lg-5 p-lg-40'>
|
||||
<div className="d-flex justify-content-between mb-5">
|
||||
<div className="d-flex align-items-center">
|
||||
<div className="container" style={{ marginBottom: "100px" }}>
|
||||
<div className=' h-100 p-0 radius-12'>
|
||||
<div className='p-3 '>
|
||||
<div className="d-flex justify-content-end mb-3">
|
||||
{/* <div className="d-flex align-items-center">
|
||||
<h6 className="text-lg mb-0">
|
||||
Day Reservations
|
||||
</h6>
|
||||
</div>
|
||||
</div> */}
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-bg-theme radius-8 px-16 py-7"
|
||||
@ -237,69 +237,58 @@ const DayReservationTableEnableInner = () => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className='row gy-3 gx-3 gx-lg-5 gy-lg-5 justify-content-center'>
|
||||
<div className="row gy-3 gx-3 gx-lg-5 gy-lg-5 justify-content-center">
|
||||
{sortedTables.map((table) => (
|
||||
<div className="col-xxl-2 col-lg-3 col-md-4 col-sm-6 col-6 text-center" key={table.name}>
|
||||
<div
|
||||
className="col-xxl-2 col-lg-3 col-md-4 col-sm-6 col-6 text-center"
|
||||
key={table.name}
|
||||
>
|
||||
<div className="d-inline-block">
|
||||
<div
|
||||
className={` cursor-pointer p-3 radius-12 ${table.enabled ? 'bg-success-focus' : 'bg-theme'} `}
|
||||
className="cursor-pointer radius-12"
|
||||
onClick={() => handleTableClick(table)}
|
||||
>
|
||||
<div className="text-center p-0 position-relative">
|
||||
<h6 className="text-lg mt-0 mb-1">{table?.tablename}</h6>
|
||||
<span className='mb-0 w-100-px h-100-px position-relative'>
|
||||
{
|
||||
table?.totalcapacity <= 2 ? (
|
||||
<div
|
||||
className={`position-relative d-inline-block p-2 radius-12`}
|
||||
style={{ width: "150px" }}
|
||||
>
|
||||
{/* Table Image */}
|
||||
<img
|
||||
src='/assets/images/seat/seating-02.png'
|
||||
alt=''
|
||||
className={classNames(
|
||||
'mx-auto d-block w-100 h-100 object-fit-cover',
|
||||
{ 'grayscale': table.status === 'booked' }
|
||||
)}
|
||||
/>
|
||||
) : table?.totalcapacity <= 4 ? (
|
||||
<img
|
||||
src='/assets/images/seat/seating-04.png'
|
||||
alt=''
|
||||
className={classNames(
|
||||
'mx-auto d-block w-100 h-100 object-fit-cover',
|
||||
{ 'grayscale': table.status === 'booked' }
|
||||
)}
|
||||
/>
|
||||
) : table?.totalcapacity <= 6 ? (
|
||||
<img
|
||||
src='/assets/images/seat/seating-06.png'
|
||||
alt=''
|
||||
className={classNames(
|
||||
'mx-auto d-block w-100 h-100 object-fit-cover',
|
||||
{ 'grayscale': table.status === 'booked' }
|
||||
)}
|
||||
/>
|
||||
) : table?.totalcapacity <= 8 ? (
|
||||
<img
|
||||
src='/assets/images/seat/seating-08.png'
|
||||
alt=''
|
||||
className={classNames(
|
||||
'mx-auto d-block w-100 h-100 object-fit-cover',
|
||||
{ 'grayscale': table.status === 'booked' }
|
||||
)}
|
||||
/>
|
||||
) : table?.totalcapacity <= 10 && (
|
||||
<img
|
||||
src='/assets/images/seat/seating-10.png'
|
||||
alt=''
|
||||
className={classNames(
|
||||
'mx-auto d-block w-100 h-100 object-fit-cover',
|
||||
{ 'grayscale': table.status === 'booked' }
|
||||
)}
|
||||
/>
|
||||
)
|
||||
src={
|
||||
table.totalcapacity <= 2
|
||||
? '/assets/images/seat/seating-24.png'
|
||||
: table.totalcapacity <= 4
|
||||
? '/assets/images/seat/seating-25.png'
|
||||
: table.totalcapacity <= 6
|
||||
? '/assets/images/seat/seating-26.png'
|
||||
: table.totalcapacity <= 8
|
||||
? '/assets/images/seat/seating-27.png'
|
||||
: '/assets/images/seat/seating-28.png'
|
||||
}
|
||||
alt=""
|
||||
className={classNames(
|
||||
'w-100 h-100 object-fit-cover',
|
||||
{ grayscale: table.status === 'booked' }
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Table name overlay at center */}
|
||||
<div className={`position-absolute top-50 start-50 translate-middle text-white ${table.enabled ? 'bg-success-500' : 'bg-theme'
|
||||
} fw-bold`}>
|
||||
<h6
|
||||
className={`position-absolute text-xs translate-middle text-white fw-bold text-center d-flex align-items-center justify-content-center ${table.enabled ? "bg-success-500" : "bg-warning-500"}`}
|
||||
style={{
|
||||
pointerEvents: "none",
|
||||
top: "55%",
|
||||
left: "50%",
|
||||
width: "50px",
|
||||
height: "50px",
|
||||
borderRadius: "50%",
|
||||
|
||||
</span>
|
||||
|
||||
}}
|
||||
>{table.tablename}
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -308,6 +297,7 @@ const DayReservationTableEnableInner = () => {
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{showModal && (
|
||||
|
||||
@ -17,15 +17,15 @@ const FloorComponent = ({ floorData, getFloor }) => {
|
||||
// const restaurantbranch = searchParams.get('restaurantbranch')
|
||||
// const RestaruntBranch = restaurantbranch
|
||||
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
const [showFloorModal, setShowFloorModal] = useState(false);
|
||||
const [isFloorEditMode, setIsFloorEditMode] = useState(false);
|
||||
const [selectedFloorId, setSelectedFloorId] = useState(null);
|
||||
const [formData, setFormData] = useState({
|
||||
const [floorFormData, setFloorFormData] = useState({
|
||||
floorname: "",
|
||||
description: "",
|
||||
});
|
||||
const [errors, setErrors] = useState({});
|
||||
const [deleteConfirm, setDeleteConfirm] = useState({ show: false, id: null });
|
||||
const [floorErrors, setFloorErrors] = useState({});
|
||||
const [floorDeleteConfirm, setFloorDeleteConfirm] = useState({ show: false, id: null });
|
||||
|
||||
const [restaruntBranch, setRestaruntBranch] = useState("")
|
||||
|
||||
@ -41,35 +41,35 @@ const FloorComponent = ({ floorData, getFloor }) => {
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
const handleChange = (e) => {
|
||||
const handleFloorChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prev) => ({ ...prev, [name]: value }));
|
||||
setFloorFormData((prev) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
const handleFloorSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const newErrors = {};
|
||||
Object.entries(formData).forEach(([key, value]) => {
|
||||
Object.entries(floorFormData).forEach(([key, value]) => {
|
||||
if (!value.trim()) newErrors[key] = `${key} is required`;
|
||||
});
|
||||
setErrors(newErrors);
|
||||
setFloorErrors(newErrors);
|
||||
if (Object.keys(newErrors).length > 0) return;
|
||||
|
||||
const body = {
|
||||
// ...(isEditMode && { name: selectedFloorId }), // only adds `name` if editing
|
||||
floorname: formData?.floorname,
|
||||
description: formData?.description,
|
||||
// ...(isFloorEditMode && { name: selectedFloorId }), // only adds `name` if editing
|
||||
floorname: floorFormData?.floorname,
|
||||
description: floorFormData?.description,
|
||||
restaurantbranch: restaruntBranch
|
||||
};
|
||||
try {
|
||||
if (isEditMode) {
|
||||
if (isFloorEditMode) {
|
||||
await client.put(`/Dine360 Floor/${selectedFloorId}`, body);
|
||||
} else {
|
||||
await client.post(`/Dine360 Floor`, body);
|
||||
}
|
||||
getFloor();
|
||||
resetForm();
|
||||
resetFloorForm();
|
||||
} catch (error) {
|
||||
if (
|
||||
error?.response?.data?.exception?.includes("DuplicateEntryError") ||
|
||||
@ -87,30 +87,30 @@ const FloorComponent = ({ floorData, getFloor }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
setFormData({
|
||||
const resetFloorForm = () => {
|
||||
setFloorFormData({
|
||||
floorname: "", description: "",
|
||||
});
|
||||
setShowModal(false);
|
||||
setIsEditMode(false);
|
||||
setShowFloorModal(false);
|
||||
setIsFloorEditMode(false);
|
||||
setSelectedFloorId(null);
|
||||
setErrors({});
|
||||
setFloorErrors({});
|
||||
};
|
||||
|
||||
const handleEdit = (floor) => {
|
||||
setIsEditMode(true);
|
||||
const handleFloorEdit = (floor) => {
|
||||
setIsFloorEditMode(true);
|
||||
setSelectedFloorId(floor.name);
|
||||
setFormData({
|
||||
setFloorFormData({
|
||||
floorname: floor.floorname || "",
|
||||
description: floor.description || "",
|
||||
});
|
||||
setShowModal(true);
|
||||
setShowFloorModal(true);
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
const handleFloorDelete = async () => {
|
||||
try {
|
||||
await client.delete(`/Dine360 Floor/${deleteConfirm.id}`);
|
||||
setDeleteConfirm({ show: false, id: null });
|
||||
await client.delete(`/Dine360 Floor/${floorDeleteConfirm.id}`);
|
||||
setFloorDeleteConfirm({ show: false, id: null });
|
||||
getFloor();
|
||||
} catch (error) {
|
||||
if (
|
||||
@ -134,7 +134,7 @@ const FloorComponent = ({ floorData, getFloor }) => {
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-bg-theme radius-8 px-20 py-11"
|
||||
onClick={() => setShowModal(true)}
|
||||
onClick={() => setShowFloorModal(true)}
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
@ -170,7 +170,7 @@ const FloorComponent = ({ floorData, getFloor }) => {
|
||||
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(floor);
|
||||
handleFloorEdit(floor);
|
||||
}}
|
||||
> <Icon icon='lucide:edit' className='menu-icon' />
|
||||
Edit
|
||||
@ -182,7 +182,7 @@ const FloorComponent = ({ floorData, getFloor }) => {
|
||||
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: floor.name });
|
||||
setFloorDeleteConfirm({ show: true, id: floor.name });
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
@ -219,69 +219,49 @@ const FloorComponent = ({ floorData, getFloor }) => {
|
||||
</div>
|
||||
|
||||
{/* Create/Edit Modal */}
|
||||
{showModal && (
|
||||
{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">
|
||||
{isEditMode ? "Edit Floor" : "Create Floor"}
|
||||
{isFloorEditMode ? "Edit Floor" : "Create Floor"}
|
||||
</h6>
|
||||
<button type="button" className="btn-close" onClick={resetForm}></button>
|
||||
<button type="button" className="btn-close" onClick={resetFloorForm}></button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<form onSubmit={handleFloorSubmit}>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Floor Name</label>
|
||||
<input
|
||||
type="text"
|
||||
className={`form-control ${errors.floorname ? "is-invalid" : ""}`}
|
||||
className={`form-control ${floorErrors.floorname ? "is-invalid" : ""}`}
|
||||
name="floorname"
|
||||
value={formData.floorname}
|
||||
onChange={handleChange}
|
||||
value={floorFormData.floorname}
|
||||
onChange={handleFloorChange}
|
||||
/>
|
||||
{errors.floorname && (
|
||||
<div className="invalid-feedback">{errors.floorname}</div>
|
||||
{floorErrors.floorname && (
|
||||
<div className="invalid-feedback">{floorErrors.floorname}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Description</label>
|
||||
<textarea
|
||||
className={`form-control ${errors.description ? "is-invalid" : ""}`}
|
||||
className={`form-control ${floorErrors.description ? "is-invalid" : ""}`}
|
||||
name="description"
|
||||
value={formData.description}
|
||||
onChange={handleChange}
|
||||
value={floorFormData.description}
|
||||
onChange={handleFloorChange}
|
||||
rows="3"
|
||||
></textarea>
|
||||
{errors.description && (
|
||||
<div className="invalid-feedback">{errors.description}</div>
|
||||
{floorErrors.description && (
|
||||
<div className="invalid-feedback">{floorErrors.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> */}
|
||||
|
||||
<div className="d-flex justify-content-end">
|
||||
<button type="submit" className="btn btn-bg-theme">
|
||||
{isEditMode ? "Update" : "Submit"}
|
||||
{isFloorEditMode ? "Update" : "Submit"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@ -292,7 +272,7 @@ const FloorComponent = ({ floorData, getFloor }) => {
|
||||
)}
|
||||
|
||||
{/* Delete Confirmation Modal */}
|
||||
{deleteConfirm.show && (
|
||||
{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">
|
||||
@ -303,18 +283,18 @@ const FloorComponent = ({ floorData, getFloor }) => {
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
onClick={() => setDeleteConfirm({ show: false, id: null })}
|
||||
onClick={() => setFloorDeleteConfirm({ show: false, id: null })}
|
||||
></button>
|
||||
</div>
|
||||
<p className="m-0">Are you sure you want to delete this floor?</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 })}
|
||||
onClick={() => setFloorDeleteConfirm({ show: false, id: null })}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button className="btn btn-danger px-14 py-6 text-sm" onClick={handleDelete}>
|
||||
<button className="btn btn-danger px-14 py-6 text-sm" onClick={handleFloorDelete}>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -24,7 +24,7 @@ const MainComponent = () => {
|
||||
}, [router]);
|
||||
|
||||
return (
|
||||
<div className="container-fluid">
|
||||
<div className="container">
|
||||
<div className='card h-100 p-0 radius-12'>
|
||||
<div className='card-body p-3 p-lg-5 p-lg-40'>
|
||||
<div className='row gy-3 gx-3 gx-lg-5 gy-lg-5 justify-content-center'>
|
||||
|
||||
@ -24,12 +24,12 @@ const AdminDashBoardMain = () => {
|
||||
}, [router]);
|
||||
|
||||
return (
|
||||
<div className="container-fluid" style={{ marginBottom: "100px" }}>
|
||||
<div className='card h-100 p-0 radius-12'>
|
||||
<div className='card-body p-3 p-lg-5 p-lg-40'>
|
||||
<div className="container" style={{ marginBottom: "100px" }}>
|
||||
<div className=' h-100 p-0 radius-12'>
|
||||
<div className=' p-3 p-lg-5 p-lg-40'>
|
||||
<div className='row gy-3 gx-3 gx-lg-5 gy-lg-5 justify-content-center'>
|
||||
<div className="col-xxl-3 col-lg-4 col-sm-6 cursor-pointer">
|
||||
<div className={`card p-3 shadow-2 radius-8 h-100 bg-theme border border-white`}>
|
||||
<div className="col-xxl-4 col-lg-4 col-sm-6 cursor-pointer">
|
||||
<div className={`card p-3 shadow-2 radius-8 h-100 border border-white`}>
|
||||
<div className="card-body text-center p-0">
|
||||
<Link
|
||||
href={`/admin/day-reservation-table?restaurantbranch=${restaruntBranch}`}
|
||||
@ -38,13 +38,13 @@ const AdminDashBoardMain = () => {
|
||||
<img src="/assets/images/day.webp" alt="reservation icon" />
|
||||
</div>
|
||||
|
||||
<h6 className="mb-0 mt-3">Day Reservation</h6>
|
||||
<h6 className="mb-0 text-theme mt-3">Day Reservation</h6>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-xxl-3 col-lg-4 col-sm-6 cursor-pointer">
|
||||
<div className={`card p-3 shadow-2 radius-8 h-100 bg-theme border border-white`}>
|
||||
<div className="col-xxl-4 col-lg-4 col-sm-6 cursor-pointer">
|
||||
<div className={`card p-3 shadow-2 radius-8 h-100 border border-white`}>
|
||||
<div className="card-body text-center p-0">
|
||||
<Link
|
||||
href={`/admin/date-reservation-table?restaurantbranch=${restaruntBranch}`}
|
||||
@ -53,13 +53,13 @@ const AdminDashBoardMain = () => {
|
||||
<img src="/assets/images/date.webp" alt="reservation icon" />
|
||||
</div>
|
||||
|
||||
<h6 className="mb-0 mt-3">Date Reservation</h6>
|
||||
<h6 className="mb-0 text-theme mt-3">Date Reservation</h6>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-xxl-3 col-lg-4 col-sm-6 cursor-pointer">
|
||||
<div className={`card p-3 shadow-2 radius-8 h-100 bg-theme border border-white`}>
|
||||
<div className="col-xxl-4 col-lg-4 col-sm-6 cursor-pointer">
|
||||
<div className={`card p-3 shadow-2 radius-8 h-100 border border-white`}>
|
||||
<div className="card-body text-center p-0">
|
||||
<Link
|
||||
href={`/admin/reserved-users?restaurantbranch=${restaruntBranch}`}
|
||||
@ -68,28 +68,28 @@ const AdminDashBoardMain = () => {
|
||||
<img src="/assets/images/reserved.webp" alt="reservation icon" />
|
||||
</div>
|
||||
|
||||
<h6 className="mb-0 mt-3">Reserved by User</h6>
|
||||
<h6 className="mb-0 text-theme mt-3">Reserved by User</h6>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-xxl-3 col-lg-4 col-sm-6 cursor-pointer">
|
||||
<div className={`card p-3 shadow-2 radius-8 h-100 bg-theme border border-white`}>
|
||||
<div className="col-xxl-4 col-lg-4 col-sm-6 cursor-pointer">
|
||||
<div className={`card p-3 shadow-2 radius-8 h-100 border border-white`}>
|
||||
<div className="card-body text-center p-0">
|
||||
<Link
|
||||
href={`/admin/pos/floor?restaurantbranch=${restaruntBranch}`}
|
||||
href={`/admin/floor-plan?restaurantbranch=${restaruntBranch}`}
|
||||
>
|
||||
<div style={{ width: "300px", height: "300px" }}>
|
||||
<img src="/assets/images/plan.webp" alt="reservation icon" />
|
||||
</div>
|
||||
|
||||
<h6 className="mb-0 mt-3">Floor Plan Update</h6>
|
||||
<h6 className="mb-0 text-theme mt-3">Floor Plan Update</h6>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-xxl-3 col-lg-4 col-sm-6 cursor-pointer">
|
||||
<div className={`card p-3 shadow-2 radius-8 h-100 bg-theme border border-white`}>
|
||||
<div className="col-xxl-4 col-lg-4 col-sm-6 cursor-pointer">
|
||||
<div className={`card p-3 shadow-2 radius-8 h-100 border border-white`}>
|
||||
<div className="card-body text-center p-0">
|
||||
<Link
|
||||
href={`/admin/pos/dashboard`}
|
||||
@ -98,7 +98,7 @@ const AdminDashBoardMain = () => {
|
||||
<img src="/assets/images/plan.webp" alt="reservation icon" />
|
||||
</div>
|
||||
|
||||
<h6 className="mb-0 mt-3">POS System</h6>
|
||||
<h6 className="mb-0 text-theme mt-3">POS System</h6>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||