New filter panel layout at client page
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m20s

This commit is contained in:
Cauê Faleiros
2026-06-23 13:46:55 -03:00
parent 62e0239ee4
commit 3524405712
6 changed files with 642 additions and 107 deletions

View File

@@ -125,25 +125,83 @@ const normalizeDateParam = (value) => {
return `${yearValue}-${monthValue}-${dayValue}`;
};
const buildDateFilter = ({ start, end } = {}) => {
const normalizeTextFilter = (value) => {
if (value === undefined || value === null) return '';
return String(value).trim();
};
const normalizeSellerFilter = (value) => {
const normalizedValue = normalizeTextFilter(value);
if (!normalizedValue) return null;
if (normalizedValue.startsWith('id:')) {
const id = normalizeTextFilter(normalizedValue.slice(3));
return id ? { type: 'id', value: id } : null;
}
if (normalizedValue.startsWith('name:')) {
const name = normalizeTextFilter(normalizedValue.slice(5));
return name ? { type: 'name', value: name } : null;
}
return { type: 'any', value: normalizedValue };
};
const appendOrderMetadataFilters = (params, filters, range = {}) => {
const marketplace = normalizeTextFilter(range.marketplace);
const salesChannel = normalizeTextFilter(range.canal_venda || range.canalVenda);
const seller = normalizeSellerFilter(range.seller || range.vendedor);
if (marketplace) {
params.push(marketplace);
filters.push(`NULLIF(TRIM(marketplace), '') = $${params.length}`);
}
if (salesChannel) {
params.push(salesChannel);
filters.push(`NULLIF(TRIM(canal_venda), '') = $${params.length}`);
}
if (seller?.type === 'id') {
params.push(seller.value);
filters.push(`NULLIF(TRIM(id_vendedor), '') = $${params.length}`);
} else if (seller?.type === 'name') {
params.push(seller.value);
filters.push(`NULLIF(TRIM(nome_vendedor), '') = $${params.length}`);
} else if (seller?.type === 'any') {
params.push(seller.value);
filters.push(`(NULLIF(TRIM(id_vendedor), '') = $${params.length} OR NULLIF(TRIM(nome_vendedor), '') = $${params.length})`);
}
};
const buildDateFilter = (range = {}) => {
const { start, end } = range;
const params = [];
const filters = ['data_pedido_date IS NOT NULL'];
const normalizedStart = normalizeDateParam(start);
const normalizedEnd = normalizeDateParam(end);
let startParamIndex = null;
let endParamIndex = null;
if (normalizedStart) {
params.push(normalizedStart);
startParamIndex = params.length;
filters.push(`data_pedido_date >= $${params.length}::date`);
}
if (normalizedEnd) {
params.push(normalizedEnd);
endParamIndex = params.length;
filters.push(`data_pedido_date <= $${params.length}::date`);
}
appendOrderMetadataFilters(params, filters, range);
return {
params,
whereClause: `WHERE ${filters.join(' AND ')}`
whereClause: `WHERE ${filters.join(' AND ')}`,
startParamIndex,
endParamIndex
};
};
@@ -576,6 +634,63 @@ const getClientAnalytics = async (range = {}) => {
return clients;
};
const getClientFilterOptions = async (range = {}) => {
const dateRange = {
start: range.start,
end: range.end
};
const { params, whereClause } = buildDateFilter(dateRange);
const [marketplaceResult, salesChannelResult, sellerResult] = await Promise.all([
pool.query(`
SELECT DISTINCT NULLIF(TRIM(marketplace), '') as value
FROM orders
${whereClause}
AND NULLIF(TRIM(marketplace), '') IS NOT NULL
ORDER BY value ASC;
`, params),
pool.query(`
SELECT DISTINCT NULLIF(TRIM(canal_venda), '') as value
FROM orders
${whereClause}
AND NULLIF(TRIM(canal_venda), '') IS NOT NULL
ORDER BY value ASC;
`, params),
pool.query(`
SELECT
NULLIF(TRIM(id_vendedor), '') as id,
NULLIF(TRIM(nome_vendedor), '') as name
FROM orders
${whereClause}
AND (
NULLIF(TRIM(id_vendedor), '') IS NOT NULL
OR NULLIF(TRIM(nome_vendedor), '') IS NOT NULL
)
GROUP BY id, name
ORDER BY COALESCE(name, id) ASC, id ASC;
`, params)
]);
const sellerOptionsByValue = new Map();
sellerResult.rows.forEach(row => {
const id = row.id || '';
const name = row.name || '';
const value = id ? `id:${id}` : `name:${name}`;
if (!value || sellerOptionsByValue.has(value)) return;
sellerOptionsByValue.set(value, {
value,
id,
name: name || id
});
});
return {
marketplaces: marketplaceResult.rows.map(row => row.value).filter(Boolean),
salesChannels: salesChannelResult.rows.map(row => row.value).filter(Boolean),
sellers: [...sellerOptionsByValue.values()]
};
};
const getOrderGroupKey = (row) => (
row.pedido_id ||
`${row.data_pedido || getDateOnly(row.data_pedido_date) || ''}_${row.valor_pedido || 0}`
@@ -720,14 +835,14 @@ const getClientDetailsAnalytics = async (clientToken, range = {}) => {
};
const getRfmAnalytics = async (range = {}) => {
const { params, whereClause } = buildDateFilter(range);
const { params, whereClause, endParamIndex } = buildDateFilter(range);
const normalizedStart = normalizeDateParam(range.start);
const normalizedEnd = normalizeDateParam(range.end);
const periodRecencyReferenceDate = normalizedEnd ? `$${params.length}::date` : 'CURRENT_DATE';
const periodRecencyReferenceDate = normalizedEnd && endParamIndex ? `$${endParamIndex}::date` : 'CURRENT_DATE';
const usePeriodAsHistory = !normalizedStart || normalizedStart <= '2000-01-01';
if (usePeriodAsHistory) {
const clientRows = await getClientAnalytics({ end: normalizedEnd });
const clientRows = await getClientAnalytics({ ...range, start: undefined, end: normalizedEnd });
const recencyEnd = normalizedEnd || new Date().toISOString().slice(0, 10);
const clients = buildRfmClients(clientRows.map(row => ({
customerKey: row.customerKey,
@@ -803,6 +918,11 @@ const getRfmAnalytics = async (range = {}) => {
const recencyReferenceDate = normalizedEnd
? `$${historyParams.push(normalizedEnd)}::date`
: 'CURRENT_DATE';
const historyFilters = [
'data_pedido_date IS NOT NULL',
`data_pedido_date <= ${recencyReferenceDate}`
];
appendOrderMetadataFilters(historyParams, historyFilters, range);
const customerKeysParam = `$${historyParams.push(periodCustomerKeys)}::text[]`;
const historyResult = await client.query(`
@@ -817,8 +937,7 @@ const getRfmAnalytics = async (range = {}) => {
MAX(data_pedido_date) as last_purchase_date,
GREATEST((${recencyReferenceDate} - MAX(data_pedido_date))::int, 0) as recency_days
FROM orders
WHERE data_pedido_date IS NOT NULL
AND data_pedido_date <= ${recencyReferenceDate}
WHERE ${historyFilters.join(' AND ')}
GROUP BY customer_key
),
scored_history AS MATERIALIZED (
@@ -923,6 +1042,7 @@ module.exports = {
isClientToken,
getFrequencyScore,
getClientDetailsAnalytics,
getClientFilterOptions,
getPreviousDate,
getRecencyScore,
getRfmAnalytics,