Files
appcakes-builds/src/components/ActivityListItem.tsx
T
2026-06-21 20:42:26 +00:00

211 lines
5.2 KiB
TypeScript

import React from 'react';
import { IonIcon } from '@ionic/react';
import {
cartOutline,
medkitOutline,
flashOutline,
phonePortraitOutline,
timeOutline,
checkmarkCircleOutline,
removeCircleOutline,
} from 'ionicons/icons';
import momImage from '../assets/mom.jpg';
import dadImage from '../assets/dad.jpg';
interface ActivityListItemProps {
id: string;
eventType: string;
title: string;
subtitle: string;
amount?: number;
statusText?: string;
isSuccess?: boolean;
avatarLabel?: string;
avatarTone?: string;
avatarImage?: string;
redeemedAmount?: number;
remainingAmount?: number;
onClick?: (id: string) => void;
}
const ActivityListItem: React.FC<ActivityListItemProps> = ({
id,
eventType,
title,
subtitle,
amount,
statusText,
isSuccess = true,
avatarLabel,
avatarTone = 'brand',
avatarImage,
redeemedAmount,
remainingAmount,
onClick,
}) => {
const getIconAndColor = () => {
if (
eventType.includes('grocery') ||
title.toLowerCase().includes('grocer')
) {
return {
icon: cartOutline,
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, badgeClass } = getIconAndColor();
const getStatusTheme = () => {
const text = statusText?.toLowerCase() ?? '';
if (
text.includes('delivered') ||
text.includes('ready') ||
(text.includes('redeemed') && !text.includes('partial'))
) {
return 'success';
}
if (
text.includes('awaiting') ||
text.includes('ready') ||
text.includes('collect')
) {
return 'info';
}
if (text.includes('expir') || text.includes('warn')) {
return 'warning';
}
if (text.includes('cancel') || text.includes('fail')) {
return 'danger';
}
return 'brand';
};
const statusTheme = getStatusTheme();
const getStatusIcon = () => {
switch (statusTheme) {
case 'success':
return checkmarkCircleOutline;
case 'info':
case 'warning':
return timeOutline;
case 'danger':
return removeCircleOutline;
default:
return timeOutline;
}
};
const statusIcon = getStatusIcon();
const resolvedAvatar =
avatarImage ??
(title.toLowerCase().includes('mum')
? momImage
: title.toLowerCase().includes('dad')
? dadImage
: undefined);
const hasVoucherBreakdown =
redeemedAmount !== undefined || remainingAmount !== 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}`}
>
<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>
)}
</div>
</div>
{statusText && !hasVoucherBreakdown && (
<div
className={`activity-feed-status activity-feed-status-${statusTheme}`}
>
<IonIcon icon={statusIcon} />
<span>{statusText}</span>
</div>
)}
{hasVoucherBreakdown && (
<div className="activity-feed-breakdown">
<div className="activity-feed-breakdown-summary">
{redeemedAmount !== undefined && (
<div className="activity-feed-breakdown-pill is-redeemed">
<IonIcon icon={checkmarkCircleOutline} />
<span>${redeemedAmount.toFixed(2)} redeemed</span>
</div>
)}
{remainingAmount !== undefined && (
<div className="activity-feed-breakdown-pill is-remaining">
<IonIcon icon={removeCircleOutline} />
<span>${remainingAmount.toFixed(2)} left</span>
</div>
)}
</div>
</div>
)}
</div>
</button>
);
};
export default ActivityListItem;