update page transaction
This commit is contained in:
@ -10,12 +10,37 @@ interface Props {
|
||||
enddate: string;
|
||||
}
|
||||
|
||||
const polarToCartesian = (cx: number, cy: number, radius: number, angleInDegrees: number) => {
|
||||
const angleInRadians = (angleInDegrees * Math.PI) / 180.0;
|
||||
return {
|
||||
x: cx + radius * Math.cos(angleInRadians),
|
||||
y: cy + radius * Math.sin(angleInRadians),
|
||||
};
|
||||
};
|
||||
|
||||
const describeArc = (
|
||||
x: number,
|
||||
y: number,
|
||||
radius: number,
|
||||
startAngle: number,
|
||||
endAngle: number
|
||||
) => {
|
||||
const start = polarToCartesian(x, y, radius, endAngle);
|
||||
const end = polarToCartesian(x, y, radius, startAngle);
|
||||
const largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
|
||||
|
||||
return [
|
||||
"M", start.x, start.y,
|
||||
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y,
|
||||
].join(" ");
|
||||
};
|
||||
|
||||
const MemberActivity = ({ startdate, enddate }: Props) => {
|
||||
const { GetData } = useCallApi();
|
||||
const [responseTransactionValue, setResponseTransactionValue] = useState<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchDataTransactionValue = async () => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const res = await GetData(`${API_URL}/active-user`, {
|
||||
date_from: startdate,
|
||||
@ -23,43 +48,33 @@ const MemberActivity = ({ startdate, enddate }: Props) => {
|
||||
});
|
||||
setResponseTransactionValue(res);
|
||||
} catch (error) {
|
||||
console.error('Error fetching transaction value:', error);
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchDataTransactionValue();
|
||||
fetchData();
|
||||
}, [startdate, enddate, GetData]);
|
||||
|
||||
const percentage = parseFloat((responseTransactionValue?.data?.total_customer_active_percentage ?? 0).toFixed(2)) ?? 0;
|
||||
const percentage = parseFloat((responseTransactionValue?.data?.total_customer_active_percentage ?? 0).toFixed(2));
|
||||
const totalCustomer = responseTransactionValue?.data?.total_customer ?? 0;
|
||||
const activeCustomer = responseTransactionValue?.data?.total_customer_active ?? 0;
|
||||
const reguler = responseTransactionValue?.data?.reguler ?? 0;
|
||||
const premium = responseTransactionValue?.data?.premium ?? 0;
|
||||
const agent = responseTransactionValue?.data?.agent ?? 0;
|
||||
|
||||
// Hitung sudut pointer
|
||||
const angle = (percentage / 100) * 180; // 0° (kiri) ke 180° (kanan)
|
||||
const radians = (angle * Math.PI) / 180;
|
||||
const radius = 40; // Radius dari setengah lingkaran
|
||||
const center = 50; // Titik pusat lingkaran
|
||||
const pointerLength = 25; // Panjang pointer
|
||||
|
||||
const x = center + pointerLength * Math.cos(radians - Math.PI); // offset agar mulai dari kiri
|
||||
const y = center + pointerLength * Math.sin(radians - Math.PI);
|
||||
|
||||
// Hitung titik akhir untuk arc aktif
|
||||
const arcAngle = (Math.PI * percentage) / 100;
|
||||
const arcX = 50 + radius * Math.cos(Math.PI - arcAngle);
|
||||
const arcY = 50 - radius * Math.sin(arcAngle);
|
||||
// Calculate pointer angle
|
||||
const angle = (percentage / 100) * 180;
|
||||
const pointerX = 50 + 25 * Math.cos((angle - 180) * Math.PI / 180);
|
||||
const pointerY = 50 + 25 * Math.sin((angle - 180) * Math.PI / 180);
|
||||
|
||||
return (
|
||||
<div className="p-6 bg-white rounded-lg shadow-md w-1/3">
|
||||
<div className="flex justify-between items-center pb-3 mb-4">
|
||||
<div className="p-6 bg-white rounded-lg shadow-md w-full max-w-md">
|
||||
<div className="pb-3 mb-4">
|
||||
<h2 className="text-lg font-semibold text-gray-700">Member Activity</h2>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-6">
|
||||
{/* Sidebar */}
|
||||
{/* Sidebar Info */}
|
||||
<ul className="space-y-4 w-1/2 text-gray-700 text-sm">
|
||||
<li className="flex items-center gap-2">
|
||||
<UsersIcon className="w-4 h-4" />
|
||||
@ -70,15 +85,15 @@ const MemberActivity = ({ startdate, enddate }: Props) => {
|
||||
<span>Active Customer: {activeCustomer}</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<UserCheckIcon className="w-4 h-4" color='blue'/>
|
||||
<UserCheckIcon className="w-4 h-4" color='blue' />
|
||||
<span>Reguler: {reguler}</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<UserCheckIcon className="w-4 h-4" color='green'/>
|
||||
<UserCheckIcon className="w-4 h-4" color='green' />
|
||||
<span>Premium: {premium}</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<UserCheckIcon className="w-4 h-4" color='orange'/>
|
||||
<UserCheckIcon className="w-4 h-4" color='orange' />
|
||||
<span>Agent: {agent}</span>
|
||||
</li>
|
||||
</ul>
|
||||
@ -88,7 +103,7 @@ const MemberActivity = ({ startdate, enddate }: Props) => {
|
||||
<div className="border border-gray-200 rounded-md p-4 text-center">
|
||||
<h3 className="text-sm text-gray-600 font-medium mb-2">Active User</h3>
|
||||
<div className="relative h-24 w-full">
|
||||
<svg className="w-full h-full" viewBox="0 0 100 50">
|
||||
<svg viewBox="0 0 100 50" className="w-full h-full">
|
||||
{/* Background arc */}
|
||||
<path
|
||||
d="M 10 50 A 40 40 0 0 1 90 50"
|
||||
@ -97,24 +112,27 @@ const MemberActivity = ({ startdate, enddate }: Props) => {
|
||||
strokeWidth="10"
|
||||
/>
|
||||
{/* Active arc */}
|
||||
<path
|
||||
d={`M 10 50 A 40 40 0 ${percentage > 50 ? 1 : 0} 1 ${arcX} ${arcY}`}
|
||||
fill="none"
|
||||
stroke="#34d399"
|
||||
strokeWidth="10"
|
||||
/>
|
||||
{percentage > 0 && (
|
||||
<path
|
||||
d={describeArc(50, 50, 40, 180, 180 + (percentage * 180 / 100))}
|
||||
fill="none"
|
||||
stroke="#34d399"
|
||||
strokeWidth="10"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
)}
|
||||
{/* Pointer */}
|
||||
<line
|
||||
x1="50"
|
||||
y1="50"
|
||||
x2={x}
|
||||
y2={y}
|
||||
x2={pointerX}
|
||||
y2={pointerY}
|
||||
stroke="#111827"
|
||||
strokeWidth="4"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
<div className="flex justify-between text-xs text-gray-500 px-1">
|
||||
<div className="flex justify-between text-xs text-gray-500 px-1 mt-1">
|
||||
<span>{percentage}%</span>
|
||||
<span>100%</span>
|
||||
</div>
|
||||
|
||||
@ -43,7 +43,11 @@ const TransactionPieChart = ({ startdate, enddate }: Props) => {
|
||||
{ name: 'Purchase', value: parseFloat((responseTransactionValue?.data?.P ?? 0).toFixed(2)), color: '#baf7c5' },
|
||||
{ name: 'Withdraw', value: parseFloat((responseTransactionValue?.data?.W ?? 0).toFixed(2)), color: '#f56565' },
|
||||
{ name: 'Top Up Partner', value: parseFloat((responseTransactionValue?.data?.N ?? 0).toFixed(2)), color: '#f7fa52' },
|
||||
{ name: 'Reward', value: parseFloat((responseTransactionValue?.data?.E ?? 0).toFixed(2)), color: '#f7fa52' },
|
||||
{ name: 'Reward', value: parseFloat((responseTransactionValue?.data?.E ?? 0).toFixed(2)), color: '#f50a19' },
|
||||
{ name: 'Purchase Loja', value: parseFloat((responseTransactionValue?.data?.L ?? 0).toFixed(2)), color: '#F0A04B' },
|
||||
{ name: 'Top Up P24', value: parseFloat((responseTransactionValue?.data?.B ?? 0).toFixed(2)), color: '#FADA7A' },
|
||||
{ name: 'Transfer Agent', value: parseFloat((responseTransactionValue?.data?.A ?? 0).toFixed(2)), color: '#B1C29E' },
|
||||
{ name: 'Withdrawal Agent', value: parseFloat((responseTransactionValue?.data?.M ?? 0).toFixed(2)), color: '#FCE7C8' },
|
||||
];
|
||||
|
||||
return (
|
||||
|
||||
@ -67,6 +67,18 @@ const TransactionValue = ({ startdate, enddate }: Props) => {
|
||||
case "E":
|
||||
type = "Reward";
|
||||
break;
|
||||
case "L":
|
||||
type = "Purchase Loja"
|
||||
break;
|
||||
case "B":
|
||||
type ="Top Up P24";
|
||||
break;
|
||||
case "A":
|
||||
type = " Transfer Agent";
|
||||
break;
|
||||
case "M":
|
||||
type = "Withdrawal Agent";
|
||||
break;
|
||||
default:
|
||||
type = "Unknown";
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user