Show RFV loading state in clients table
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m30s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m30s
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user