156 lines
3.9 KiB
TypeScript
156 lines
3.9 KiB
TypeScript
import React from 'react';
|
|
import { IonIcon } from '@ionic/react';
|
|
import {
|
|
medkitOutline,
|
|
flashOutline,
|
|
phonePortraitOutline,
|
|
chevronForwardOutline,
|
|
} from 'ionicons/icons';
|
|
import momImage from '../assets/mom.jpg';
|
|
import dadImage from '../assets/dad.jpg';
|
|
import basketIcon from '../assets/basket.png';
|
|
|
|
interface ActivityListItemProps {
|
|
id: string;
|
|
eventType: string;
|
|
title: string;
|
|
subtitle: string;
|
|
amount?: number;
|
|
statusText?: string;
|
|
statusTone?: 'success' | 'warning' | 'partial';
|
|
avatarLabel?: string;
|
|
avatarTone?: string;
|
|
avatarImage?: string;
|
|
onClick?: (id: string) => void;
|
|
onStatusClick?: () => void;
|
|
}
|
|
|
|
const ActivityListItem: React.FC<ActivityListItemProps> = ({
|
|
id,
|
|
eventType,
|
|
title,
|
|
subtitle,
|
|
amount,
|
|
statusText,
|
|
statusTone = 'warning',
|
|
avatarLabel,
|
|
avatarTone = 'brand',
|
|
avatarImage,
|
|
onClick,
|
|
onStatusClick,
|
|
}) => {
|
|
const getIconAndColor = () => {
|
|
if (
|
|
eventType.includes('grocery') ||
|
|
title.toLowerCase().includes('grocer')
|
|
) {
|
|
return {
|
|
iconSrc: basketIcon,
|
|
badgeClass: 'grocery',
|
|
};
|
|
}
|
|
if (
|
|
eventType.includes('medication') ||
|
|
title.toLowerCase().includes('medic')
|
|
) {
|
|
return {
|
|
icon: medkitOutline,
|
|
badgeClass: 'medication',
|
|
};
|
|
}
|
|
if (
|
|
eventType.includes('airtime') ||
|
|
title.toLowerCase().includes('airtime')
|
|
) {
|
|
return {
|
|
icon: phonePortraitOutline,
|
|
badgeClass: 'airtime',
|
|
};
|
|
}
|
|
return {
|
|
icon: flashOutline,
|
|
badgeClass: 'electricity',
|
|
};
|
|
};
|
|
|
|
const { icon, iconSrc, badgeClass } = getIconAndColor();
|
|
|
|
const avatarSearchText =
|
|
`${title} ${subtitle} ${avatarLabel ?? ''}`.toLowerCase();
|
|
const resolvedAvatar =
|
|
avatarImage ??
|
|
(avatarSearchText.includes('mum') || avatarSearchText.includes('mom')
|
|
? momImage
|
|
: avatarSearchText.includes('dad') || avatarSearchText.includes('father')
|
|
? dadImage
|
|
: undefined);
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={() => onClick && onClick(id)}
|
|
className="activity-feed-item"
|
|
disabled={!onClick}
|
|
>
|
|
<div className="activity-feed-avatar-wrap">
|
|
<div
|
|
className={`activity-feed-avatar activity-feed-avatar-${avatarTone}`}
|
|
>
|
|
{resolvedAvatar ? (
|
|
<img
|
|
src={resolvedAvatar}
|
|
alt=""
|
|
className="activity-feed-avatar-image"
|
|
/>
|
|
) : (
|
|
<span>{avatarLabel ?? 'KU'}</span>
|
|
)}
|
|
<div
|
|
className={`activity-feed-avatar-badge activity-feed-avatar-badge-${badgeClass}`}
|
|
>
|
|
{iconSrc ? (
|
|
<img src={iconSrc} alt="" className="activity-feed-badge-image" />
|
|
) : (
|
|
<IonIcon icon={icon} />
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="activity-feed-main">
|
|
<div className="activity-feed-row">
|
|
<div className="activity-feed-copy">
|
|
<p className="activity-feed-title">{title}</p>
|
|
<p className="activity-feed-subtitle">{subtitle}</p>
|
|
</div>
|
|
|
|
<div className="activity-feed-right">
|
|
{amount !== undefined && (
|
|
<p className="activity-feed-amount">${amount.toFixed(2)}</p>
|
|
)}
|
|
{statusText && (
|
|
<button
|
|
type="button"
|
|
className={`activity-feed-status activity-feed-status-${statusTone}`}
|
|
onClick={(event) => {
|
|
event.stopPropagation();
|
|
if (onStatusClick) {
|
|
onStatusClick();
|
|
return;
|
|
}
|
|
onClick?.(id);
|
|
}}
|
|
>
|
|
<span>{statusText}</span>
|
|
<IonIcon icon={chevronForwardOutline} />
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</button>
|
|
);
|
|
};
|
|
|
|
export default ActivityListItem;
|