Files
graphs/src/dataService.ts
Cauê Faleiros fc7a50fddf
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m5s
Fix RFM date range consistency
2026-06-15 10:48:00 -03:00

223 lines
6.7 KiB
TypeScript

import type { CampaignPreview, CampaignProcessSummary, CampaignQueueSummary, DashboardAnalytics, DateRange, OrderData, RfmAnalytics, StockData } from './types';
import { formatDateParam } from './dateRanges';
const API_URL = import.meta.env.VITE_API_URL || '/api';
export const login = async (email: string, password: string): Promise<boolean> => {
try {
const response = await fetch(`${API_URL}/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
});
if (response.ok) {
const data = await response.json();
localStorage.setItem('auth_token', data.token);
return true;
}
return false;
} catch (error) {
console.error('Login failed', error);
return false;
}
};
export const logout = () => {
localStorage.removeItem('auth_token');
window.location.href = '/#/login';
};
export const isAuthenticated = (): boolean => {
return !!localStorage.getItem('auth_token');
};
export const fetchStock = async (): Promise<StockData[]> => {
try {
const token = localStorage.getItem('auth_token');
const response = await fetch(`${API_URL}/stock`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.status === 401 || response.status === 403) {
logout();
return [];
}
if (!response.ok) return [];
return await response.json();
} catch {
return [];
}
};
export const fetchData = async (): Promise<OrderData[]> => {
try {
const token = localStorage.getItem('auth_token');
const response = await fetch(`${API_URL}/data`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.status === 401 || response.status === 403) {
logout();
return [];
}
if (!response.ok) return [];
return await response.json();
} catch (error) {
console.error("Fetch failed", error);
return [];
}
};
const authFetch = async (path: string, options: RequestInit = {}): Promise<Response> => {
const token = localStorage.getItem('auth_token');
const response = await fetch(`${API_URL}${path}`, {
...options,
headers: {
...(options.headers || {}),
'Authorization': `Bearer ${token}`
}
});
if (response.status === 401 || response.status === 403) {
logout();
}
return response;
};
export const fetchDashboardAnalytics = async (dateRange: DateRange): Promise<DashboardAnalytics | null> => {
try {
const params = new URLSearchParams({
start: formatDateParam(dateRange.start),
end: formatDateParam(dateRange.end)
});
const response = await authFetch(`/analytics/dashboard?${params.toString()}`);
if (!response.ok) return null;
return await response.json();
} catch (error) {
console.error('Fetch dashboard analytics failed', error);
return null;
}
};
export const fetchRfmAnalytics = async (dateRange: DateRange): Promise<RfmAnalytics | null> => {
try {
const params = new URLSearchParams({
start: formatDateParam(dateRange.start),
end: formatDateParam(dateRange.end)
});
const response = await authFetch(`/analytics/rfm?${params.toString()}`);
if (!response.ok) return null;
return await response.json();
} catch (error) {
console.error('Fetch RFM analytics failed', error);
return null;
}
};
export const fetchCampaigns = async (): Promise<CampaignQueueSummary | null> => {
try {
const response = await authFetch('/campaigns');
if (!response.ok) return null;
return await response.json();
} catch (error) {
console.error('Fetch campaigns failed', error);
return null;
}
};
export const fetchCampaignPreview = async (): Promise<CampaignPreview | null> => {
try {
const response = await authFetch('/campaigns/preview');
if (!response.ok) return null;
return await response.json();
} catch (error) {
console.error('Fetch campaign preview failed', error);
return null;
}
};
export const processCampaignsNow = async (): Promise<CampaignProcessSummary | null> => {
try {
const response = await authFetch('/campaigns/process', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({})
});
if (!response.ok) return null;
return await response.json();
} catch (error) {
console.error('Process campaigns failed', error);
return null;
}
};
export const retryCampaignGroup = async (baseProductName: string): Promise<boolean> => {
try {
const response = await authFetch('/campaigns/retry', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ baseProductName })
});
return response.ok;
} catch (error) {
console.error('Retry campaign failed', error);
return false;
}
};
export const parseOrderDate = (dateStr: string): Date => {
if (!dateStr) return new Date(0);
if (dateStr.includes('T')) return new Date(dateStr);
const parts = dateStr.split(/[-/]/);
if (parts.length === 3) {
if (parts[0].length === 4) {
// YYYY-MM-DD
return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
} else {
// DD-MM-YYYY
return new Date(Number(parts[2]), Number(parts[1]) - 1, Number(parts[0]));
}
}
const fallback = new Date(dateStr);
return isNaN(fallback.getTime()) ? new Date(0) : fallback;
};
export const exportToCSV = (data: Record<string, unknown>[], filename: string) => {
if (!data || !data.length) return;
const headers = Object.keys(data[0]);
const csvRows = [];
// Add headers
csvRows.push(headers.join(','));
// Add rows
for (const row of data) {
const values = headers.map(header => {
const val = row[header];
const escaped = String(val ?? '').replace(/"/g, '""');
return `"${escaped}"`;
});
csvRows.push(values.join(','));
}
const csvString = csvRows.join('\n');
const blob = new Blob([csvString], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
if (link.download !== undefined) {
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
};