1628 lines
53 KiB
React
1628 lines
53 KiB
React
|
|
import React, { useState, useEffect } from 'react';
|
||
|
|
import { useSelector, useDispatch } from 'react-redux';
|
||
|
|
import { useNavigate } from 'react-router-dom';
|
||
|
|
import {
|
||
|
|
Form,
|
||
|
|
Input,
|
||
|
|
Select,
|
||
|
|
InputNumber,
|
||
|
|
Button,
|
||
|
|
DatePicker,
|
||
|
|
Space,
|
||
|
|
Card,
|
||
|
|
Row,
|
||
|
|
Col,
|
||
|
|
Checkbox,
|
||
|
|
Collapse,
|
||
|
|
Tooltip,
|
||
|
|
Modal,
|
||
|
|
Table,
|
||
|
|
Tag,
|
||
|
|
Switch,
|
||
|
|
Radio,
|
||
|
|
TimePicker,
|
||
|
|
Divider,
|
||
|
|
TreeSelect,
|
||
|
|
Avatar,
|
||
|
|
List
|
||
|
|
} from 'antd';
|
||
|
|
import {
|
||
|
|
PlusOutlined,
|
||
|
|
DeleteOutlined,
|
||
|
|
InfoCircleOutlined,
|
||
|
|
ArrowRightOutlined,
|
||
|
|
BlockOutlined,
|
||
|
|
DollarOutlined,
|
||
|
|
FlagOutlined,
|
||
|
|
CalendarOutlined,
|
||
|
|
ShopOutlined,
|
||
|
|
TeamOutlined,
|
||
|
|
CloseCircleOutlined,
|
||
|
|
UserOutlined,
|
||
|
|
EditOutlined
|
||
|
|
} from '@ant-design/icons';
|
||
|
|
import moment from 'moment';
|
||
|
|
import { getCategories, getProductListBasedSubcat, getSubCategories, GlobalCategories, GlobalProductBasedSubcat, GlobalSubCategories, PutSlotBlock } from '../../Features/SlotManagement/SlotManagement';
|
||
|
|
import { getSession } from '../../Services/Others';
|
||
|
|
import { DropDowns } from '../../Components/Forms/DropDown';
|
||
|
|
import { InputField } from '../../Components/Forms/InputField';
|
||
|
|
import "./SlotManagement.scss"
|
||
|
|
import { changeBreadCrumb } from '../../Features/AppPage/CenterPage';
|
||
|
|
import Buttons from '../../Components/Forms/Buttons';
|
||
|
|
|
||
|
|
|
||
|
|
const { Option } = Select;
|
||
|
|
const { Panel } = Collapse;
|
||
|
|
const { RangePicker } = DatePicker;
|
||
|
|
const { TextArea } = Input;
|
||
|
|
const { TreeNode } = TreeSelect;
|
||
|
|
const subDirectory = import.meta.env.BASE_URL;
|
||
|
|
const SlotManagementForm = () => {
|
||
|
|
const CompId = getSession('CompId');
|
||
|
|
const BranchId = getSession('BranchId');
|
||
|
|
const AppId = getSession('AppId');
|
||
|
|
const UserId = getSession('UserId');
|
||
|
|
const dispatch = useDispatch();
|
||
|
|
const navigate = useNavigate();
|
||
|
|
// UseSlectors
|
||
|
|
const CategoriesData = useSelector(GlobalCategories);
|
||
|
|
const SubCategoriesData = useSelector(GlobalSubCategories);
|
||
|
|
const ProductList = useSelector(GlobalProductBasedSubcat)
|
||
|
|
|
||
|
|
// States
|
||
|
|
const [form] = Form.useForm();
|
||
|
|
const [selectedCategory, setSelectedCategory] = useState(null);
|
||
|
|
const [selectedSubCategory, setSelectedSubCategory] = useState(null);
|
||
|
|
const [selectedFacility, setSelectedFacility] = useState(null);
|
||
|
|
const [selectedCoach, setSelectedCoach] = useState(null);
|
||
|
|
const [actionMode, setActionMode] = useState(null);
|
||
|
|
const [closureType, setClosureType] = useState(null);
|
||
|
|
const [dateRange, setDateRange] = useState([]);
|
||
|
|
console.log(closureType, "closureType")
|
||
|
|
const [selectedDays, setSelectedDays] = useState({
|
||
|
|
monday: false,
|
||
|
|
tuesday: false,
|
||
|
|
wednesday: false,
|
||
|
|
thursday: false,
|
||
|
|
friday: false,
|
||
|
|
saturday: false,
|
||
|
|
sunday: false
|
||
|
|
});
|
||
|
|
const [priceChangeType, setPriceChangeType] = useState('full');
|
||
|
|
const [SlotChangeType, setSlotChangeType] = useState('all');
|
||
|
|
const [weekendPremium, setWeekendPremium] = useState(false);
|
||
|
|
const [weekendPrice, setWeekendPrice] = useState(0);
|
||
|
|
const [newPrice, setNewPrice] = useState(null);
|
||
|
|
const [selectAllDays, setSelectAllDays] = useState(false);
|
||
|
|
const [selectedSlots, setSelectedSlots] = useState([]);
|
||
|
|
const [managementHistory, setManagementHistory] = useState([]);
|
||
|
|
const [selectedBranches, setSelectedBranches] = useState([]);
|
||
|
|
const [closureReason, setClosureReason] = useState(null);
|
||
|
|
const [individualSlotPrices, setIndividualSlotPrices] = useState({}); // NEW: Store individual slot prices
|
||
|
|
const [Slots, setSlots] = useState([]);
|
||
|
|
const [individualPricing, setIndividualPricing] = useState(false);
|
||
|
|
const [individualDefaultPrice, setIndividualDefaultPrice] = useState(0);
|
||
|
|
const [slotPrices, setSlotPrices] = useState({});
|
||
|
|
const [types, setTypes] = useState([]);
|
||
|
|
|
||
|
|
const items = [
|
||
|
|
{
|
||
|
|
name: 'Home',
|
||
|
|
link: `${subDirectory}app-page/home`,
|
||
|
|
},
|
||
|
|
|
||
|
|
{
|
||
|
|
name: 'Slot Management',
|
||
|
|
link: `${subDirectory}setting/slot-management-list`,
|
||
|
|
},
|
||
|
|
];
|
||
|
|
useEffect(() => {
|
||
|
|
try {
|
||
|
|
dispatch(changeBreadCrumb({ items: items }));
|
||
|
|
} catch (err) {
|
||
|
|
console.log(err, 'err');
|
||
|
|
}
|
||
|
|
|
||
|
|
}, []);
|
||
|
|
// Mock data for branches
|
||
|
|
const branches = [
|
||
|
|
{ id: 1, name: 'Main Sports Center', address: '123 Main St, City' },
|
||
|
|
{ id: 2, name: 'North Branch', address: '456 North Ave, City' },
|
||
|
|
{ id: 3, name: 'South Complex', address: '789 South Rd, City' },
|
||
|
|
{ id: 4, name: 'East Arena', address: '321 East Blvd, City' },
|
||
|
|
{ id: 5, name: 'West Facility', address: '654 West St, City' }
|
||
|
|
];
|
||
|
|
|
||
|
|
// Mock data for categories and sub-categories
|
||
|
|
const categories = [
|
||
|
|
{ id: 1, name: 'Sports' },
|
||
|
|
{ id: 2, name: 'Fitness' },
|
||
|
|
{ id: 3, name: 'Wellness' },
|
||
|
|
{ id: 4, name: 'Entertainment' }
|
||
|
|
];
|
||
|
|
|
||
|
|
const subCategories = {
|
||
|
|
1: [ // Sports
|
||
|
|
{ id: 101, name: 'Cricket' },
|
||
|
|
{ id: 102, name: 'Football' },
|
||
|
|
{ id: 103, name: 'Tennis' },
|
||
|
|
{ id: 104, name: 'Badminton' },
|
||
|
|
{ id: 105, name: 'Swimming' }
|
||
|
|
],
|
||
|
|
2: [ // Fitness
|
||
|
|
{ id: 201, name: 'Gym' },
|
||
|
|
{ id: 202, name: 'Yoga' },
|
||
|
|
{ id: 203, name: 'Zumba' },
|
||
|
|
{ id: 204, name: 'Pilates' }
|
||
|
|
],
|
||
|
|
3: [ // Wellness
|
||
|
|
{ id: 301, name: 'Spa' },
|
||
|
|
{ id: 302, name: 'Massage' },
|
||
|
|
{ id: 303, name: 'Meditation' }
|
||
|
|
],
|
||
|
|
4: [ // Entertainment
|
||
|
|
{ id: 401, name: 'Movie' },
|
||
|
|
{ id: 402, name: 'Games' }
|
||
|
|
]
|
||
|
|
};
|
||
|
|
|
||
|
|
// Mock data for facilities
|
||
|
|
const facilities = [
|
||
|
|
{ id: 1, name: 'Cricket Ground A', categoryId: 1, subCategoryId: 101, branchId: 1 },
|
||
|
|
{ id: 2, name: 'Cricket Ground B', categoryId: 1, subCategoryId: 101, branchId: 1 },
|
||
|
|
{ id: 3, name: 'Football Field', categoryId: 1, subCategoryId: 102, branchId: 2 },
|
||
|
|
{ id: 4, name: 'Tennis Court 1', categoryId: 1, subCategoryId: 103, branchId: 1 },
|
||
|
|
{ id: 5, name: 'Tennis Court 2', categoryId: 1, subCategoryId: 103, branchId: 3 },
|
||
|
|
{ id: 6, name: 'Badminton Court', categoryId: 1, subCategoryId: 104, branchId: 2 },
|
||
|
|
{ id: 7, name: 'Swimming Pool', categoryId: 1, subCategoryId: 105, branchId: 4 },
|
||
|
|
{ id: 8, name: 'Gym Area', categoryId: 2, subCategoryId: 201, branchId: 1 },
|
||
|
|
{ id: 9, name: 'Yoga Studio', categoryId: 2, subCategoryId: 202, branchId: 2 },
|
||
|
|
{ id: 10, name: 'Spa Center', categoryId: 3, subCategoryId: 301, branchId: 1 }
|
||
|
|
];
|
||
|
|
|
||
|
|
// Mock data for coaches
|
||
|
|
const coaches = [
|
||
|
|
{
|
||
|
|
id: 1,
|
||
|
|
name: 'John Smith',
|
||
|
|
sport: 'Cricket',
|
||
|
|
specialization: 'Batting',
|
||
|
|
categoryId: 1,
|
||
|
|
subCategoryId: 101,
|
||
|
|
facilities: [1, 2],
|
||
|
|
branchId: 1
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: 2,
|
||
|
|
name: 'Mike Johnson',
|
||
|
|
sport: 'Cricket',
|
||
|
|
specialization: 'Bowling',
|
||
|
|
categoryId: 1,
|
||
|
|
subCategoryId: 101,
|
||
|
|
facilities: [1],
|
||
|
|
branchId: 1
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: 3,
|
||
|
|
name: 'Sarah Wilson',
|
||
|
|
sport: 'Tennis',
|
||
|
|
specialization: 'Singles',
|
||
|
|
categoryId: 1,
|
||
|
|
subCategoryId: 103,
|
||
|
|
facilities: [4, 5],
|
||
|
|
branchId: 1
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: 4,
|
||
|
|
name: 'David Brown',
|
||
|
|
sport: 'Football',
|
||
|
|
specialization: 'Goal Keeping',
|
||
|
|
categoryId: 1,
|
||
|
|
subCategoryId: 102,
|
||
|
|
facilities: [3],
|
||
|
|
branchId: 2
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: 5,
|
||
|
|
name: 'Emma Davis',
|
||
|
|
sport: 'Swimming',
|
||
|
|
specialization: 'Competitive',
|
||
|
|
categoryId: 1,
|
||
|
|
subCategoryId: 105,
|
||
|
|
facilities: [7],
|
||
|
|
branchId: 4
|
||
|
|
}
|
||
|
|
];
|
||
|
|
|
||
|
|
|
||
|
|
// Closure types configuration
|
||
|
|
const closureTypes = {
|
||
|
|
block: [
|
||
|
|
{ value: 'full_branch', label: 'Full Branch Block', icon: <ShopOutlined />, color: 'red' },
|
||
|
|
{ value: 'category', label: 'Category Block', icon: <TeamOutlined />, color: 'orange' },
|
||
|
|
{ value: 'subcategory', label: 'Sub-Category Block', icon: <TeamOutlined />, color: 'volcano' },
|
||
|
|
{ value: 'product', label: 'Facility Block', color: 'gold' }
|
||
|
|
],
|
||
|
|
priceChange: [
|
||
|
|
|
||
|
|
{ value: 'product', label: 'Facility Price Change', icon: <DollarOutlined />, color: 'purple' },
|
||
|
|
|
||
|
|
],
|
||
|
|
holiday: [
|
||
|
|
{ value: 'full_branch', label: 'Full Branch Holiday', icon: <FlagOutlined />, color: 'red' },
|
||
|
|
{ value: 'category', label: 'Category Holiday', icon: <FlagOutlined />, color: 'orange' },
|
||
|
|
{ value: 'subcategory', label: 'Sub-Category Holiday', icon: <TeamOutlined />, color: 'volcano' },
|
||
|
|
{ value: 'product', label: 'Facility Holiday', icon: <FlagOutlined />, color: 'gold' }
|
||
|
|
]
|
||
|
|
};
|
||
|
|
// const types = closureTypes[actionMode] || [];
|
||
|
|
useEffect(() => {
|
||
|
|
// Fetch categories on component mount
|
||
|
|
let baseData = {
|
||
|
|
CompId,
|
||
|
|
BranchId,
|
||
|
|
AppId,
|
||
|
|
};
|
||
|
|
dispatch(getCategories(baseData));
|
||
|
|
}
|
||
|
|
, []);
|
||
|
|
useEffect(() => {
|
||
|
|
if(types?.length == 1){
|
||
|
|
const singleOption = types[0];
|
||
|
|
form.setFieldsValue({ closureType: singleOption.value });
|
||
|
|
handleClosureTypeChange(singleOption.value);
|
||
|
|
}
|
||
|
|
|
||
|
|
}, [types]);
|
||
|
|
// Slot Price update
|
||
|
|
useEffect(() => {
|
||
|
|
setSlotPrices(prev => {
|
||
|
|
const updated = { ...prev };
|
||
|
|
selectedSlots.forEach(slot => {
|
||
|
|
if (!updated[slot]) {
|
||
|
|
updated[slot] = {
|
||
|
|
fullSlotPrice: Number(newPrice) || 0,
|
||
|
|
individualPrice: Number(individualDefaultPrice) || 0
|
||
|
|
};
|
||
|
|
}
|
||
|
|
});
|
||
|
|
// Remove prices for deselected slots
|
||
|
|
Object.keys(updated).forEach(slot => {
|
||
|
|
if (!selectedSlots.includes(slot)) {
|
||
|
|
delete updated[slot];
|
||
|
|
}
|
||
|
|
});
|
||
|
|
return updated;
|
||
|
|
});
|
||
|
|
}, [selectedSlots, newPrice, individualDefaultPrice]);
|
||
|
|
const handleFullSlotPriceChange = (slot, value) => {
|
||
|
|
setSlotPrices(prev => ({
|
||
|
|
...prev,
|
||
|
|
[slot]: {
|
||
|
|
...prev[slot],
|
||
|
|
fullSlotPrice: value
|
||
|
|
}
|
||
|
|
}));
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleIndividualPriceChange = (slot, value) => {
|
||
|
|
setSlotPrices(prev => ({
|
||
|
|
...prev,
|
||
|
|
[slot]: {
|
||
|
|
...prev[slot],
|
||
|
|
individualPrice: value
|
||
|
|
}
|
||
|
|
}));
|
||
|
|
};
|
||
|
|
// Day selection handlers
|
||
|
|
const handleDayChange = (day) => {
|
||
|
|
setSelectedDays(prev => ({
|
||
|
|
...prev,
|
||
|
|
[day]: !prev[day]
|
||
|
|
}));
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleSelectAllDays = (checked) => {
|
||
|
|
setSelectAllDays(checked);
|
||
|
|
if (checked) {
|
||
|
|
setSelectedDays({
|
||
|
|
monday: true,
|
||
|
|
tuesday: true,
|
||
|
|
wednesday: true,
|
||
|
|
thursday: true,
|
||
|
|
friday: true,
|
||
|
|
saturday: true,
|
||
|
|
sunday: true
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
setSelectedDays({
|
||
|
|
monday: false,
|
||
|
|
tuesday: false,
|
||
|
|
wednesday: false,
|
||
|
|
thursday: false,
|
||
|
|
friday: false,
|
||
|
|
saturday: false,
|
||
|
|
sunday: false
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// Update select all when individual days change
|
||
|
|
useEffect(() => {
|
||
|
|
const allSelected = Object.values(selectedDays).every(day => day);
|
||
|
|
setSelectAllDays(allSelected);
|
||
|
|
}, [selectedDays]);
|
||
|
|
|
||
|
|
// Handle category change
|
||
|
|
const handleCategoryChange = async (value) => {
|
||
|
|
console.log("Category value", value);
|
||
|
|
setSelectedCategory(value);
|
||
|
|
form.setFieldsValue({
|
||
|
|
category: value,
|
||
|
|
|
||
|
|
});
|
||
|
|
|
||
|
|
// Fetch sub-categories based on selected category
|
||
|
|
let data = { CompId: CompId, BranchId: BranchId, AppId: AppId, ProdCat: value };
|
||
|
|
await dispatch(getSubCategories(data));
|
||
|
|
setSelectedSubCategory(null);
|
||
|
|
setSelectedFacility(null);
|
||
|
|
form.setFieldsValue({
|
||
|
|
subCategory: undefined,
|
||
|
|
facility: undefined
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
// Handle sub category change
|
||
|
|
const handleSubCategoryChange = async (value) => {
|
||
|
|
setSelectedSubCategory(value);
|
||
|
|
form.setFieldsValue({
|
||
|
|
subCategory: value,
|
||
|
|
|
||
|
|
});
|
||
|
|
let data = { CompId: CompId, BranchId: BranchId, AppId: AppId, ProdSubCat: value };
|
||
|
|
await dispatch(getProductListBasedSubcat(data));
|
||
|
|
setSelectedFacility(null);
|
||
|
|
form.setFieldsValue({ facility: undefined });
|
||
|
|
};
|
||
|
|
|
||
|
|
// Handle facility change
|
||
|
|
const handleFacilityChange = (value) => {
|
||
|
|
setSelectedFacility(value);
|
||
|
|
form.setFieldsValue({
|
||
|
|
facility: value,
|
||
|
|
|
||
|
|
});
|
||
|
|
// Auto-populate category and sub-category based on facility
|
||
|
|
const facilityData = ProductList.find(f => f.ProdId === value);
|
||
|
|
|
||
|
|
let datawithinward = facilityData?.ProductDetail?.[0]?.ProdVariantDetails?.flatMap(item => item.StockDetails.map(stock => ({
|
||
|
|
...item,
|
||
|
|
ProdInwardDtlId: stock.InwardDtlId,
|
||
|
|
})))
|
||
|
|
setSlots(facilityData?.ProductDetail?.[0]?.ProdVariantDetails?.length > 0 ? datawithinward : []);
|
||
|
|
};
|
||
|
|
|
||
|
|
// Handle coach change
|
||
|
|
const handleCoachChange = (value) => {
|
||
|
|
setSelectedCoach(value);
|
||
|
|
// Auto-populate category, sub-category, and facility based on coach
|
||
|
|
const coachData = coaches.find(c => c.id === value);
|
||
|
|
if (coachData) {
|
||
|
|
setSelectedCategory(coachData.categoryId);
|
||
|
|
setSelectedSubCategory(coachData.subCategoryId);
|
||
|
|
form.setFieldsValue({
|
||
|
|
category: coachData.categoryId,
|
||
|
|
subCategory: coachData.subCategoryId
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// Handle action mode change
|
||
|
|
const handleActionModeChange = (value) => {
|
||
|
|
setActionMode(value);
|
||
|
|
form.setFieldsValue({ actionMode: value });
|
||
|
|
setTypes(closureTypes[value] || []);
|
||
|
|
setClosureType(null);
|
||
|
|
setSlotChangeType('all');
|
||
|
|
setDateRange([]);
|
||
|
|
form.setFieldsValue({ dateRange: [] });
|
||
|
|
form.setFieldsValue({
|
||
|
|
category: undefined,
|
||
|
|
subCategory: undefined,
|
||
|
|
product: undefined,
|
||
|
|
closureType: undefined,
|
||
|
|
});
|
||
|
|
// Reset related states when mode changes
|
||
|
|
if (value !== 'priceChange') {
|
||
|
|
setNewPrice(null);
|
||
|
|
setWeekendPremium(false);
|
||
|
|
setWeekendPrice(0);
|
||
|
|
setIndividualSlotPrices({});
|
||
|
|
}
|
||
|
|
|
||
|
|
if (value !== 'block' && value !== 'priceChange') {
|
||
|
|
setSelectedSlots([]);
|
||
|
|
}
|
||
|
|
setClosureReason(null);
|
||
|
|
};
|
||
|
|
|
||
|
|
// Handle closure type change
|
||
|
|
const handleClosureTypeChange = (value) => {
|
||
|
|
setClosureType(value);
|
||
|
|
form.setFieldsValue({
|
||
|
|
closureType: value
|
||
|
|
});
|
||
|
|
|
||
|
|
// Reset selections when closure type changes
|
||
|
|
setSelectedCategory(null);
|
||
|
|
setSelectedSubCategory(null);
|
||
|
|
setSelectedFacility(null);
|
||
|
|
setSelectedCoach(null);
|
||
|
|
setSelectedBranches([]);
|
||
|
|
setSelectedSlots([]);
|
||
|
|
setIndividualSlotPrices({});
|
||
|
|
setClosureReason(null);
|
||
|
|
form.setFieldsValue({
|
||
|
|
category: undefined,
|
||
|
|
subCategory: undefined,
|
||
|
|
product: undefined,
|
||
|
|
coach: undefined,
|
||
|
|
branches: undefined
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
// Handle slot selection
|
||
|
|
const handleSlotSelection = (slot) => {
|
||
|
|
if (selectedSlots.includes(slot)) {
|
||
|
|
setSelectedSlots(selectedSlots.filter(s => s !== slot));
|
||
|
|
// Remove from individual prices when deselected
|
||
|
|
setIndividualSlotPrices(prev => {
|
||
|
|
const newPrices = { ...prev };
|
||
|
|
delete newPrices[slot];
|
||
|
|
return newPrices;
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
setSelectedSlots([...selectedSlots, slot]);
|
||
|
|
// Initialize with base price when selected
|
||
|
|
setIndividualSlotPrices(prev => ({
|
||
|
|
...prev,
|
||
|
|
[slot]: newPrice || 0
|
||
|
|
}));
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const to12Hour = (timeStr) => {
|
||
|
|
if (!timeStr) return '';
|
||
|
|
let [h, m] = timeStr.split(':');
|
||
|
|
h = parseInt(h, 10);
|
||
|
|
const suffix = h >= 12 ? 'PM' : 'AM';
|
||
|
|
h = h % 12 || 12;
|
||
|
|
return `${h}:${m}${suffix}`;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Select all slots
|
||
|
|
const handleSelectAllSlots = () => {
|
||
|
|
if (selectedSlots.length === Slots.length) {
|
||
|
|
setSelectedSlots([]);
|
||
|
|
setIndividualSlotPrices({});
|
||
|
|
} else {
|
||
|
|
setSelectedSlots([...Slots?.map(slot => slot.ProdInwardDtlId)]);
|
||
|
|
// Initialize all with base price
|
||
|
|
const initialPrices = {};
|
||
|
|
Slots.forEach(slot => {
|
||
|
|
initialPrices[slot] = newPrice || 0;
|
||
|
|
});
|
||
|
|
setIndividualSlotPrices(initialPrices);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// Handle individual slot price change
|
||
|
|
const handleIndividualSlotPriceChange = (slot, price) => {
|
||
|
|
setIndividualSlotPrices(prev => ({
|
||
|
|
...prev,
|
||
|
|
[slot]: price
|
||
|
|
}));
|
||
|
|
};
|
||
|
|
|
||
|
|
// Apply base price to all selected slots
|
||
|
|
const applyBasePriceToAllSlots = () => {
|
||
|
|
const updatedPrices = {};
|
||
|
|
selectedSlots.forEach(slot => {
|
||
|
|
updatedPrices[slot] = newPrice;
|
||
|
|
});
|
||
|
|
setIndividualSlotPrices(updatedPrices);
|
||
|
|
};
|
||
|
|
|
||
|
|
// Get selected days display text
|
||
|
|
const getSelectedDaysText = () => {
|
||
|
|
const daysMap = {
|
||
|
|
monday: 'Mon',
|
||
|
|
tuesday: 'Tue',
|
||
|
|
wednesday: 'Wed',
|
||
|
|
thursday: 'Thu',
|
||
|
|
friday: 'Fri',
|
||
|
|
saturday: 'Sat',
|
||
|
|
sunday: 'Sun'
|
||
|
|
};
|
||
|
|
|
||
|
|
const selected = Object.entries(selectedDays)
|
||
|
|
.filter(([_, isSelected]) => isSelected)
|
||
|
|
.map(([day]) => daysMap[day]);
|
||
|
|
|
||
|
|
return selected.length > 0 ? selected.join(', ') : 'No days selected';
|
||
|
|
};
|
||
|
|
|
||
|
|
// Get action mode display text
|
||
|
|
const getActionModeText = () => {
|
||
|
|
switch (actionMode) {
|
||
|
|
case 'block':
|
||
|
|
return 'Block';
|
||
|
|
case 'priceChange':
|
||
|
|
return 'Price Change';
|
||
|
|
case 'holiday':
|
||
|
|
return 'Holiday';
|
||
|
|
default:
|
||
|
|
return '';
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// Get closure type display text
|
||
|
|
const getClosureTypeText = () => {
|
||
|
|
const allClosureTypes = [...closureTypes.block, ...closureTypes.priceChange, ...closureTypes.holiday];
|
||
|
|
const type = allClosureTypes.find(t => t.value === closureType);
|
||
|
|
return type ? type.label : 'No Type Selected';
|
||
|
|
};
|
||
|
|
|
||
|
|
// Filter facilities based on category and sub-category
|
||
|
|
const getFilteredFacilities = () => {
|
||
|
|
let filtered = facilities;
|
||
|
|
if (selectedCategory) {
|
||
|
|
filtered = filtered.filter(f => f.categoryId === selectedCategory);
|
||
|
|
}
|
||
|
|
if (selectedSubCategory) {
|
||
|
|
filtered = filtered.filter(f => f.subCategoryId === selectedSubCategory);
|
||
|
|
}
|
||
|
|
return filtered;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Filter coaches based on category and sub-category
|
||
|
|
const getFilteredCoaches = () => {
|
||
|
|
let filtered = coaches;
|
||
|
|
if (selectedCategory) {
|
||
|
|
filtered = filtered.filter(c => c.categoryId === selectedCategory);
|
||
|
|
}
|
||
|
|
if (selectedSubCategory) {
|
||
|
|
filtered = filtered.filter(c => c.subCategoryId === selectedSubCategory);
|
||
|
|
}
|
||
|
|
return filtered;
|
||
|
|
};
|
||
|
|
// Check if time slot selection should be shown
|
||
|
|
const ShouldCategoryShow = () => {
|
||
|
|
if (closureType !== 'full_branch' && actionMode && closureType) {
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
const ShouldSubCategoryShow = () => {
|
||
|
|
if (actionMode && closureType && selectedCategory) {
|
||
|
|
if (closureType === 'subcategory' || closureType === 'product') {
|
||
|
|
return true;
|
||
|
|
} else {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
const ShouldFacilityShow = () => {
|
||
|
|
if (actionMode && closureType && selectedSubCategory) {
|
||
|
|
if (closureType === 'product') {
|
||
|
|
return true;
|
||
|
|
} else {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
// Check if time slot selection should be shown
|
||
|
|
const shouldShowTimeSlotSelection = () => {
|
||
|
|
if (actionMode === 'block' || actionMode === 'priceChange') {
|
||
|
|
return SlotChangeType === 'individual';
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Check if day selection should be shown
|
||
|
|
const shouldShowDaySelection = () => {
|
||
|
|
if (actionMode === 'block' || actionMode === 'priceChange') {
|
||
|
|
return SlotChangeType === 'individual';
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
};
|
||
|
|
const showslotselection = () => {
|
||
|
|
if (actionMode === 'block' || actionMode === 'priceChange') {
|
||
|
|
|
||
|
|
return dateRange?.length > 0 && closureType == 'product' && selectedFacility;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
// Check if reason input should be shown
|
||
|
|
const shouldShowReasonInput = () => {
|
||
|
|
return actionMode === 'block' && closureType && closureType !== 'priceChange';
|
||
|
|
};
|
||
|
|
|
||
|
|
// Check if individual slot price table should be shown
|
||
|
|
const shouldShowIndividualSlotPriceTable = () => {
|
||
|
|
return actionMode === 'priceChange' &&
|
||
|
|
selectedSlots.length > 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Apply management action
|
||
|
|
const applyManagementAction = async () => {
|
||
|
|
if (!actionMode || !closureType || !dateRange || dateRange.length === 0) {
|
||
|
|
Modal.error({
|
||
|
|
title: 'Validation Error',
|
||
|
|
content: 'Please fill all required fields: Slot Action, Activity Type, and Date Range',
|
||
|
|
});
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Validation based on closure type
|
||
|
|
// if (closureType === 'full_branch' && selectedBranches.length === 0) {
|
||
|
|
// Modal.error({
|
||
|
|
// title: 'Validation Error',
|
||
|
|
// content: 'Please select at least one branch for full branch closure',
|
||
|
|
// });
|
||
|
|
// return;
|
||
|
|
// }
|
||
|
|
|
||
|
|
if ((closureType === 'category' || closureType === 'subcategory') && !selectedCategory) {
|
||
|
|
Modal.error({
|
||
|
|
title: 'Validation Error',
|
||
|
|
content: `Please select category for ${closureType} `,
|
||
|
|
});
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (closureType === 'subcategory' && !selectedSubCategory) {
|
||
|
|
Modal.error({
|
||
|
|
title: 'Validation Error',
|
||
|
|
content: 'Please select sub-category ',
|
||
|
|
});
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((closureType === 'product' || closureType === 'individual_slot') && !selectedFacility) {
|
||
|
|
Modal.error({
|
||
|
|
title: 'Validation Error',
|
||
|
|
content: 'Please select facility',
|
||
|
|
});
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (closureType === 'coach_leave' && !selectedCoach) {
|
||
|
|
Modal.error({
|
||
|
|
title: 'Validation Error',
|
||
|
|
content: 'Please select coach for coach leave',
|
||
|
|
});
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check for day selection for time slot operations
|
||
|
|
if (shouldShowDaySelection() && !Object.values(selectedDays).some(day => day)) {
|
||
|
|
Modal.error({
|
||
|
|
title: 'Validation Error',
|
||
|
|
content: 'Please select at least one day for time slot operations',
|
||
|
|
});
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check for slot selection for individual time slot operations
|
||
|
|
if ((SlotChangeType === 'individual') && selectedSlots.length === 0) {
|
||
|
|
Modal.error({
|
||
|
|
title: 'Validation Error',
|
||
|
|
content: 'Please select at least one time slot',
|
||
|
|
});
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check for price in price change operations
|
||
|
|
if (actionMode === 'priceChange') {
|
||
|
|
if (priceChangeType === 'full' && newPrice <= 0) {
|
||
|
|
Modal.error({
|
||
|
|
title: 'Validation Error',
|
||
|
|
content: 'Please enter a valid price for price change',
|
||
|
|
});
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// if (priceChangeType === 'full') {
|
||
|
|
|
||
|
|
// Check if all selected slots have valid prices
|
||
|
|
const invalidSlots = selectedSlots?.filter(slot =>
|
||
|
|
!slotPrices[slot] || Number(slotPrices[slot]?.fullSlotPrice) <= 0
|
||
|
|
);
|
||
|
|
console.log(selectedSlots?.filter(slot =>
|
||
|
|
!slotPrices[slot] || Number(slotPrices[slot]?.fullSlotPrice) <= 0
|
||
|
|
), "selectedSlots?.filter")
|
||
|
|
if (invalidSlots.length > 0) {
|
||
|
|
Modal.error({
|
||
|
|
title: 'Validation Error',
|
||
|
|
content: `Please enter valid prices for all selected slots. Missing or invalid prices `,
|
||
|
|
});
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// }
|
||
|
|
|
||
|
|
// Check for reason in block operations
|
||
|
|
if (actionMode === 'block' && !closureReason?.trim()) {
|
||
|
|
Modal.error({
|
||
|
|
title: 'Validation Error',
|
||
|
|
content: 'Please provide a reason for the block',
|
||
|
|
});
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
let slotDetails = {
|
||
|
|
"AppId": AppId,
|
||
|
|
"CompId": CompId,
|
||
|
|
"BranchId": BranchId,
|
||
|
|
"ModeOfException": SlotChangeType == 'individual' ? 'slot' : closureType,
|
||
|
|
"ExceptionType": actionMode,
|
||
|
|
"Reason": closureReason,
|
||
|
|
"IsHoliday": actionMode == "holiday" ? 'Y' : 'N',
|
||
|
|
"DayOfWeek":
|
||
|
|
Object.entries(selectedDays).filter(([_, selected]) => selected).map(([day]) => day),
|
||
|
|
|
||
|
|
"SlotDetails":
|
||
|
|
SlotChangeType === 'individual'
|
||
|
|
? selectedSlots?.map(inwardId => ({
|
||
|
|
ProdCat: selectedCategory || null,
|
||
|
|
ProdSubCat: selectedSubCategory || null,
|
||
|
|
ProdId: selectedFacility || null,
|
||
|
|
InwardDtlId: inwardId,
|
||
|
|
ExceptionFrom: dateRange[0]?.format('YYYY-MM-DD'),
|
||
|
|
ExceptionTo: dateRange[1]?.format('YYYY-MM-DD'),
|
||
|
|
NewPrice: slotPrices[inwardId]?.fullSlotPrice || 0,
|
||
|
|
SinglePrice: slotPrices[inwardId]?.individualPrice || 0
|
||
|
|
}))
|
||
|
|
: [
|
||
|
|
{
|
||
|
|
ProdCat: selectedCategory || null,
|
||
|
|
ProdSubCat: selectedSubCategory || null,
|
||
|
|
ProdId: selectedFacility || null,
|
||
|
|
InwardDtlId: null,
|
||
|
|
ExceptionFrom: dateRange[0]?.format('YYYY-MM-DD'),
|
||
|
|
ExceptionTo: dateRange[1]?.format('YYYY-MM-DD'),
|
||
|
|
NewPrice: newPrice || 0,
|
||
|
|
SinglePrice: individualDefaultPrice || 0
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"UpdatedBy": UserId
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log("Management Record", slotDetails);
|
||
|
|
let response = await dispatch(PutSlotBlock(slotDetails)).unwrap()
|
||
|
|
console.log("response", response);
|
||
|
|
if (response?.data?.statusCode == 1) {
|
||
|
|
navigate(`${subDirectory}setting/slot-management-list`, {
|
||
|
|
state: {
|
||
|
|
Notiffy: {
|
||
|
|
messageType: 'success',
|
||
|
|
messageData:`${getActionModeText()} - ${getClosureTypeText()} applied successfully!`,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
});
|
||
|
|
// Modal.success({
|
||
|
|
// title: 'Success',
|
||
|
|
// content: `${getActionModeText()} - ${getClosureTypeText()} applied successfully!`,
|
||
|
|
// });
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// Modal.success({
|
||
|
|
// title: 'Success',
|
||
|
|
// content: `${getActionModeText()} - ${getClosureTypeText()} applied successfully!`,
|
||
|
|
// });
|
||
|
|
|
||
|
|
// Reset form
|
||
|
|
form.resetFields();
|
||
|
|
setSelectedCategory(null);
|
||
|
|
setSelectedSubCategory(null);
|
||
|
|
setSelectedFacility(null);
|
||
|
|
setSelectedCoach(null);
|
||
|
|
setActionMode(null);
|
||
|
|
setClosureType(null);
|
||
|
|
setDateRange([]);
|
||
|
|
setSelectedDays({
|
||
|
|
monday: false, tuesday: false, wednesday: false, thursday: false,
|
||
|
|
friday: false, saturday: false, sunday: false
|
||
|
|
});
|
||
|
|
setSelectedSlots([]);
|
||
|
|
setSelectedBranches([]);
|
||
|
|
setNewPrice(null);
|
||
|
|
setWeekendPremium(false);
|
||
|
|
setWeekendPrice(0);
|
||
|
|
setClosureReason(null);
|
||
|
|
setIndividualSlotPrices({});
|
||
|
|
setSlotChangeType('all');
|
||
|
|
setPriceChangeType('full');
|
||
|
|
setSelectAllDays(false);
|
||
|
|
};
|
||
|
|
|
||
|
|
// Remove management record
|
||
|
|
const removeManagementRecord = (id) => {
|
||
|
|
Modal.confirm({
|
||
|
|
title: 'Confirm Removal',
|
||
|
|
content: 'Are you sure you want to remove this management record?',
|
||
|
|
okText: 'Yes',
|
||
|
|
cancelText: 'No',
|
||
|
|
onOk() {
|
||
|
|
setManagementHistory(prev => prev.filter(record => record.id !== id));
|
||
|
|
}
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
// Toggle management record status
|
||
|
|
const toggleManagementStatus = (id) => {
|
||
|
|
setManagementHistory(prev => prev.map(record =>
|
||
|
|
record.id === id
|
||
|
|
? { ...record, status: record.status === 'active' ? 'inactive' : 'active' }
|
||
|
|
: record
|
||
|
|
));
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
// Calculate summary statistics
|
||
|
|
const calculateSummary = () => {
|
||
|
|
const activeRecords = managementHistory.filter(record => record.status === 'active');
|
||
|
|
const blockedSlots = activeRecords.filter(record => record.action === 'block').length;
|
||
|
|
const priceChanges = activeRecords.filter(record => record.action === 'priceChange').length;
|
||
|
|
const holidayBlocks = activeRecords.filter(record => record.action === 'holiday').length;
|
||
|
|
|
||
|
|
// Count by closure type
|
||
|
|
const closureTypeCounts = {};
|
||
|
|
activeRecords.forEach(record => {
|
||
|
|
closureTypeCounts[record.closureType] = (closureTypeCounts[record.closureType] || 0) + 1;
|
||
|
|
});
|
||
|
|
|
||
|
|
return {
|
||
|
|
blockedSlots,
|
||
|
|
priceChanges,
|
||
|
|
holidayBlocks,
|
||
|
|
total: activeRecords.length,
|
||
|
|
closureTypeCounts
|
||
|
|
};
|
||
|
|
};
|
||
|
|
|
||
|
|
const summary = calculateSummary();
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
// Slot price management columns
|
||
|
|
const slotPriceColumns = [
|
||
|
|
{
|
||
|
|
title: 'Sl.No',
|
||
|
|
key: 'sno',
|
||
|
|
align: 'center',
|
||
|
|
width: 60,
|
||
|
|
render: (text, record, index) => index + 1,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: 'Slot',
|
||
|
|
dataIndex: 'time',
|
||
|
|
key: 'time',
|
||
|
|
align: 'center',
|
||
|
|
render: (slot) => <strong>{slot}</strong>,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: 'Full Slot Price (₹)',
|
||
|
|
key: 'fullSlotPrice',
|
||
|
|
align: 'center',
|
||
|
|
render: (record) => (
|
||
|
|
<InputNumber
|
||
|
|
value={slotPrices[record.slot]?.fullSlotPrice || 0}
|
||
|
|
min={0}
|
||
|
|
style={{ width: 120 }}
|
||
|
|
formatter={value => `₹ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
|
||
|
|
parser={value => value.replace(/₹\s?|(,*)/g, '')}
|
||
|
|
onChange={value => handleFullSlotPriceChange(record.slot, value)}
|
||
|
|
placeholder="Full Slot Price"
|
||
|
|
/>
|
||
|
|
),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: 'Individual Price (₹)',
|
||
|
|
key: 'individualPrice',
|
||
|
|
align: 'center',
|
||
|
|
render: (record) => (
|
||
|
|
<InputNumber
|
||
|
|
value={slotPrices[record.slot]?.individualPrice || 0}
|
||
|
|
min={0}
|
||
|
|
style={{ width: 120 }}
|
||
|
|
formatter={value => `₹ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
|
||
|
|
parser={value => value.replace(/₹\s?|(,*)/g, '')}
|
||
|
|
onChange={value => handleIndividualPriceChange(record.slot, value)}
|
||
|
|
placeholder="Individual Price"
|
||
|
|
/>
|
||
|
|
),
|
||
|
|
},
|
||
|
|
];
|
||
|
|
|
||
|
|
const BasicActionType = [
|
||
|
|
{ label: 'Block', value: 'block', icon: <BlockOutlined /> },
|
||
|
|
{ label: 'Price Change', value: 'priceChange', icon: <DollarOutlined /> },
|
||
|
|
{ label: 'Holiday', value: 'holiday', icon: <FlagOutlined /> },
|
||
|
|
];
|
||
|
|
const PriceTypeChange = (e) => {
|
||
|
|
setPriceChangeType(e.target.value)
|
||
|
|
setNewPrice(null);
|
||
|
|
}
|
||
|
|
const SlotTypeChange = (e) => {
|
||
|
|
setSlotChangeType(e.target.value)
|
||
|
|
}
|
||
|
|
const navigatelist = () => {
|
||
|
|
navigate(`${subDirectory}setting/slot-management-list`)
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="slot-management">
|
||
|
|
<div className="slot-management__header">
|
||
|
|
<div>
|
||
|
|
|
||
|
|
<h1 className="slot-management__header-title">
|
||
|
|
Slot Management
|
||
|
|
</h1>
|
||
|
|
|
||
|
|
</div>
|
||
|
|
{/* <div className="slot-management__header-link" onClick={navigatelist}>
|
||
|
|
View SlotDetails
|
||
|
|
</div> */}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<Form
|
||
|
|
form={form}
|
||
|
|
layout="vertical"
|
||
|
|
initialValues={{
|
||
|
|
priceChangeType: 'full',
|
||
|
|
SlotSelectionType: 'all',
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
{/* Basic Configuration Section */}
|
||
|
|
<div className="slot-management__config-section">
|
||
|
|
<div className="slot-management__form-row">
|
||
|
|
<div className="slot-management__form-col">
|
||
|
|
|
||
|
|
<Form.Item
|
||
|
|
name="actionMode"
|
||
|
|
// label="Action Type"
|
||
|
|
rules={[{ required: true, message: 'Please select action type' }]}
|
||
|
|
>
|
||
|
|
<DropDowns
|
||
|
|
options={BasicActionType?.map((option) => ({
|
||
|
|
value: option.value,
|
||
|
|
label: option.label
|
||
|
|
}))}
|
||
|
|
label={<label class="required">Slot Action</label>}
|
||
|
|
className="field-DropDown"
|
||
|
|
// isOnchanges={
|
||
|
|
// editstate?.UOM || SelectedUom ? true : false
|
||
|
|
// }
|
||
|
|
onChangeFunction={handleActionModeChange}
|
||
|
|
// valueData={SelectedUom}
|
||
|
|
// disabled={formType == 'edit' ? true : false}
|
||
|
|
/>
|
||
|
|
</Form.Item>
|
||
|
|
</div>
|
||
|
|
{actionMode &&
|
||
|
|
<div className="slot-management__form-col">
|
||
|
|
<Form.Item
|
||
|
|
name="closureType"
|
||
|
|
// label="Closure Type"
|
||
|
|
rules={[{ required: true, message: 'Please select closure type' }]}
|
||
|
|
>
|
||
|
|
<DropDowns
|
||
|
|
options={types?.map((option) => ({
|
||
|
|
value: option.value,
|
||
|
|
label: option.label
|
||
|
|
}))}
|
||
|
|
label={<label className="required">Activity Type</label>}
|
||
|
|
className="field-DropDown"
|
||
|
|
isOnchanges={
|
||
|
|
closureType ? true : false
|
||
|
|
}
|
||
|
|
onChangeFunction={handleClosureTypeChange}
|
||
|
|
valueData={closureType}
|
||
|
|
// disabled={formType == 'edit' ? true : false}
|
||
|
|
/>
|
||
|
|
{/* <Select
|
||
|
|
placeholder={`-- Select ${getActionModeText()} Type --`}
|
||
|
|
onChange={handleClosureTypeChange}
|
||
|
|
allowClear
|
||
|
|
>
|
||
|
|
{types.map(type => (
|
||
|
|
<Option key={type.value} value={type.value}>
|
||
|
|
<Space>
|
||
|
|
{type.icon}
|
||
|
|
{type.label}
|
||
|
|
</Space>
|
||
|
|
</Option>
|
||
|
|
))}
|
||
|
|
</Select> */}
|
||
|
|
</Form.Item>
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
{closureType &&
|
||
|
|
<div className="slot-management__form-col">
|
||
|
|
<Form.Item
|
||
|
|
name="dateRange"
|
||
|
|
label="Date Range"
|
||
|
|
rules={[{ required: true, message: 'Please select date range' }]}
|
||
|
|
>
|
||
|
|
<RangePicker
|
||
|
|
style={{ width: '100%' }}
|
||
|
|
onChange={setDateRange}
|
||
|
|
format="DD-MMM-YYYY"
|
||
|
|
value={dateRange}
|
||
|
|
disabledDate={current => current && current < moment().startOf('day')}
|
||
|
|
/>
|
||
|
|
</Form.Item>
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
{/* <div style={{ marginLeft: 'auto' }}>
|
||
|
|
<Tooltip title="Configure slot management settings">
|
||
|
|
<InfoCircleOutlined style={{ color: '#1890ff', fontSize: 20 }} />
|
||
|
|
</Tooltip>
|
||
|
|
</div> */}
|
||
|
|
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Closure Specific Fields */}
|
||
|
|
<div className='seletcCategorylabel'>
|
||
|
|
{ShouldCategoryShow() &&
|
||
|
|
<Form.Item
|
||
|
|
name="category"
|
||
|
|
// label="Select Category"
|
||
|
|
rules={[{ required: true, message: 'Please select category' }]}
|
||
|
|
>
|
||
|
|
<DropDowns
|
||
|
|
options={CategoriesData?.map((option) => ({
|
||
|
|
value: option.ProdCat,
|
||
|
|
label: option.ProdCatName
|
||
|
|
}))}
|
||
|
|
label={<label className="required">Category</label>}
|
||
|
|
className="field-DropDown"
|
||
|
|
isOnchanges={
|
||
|
|
selectedCategory ? true : false
|
||
|
|
}
|
||
|
|
onChangeFunction={handleCategoryChange}
|
||
|
|
valueData={selectedCategory}
|
||
|
|
// disabled={formType == 'edit' ? true : false}
|
||
|
|
/>
|
||
|
|
|
||
|
|
</Form.Item>
|
||
|
|
}
|
||
|
|
{ShouldSubCategoryShow() && (
|
||
|
|
<Form.Item
|
||
|
|
name="subCategory"
|
||
|
|
rules={[{ required: true, message: 'Please select sub category' }]}
|
||
|
|
>
|
||
|
|
<DropDowns
|
||
|
|
options={SubCategoriesData?.map((option) => ({
|
||
|
|
value: option.ProdSubCat,
|
||
|
|
label: option.ProdSubCatName
|
||
|
|
}))}
|
||
|
|
label={<label className="required">Sub Category</label>}
|
||
|
|
className="field-DropDown"
|
||
|
|
isOnchanges={
|
||
|
|
selectedSubCategory ? true : false
|
||
|
|
}
|
||
|
|
onChangeFunction={handleSubCategoryChange}
|
||
|
|
valueData={selectedSubCategory}
|
||
|
|
// disabled={formType == 'edit' ? true : false}
|
||
|
|
/>
|
||
|
|
</Form.Item>
|
||
|
|
)}
|
||
|
|
{ShouldFacilityShow() &&
|
||
|
|
<Form.Item
|
||
|
|
name="facility"
|
||
|
|
// label="Select Facility"
|
||
|
|
rules={[{ required: true, message: 'Please select facility' }]}
|
||
|
|
>
|
||
|
|
<DropDowns
|
||
|
|
options={ProductList?.map((option) => ({
|
||
|
|
value: option.ProdId,
|
||
|
|
label: option.ProdName
|
||
|
|
}))}
|
||
|
|
label={<label className="required">Facility</label>}
|
||
|
|
className="field-DropDown"
|
||
|
|
isOnchanges={
|
||
|
|
selectedFacility ? true : false
|
||
|
|
}
|
||
|
|
onChangeFunction={handleFacilityChange}
|
||
|
|
valueData={selectedFacility}
|
||
|
|
// disabled={formType == 'edit' ? true : false}
|
||
|
|
/>
|
||
|
|
{/* <Select
|
||
|
|
placeholder="-- Select Facility --"
|
||
|
|
onChange={handleFacilityChange}
|
||
|
|
allowClear
|
||
|
|
showSearch
|
||
|
|
optionFilterProp="children"
|
||
|
|
filterOption={(input, option) =>
|
||
|
|
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||
|
|
}
|
||
|
|
>
|
||
|
|
{facilities.map(facility => (
|
||
|
|
<Option key={facility.id} value={facility.id}>
|
||
|
|
{facility.name} - {branches.find(b => b.id === facility.branchId)?.name}
|
||
|
|
({CategoriesData?.find(c => c.ProdCat === facility.ProdCat)?.ProdCatName} -
|
||
|
|
{SubCategoriesData?.find(s => s.ProdSubCat === facility.subCategoryId)?.ProdSubCatName})
|
||
|
|
</Option>
|
||
|
|
))}
|
||
|
|
</Select> */}
|
||
|
|
</Form.Item>
|
||
|
|
}
|
||
|
|
{showslotselection() &&
|
||
|
|
<div style={{ flex: '1 1 250px', minWidth: 220 }}>
|
||
|
|
<Form.Item
|
||
|
|
name="SlotSelectionType"
|
||
|
|
label="Slot Selection Type"
|
||
|
|
>
|
||
|
|
<Radio.Group
|
||
|
|
onChange={(e) => SlotTypeChange(e)}
|
||
|
|
value={SlotChangeType}
|
||
|
|
>
|
||
|
|
<Radio value="all">All Slots</Radio>
|
||
|
|
<Radio value="individual">Individual Slots</Radio>
|
||
|
|
</Radio.Group>
|
||
|
|
</Form.Item>
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* {renderClosureSpecificFields()} */}
|
||
|
|
|
||
|
|
{/* Reason Input for Block Actions */}
|
||
|
|
{shouldShowReasonInput() && (
|
||
|
|
<Form.Item
|
||
|
|
|
||
|
|
label= {<label className="required">Reason for Block</label>}
|
||
|
|
rules={[{ required: true, message: 'Please provide a reason for the block' }]}
|
||
|
|
>
|
||
|
|
<TextArea
|
||
|
|
value={closureReason}
|
||
|
|
onChange={(e) => setClosureReason(e.target.value)}
|
||
|
|
placeholder="Enter the reason for this block (e.g., Maintenance, Repair, Special Event, etc.)"
|
||
|
|
rows={3}
|
||
|
|
showCount
|
||
|
|
maxLength={500}
|
||
|
|
/>
|
||
|
|
</Form.Item>
|
||
|
|
)}
|
||
|
|
|
||
|
|
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Day Selection Section for Time Slot Operations */}
|
||
|
|
{shouldShowDaySelection() && (
|
||
|
|
<div
|
||
|
|
style={{
|
||
|
|
marginBottom: 20,
|
||
|
|
padding: 24,
|
||
|
|
background: '#fff',
|
||
|
|
borderRadius: 8,
|
||
|
|
boxShadow: '0 2px 8px #f0f1f2',
|
||
|
|
border: '1px solid #f0f0f0'
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<div style={{ fontWeight: 600, fontSize: 18, marginBottom: 12 }}>
|
||
|
|
Day Selection
|
||
|
|
</div>
|
||
|
|
<Form.Item >
|
||
|
|
{/* label="Select Days for Action" required */}
|
||
|
|
<div
|
||
|
|
style={{
|
||
|
|
display: 'flex',
|
||
|
|
flexWrap: 'wrap',
|
||
|
|
padding: '16px',
|
||
|
|
border: '1px solid #d9d9d9',
|
||
|
|
borderRadius: '6px',
|
||
|
|
backgroundColor: '#fafafa'
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<div style={{
|
||
|
|
|
||
|
|
minWidth: 120,
|
||
|
|
padding: '4px 0'
|
||
|
|
}}>
|
||
|
|
<Checkbox
|
||
|
|
checked={selectAllDays}
|
||
|
|
onChange={(e) => handleSelectAllDays(e.target.checked)}
|
||
|
|
>
|
||
|
|
<strong>Select All Days</strong>
|
||
|
|
</Checkbox>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div
|
||
|
|
style={{
|
||
|
|
display: 'flex',
|
||
|
|
flexWrap: 'wrap',
|
||
|
|
gap: '12px 0',
|
||
|
|
marginBottom: '12px'
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
|
||
|
|
{Object.entries(selectedDays)?.map(([day, isSelected]) => (
|
||
|
|
<div
|
||
|
|
key={day}
|
||
|
|
style={{
|
||
|
|
|
||
|
|
minWidth: 120,
|
||
|
|
padding: '4px 0'
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<Checkbox
|
||
|
|
checked={isSelected}
|
||
|
|
onChange={() => handleDayChange(day)}
|
||
|
|
>
|
||
|
|
{day === 'saturday' || day === 'sunday' ? (
|
||
|
|
<strong style={{ color: '#ff4d4f' }}>
|
||
|
|
{day.charAt(0).toUpperCase() + day.slice(1)}
|
||
|
|
</strong>
|
||
|
|
) : (
|
||
|
|
day.charAt(0).toUpperCase() + day.slice(1)
|
||
|
|
)}
|
||
|
|
</Checkbox>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* <div className="slot-management__day-selection-summary">
|
||
|
|
<strong>Selected Days:</strong> {getSelectedDaysText()}
|
||
|
|
</div> */}
|
||
|
|
</div>
|
||
|
|
</Form.Item>
|
||
|
|
{shouldShowTimeSlotSelection() && (
|
||
|
|
<div>
|
||
|
|
<div className="slot-management__section-title">
|
||
|
|
Time Slot Selection
|
||
|
|
</div>
|
||
|
|
<div style={{ marginBottom: '12px', display: 'flex', alignItems: 'center' }}>
|
||
|
|
<Button
|
||
|
|
type="dashed"
|
||
|
|
onClick={handleSelectAllSlots}
|
||
|
|
size="small"
|
||
|
|
>
|
||
|
|
{selectedSlots.length === Slots?.length ? 'Deselect All' : 'Select All'} Slots
|
||
|
|
</Button>
|
||
|
|
<span style={{ marginLeft: '12px', color: '#666' }}>
|
||
|
|
{selectedSlots.length} slots selected
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="slot-management__slot-grid">
|
||
|
|
{Slots?.map(slot => (
|
||
|
|
<div
|
||
|
|
key={slot?.ProdInwardDtlId}
|
||
|
|
onClick={() => handleSlotSelection(slot?.ProdInwardDtlId)}
|
||
|
|
className={`slot-management__slot-item ${selectedSlots.includes(slot?.ProdInwardDtlId) ? 'slot-management__slot-item--selected' : ''
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
{to12Hour(slot?.AvailableFrom)} - {to12Hour(slot?.AvailableTo)}
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Time Slot Selection for Block and Price Change Operations */}
|
||
|
|
|
||
|
|
|
||
|
|
{/* Price Change Configuration */}
|
||
|
|
{(actionMode === 'priceChange' && selectedFacility) && (
|
||
|
|
<div className="slot-management__config-section">
|
||
|
|
<div className="slot-management__section-title">
|
||
|
|
Price Change Configuration
|
||
|
|
</div>
|
||
|
|
<div className="slot-management__price-config-row">
|
||
|
|
{/* <div style={{ flex: '1 1 250px', minWidth: 220 }}>
|
||
|
|
<Form.Item
|
||
|
|
name="priceChangeType"
|
||
|
|
label="Price Change Type"
|
||
|
|
>
|
||
|
|
<Radio.Group
|
||
|
|
onChange={(e) => PriceTypeChange(e) }
|
||
|
|
value={priceChangeType}
|
||
|
|
>
|
||
|
|
|
||
|
|
<Radio value="full">Full Slot Price</Radio>
|
||
|
|
<Radio value="individual">Individual Slot Price</Radio>
|
||
|
|
</Radio.Group>
|
||
|
|
</Form.Item>
|
||
|
|
</div> */}
|
||
|
|
<div className="slot-management__form-col">
|
||
|
|
<div className='IndividualInput'>
|
||
|
|
|
||
|
|
<Form.Item
|
||
|
|
// label={"New Price (₹)" }
|
||
|
|
rules={[{ required: true, message: 'Please Give Price' }]}
|
||
|
|
>
|
||
|
|
<InputField
|
||
|
|
value={newPrice}
|
||
|
|
onChange={(e) => setNewPrice(e.target.value)}
|
||
|
|
min={0}
|
||
|
|
style={{ width: '100%' }}
|
||
|
|
placeholder={"Enter new price"}
|
||
|
|
inputMode="decimal"
|
||
|
|
onInput={(e) => {
|
||
|
|
let cleanedValue = e.target.value.replace(
|
||
|
|
/[^0-9.]/g,
|
||
|
|
''
|
||
|
|
); // Remove invalid characters
|
||
|
|
const parts = cleanedValue.split('.');
|
||
|
|
|
||
|
|
if (cleanedValue.startsWith('.')) {
|
||
|
|
cleanedValue = '0' + cleanedValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
e.target.value =
|
||
|
|
parts.length > 2
|
||
|
|
? `${parts[0]}.${parts.slice(1).join('')}`
|
||
|
|
: cleanedValue;
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
</Form.Item>
|
||
|
|
|
||
|
|
<Form.Item label="Individual Pricing">
|
||
|
|
<Checkbox
|
||
|
|
checked={individualPricing}
|
||
|
|
onChange={(e) => setIndividualPricing(e.target.checked)}
|
||
|
|
>
|
||
|
|
Enable Individual Pricing
|
||
|
|
</Checkbox>
|
||
|
|
</Form.Item>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
{individualPricing && (
|
||
|
|
|
||
|
|
<Form.Item
|
||
|
|
name="individualDefaultPrice"
|
||
|
|
// label="Individual Default Price (₹)"
|
||
|
|
|
||
|
|
>
|
||
|
|
<InputField
|
||
|
|
min={0}
|
||
|
|
// className="sports-master__input-number"
|
||
|
|
formatter={value => `₹ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
|
||
|
|
parser={value => value.replace(/₹\s?|(,*)/g, '')}
|
||
|
|
onChange={(e) => setIndividualDefaultPrice(e.target.value)}
|
||
|
|
value={individualDefaultPrice}
|
||
|
|
placeholder={"Enter individual price"}
|
||
|
|
inputMode="decimal"
|
||
|
|
onInput={(e) => {
|
||
|
|
let cleanedValue = e.target.value.replace(
|
||
|
|
/[^0-9.]/g,
|
||
|
|
''
|
||
|
|
); // Remove invalid characters
|
||
|
|
const parts = cleanedValue.split('.');
|
||
|
|
|
||
|
|
if (cleanedValue.startsWith('.')) {
|
||
|
|
cleanedValue = '0' + cleanedValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
e.target.value =
|
||
|
|
parts.length > 2
|
||
|
|
? `${parts[0]}.${parts.slice(1).join('')}`
|
||
|
|
: cleanedValue;
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
</Form.Item>
|
||
|
|
|
||
|
|
)}
|
||
|
|
{SlotChangeType == 'individual' ?
|
||
|
|
<Button
|
||
|
|
className="slot-management__apply-price-btn"
|
||
|
|
onClick={() => {
|
||
|
|
// Apply newPrice to all selected slots
|
||
|
|
const updated = { ...slotPrices };
|
||
|
|
selectedSlots.forEach(slot => {
|
||
|
|
updated[slot] = {
|
||
|
|
...updated[slot],
|
||
|
|
fullSlotPrice: Number(newPrice) || 0,
|
||
|
|
individualPrice:
|
||
|
|
individualDefaultPrice !== undefined && individualDefaultPrice !== null && individualDefaultPrice !== ''
|
||
|
|
? Number(individualDefaultPrice)
|
||
|
|
: updated[slot]?.individualPrice || 0
|
||
|
|
};
|
||
|
|
});
|
||
|
|
setSlotPrices(updated);
|
||
|
|
}}
|
||
|
|
disabled={!newPrice}
|
||
|
|
>
|
||
|
|
Apply Price
|
||
|
|
</Button>
|
||
|
|
: ''
|
||
|
|
}
|
||
|
|
</div>
|
||
|
|
{/* Individual Slot Price Table */}
|
||
|
|
{shouldShowIndividualSlotPriceTable() && (
|
||
|
|
<div style={{ marginTop: '16px' }}>
|
||
|
|
<Divider orientation="left">
|
||
|
|
Individual Slot Prices ({selectedSlots.length} slots selected)
|
||
|
|
</Divider>
|
||
|
|
{/* <div style={{ marginBottom: '12px' }}>
|
||
|
|
<Button
|
||
|
|
type="dashed"
|
||
|
|
onClick={applyBasePriceToAllSlots}
|
||
|
|
icon={<EditOutlined />}
|
||
|
|
size="small"
|
||
|
|
>
|
||
|
|
Apply Base Price to All Selected Slots
|
||
|
|
</Button>
|
||
|
|
<span style={{ marginLeft: '12px', color: '#666', fontSize: '12px' }}>
|
||
|
|
Base Price: ₹{newPrice || 0}
|
||
|
|
</span>
|
||
|
|
</div> */}
|
||
|
|
{/* <Table
|
||
|
|
columns={individualSlotPriceColumns}
|
||
|
|
dataSource={selectedSlots.map(slot => ({ slot }))}
|
||
|
|
pagination={{ pageSize: 10 }}
|
||
|
|
rowKey="slot"
|
||
|
|
size="small"
|
||
|
|
scroll={{ x: 600 }}
|
||
|
|
/> */}
|
||
|
|
<Table
|
||
|
|
columns={slotPriceColumns}
|
||
|
|
// dataSource={selectedSlots.map(slot => ({ slot }))}
|
||
|
|
dataSource={selectedSlots.map(slotId => {
|
||
|
|
const slotObj = Slots.find(s => s.ProdInwardDtlId === slotId);
|
||
|
|
return {
|
||
|
|
slot: slotId,
|
||
|
|
time: slotObj ? `${to12Hour(slotObj.AvailableFrom)} - ${to12Hour(slotObj.AvailableTo)}` : ''
|
||
|
|
};
|
||
|
|
})}
|
||
|
|
pagination={{ pageSize: 10 }}
|
||
|
|
rowKey="slot"
|
||
|
|
size="small"
|
||
|
|
scroll={{ x: 600 }}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Action Summary */}
|
||
|
|
{(actionMode && closureType && dateRange?.length > 0) && (
|
||
|
|
<Card
|
||
|
|
title="Action Summary"
|
||
|
|
style={{ marginBottom: 20 }}
|
||
|
|
type="inner"
|
||
|
|
>
|
||
|
|
<Row gutter={16}>
|
||
|
|
<Col xs={24} md={4}>
|
||
|
|
<div style={{ textAlign: 'center' }}>
|
||
|
|
<div style={{ fontSize: '12px', color: '#666' }}>Slot Action</div>
|
||
|
|
<div style={{ fontSize: '14px', fontWeight: 'bold', color: '#1890ff' }}>
|
||
|
|
{getActionModeText()}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</Col>
|
||
|
|
<Col xs={24} md={4}>
|
||
|
|
<div style={{ textAlign: 'center' }}>
|
||
|
|
<div style={{ fontSize: '12px', color: '#666' }}>Activity Type</div>
|
||
|
|
<div style={{ fontSize: '14px', fontWeight: 'bold', color: '#52c41a' }}>
|
||
|
|
{getClosureTypeText()}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</Col>
|
||
|
|
<Col xs={24} md={4}>
|
||
|
|
<div style={{ textAlign: 'center' }}>
|
||
|
|
<div style={{ fontSize: '12px', color: '#666' }}>Category</div>
|
||
|
|
<div style={{ fontSize: '14px', fontWeight: 'bold', color: '#fa8c16' }}>
|
||
|
|
{selectedCategory ? CategoriesData?.find(c => c.ProdCat === selectedCategory)?.ProdCatName : '-'}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</Col>
|
||
|
|
<Col xs={24} md={4}>
|
||
|
|
<div style={{ textAlign: 'center' }}>
|
||
|
|
<div style={{ fontSize: '12px', color: '#666' }}>Sub Category</div>
|
||
|
|
<div style={{ fontSize: '14px', fontWeight: 'bold', color: '#eb2f96' }}>
|
||
|
|
{selectedSubCategory ? SubCategoriesData?.find(s => s.ProdSubCat === selectedSubCategory)?.ProdSubCatName : '-'}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</Col>
|
||
|
|
<Col xs={24} md={4}>
|
||
|
|
<div style={{ textAlign: 'center' }}>
|
||
|
|
<div style={{ fontSize: '12px', color: '#666' }}>Date Range</div>
|
||
|
|
<div style={{ fontSize: '14px', fontWeight: 'bold', color: '#722ed1' }}>
|
||
|
|
{dateRange[0]?.format('DD-MMM-YY')} - {dateRange[1]?.format('DD-MMM-YY')}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</Col>
|
||
|
|
|
||
|
|
</Row>
|
||
|
|
|
||
|
|
{shouldShowDaySelection() && (
|
||
|
|
<div style={{ marginTop: '26px', textAlign: 'left' }}>
|
||
|
|
<div style={{ fontSize: '14px', color: '#666' }}>
|
||
|
|
<strong>Days:</strong> {getSelectedDaysText()}
|
||
|
|
</div>
|
||
|
|
{shouldShowTimeSlotSelection() && (
|
||
|
|
<div style={{ fontSize: '14px', color: '#666' }}>
|
||
|
|
<strong>Time Slots:</strong> {selectedSlots.length} selected
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{actionMode === 'block' && closureReason && (
|
||
|
|
<div style={{ marginTop: '12px', textAlign: 'left' }}>
|
||
|
|
<div style={{ fontSize: '14px', color: '#666' }}>
|
||
|
|
<strong>Reason:</strong> {closureReason}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* {actionMode === 'priceChange' && (
|
||
|
|
<div style={{ marginTop: '12px', textAlign: 'left' }}>
|
||
|
|
<div style={{ fontSize: '14px', color: '#666' }}>
|
||
|
|
<strong>Price Type:</strong> {priceChangeType === 'individual' ? 'Individual Slots' : 'Full Day'}
|
||
|
|
</div>
|
||
|
|
{priceChangeType === 'full' && (
|
||
|
|
<div style={{ fontSize: '14px', color: '#666' }}>
|
||
|
|
<strong>Price:</strong> ₹{newPrice}
|
||
|
|
{weekendPremium && (
|
||
|
|
<span style={{ marginLeft: '12px' }}>
|
||
|
|
<strong>Weekend Price:</strong> ₹{weekendPrice}
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
{priceChangeType === 'individual' && (
|
||
|
|
<div style={{ fontSize: '14px', color: '#666' }}>
|
||
|
|
<strong>Individual Prices Set for:</strong> {selectedSlots.length} slots
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)} */}
|
||
|
|
</Card>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Apply Action Button */}
|
||
|
|
<Form.Item>
|
||
|
|
<Buttons
|
||
|
|
buttonText={`Apply ${getActionModeText()}`}
|
||
|
|
disabled={!actionMode || !closureType || !dateRange || dateRange.length === 0}
|
||
|
|
handleSubmit={() => applyManagementAction()}
|
||
|
|
color="901D77"
|
||
|
|
icon={<ArrowRightOutlined />}
|
||
|
|
/>
|
||
|
|
{/* <Buttons
|
||
|
|
type="primary"
|
||
|
|
onClick={applyManagementAction}
|
||
|
|
size="large"
|
||
|
|
icon={< />}
|
||
|
|
disabled={!actionMode || !closureType || !dateRange || dateRange.length === 0}
|
||
|
|
style={{
|
||
|
|
height: '50px',
|
||
|
|
fontSize: '16px',
|
||
|
|
padding: '0 30px'
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
Apply {getActionModeText()}
|
||
|
|
</Buttons> */}
|
||
|
|
</Form.Item>
|
||
|
|
</Form>
|
||
|
|
|
||
|
|
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default SlotManagementForm;
|