501 lines
19 KiB
JavaScript
501 lines
19 KiB
JavaScript
import { useCallback, useEffect, useState } from 'react';
|
|
import {
|
|
Crown,
|
|
X,
|
|
Calendar,
|
|
Star,
|
|
Zap,
|
|
ChevronDown,
|
|
ChevronUp,
|
|
CrownIcon,
|
|
} from 'lucide-react';
|
|
import './BSMembership.scss';
|
|
import {
|
|
createMembershipSubscription,
|
|
getMembership,
|
|
} from '../../../../Features/Membership/Membership';
|
|
import { getSession } from '../../../../Services/Others';
|
|
import { useDispatch } from 'react-redux';
|
|
import SubscribeMembershipModal from './SubscribeMembershipModal';
|
|
import { getAllCustomer } from '../../../../Features/BookingScreen/BookingData/BookingData';
|
|
import {
|
|
getAddCustomerDetails,
|
|
GlobalCustomerRefreshTrigger,
|
|
triggerCustomerRefresh,
|
|
} from '../../../../Features/BookingScreen/Customer/addCustomer';
|
|
import { Messages } from '../../../../Components/Notifications/Messages';
|
|
import { Tooltip } from 'antd';
|
|
import { useSelector } from 'react-redux';
|
|
import {
|
|
changeMembershipNumber,
|
|
changeSelfBookingCustomerDtls,
|
|
GlobalMembershipDetail,
|
|
GlobalSelfBookingCustomerDtls,
|
|
PostSelfBookingCustomer,
|
|
} from '../../../../Features/BookingScreen/BookingData/KioskBookingData';
|
|
import { DefaultModal } from '../../../../Components/Modal/DefaultModal';
|
|
import { ArrowRightOutlined } from '@ant-design/icons';
|
|
const BSMembership = ({ modelOpen = false, setMemberShipOpen, drawerOpen = false, setDrawerOpen = () => { } }) => {
|
|
const dispatch = useDispatch();
|
|
|
|
const AppId = getSession('AppId');
|
|
const CompId = getSession('CompId');
|
|
const BranchId = getSession('BranchId');
|
|
const UserId = getSession('UserId');
|
|
const AppName = sessionStorage.getItem('AppName');
|
|
const MembershipDetail = useSelector(
|
|
GlobalMembershipDetail
|
|
)?.MembershipDetail;
|
|
const customerRefreshTrigger = useSelector(GlobalCustomerRefreshTrigger);
|
|
const [showUserModal, setShowUserModal] = useState(false);
|
|
const [isOpen, setIsOpen] = useState(modelOpen);
|
|
const [expandedMembership, setExpandedMembership] = useState(null);
|
|
const [membershipData, setMembershipData] = useState([]);
|
|
const [messageType, setMessageType] = useState(null);
|
|
const [messageData, setMessageData] = useState(null);
|
|
const [subscribeModalVisible, setSubscribeModalVisible] = useState(false);
|
|
const [selectedPlan, setSelectedPlan] = useState(null);
|
|
const [selectedMembership, setSelectedMembership] = useState(null);
|
|
const CustomerDetails = useSelector(GlobalSelfBookingCustomerDtls);
|
|
// These should come from your Redux store or API
|
|
const [customers, setCustomers] = useState([]);
|
|
const [userNumber, setUserNumber] = useState('');
|
|
const [paymentModes, setPaymentModes] = useState([]);
|
|
|
|
useEffect(() => {
|
|
fetchMembershipData();
|
|
getCustomerData();
|
|
}, [customerRefreshTrigger]);
|
|
|
|
const getCustomerData = async () => {
|
|
const res = await dispatch(
|
|
getAllCustomer({ CompId: CompId, AppId: AppId, branchId: BranchId })
|
|
)?.unwrap();
|
|
if (res?.data?.statusCode === 1) {
|
|
setCustomers(res?.data?.data);
|
|
}
|
|
await dispatch(
|
|
getAddCustomerDetails({
|
|
CompId: CompId,
|
|
AppId: AppId,
|
|
branchId: BranchId,
|
|
})
|
|
);
|
|
};
|
|
|
|
const fetchMembershipData = async () => {
|
|
const data = {
|
|
AppId: AppId,
|
|
CompId: CompId,
|
|
BranchId: BranchId,
|
|
ActiveStatus: 'A',
|
|
};
|
|
const res = await dispatch(getMembership(data)).unwrap();
|
|
if (res?.data?.statusCode === 1) {
|
|
setMembershipData(res?.data?.data);
|
|
} else {
|
|
setMembershipData([]);
|
|
}
|
|
};
|
|
|
|
const toggleMembership = (membershipId) => {
|
|
setExpandedMembership((prev) =>
|
|
prev === membershipId ? null : membershipId
|
|
);
|
|
};
|
|
|
|
const calculateFinalPrice = (plan) => {
|
|
let price = plan.DisplayPrice || 0;
|
|
if (plan.Discount > 0) {
|
|
if (plan.DiscountType === 'F') {
|
|
price -= plan.Discount;
|
|
} else if (plan.DiscountType === 'P') {
|
|
price -= (price * plan.Discount) / 100;
|
|
}
|
|
}
|
|
return price + (plan.TaxAmount || 0);
|
|
};
|
|
|
|
const getIcon = (priority) => {
|
|
if (priority === 'Y') return Zap;
|
|
if (priority === 'N') return Star;
|
|
return Calendar;
|
|
};
|
|
|
|
const handleSubscribeClick = (plan, membership) => {
|
|
setSelectedPlan(plan);
|
|
setSelectedMembership(membership);
|
|
setSubscribeModalVisible(true);
|
|
};
|
|
|
|
const handleSubscribe = async (payload) => {
|
|
try {
|
|
const response = await dispatch(
|
|
createMembershipSubscription(payload)
|
|
).unwrap();
|
|
if (response?.data?.statusCode === 1) {
|
|
setSubscribeModalVisible(false);
|
|
setMessageType('success');
|
|
setMessageData('Membership subscribed successfully!');
|
|
dispatch(triggerCustomerRefresh());
|
|
} else {
|
|
setMessageType('error');
|
|
setMessageData('Failed to subscribe membership');
|
|
}
|
|
console.log('Subscription Payload:', payload);
|
|
} catch (error) {
|
|
console.error('Subscription error:', error);
|
|
}
|
|
};
|
|
|
|
const onComplete = useCallback(() => {
|
|
setMessageData(null);
|
|
setMessageType(null);
|
|
}, []);
|
|
const handlePostCustnumber = async () => {
|
|
try {
|
|
let response = await dispatch(
|
|
PostSelfBookingCustomer({
|
|
CompId: CompId,
|
|
BranchId: BranchId,
|
|
AppId: AppId,
|
|
CustMobile: userNumber,
|
|
})
|
|
).unwrap();
|
|
if (response?.data?.statusCode == 1 || response?.data?.statusCode == 2) {
|
|
dispatch(
|
|
changeSelfBookingCustomerDtls(response?.data?.CustomerDetails?.[0])
|
|
);
|
|
setShowUserModal(false);
|
|
setIsOpen(true);
|
|
} else {
|
|
dispatch(changeSelfBookingCustomerDtls(null));
|
|
}
|
|
} catch (error) {
|
|
console.log(error);
|
|
}
|
|
};
|
|
|
|
// if (!CustomerDetails && AppName?.toLowerCase() == "sports") {
|
|
// return (
|
|
// <div onClick={() => {
|
|
|
|
// if (!CustomerDetails) setShowUserModal(true)
|
|
// else setIsOpen(true)
|
|
|
|
// }}> <CrownIcon color="#f16d00ff" size={32} />
|
|
|
|
// <DefaultModal
|
|
// open={showUserModal}
|
|
// title="Enter Your Number"
|
|
// handleCancel={(e) => {
|
|
// e?.stopPropagation?.()
|
|
// setShowUserModal(false);
|
|
// setUserNumber('');
|
|
// }}
|
|
// footer={false}
|
|
// handleSubmit={handlePostCustnumber}
|
|
// okText="Save"
|
|
// width={400}
|
|
// children={
|
|
// <div style={{ padding: '20px' }}>
|
|
// <input
|
|
// type="text"
|
|
// value={userNumber}
|
|
// onChange={(e) => {
|
|
// const value = e.target.value;
|
|
// // Allow only numbers and max 10 digits
|
|
// if (/^\d{0,10}$/.test(value)) {
|
|
// setUserNumber(value);
|
|
// dispatch(changeMembershipNumber(value))
|
|
// }
|
|
// }}
|
|
// placeholder="Enter user number"
|
|
// style={{
|
|
// width: '100%',
|
|
// padding: '8px',
|
|
// borderRadius: '4px',
|
|
// border: '1px solid #d9d9d9'
|
|
// }}
|
|
// maxLength={10}
|
|
// />
|
|
// {userNumber.length > 0 && userNumber.length < 10 && (
|
|
// <p style={{ color: 'red', marginTop: '8px', fontSize: '12px' }}>
|
|
// Number must be 10 digits
|
|
// </p>
|
|
// )}
|
|
// <div style={{ display: 'flex', flexDirection: "row-reverse", paddingTop: "10px" }}>
|
|
// <button
|
|
// onClick={handlePostCustnumber}
|
|
// disabled={userNumber.length !== 10}
|
|
// style={{
|
|
// backgroundColor: userNumber.length === 10 ? '#901D77' : '#ccc',
|
|
// color: 'white',
|
|
// border: 'none',
|
|
// borderRadius: '6px',
|
|
// padding: '10px 16px',
|
|
// display: 'flex',
|
|
// alignItems: 'center',
|
|
// justifyContent: 'center',
|
|
// gap: '8px',
|
|
// cursor: userNumber.length === 10 ? 'pointer' : 'not-allowed',
|
|
// transition: 'all 0.2s ease-in-out',
|
|
// textTransform: 'uppercase',
|
|
// }}
|
|
// >
|
|
// Submit <ArrowRightOutlined />
|
|
// </button>
|
|
|
|
// </div>
|
|
// </div>
|
|
// }
|
|
// /></div>
|
|
// )
|
|
// }
|
|
|
|
useEffect(() => {
|
|
if (drawerOpen?.membership) {
|
|
setIsOpen(true);
|
|
setDrawerOpen(prev => ({ ...prev, membership: false }));
|
|
}
|
|
}, [drawerOpen?.membership])
|
|
|
|
return (
|
|
<>
|
|
<Messages
|
|
messageType={messageType}
|
|
messageData={messageData}
|
|
onComplete={onComplete}
|
|
/>
|
|
{/* Membership Icon Button */}
|
|
{membershipData?.length > 0 && AppName?.toLowerCase() !== 'sports' && (
|
|
<Tooltip
|
|
title="Membership"
|
|
placement="bottom"
|
|
children={
|
|
<button
|
|
onClick={() => setIsOpen(true)}
|
|
className="bs-membership__icon-btn"
|
|
aria-label="Buy Membership"
|
|
>
|
|
<Crown
|
|
size={23}
|
|
// color="#fbbf24"
|
|
style={{
|
|
display: 'flex',
|
|
cursor: 'pointer',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
}}
|
|
/>
|
|
</button>
|
|
}
|
|
/>
|
|
)}
|
|
|
|
{/* Overlay */}
|
|
{isOpen && (
|
|
<div
|
|
className="bs-membership__overlay"
|
|
onClick={() => setIsOpen(false)}
|
|
/>
|
|
)}
|
|
|
|
{/* Drawer */}
|
|
<div
|
|
className={`bs-membership__drawer ${isOpen ? 'bs-membership__drawer--open' : ''}`}
|
|
>
|
|
<div className="bs-membership__drawer-content">
|
|
{/* Header */}
|
|
<div className="bs-membership__header">
|
|
<div className="bs-membership__header-title">
|
|
<Crown size={32} />
|
|
<h2>Memberships</h2>
|
|
</div>
|
|
<button
|
|
onClick={() => {
|
|
(setIsOpen(false), setMemberShipOpen(false));
|
|
}}
|
|
className="bs-membership__close-btn"
|
|
aria-label="Close"
|
|
>
|
|
<X size={24} />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div className="bs-membership__content">
|
|
<div className="bs-membership__list">
|
|
{membershipData.map((membership) => {
|
|
const isExpanded =
|
|
expandedMembership === membership.MembershipId;
|
|
const gradientClass = `bs-membership__membership-header--${membership.MembershipName.toLowerCase()}`;
|
|
return (
|
|
<div
|
|
key={membership.UniqueId}
|
|
className="bs-membership__membership"
|
|
>
|
|
{/* Membership Header */}
|
|
<button
|
|
onClick={() => toggleMembership(membership.MembershipId)}
|
|
className={`bs-membership__membership-header ${gradientClass}`}
|
|
>
|
|
<div className="bs-membership__membership-header-left">
|
|
<Crown size={24} />
|
|
<div className="membershiplength">
|
|
<h3>{membership.MembershipName}</h3>
|
|
<p>
|
|
{membership.MembershipPlanDtl.length}{' '}
|
|
{membership.MembershipPlanDtl.length === 1
|
|
? 'Plan'
|
|
: 'Plans'}{' '}
|
|
Available
|
|
</p>
|
|
</div>
|
|
</div>
|
|
{isExpanded ? (
|
|
<ChevronUp size={20} />
|
|
) : (
|
|
<ChevronDown size={20} />
|
|
)}
|
|
</button>
|
|
|
|
{/* Plans (Expandable) */}
|
|
{isExpanded && (
|
|
<div className="bs-membership__plans">
|
|
{membership.MembershipPlanDtl.map((plan, index) => {
|
|
const IconComponent = getIcon(plan.Priority);
|
|
const planGradientClass = `bs-membership__plan--${plan.Priority === 'Y' ? 'priority' : `color${index % 4}`}`;
|
|
const finalPrice = calculateFinalPrice(plan);
|
|
|
|
return (
|
|
<div
|
|
key={plan.UniqueId}
|
|
className={`bs-membership__plan ${planGradientClass}`}
|
|
>
|
|
{plan.Priority === 'Y' && (
|
|
<span className="bs-membership__plan-priority">
|
|
<Zap size={10} />
|
|
Priority
|
|
</span>
|
|
)}
|
|
|
|
<div className="bs-membership__plan-top">
|
|
<div className="bs-membership__plan-top-left">
|
|
<div className="bs-membership__plan-icon">
|
|
<IconComponent size={16} />
|
|
</div>
|
|
<div>
|
|
<h4>{plan.PlanDuration} Days</h4>
|
|
<p>
|
|
{plan.Priority === 'Y'
|
|
? 'Priority Access'
|
|
: 'Standard'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="bs-membership__plan-top-right">
|
|
{plan.Discount > 0 && (
|
|
<div className="bs-membership__plan-price-strike">
|
|
₹{plan.Price}
|
|
</div>
|
|
)}
|
|
<span className="bs-membership__plan-price">
|
|
₹
|
|
{(
|
|
plan.DisplayPrice - (plan.TaxAmount || 0)
|
|
).toFixed(2)}
|
|
</span>
|
|
{plan.TaxAmount > 0 && (
|
|
<div className="bs-membership__plan-tax">
|
|
+₹{plan.TaxAmount} tax
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<ul className="bs-membership__plan-features">
|
|
<li>
|
|
<span className="bs-membership__plan-feature-check">
|
|
✓
|
|
</span>
|
|
<span>
|
|
{plan.FreeSessionHrs} Free Session Hours
|
|
</span>
|
|
</li>
|
|
{plan.Discount > 0 && (
|
|
<li>
|
|
<span className="bs-membership__plan-feature-check">
|
|
✓
|
|
</span>
|
|
<span>
|
|
Save{' '}
|
|
{plan.DiscountType === 'F'
|
|
? `₹${plan.Discount}`
|
|
: `${plan.Discount}%`}{' '}
|
|
after free sessions.
|
|
</span>
|
|
</li>
|
|
)}
|
|
{plan.Priority === 'Y' &&
|
|
plan.Prioritydays.length > 0 && (
|
|
<li>
|
|
<span className="bs-membership__plan-feature-check">
|
|
✓
|
|
</span>
|
|
<span>
|
|
Priority:{' '}
|
|
{plan.Prioritydays?.[0]
|
|
?.split?.(',')
|
|
.join(', ')}
|
|
</span>
|
|
</li>
|
|
)}
|
|
</ul>
|
|
|
|
{plan.Remarks && plan.Remarks.trim() && (
|
|
<div className="bs-membership__plan-remarks">
|
|
{plan.Remarks}
|
|
</div>
|
|
)}
|
|
|
|
<button
|
|
className="bs-membership__plan-btn"
|
|
onClick={() =>
|
|
handleSubscribeClick(plan, membership)
|
|
}
|
|
>
|
|
Subscribe Now
|
|
</button>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Footer */}
|
|
<div className="bs-membership__footer">
|
|
<p>Cancel anytime. No hidden fees.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<SubscribeMembershipModal
|
|
visible={subscribeModalVisible}
|
|
onClose={() => setSubscribeModalVisible(false)}
|
|
plan={selectedPlan}
|
|
membership={selectedMembership}
|
|
customers={customers}
|
|
paymentModes={paymentModes}
|
|
onSubscribe={handleSubscribe}
|
|
/>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default BSMembership;
|