Show RFV loading state in clients table
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m30s

This commit is contained in:
Cauê Faleiros
2026-06-30 12:49:39 -03:00
parent 1e511f35a9
commit 839e1f814e

View File

@@ -188,6 +188,7 @@ const Clients = () => {
const [rfmAnalytics, setRfmAnalytics] = useState<RfmAnalytics | null>(initialRfmAnalytics || null); const [rfmAnalytics, setRfmAnalytics] = useState<RfmAnalytics | null>(initialRfmAnalytics || null);
const [clientAnalytics, setClientAnalytics] = useState<ClientAnalyticsItem[]>(initialClientAnalytics || []); const [clientAnalytics, setClientAnalytics] = useState<ClientAnalyticsItem[]>(initialClientAnalytics || []);
const [isLoading, setIsLoading] = useState(!initialClientAnalytics); const [isLoading, setIsLoading] = useState(!initialClientAnalytics);
const [isRfmLoading, setIsRfmLoading] = useState(!initialRfmAnalytics && Boolean(initialClientAnalytics));
// Pagination state // Pagination state
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
@@ -207,6 +208,7 @@ const Clients = () => {
if (cachedClients) setClientAnalytics(cachedClients); if (cachedClients) setClientAnalytics(cachedClients);
setRfmAnalytics(cachedRfm || null); setRfmAnalytics(cachedRfm || null);
setIsLoading(!hasCachedClients); setIsLoading(!hasCachedClients);
setIsRfmLoading(!cachedRfm && hasCachedClients);
} }
const filterOptionsPromise = fetchClientFilterOptions(dateRange, { force: true }); const filterOptionsPromise = fetchClientFilterOptions(dateRange, { force: true });
@@ -218,11 +220,13 @@ const Clients = () => {
setFilterOptions(options); setFilterOptions(options);
setClientAnalytics(clientsData); setClientAnalytics(clientsData);
setIsLoading(false); setIsLoading(false);
setIsRfmLoading(!cachedRfm);
} }
const rfmData = await rfmPromise; const rfmData = await rfmPromise;
if (isMounted) { if (isMounted) {
setRfmAnalytics(rfmData); setRfmAnalytics(rfmData);
setIsRfmLoading(false);
} }
}; };
@@ -441,6 +445,7 @@ const Clients = () => {
(sortBy === 'recent' ? 0 : 1); (sortBy === 'recent' ? 0 : 1);
const hasActiveFilters = activeFilterCount > 0; const hasActiveFilters = activeFilterCount > 0;
const isRefreshing = isLoading && clientAnalytics.length > 0; const isRefreshing = isLoading && clientAnalytics.length > 0;
const shouldShowRfmLoading = isRfmLoading && clientAnalytics.length > 0;
return ( return (
<div className="space-y-6"> <div className="space-y-6">
@@ -672,24 +677,36 @@ const Clients = () => {
</td> </td>
<td className="px-6 py-2.5 font-semibold text-zinc-900 dark:text-dark-text">{client.name}</td> <td className="px-6 py-2.5 font-semibold text-zinc-900 dark:text-dark-text">{client.name}</td>
<td className="px-6 py-2.5"> <td className="px-6 py-2.5">
<span {shouldShowRfmLoading ? (
className="inline-flex rounded-full border px-3 py-1 text-xs font-bold" <span className="skeleton inline-flex h-7 w-24 rounded-full" />
style={clientTypePillStyle(clientTypeStyle)} ) : (
> <span
{client.clientType} className="inline-flex rounded-full border px-3 py-1 text-xs font-bold"
</span> style={clientTypePillStyle(clientTypeStyle)}
>
{client.clientType}
</span>
)}
</td> </td>
<td className="px-6 py-2.5"> <td className="px-6 py-2.5">
<div className="flex items-center gap-1"> {shouldShowRfmLoading ? (
{client.rfmScore.split('').map((score, scoreIndex) => ( <div className="flex items-center gap-1">
<span {[0, 1, 2].map(item => (
key={`${client.name}-${scoreIndex}`} <span key={`rfm-score-loading-${client.customerKey}-${item}`} className="skeleton h-6 w-6 rounded-md" />
className="inline-flex h-6 w-6 items-center justify-center rounded-md border border-dark-border bg-dark-input text-[11px] font-bold text-dark-text" ))}
> </div>
{score} ) : (
</span> <div className="flex items-center gap-1">
))} {client.rfmScore.split('').map((score, scoreIndex) => (
</div> <span
key={`${client.name}-${scoreIndex}`}
className="inline-flex h-6 w-6 items-center justify-center rounded-md border border-dark-border bg-dark-input text-[11px] font-bold text-dark-text"
>
{score}
</span>
))}
</div>
)}
</td> </td>
<td className="px-6 py-2.5 text-brand-primary font-bold">{formatCurrency(client.totalSpent)}</td> <td className="px-6 py-2.5 text-brand-primary font-bold">{formatCurrency(client.totalSpent)}</td>
<td className="px-6 py-2.5 text-zinc-700 dark:text-dark-text font-semibold">{formatCurrency(client.averageTicket)}</td> <td className="px-6 py-2.5 text-zinc-700 dark:text-dark-text font-semibold">{formatCurrency(client.averageTicket)}</td>