PozoAppOptimUpdated/src/check.jsx

599 lines
17 KiB
React
Raw Normal View History

2025-11-05 17:52:07 +05:30
import { useEffect, useState, useRef } from 'react';
import './MembershipCard.scss';
import { useDispatch } from 'react-redux';
import { useSelector } from 'react-redux';
import { StoredSessionData } from '../../../../Features/ThemeChange/ThemeChange';
import { getBranchDetail, getCompBranchData } from '../../../../Features/BrachLogin/BranchLogin';
import { Button, Input, Modal, message } from 'antd';
import { PrinterOutlined, ShareAltOutlined } from '@ant-design/icons';
import html2canvas from 'html2canvas';
import { FcSportsMode } from "react-icons/fc";
import defaultuser from "../../../../Images/dashboard/user.jpg";
import { printDiv } from '../../../../Services/Others';
function safeNumber(v) {
const n = Number(v);
return Number.isFinite(n) ? n : 0;
}
function getCurrentMembership(memberships) {
if (!memberships?.length) return null;
const sorted = [...memberships].sort(
(a, b) => new Date(a.CreatedDate) - new Date(b.CreatedDate)
);
const active = sorted.find(
(m) => m.RemainingDays > 0 || m.RemainingSessionHrs > 0
);
if (active) return active;
const now = new Date();
const next = sorted.find((m) => new Date(m.CreatedDate) > now);
return next || null;
}
function formatAadhaar(aadhaar) {
if (!aadhaar) return '';
const str = String(aadhaar);
if (str.length <= 4) return str;
const lastFour = str.slice(-4);
const masked = 'X'.repeat(str.length - 4);
return `${masked}${lastFour}`;
}
function formatDate(dateStr) {
if (!dateStr) return '';
const date = new Date(dateStr);
const day = String(date.getDate()).padStart(2, '0');
const month = date.toLocaleString('en-US', { month: 'short' });
const year = date.getFullYear();
return `${day} ${month} ${year}`;
}
const MembershipCard = ({ MembershipDetail = [], selectedCustomer = {}, showCard = false }) => {
const dispatch = useDispatch();
const SessionData = useSelector(StoredSessionData);
const AppId = SessionData?.AppId;
const CompId = SessionData?.CompId;
const BranchId = SessionData?.BranchId;
const UserId = SessionData?.UserId;
console.log(selectedCustomer, "selectedCustomer")
const [activeMembership, setActiveMembership] = useState(null);
const [branchName, setBranchName] = useState('Guest');
const [branchLogo, setBranchLogo] = useState(null);
const [emailModalVisible, setEmailModalVisible] = useState(false);
const [emailInput, setEmailInput] = useState('');
const [base64Image, setBase64Image] = useState(null);
const [base64CustImage, setBase64CustImage] = useState(null);
const cardRef = useRef(null);
const duration = safeNumber(activeMembership?.PlanDuration);
const remaining = safeNumber(activeMembership?.RemainingDays);
const usedDays = Math.max(0, duration - remaining);
const daysPct = duration > 0 ? Math.round((usedDays / duration) * 100) : 0;
const freeHrs = safeNumber(activeMembership?.FreeSessionHrs);
const remainingHrs = safeNumber(activeMembership?.RemainingSessionHrs);
const usedHrs = Math.max(0, freeHrs - remainingHrs);
const hrsPct = freeHrs > 0 ? Math.round((usedHrs / freeHrs) * 100) : 0;
const discountLabel = `${activeMembership?.Discount}${activeMembership?.DiscountType === 'P' ? '%' : ''}`;
useEffect(() => {
if (MembershipDetail?.length === 0) return;
const currentActiveMembership = getCurrentMembership(MembershipDetail);
if (currentActiveMembership) {
setActiveMembership(currentActiveMembership);
} else {
setActiveMembership(null);
}
fetchBranchDtls();
}, [MembershipDetail]);
const fetchBranchDtls = async () => {
const response = await dispatch(
getBranchDetail({ BrId: BranchId })
).unwrap();
if (response?.data?.statusCode === 1) {
setBranchName(
response?.data?.data?.filter((item) => item?.BrId == BranchId)?.[0]?.BrName || 'Guest'
);
setBranchLogo(
response?.data?.data?.filter((item) => item?.BrId == BranchId)?.[0]?.CompLogo || 'Guest'
);
}
};
useEffect(() => {
async function fetchImage() {
try {
const base64 = await imageUrlToBase64(branchLogo);
setBase64Image(base64);
} catch (error) {
console.log('Error converting image', error.message);
}
}
if (branchLogo) {
fetchImage();
}
}, [branchLogo]);
useEffect(() => {
async function fetchCustomerImage() {
try {
const base64 = await imageUrlToBase64(selectedCustomer?.CustomerProfile);
setBase64CustImage(base64);
} catch (error) {
console.log('Error converting image', error.message);
}
}
if (selectedCustomer?.CustomerProfile) {
fetchCustomerImage();
}
}, [selectedCustomer?.CustomerProfile])
const imageUrlToBase64 = async (url) => {
try {
const response = await fetch(url);
const blob = await response.blob();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
} catch (error) {
console.error('Error fetching or converting image:', error);
throw error;
}
};
const handlePrint = async () => {
if (!cardRef.current) return;
const style = `
<style>
.membershipCardContainer {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: 20px;
}
.physicalMembershipCard {
font-family: 'Poppins' !important;
width: 340px;
height: 225px;
background-image: linear-gradient(to top, #1e3c72 0%, #1e3c72 1%, #2a5298 100%);
border-radius: 16px;
padding: 20px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
color: white;
position: relative;
overflow: hidden;
}
.physicalMembershipCard::before {
content: '';
position: absolute;
top: -50%;
right: -20%;
width: 200px;
height: 200px;
background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
border-radius: 50%;
}
.cardHeader {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 16px;
}
.cardLogo {
display: flex;
align-items: center;
gap: 8px;
}
.logoIcon {
background: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
padding: 5px;
}
.brandName {
font-size: 14px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.priorityBadge {
background-color: #ff9800;
padding: 4px 12px;
border-radius: 12px;
font-size: 10px;
font-weight: 700;
letter-spacing: 0.5px;
}
.priorityBadge span {
color: #fff;
}
.cardMemberName {
font-size: 20px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 4px;
}
.cardMemberId {
font-size: 11px;
opacity: 0.9;
margin-bottom: 12px;
}
.cardDates {
display: flex;
gap: 24px;
margin-bottom: 12px;
font-size: 11px;
}
.dateGroup .dateLabel {
opacity: 0.8;
font-size: 9px;
margin-bottom: 2px;
}
.dateGroup .dateValue {
font-weight: 600;
font-size: 11px;
}
.cardInfo {
margin-bottom: 12px;
}
.infoRow {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
font-size: 11px;
}
.infoLabel {
opacity: 0.8;
font-size: 9px;
}
.infoValue {
font-weight: 600;
}
.membership-name {
position: absolute;
right: 20px;
top: 42px;
background-color: #019b01;
padding: 4px 12px;
border-radius: 12px;
font-size: 13px;
font-weight: 600;
letter-spacing: 0.3px;
}
.cardFooter {
position: absolute;
bottom: 22%;
right: 24px;
}
.user-profile img {
border-radius: 6px;
}
.cardActions {
display: flex;
gap: 12px;
justify-content: center;
}
.cardActions button {
min-width: 120px;
}
@media (max-width: 420px) {
.physicalMembershipCard {
width: 300px;
height: 190px;
padding: 16px;
}
.logoIcon {
width: 28px;
height: 28px;
font-size: 16px;
}
.brandName {
font-size: 12px;
}
.cardMemberName {
font-size: 18px;
}
.cardMemberId {
font-size: 10px;
}
.cardDates {
gap: 16px;
font-size: 10px;
}
.dateGroup .dateLabel {
font-size: 8px;
}
.dateGroup .dateValue {
font-size: 10px;
}
.infoRow {
font-size: 10px;
}
.infoLabel {
font-size: 8px;
}
.cardActions {
flex-direction: column;
}
.cardActions button {
width: 100%;
}
}
</style>
`;
const printStyles = document.createElement('style');
printStyles.innerHTML = `
@page { size: A4; margin: 0.5in; }
@media print {
* { -webkit-print-color-adjust: exact !important; }
body * { visibility: hidden; }
#physicalMembershipCard, #physicalMembershipCard * { visibility: visible; }
#physicalMembershipCard {
position: absolute !important;
left: 0 !important;
top: 0 !important;
width: 340px !important;
height: 225px !important;
background: linear-gradient(to top, #1e3c72 0%, #2a5298 100%) !important;
border-radius: 16px !important;
padding: 20px !important;
color: white !important;
font-family: Arial, sans-serif !important;
box-shadow: none !important;
}
.cardHeader { display: flex !important; justify-content: space-between !important; }
.cardLogo { display: flex !important; align-items: center !important; gap: 8px !important; }
.logoIcon { background: white !important; border-radius: 50% !important; padding: 5px !important; }
.brandName { font-size: 14px !important; font-weight: 700 !important; }
.priorityBadge { background: #ff9800 !important; padding: 4px 12px !important; border-radius: 12px !important; }
.membership-name { position: absolute !important; right: 20px !important; top: 42px !important; background: #019b01 !important; padding: 4px 12px !important; border-radius: 12px !important; }
.cardMemberName { font-size: 20px !important; font-weight: 700 !important; }
.cardDates { display: flex !important; gap: 24px !important; }
.cardFooter { position: absolute !important; bottom: 22% !important; right: 24px !important; }
}
`;
document.head.appendChild(printStyles);
window.print();
document.head.removeChild(printStyles);
};
const handleShare = () => {
if (selectedCustomer?.CustEmail) {
shareCard(selectedCustomer.CustEmail);
} else {
setEmailModalVisible(true);
}
};
const shareCard = async (email) => {
try {
// Your API call here
// await dispatch(shareCardAction({ email, cardData: ... })).unwrap();
message.success(`Card shared successfully to ${email}`);
setEmailModalVisible(false);
setEmailInput('');
} catch (error) {
message.error('Failed to share card');
}
};
const handleEmailSubmit = () => {
if (!emailInput || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailInput)) {
message.error('Please enter a valid email address');
return;
}
shareCard(emailInput);
};
if (!showCard) {
// Original membership details view
return (
<div className="memberShipCard" role="region" aria-label={`${activeMembership?.MemberName} membership card`}>
<div className="memberShipHeader">
<div className="memberShipTitle">{activeMembership?.MemberName || '-'}</div>
<div className="memberShipRemark">{activeMembership?.Remarks || ''}</div>
</div>
<div className="memberShipBody">
<div className="memberShipInfoRow">
<div className="memberShipLabel">Duration</div>
<div className="memberShipValue">{duration} days</div>
</div>
<div className="memberShipProgressGroup">
<div className="memberShipSmallLabel">Remaining</div>
<div className="memberShipProgressBar">
<div className="memberShipProgress" style={{ width: `${Math.max(0, 100 - daysPct)}%` }} />
</div>
<div className="memberShipSmallValue">{remaining}d left</div>
</div>
<div className="memberShipInfoRow">
<div className="memberShipLabel">Free Hrs</div>
<div className="memberShipValue">{freeHrs} hrs</div>
</div>
<div className="memberShipProgressGroup">
<div className="memberShipSmallLabel">Sessions left</div>
<div className="memberShipProgressBar">
<div className="memberShipProgress" style={{ width: `${Math.max(0, 100 - hrsPct)}%` }} />
</div>
<div className="memberShipSmallValue">{remainingHrs}h</div>
</div>
<div className="memberShipGridRow">
<div>
<div className="memberShipGridLabel">Discount</div>
<div className="memberShipGridValue">{discountLabel}</div>
</div>
<div>
<div className="memberShipGridLabel">Priority</div>
<div className="memberShipGridValue">{activeMembership?.Priority === 'Y' ? 'Yes' : 'No'}</div>
</div>
</div>
</div>
{activeMembership?.Priority === 'Y' && (
<div className="memberShipFooter">
<div className="memberShipPriorityDays" title={activeMembership?.Prioritydays}>
{activeMembership?.Prioritydays || '-'}
</div>
</div>
)}
</div>
);
}
// Card view
return (
<div className="membershipCardContainer">
<div ref={cardRef} id='physicalMembershipCard' className="physicalMembershipCard">
<div className="cardHeader">
<div className="cardLogo">
<div className="logoIcon">
{base64Image ? <img src={base64Image} alt="Branch Logo" height={"30"} width={"30"} /> : <FcSportsMode size={25} />}
</div>
<span className="brandName">{branchName}</span>
</div>
{activeMembership?.Priority === 'Y' && (
<div className="priorityBadge">
<span>PRIORITY</span>
</div>
)}
<div className='membership-name'>
{activeMembership?.MemberName}
</div>
</div>
<div className="cardMemberName">{selectedCustomer?.CustName || 'Member'}</div>
<div className="cardMemberId">ID: {selectedCustomer?.CustId || '-'}</div>
<div className="cardDates">
<div className="dateGroup">
<div className="dateLabel">VALID FROM</div>
<div className="dateValue">{formatDate(activeMembership?.PlanStartDate)}</div>
</div>
<div className="dateGroup">
<div className="dateLabel">VALID UNTIL</div>
<div className="dateValue">{formatDate(activeMembership?.PlanEndDate)}</div>
</div>
</div>
<div className="cardInfo">
<div className="infoRow">
<span className="infoLabel">MOBILE</span>
<span className="infoValue">{selectedCustomer?.value || '-'}</span>
</div>
{selectedCustomer?.AadhaarNo && <div className="infoRow">
<span className="infoLabel">AADHAAR</span>
<span className="infoValue">{formatAadhaar(selectedCustomer?.AadhaarNo)}</span>
</div>}
</div>
<div className="cardFooter">
{/* <div className="qrPlaceholder">
<div className="qrGrid">
{[...Array(16)].map((_, i) => (
<div key={i} className="qrCell" />
))}
</div>
</div> */}
<div className='user-profile'>
{base64CustImage ? <img src={base64CustImage} alt="Customer Profile" height={"50"} width={"50"} /> :
<img src={defaultuser} alt="Customer Profile" height={"50"} width={"50"} />
}
</div>
</div>
</div>
<div className="cardActions">
<Button
icon={<PrinterOutlined />}
onClick={handlePrint}
type="default"
>
Print
</Button>
<Button
icon={<ShareAltOutlined />}
onClick={handleShare}
type="primary"
>
Share
</Button>
</div>
<Modal
title="Enter Email Address"
open={emailModalVisible}
onOk={handleEmailSubmit}
onCancel={() => {
setEmailModalVisible(false);
setEmailInput('');
}}
okText="Share"
>
<Input
placeholder="Enter email address"
value={emailInput}
onChange={(e) => setEmailInput(e.target.value)}
onPressEnter={handleEmailSubmit}
/>
</Modal>
</div>
);
};
export default MembershipCard;