From 39bb733a8411a8d6ac62b3dac9dadbf01dfbcdaf Mon Sep 17 00:00:00 2001 From: N0Obitaz Date: Tue, 17 Feb 2026 09:37:06 +0800 Subject: [PATCH 1/4] feat: added skeleton on portfolio-view --- client/components/portfolio-overview.tsx | 53 ++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/client/components/portfolio-overview.tsx b/client/components/portfolio-overview.tsx index 00bccd6..7bdd7b2 100644 --- a/client/components/portfolio-overview.tsx +++ b/client/components/portfolio-overview.tsx @@ -1,8 +1,11 @@ 'use client' +import { useEffect, useState } from 'react' import { TrendUp, TrendDown, Wallet, Coins } from '@phosphor-icons/react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { useAPAXStore, formatCurrency, formatWeight } from '@/lib/store' +import { Skeleton } from '@/components/ui/skeleton' +import React from 'react' export function PortfolioOverview() { const { userHoldings, metalPrices } = useAPAXStore() @@ -49,6 +52,17 @@ export function PortfolioOverview() { } ] + const [isLoading, setIsLoading ] = useState(true) + + useEffect(() => { + const timer = setTimeout(() => setIsLoading(false), 2000) + return () => clearTimeout(timer) + }, []) + + + if(isLoading) { + return + } return (
{/* Primary Card - Spans 2 cols for visibility */} @@ -122,3 +136,42 @@ export function PortfolioOverview() {
) } + + function PortfolioOverviewSkeleton() { + return ( +
+ + {/* 1. Primary Card Skeleton (Total Portfolio) */} + + + + + + + + + {/* Trend Badge & Subtext */} +
+ + +
+
+
+ + {/* Metal Token Cards Skeletons (Gold, Silver, Platinum) */} + {[...Array(3)].map((_, i) => ( + + + + + + + + + + + ))} + +
+ ) +} \ No newline at end of file From c5a9001983f826ab40014011cd485169965e3b4a Mon Sep 17 00:00:00 2001 From: N0Obitaz Date: Tue, 17 Feb 2026 09:41:05 +0800 Subject: [PATCH 2/4] feat: added Skeleton from imports --- client/components/asset-allocation-chart.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/components/asset-allocation-chart.tsx b/client/components/asset-allocation-chart.tsx index 0eedb6b..9701b6f 100644 --- a/client/components/asset-allocation-chart.tsx +++ b/client/components/asset-allocation-chart.tsx @@ -3,6 +3,7 @@ import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { useAPAXStore, formatCurrency } from '@/lib/store' +import { Skeleton } from '@/components/ui/skeleton' const COLORS = { gold: '#D4AF37', From a22ca19841887146a5eb861dda32dfedc23b248c Mon Sep 17 00:00:00 2001 From: N0Obitaz Date: Tue, 17 Feb 2026 09:56:40 +0800 Subject: [PATCH 3/4] feat: added AssetAllocationSkeleton for the chart --- client/components/asset-allocation-chart.tsx | 104 ++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/client/components/asset-allocation-chart.tsx b/client/components/asset-allocation-chart.tsx index 9701b6f..e8486ad 100644 --- a/client/components/asset-allocation-chart.tsx +++ b/client/components/asset-allocation-chart.tsx @@ -4,6 +4,7 @@ import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { useAPAXStore, formatCurrency } from '@/lib/store' import { Skeleton } from '@/components/ui/skeleton' +import {useEffect, useState } from 'react' const COLORS = { gold: '#D4AF37', @@ -51,6 +52,11 @@ export function AssetAllocationChart() { { name: 'Platinum', value: 10, color: COLORS.platinum } ] + + + + + const CustomTooltip = ({ active, payload }: { active?: boolean; payload?: Array<{ payload: typeof data[0] }> }) => { if (active && payload && payload.length) { const item = payload[0].payload @@ -65,11 +71,25 @@ export function AssetAllocationChart() { ) } return null + } + + const [isLoading, setIsLoading ] = useState(true); + + useEffect(() => + { + setTimeout(() => { + setIsLoading(false); + }, 2000); + }) + if (isLoading) { + return + } + return (
- {/* Your Holdings Chart */} + {/* Holdings Chart */} Your Asset Allocation @@ -214,3 +234,85 @@ export function AssetAllocationChart() {
) } + + +function AssetAllocationSkeleton() { + return ( +
+ + {/* 1. Left Card: Your Asset Allocation */} + + + {/* Title */} + {/* Desc */} + + + + {/* Donut Chart Placeholder */} +
+ +
+
+ + {/* Legend Grid Placeholder */} +
+
+ {[...Array(3)].map((_, i) => ( +
+
+ + +
+ + +
+ ))} +
+ {/* Divider Line */} +
+
+ + + + {/* Right Card: APX-i Index Token */} + + +
+ +
+ + +
+
+
+ + + {/* Donut Chart Placeholder */} +
+ +
+
+ +
+ {/* Legend Grid */} +
+ {[...Array(3)].map((_, i) => ( +
+
+ + +
+ +
+ ))} +
+ + {/* Bottom Holdings Box Placeholder */} + +
+ + + +
+ ) +} \ No newline at end of file From e0333eeae81aff6304bbfff9ca84fdb217a24619 Mon Sep 17 00:00:00 2001 From: N0Obitaz Date: Tue, 17 Feb 2026 10:08:18 +0800 Subject: [PATCH 4/4] feat: added skeleton loader for sharia certification --- .../components/sharia-certification-hub.tsx | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/client/components/sharia-certification-hub.tsx b/client/components/sharia-certification-hub.tsx index 6932a37..603b9cb 100644 --- a/client/components/sharia-certification-hub.tsx +++ b/client/components/sharia-certification-hub.tsx @@ -4,6 +4,9 @@ import { FileText, Download, Shield, CheckCircle, ExternalLink } from 'lucide-re import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' +import { Skeleton } from '@/components/ui/skeleton' +import {useEffect, useState } from 'react' + const certifications = [ { @@ -51,7 +54,25 @@ const typeIcons = { report: '📋' } + + + + + export function ShariaCertificationHub() { + + const [isLoading, setIsLoading ] = useState(true); + + useEffect(() => + { + setTimeout(() => { + setIsLoading(false); + }, 2000); + }) + + if (isLoading) { + return + } return ( @@ -153,3 +174,76 @@ export function ShariaCertificationHub() { ) } + +function ShariaCertificationHubSkeleton() { + return ( + + +
+
+ {/* Shield Icon Placeholder */} + + +
+ {/* Title Placeholder */} + + {/* Description Placeholder (Hidden on mobile to match real component) */} + +
+
+ + {/* Badge Placeholder */} + +
+
+ + + {/* Certificate Grid Skeleton */} +
+ {/* Generate 2 placeholders to match typical list size */} + {[...Array(2)].map((_, i) => ( +
+
+ {/* Certificate Icon */} + + +
+ {/* Cert Title */} + + {/* Cert Description (2 lines) */} +
+ + +
+ {/* Meta Row (Issuer | Date) */} + +
+
+ + {/* Action Buttons Row */} +
+ + +
+
+ ))} +
+ + {/* Bottom Verification Banner Skeleton */} +
+
+ +
+ + +
+ +
+
+
+
+ ) +} \ No newline at end of file