krishnasales_mobile/src/components/cards/DailyLogCard.tsx
2026-07-16 16:11:47 +05:30

120 lines
4.5 KiB
TypeScript

import { formatValue } from '../../lib/format';
import { User as UserIcon, Clock, LogOut } from 'lucide-react';
import { Button } from '../buttons/Button';
import './card.css';
export function DailyLogCard({ row, onPunchOut }: { row: Record<string, any>; onPunchOut?: (row: any) => void }) {
const stateName = String(row.status || row.current_state_name || 'Logged');
// User details
const userObj = (row.sales_officer_name || row.user_id || row.user) as Record<string, any> | null;
const userName = formatValue(userObj?.name || row.user_name || 'Unknown User');
// Date
let dateStr = '—';
if (row.date) dateStr = String(row.date).split('T')[0];
else if (row.created_at) dateStr = String(row.created_at).split('T')[0];
try {
if (dateStr !== '—') {
const d = new Date(dateStr);
if (!isNaN(d.getTime())) {
dateStr = d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' }).replace(/ /g, '-');
}
}
} catch (e) {}
const formatTimeStr = (t: string | undefined | null) => {
if (!t) return '—';
const str = String(t);
if (str === '—') return str;
try {
let timeParts = str.split(':');
if (str.includes('T')) {
timeParts = str.split('T')[1].replace('Z', '').split('.')[0].split(':');
}
if (timeParts.length >= 2) {
let h = parseInt(timeParts[0]);
const m = timeParts[1];
const ampm = h >= 12 ? 'PM' : 'AM';
h = h % 12;
h = h ? h : 12;
const hStr = h < 10 ? '0' + h : h;
return `${hStr}:${m} ${ampm}`;
}
return str.split('.')[0];
} catch {
return str.split('.')[0];
}
};
// Checkin time
let checkInTimeRaw = row.time || row.created_at || row.punch_in_time;
let checkInTime = formatTimeStr(checkInTimeRaw);
// Check out time
let checkOutTimeRaw = row.check_out_time || row.punch_out_time;
if (!checkOutTimeRaw && stateName.toLowerCase().includes('out') && row.time) {
checkOutTimeRaw = row.time;
}
let checkOutTime = checkOutTimeRaw ? formatTimeStr(checkOutTimeRaw) : null;
const isPunchedIn = stateName.toLowerCase().includes('in') || stateName.toLowerCase().includes('active');
let statusClass = 'z-card-status--neutral';
if (isPunchedIn) statusClass = 'z-card-status--success';
else if (stateName.toLowerCase().includes('out')) statusClass = 'z-card-status--primary';
return (
<div className="z-card">
<div className="z-card-header">
<div className="z-card-header-icon">
<UserIcon size={16} className="text-strong" />
<span className="text-strong">{userName}</span>
</div>
<span className={`z-card-status ${statusClass}`}>
{stateName}
</span>
</div>
<div className="z-card-divider"></div>
<div className="z-card-footer" style={{ flexDirection: 'column', alignItems: 'flex-start', gap: '16px' }}>
<div className="z-card-footer-item" style={{ width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: '4px' }}>
<div className="z-card-footer-label" style={{ whiteSpace: 'nowrap' }}><Clock size={14} /> PUNCH-IN TIME</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '6px', whiteSpace: 'nowrap' }}>
<span className="z-card-footer-value" style={{ display: 'flex', gap: '6px', fontSize: '13px' }}>
<span>{dateStr}</span>
<span>{checkInTime}</span>
</span>
</div>
</div>
{checkOutTime && (
<div className="z-card-footer-item" style={{ width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: '4px' }}>
<div className="z-card-footer-label" style={{ whiteSpace: 'nowrap' }}><Clock size={14} /> PUNCH-OUT TIME</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '6px', whiteSpace: 'nowrap' }}>
<span className="z-card-footer-value" style={{ display: 'flex', gap: '6px', fontSize: '13px' }}>
<span>{dateStr}</span>
<span>{checkOutTime}</span>
</span>
</div>
</div>
)}
</div>
{isPunchedIn && onPunchOut && (
<div style={{ padding: '0 6px 0px 6px' }}>
<Button
variant="danger"
full
iconLeft={<LogOut size={16} />}
onClick={(e) => { e.stopPropagation(); onPunchOut(row); }}
>
Punch Out
</Button>
</div>
)}
</div>
);
}