Init
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { ExternalIcon } from '../../icons';
|
||||
import { parseDate, timeAgo, initials } from '../../../utils/format.utils';
|
||||
import type { Ticket } from '../../../types/ticket.types';
|
||||
import styles from './BoardCard.module.scss';
|
||||
|
||||
function daysSince(v: string | null): number | null {
|
||||
const d = parseDate(v);
|
||||
if (!d) return null;
|
||||
return Math.floor((Date.now() - d.getTime()) / 86_400_000);
|
||||
}
|
||||
|
||||
interface BoardCardProps {
|
||||
ticket: Ticket;
|
||||
color: string;
|
||||
brandColor?: string;
|
||||
onSelect: (t: Ticket) => void;
|
||||
}
|
||||
|
||||
export default function BoardCard({ ticket, color, brandColor, onSelect }: BoardCardProps) {
|
||||
const lifetime = daysSince(ticket.openedAt);
|
||||
const inState = daysSince(ticket.stateChangedAt);
|
||||
const bm = [ticket.brand, ticket.market].filter(Boolean).join(' · ');
|
||||
|
||||
return (
|
||||
<div className={styles.card} style={{ '--col': color } as React.CSSProperties} onClick={() => onSelect(ticket)}>
|
||||
<div className={styles.top}>
|
||||
{ticket.link ? (
|
||||
<a href={ticket.link} target="_blank" rel="noopener noreferrer" className={styles.number}
|
||||
onClick={e => e.stopPropagation()} title="Open in ServiceNow">
|
||||
{ticket.number}<ExternalIcon size={11} />
|
||||
</a>
|
||||
) : (
|
||||
<span className={styles.number}>{ticket.number}</span>
|
||||
)}
|
||||
{ticket.jira?.status && <span className={styles.jira}>{ticket.jira.status}</span>}
|
||||
</div>
|
||||
|
||||
<div className={styles.title} title={ticket.shortDesc}>{ticket.shortDesc || '—'}</div>
|
||||
|
||||
{bm && <span className={styles.bm} style={brandColor ? { background: `${brandColor}1a`, color: brandColor, borderColor: `${brandColor}55` } : undefined}>{bm}</span>}
|
||||
|
||||
<div className={styles.foot}>
|
||||
<span className={styles.assignee}>
|
||||
<span className={styles.avatar}>{initials(ticket.assignedTo)}</span>
|
||||
<span className={styles.aName}>{ticket.assignedTo ?? 'Unassigned'}</span>
|
||||
</span>
|
||||
{inState != null && <span className={styles.pill} title="days in current state">{inState}d</span>}
|
||||
</div>
|
||||
|
||||
<div className={styles.meta}>
|
||||
{lifetime != null && <span title="lifetime">⏱ {lifetime}d</span>}
|
||||
<span title="last activity">✎ {timeAgo(ticket.lastActivityAt)}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user