daily log detail view is done

This commit is contained in:
suryacp23 2026-07-17 18:30:28 +05:30
parent 8b022bfbce
commit 98ab87fcbd
3 changed files with 113 additions and 30 deletions

View File

@ -1,14 +1,25 @@
import { formatValue } from '../../lib/format'; import { formatValue } from '../../lib/format';
import { User as UserIcon, Clock, LogOut } from 'lucide-react'; import { User as UserIcon, Clock, LogOut, FileText } from 'lucide-react';
import { Button } from '../buttons/Button'; import { Button } from '../buttons/Button';
import './card.css'; import './card.css';
export function DailyLogCard({ row, onPunchOut }: { row: Record<string, any>; onPunchOut?: (row: any) => void }) { export function DailyLogCard({ row, onPunchOut, isDetailView = false }: { row: Record<string, any>; onPunchOut?: (row: any) => void; isDetailView?: boolean }) {
const stateName = String(row.status || row.current_state_name || 'Logged'); const stateName = String(row.status || row.current_state_name || 'Logged');
// User details // User details
const userObj = (row.sales_officer_name || row.user_id || row.user) as Record<string, any> | null; 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'); const userName = formatValue(userObj?.name || row.user_name || 'Unknown User');
const userEmail = formatValue(userObj?.email || row.performed_by_email || row.user_email || '—');
const initials = userName !== '—' ? String(userName).substring(0, 2).toUpperCase() : 'SO';
// Route Details
const routeCode = formatValue(row.route_code || row.route || '—');
const subRoute = formatValue(row.sub_route || row.area || '—');
// End of Day Stats
const prodCalls = formatValue(row.total_productive_calls || 0);
const nonProdCalls = formatValue(row.total_non_productive_calls || 0);
const eodNotes = formatValue(row.eod_notes_remarks || row.notes || '—');
// Date // Date
let dateStr = '—'; let dateStr = '—';
@ -59,7 +70,7 @@ export function DailyLogCard({ row, onPunchOut }: { row: Record<string, any>; on
} }
let checkOutTime = checkOutTimeRaw ? formatTimeStr(checkOutTimeRaw) : null; let checkOutTime = checkOutTimeRaw ? formatTimeStr(checkOutTimeRaw) : null;
const isPunchedIn = stateName.toLowerCase().includes('in') || stateName.toLowerCase().includes('active'); const isPunchedIn = stateName.toLowerCase().includes('punched in') || stateName.toLowerCase().includes('active') || (stateName.toLowerCase().includes('in') && !stateName.toLowerCase().includes('out'));
let statusClass = 'z-card-status--neutral'; let statusClass = 'z-card-status--neutral';
if (isPunchedIn) statusClass = 'z-card-status--success'; if (isPunchedIn) statusClass = 'z-card-status--success';
@ -69,16 +80,33 @@ export function DailyLogCard({ row, onPunchOut }: { row: Record<string, any>; on
<div className="z-card"> <div className="z-card">
<div className="z-card-header"> <div className="z-card-header">
<div className="z-card-header-icon"> <div className="z-card-header-icon">
{isDetailView ? (
<div className="z-card-so-info" style={{ marginTop: 0 }}>
<div className="z-card-so-avatar">
{initials}
</div>
<div className="z-card-so-details">
<p className="z-card-so-name" style={{ fontSize: '15px' }}>{userName}</p>
{userEmail !== '—' && (
<p className="z-card-so-email">{userEmail}</p>
)}
</div>
</div>
) : (
<>
<UserIcon size={16} className="text-strong" /> <UserIcon size={16} className="text-strong" />
<span className="text-strong">{userName}</span> <span className="text-strong">{userName}</span>
</>
)}
</div> </div>
<span className={`z-card-status ${statusClass}`}> <span className={`z-card-status ${statusClass}`}>
{stateName} {stateName}
</span> </span>
</div> </div>
{!isDetailView && (
<>
<div className="z-card-divider"></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" 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-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 className="z-card-footer-label" style={{ whiteSpace: 'nowrap' }}><Clock size={14} /> PUNCH-IN TIME</div>
@ -101,9 +129,64 @@ export function DailyLogCard({ row, onPunchOut }: { row: Record<string, any>; on
</div> </div>
)} )}
</div> </div>
</>
)}
{isDetailView && (
<>
<div className="z-card-route mt-4">
<div>
<p className="z-card-grid-item-label">Route Code</p>
<p className="z-card-route-val">{routeCode}</p>
</div>
<div>
<p className="z-card-grid-item-label">Sub Route</p>
<p className="z-card-route-val">{subRoute}</p>
</div>
</div>
<div className="z-card-route mt-4" style={{ paddingTop: '16px', gridTemplateColumns: 'repeat(2, 1fr)' }}>
<div>
<p className="z-card-grid-item-label flex items-center gap-1"><Clock size={12} /> PUNCH-IN</p>
<p className="z-card-route-val" style={{ fontSize: '13px' }}>{dateStr} {checkInTime}</p>
</div>
{checkOutTime && (
<div>
<p className="z-card-grid-item-label flex items-center gap-1"><Clock size={12} /> PUNCH-OUT</p>
<p className="z-card-route-val" style={{ fontSize: '13px' }}>{dateStr} {checkOutTime}</p>
</div>
)}
</div>
{!isPunchedIn && (
<>
<div className="mt-6 flex justify-between items-center bg-gray-50 p-4 rounded-xl border border-gray-200 shadow-sm">
<div className="flex flex-col">
<span className="z-card-grid-item-label" style={{ fontSize: '11px' }}>Productive</span>
<span className="text-xl font-black text-gray-900 mt-1">{prodCalls} <span className="z-card-meta">Calls</span></span>
</div>
<div className="flex flex-col text-right">
<span className="z-card-grid-item-label" style={{ fontSize: '11px' }}>Non Productive</span>
<span className="text-xl font-black text-gray-900 mt-1">{nonProdCalls} <span className="z-card-meta">Calls</span></span>
</div>
</div>
{eodNotes !== '—' && (
<div className="mt-4 p-4 bg-gray-50 rounded-xl border border-gray-200">
<div className="flex items-center gap-2 mb-2 text-gray-700">
<FileText size={16} className="text-gray-500" />
<span className="z-card-grid-item-label" style={{ fontSize: '12px' }}>EOD Notes</span>
</div>
<p className="z-card-meta-val leading-relaxed">{eodNotes}</p>
</div>
)}
</>
)}
</>
)}
{isPunchedIn && onPunchOut && ( {isPunchedIn && onPunchOut && (
<div style={{ padding: '0 6px 0px 6px' }}> <div style={{ padding: '16px 6px 0px 6px' }}>
<Button <Button
variant="danger" variant="danger"
full full

View File

@ -211,7 +211,7 @@
.z-card-grid-item-label { .z-card-grid-item-label {
font-size: 10px; font-size: 10px;
font-weight: 700; font-weight: 700;
color: var(--z-text-neutral-400); color: var(--z-text-neutral-600);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.1em; letter-spacing: 0.1em;
} }
@ -266,7 +266,7 @@
.z-card-route-val { .z-card-route-val {
font-weight: 600; font-weight: 600;
color: var(--z-text-neutral-700); color: var(--z-text-neutral-900);
margin-top: 2px; margin-top: 2px;
font-size: 13px; font-size: 13px;
} }

View File

@ -15,7 +15,7 @@ export function DailyLogDetail({ instanceId }: WiredDetailViewProps) {
return ( return (
<div className="w-full"> <div className="w-full">
<DailyLogCard row={data} /> <DailyLogCard row={data} isDetailView={true} />
</div> </div>
); );
} }