feat: Frontend CSS refactoring and test improvements
Frontend: - Refactored CSS architecture with new utility classes - Updated dashboard components styling - Improved responsive grid system - Enhanced typography and variables - Updated E2E and integration tests Added: - Claude Code slash commands for validation - SSH tunnel and start test scripts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -26,8 +26,8 @@ export const useDashboardStore = defineStore("dashboard", () => {
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
const response = await apiService.get('/dashboard/summary', {
|
||||
params: { company: companyId }
|
||||
const response = await apiService.get("/dashboard/summary", {
|
||||
params: { company: companyId },
|
||||
});
|
||||
summary.value = response.data;
|
||||
return { success: true };
|
||||
@@ -40,49 +40,58 @@ export const useDashboardStore = defineStore("dashboard", () => {
|
||||
}
|
||||
};
|
||||
|
||||
const loadTrendData = async (companyId, period = '12m', chartType = 'line') => {
|
||||
const loadTrendData = async (
|
||||
companyId,
|
||||
period = "12m",
|
||||
chartType = "line",
|
||||
) => {
|
||||
isLoading.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
console.log(`Loading trend data for company ${companyId}, period: ${period}`);
|
||||
|
||||
const response = await apiService.get('/dashboard/trends', {
|
||||
params: {
|
||||
company: companyId,
|
||||
period: period
|
||||
}
|
||||
console.log(
|
||||
`Loading trend data for company ${companyId}, period: ${period}`,
|
||||
);
|
||||
|
||||
const response = await apiService.get("/dashboard/trends", {
|
||||
params: {
|
||||
company: companyId,
|
||||
period: period,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
// Validate response structure
|
||||
if (!response.data) {
|
||||
throw new Error('Empty response from trends API');
|
||||
throw new Error("Empty response from trends API");
|
||||
}
|
||||
|
||||
console.log('Raw trends response:', response.data);
|
||||
|
||||
|
||||
console.log("Raw trends response:", response.data);
|
||||
|
||||
// Transform backend response to Chart.js format
|
||||
const backendData = response.data;
|
||||
const transformedData = transformTrendsData(backendData);
|
||||
|
||||
|
||||
if (!transformedData) {
|
||||
throw new Error('Failed to transform trends data - invalid format');
|
||||
throw new Error("Failed to transform trends data - invalid format");
|
||||
}
|
||||
|
||||
|
||||
trends.value = transformedData;
|
||||
console.log('Transformed trends data:', transformedData);
|
||||
|
||||
console.log("Transformed trends data:", transformedData);
|
||||
|
||||
return { success: true, data: transformedData };
|
||||
} catch (err) {
|
||||
const errorMessage = err.response?.data?.detail || err.message || "Failed to load trend data";
|
||||
const errorMessage =
|
||||
err.response?.data?.detail ||
|
||||
err.message ||
|
||||
"Failed to load trend data";
|
||||
error.value = errorMessage;
|
||||
console.error("Failed to load trend data:", err);
|
||||
console.error("Error details:", {
|
||||
status: err.response?.status,
|
||||
statusText: err.response?.statusText,
|
||||
data: err.response?.data
|
||||
data: err.response?.data,
|
||||
});
|
||||
|
||||
|
||||
// Clear trends data and return error - no more mock data
|
||||
trends.value = null;
|
||||
return { success: false, error: error.value };
|
||||
@@ -93,13 +102,24 @@ export const useDashboardStore = defineStore("dashboard", () => {
|
||||
|
||||
// Transform backend trends data to Chart.js format AND preserve raw data
|
||||
const transformTrendsData = (backendData) => {
|
||||
if (!backendData || !backendData.periods || !Array.isArray(backendData.periods) || backendData.periods.length === 0) {
|
||||
console.warn('Invalid trends data received:', backendData);
|
||||
if (
|
||||
!backendData ||
|
||||
!backendData.periods ||
|
||||
!Array.isArray(backendData.periods) ||
|
||||
backendData.periods.length === 0
|
||||
) {
|
||||
console.warn("Invalid trends data received:", backendData);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Validate that we have all required data
|
||||
const requiredFields = ['trezorerie_sold', 'clienti_sold', 'furnizori_sold', 'clienti_incasat', 'furnizori_achitat'];
|
||||
const requiredFields = [
|
||||
"trezorerie_sold",
|
||||
"clienti_sold",
|
||||
"furnizori_sold",
|
||||
"clienti_incasat",
|
||||
"furnizori_achitat",
|
||||
];
|
||||
for (const field of requiredFields) {
|
||||
if (!backendData[field] || !Array.isArray(backendData[field])) {
|
||||
console.warn(`Missing ${field} data`);
|
||||
@@ -111,10 +131,13 @@ export const useDashboardStore = defineStore("dashboard", () => {
|
||||
const periods = [...backendData.periods];
|
||||
|
||||
// Format labels for monthly data (YYYY-MM -> MM/YYYY)
|
||||
const formattedPeriods = periods.map(period => {
|
||||
const [year, month] = period.split('-');
|
||||
const formattedPeriods = periods.map((period) => {
|
||||
const [year, month] = period.split("-");
|
||||
const date = new Date(year, month - 1);
|
||||
return date.toLocaleDateString('ro-RO', { month: '2-digit', year: 'numeric' });
|
||||
return date.toLocaleDateString("ro-RO", {
|
||||
month: "2-digit",
|
||||
year: "numeric",
|
||||
});
|
||||
});
|
||||
|
||||
// Preserve all raw data from backend for card calculations
|
||||
@@ -143,35 +166,41 @@ export const useDashboardStore = defineStore("dashboard", () => {
|
||||
},
|
||||
datasets: [
|
||||
{
|
||||
label: 'Trezorerie - Sold Net',
|
||||
data: [...backendData.trezorerie_sold].map(val => Number(val) || 0),
|
||||
borderColor: 'rgb(59, 130, 246)',
|
||||
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
||||
label: "Trezorerie - Sold Net",
|
||||
data: [...backendData.trezorerie_sold].map((val) => Number(val) || 0),
|
||||
borderColor: "rgb(59, 130, 246)",
|
||||
backgroundColor: "rgba(59, 130, 246, 0.1)",
|
||||
tension: 0.4,
|
||||
fill: false,
|
||||
pointBackgroundColor: 'rgb(59, 130, 246)',
|
||||
pointBorderColor: '#ffffff',
|
||||
pointBackgroundColor: "rgb(59, 130, 246)",
|
||||
pointBorderColor: "#ffffff",
|
||||
pointBorderWidth: 2,
|
||||
pointRadius: 4,
|
||||
pointHoverRadius: 6
|
||||
}
|
||||
]
|
||||
pointHoverRadius: 6,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const loadDetailedData = async (dataType, companyId, page = 1, pageSize = 25, search = '') => {
|
||||
const loadDetailedData = async (
|
||||
dataType,
|
||||
companyId,
|
||||
page = 1,
|
||||
pageSize = 25,
|
||||
search = "",
|
||||
) => {
|
||||
isLoading.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
const response = await apiService.get('/dashboard/detailed-data', {
|
||||
const response = await apiService.get("/dashboard/detailed-data", {
|
||||
params: {
|
||||
company: companyId,
|
||||
data_type: dataType,
|
||||
page: page,
|
||||
page_size: pageSize,
|
||||
search: search
|
||||
}
|
||||
search: search,
|
||||
},
|
||||
});
|
||||
|
||||
// Store total for pagination
|
||||
@@ -179,12 +208,13 @@ export const useDashboardStore = defineStore("dashboard", () => {
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data || [], // Backend returns 'data' not 'items'
|
||||
data: response.data.data || [], // Backend returns 'data' not 'items'
|
||||
total: response.data.total || 0,
|
||||
page: response.data.page || 1
|
||||
page: response.data.page || 1,
|
||||
};
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.detail || "Failed to load detailed data";
|
||||
error.value =
|
||||
err.response?.data?.detail || "Failed to load detailed data";
|
||||
console.error("Failed to load detailed data:", err);
|
||||
|
||||
// Return mock data structure for testing
|
||||
@@ -195,7 +225,7 @@ export const useDashboardStore = defineStore("dashboard", () => {
|
||||
error: error.value,
|
||||
data: mockData,
|
||||
total: mockData.length,
|
||||
page: 1
|
||||
page: 1,
|
||||
};
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
@@ -204,30 +234,135 @@ export const useDashboardStore = defineStore("dashboard", () => {
|
||||
|
||||
// Generate mock data for testing until backend endpoint is implemented
|
||||
const generateMockDetailedData = (dataType) => {
|
||||
switch(dataType) {
|
||||
case 'clients':
|
||||
switch (dataType) {
|
||||
case "clients":
|
||||
return [
|
||||
{ id: 1, client: 'SC ALPHA SRL', facturat: 15000, incasat: 12000, sold: 3000, status: 'Activ' },
|
||||
{ id: 2, client: 'SC BETA SRL', facturat: 8500, incasat: 8500, sold: 0, status: 'Activ' },
|
||||
{ id: 3, client: 'SC GAMMA SRL', facturat: 22000, incasat: 15000, sold: 7000, status: 'Activ' },
|
||||
{ id: 4, client: 'SC DELTA SRL', facturat: 5500, incasat: 2000, sold: 3500, status: 'Întârziere' },
|
||||
{ id: 5, client: 'SC EPSILON SRL', facturat: 18000, incasat: 18000, sold: 0, status: 'Activ' }
|
||||
{
|
||||
id: 1,
|
||||
client: "SC ALPHA SRL",
|
||||
facturat: 15000,
|
||||
incasat: 12000,
|
||||
sold: 3000,
|
||||
status: "Activ",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
client: "SC BETA SRL",
|
||||
facturat: 8500,
|
||||
incasat: 8500,
|
||||
sold: 0,
|
||||
status: "Activ",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
client: "SC GAMMA SRL",
|
||||
facturat: 22000,
|
||||
incasat: 15000,
|
||||
sold: 7000,
|
||||
status: "Activ",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
client: "SC DELTA SRL",
|
||||
facturat: 5500,
|
||||
incasat: 2000,
|
||||
sold: 3500,
|
||||
status: "Întârziere",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
client: "SC EPSILON SRL",
|
||||
facturat: 18000,
|
||||
incasat: 18000,
|
||||
sold: 0,
|
||||
status: "Activ",
|
||||
},
|
||||
];
|
||||
case 'suppliers':
|
||||
case "suppliers":
|
||||
return [
|
||||
{ id: 1, furnizor: 'SC SUPPLIER A SRL', facturat: 12000, achitat: 10000, sold: 2000, status: 'Activ' },
|
||||
{ id: 2, furnizor: 'SC SUPPLIER B SRL', facturat: 7500, achitat: 7500, sold: 0, status: 'Activ' },
|
||||
{ id: 3, furnizor: 'SC SUPPLIER C SRL', facturat: 19000, achitat: 12000, sold: 7000, status: 'Pendente' },
|
||||
{ id: 4, furnizor: 'SC SUPPLIER D SRL', facturat: 4200, achitat: 4200, sold: 0, status: 'Activ' },
|
||||
{ id: 5, furnizor: 'SC SUPPLIER E SRL', facturat: 16800, achitat: 8000, sold: 8800, status: 'Pendente' }
|
||||
{
|
||||
id: 1,
|
||||
furnizor: "SC SUPPLIER A SRL",
|
||||
facturat: 12000,
|
||||
achitat: 10000,
|
||||
sold: 2000,
|
||||
status: "Activ",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
furnizor: "SC SUPPLIER B SRL",
|
||||
facturat: 7500,
|
||||
achitat: 7500,
|
||||
sold: 0,
|
||||
status: "Activ",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
furnizor: "SC SUPPLIER C SRL",
|
||||
facturat: 19000,
|
||||
achitat: 12000,
|
||||
sold: 7000,
|
||||
status: "Pendente",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
furnizor: "SC SUPPLIER D SRL",
|
||||
facturat: 4200,
|
||||
achitat: 4200,
|
||||
sold: 0,
|
||||
status: "Activ",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
furnizor: "SC SUPPLIER E SRL",
|
||||
facturat: 16800,
|
||||
achitat: 8000,
|
||||
sold: 8800,
|
||||
status: "Pendente",
|
||||
},
|
||||
];
|
||||
case 'treasury':
|
||||
case "treasury":
|
||||
return [
|
||||
{ id: 1, cont: '5121', nume_cont: 'Cont curent BCR', sold: 45000, valuta: 'RON', tip: 'Bancă' },
|
||||
{ id: 2, cont: '5311', nume_cont: 'Casa RON', sold: 2500, valuta: 'RON', tip: 'Numerar' },
|
||||
{ id: 3, cont: '5124', nume_cont: 'Cont curent BRD EUR', sold: 8500, valuta: 'EUR', tip: 'Bancă' },
|
||||
{ id: 4, cont: '5125', nume_cont: 'Cont economii ING', sold: 125000, valuta: 'RON', tip: 'Economii' },
|
||||
{ id: 5, cont: '5312', nume_cont: 'Casa valută', sold: 500, valuta: 'EUR', tip: 'Numerar' }
|
||||
{
|
||||
id: 1,
|
||||
cont: "5121",
|
||||
nume_cont: "Cont curent BCR",
|
||||
sold: 45000,
|
||||
valuta: "RON",
|
||||
tip: "Bancă",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
cont: "5311",
|
||||
nume_cont: "Casa RON",
|
||||
sold: 2500,
|
||||
valuta: "RON",
|
||||
tip: "Numerar",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
cont: "5124",
|
||||
nume_cont: "Cont curent BRD EUR",
|
||||
sold: 8500,
|
||||
valuta: "EUR",
|
||||
tip: "Bancă",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
cont: "5125",
|
||||
nume_cont: "Cont economii ING",
|
||||
sold: 125000,
|
||||
valuta: "RON",
|
||||
tip: "Economii",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
cont: "5312",
|
||||
nume_cont: "Casa valută",
|
||||
sold: 500,
|
||||
valuta: "EUR",
|
||||
tip: "Numerar",
|
||||
},
|
||||
];
|
||||
default:
|
||||
return [];
|
||||
@@ -235,92 +370,92 @@ export const useDashboardStore = defineStore("dashboard", () => {
|
||||
};
|
||||
|
||||
// Funcții noi pentru carduri
|
||||
const loadPerformanceData = async (companyId, period = '7d') => {
|
||||
const loadPerformanceData = async (companyId, period = "7d") => {
|
||||
const cacheKey = `performance-${companyId}-${period}`;
|
||||
|
||||
|
||||
// Check cache
|
||||
if (dataCache.has(cacheKey)) {
|
||||
performanceData.value[period] = dataCache.get(cacheKey);
|
||||
return { success: true, data: dataCache.get(cacheKey) };
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const response = await apiService.get('/dashboard/performance', {
|
||||
params: { company: companyId, period }
|
||||
const response = await apiService.get("/dashboard/performance", {
|
||||
params: { company: companyId, period },
|
||||
});
|
||||
|
||||
|
||||
performanceData.value[period] = response.data;
|
||||
dataCache.set(cacheKey, response.data);
|
||||
|
||||
|
||||
return { success: true, data: response.data };
|
||||
} catch (err) {
|
||||
console.error('Failed to load performance data:', err);
|
||||
console.error("Failed to load performance data:", err);
|
||||
return { success: false, error: err.message };
|
||||
}
|
||||
};
|
||||
|
||||
const loadCashFlowData = async (companyId, period = '7d') => {
|
||||
|
||||
const loadCashFlowData = async (companyId, period = "7d") => {
|
||||
const cacheKey = `cashflow-${companyId}-${period}`;
|
||||
|
||||
|
||||
if (dataCache.has(cacheKey)) {
|
||||
cashflowData.value[period] = dataCache.get(cacheKey);
|
||||
return { success: true, data: dataCache.get(cacheKey) };
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const response = await apiService.get('/dashboard/cashflow', {
|
||||
params: { company: companyId, period }
|
||||
const response = await apiService.get("/dashboard/cashflow", {
|
||||
params: { company: companyId, period },
|
||||
});
|
||||
|
||||
|
||||
cashflowData.value[period] = response.data;
|
||||
dataCache.set(cacheKey, response.data);
|
||||
|
||||
|
||||
return { success: true, data: response.data };
|
||||
} catch (err) {
|
||||
console.error('Failed to load cashflow data:', err);
|
||||
console.error("Failed to load cashflow data:", err);
|
||||
return { success: false, error: err.message };
|
||||
}
|
||||
};
|
||||
|
||||
const loadMaturityData = async (companyId, period = '7d') => {
|
||||
|
||||
const loadMaturityData = async (companyId, period = "7d") => {
|
||||
const cacheKey = `maturity-${companyId}-${period}`;
|
||||
|
||||
|
||||
if (dataCache.has(cacheKey)) {
|
||||
maturityData.value[period] = dataCache.get(cacheKey);
|
||||
return { success: true, data: dataCache.get(cacheKey) };
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const response = await apiService.get('/dashboard/maturity', {
|
||||
params: { company: companyId, period }
|
||||
const response = await apiService.get("/dashboard/maturity", {
|
||||
params: { company: companyId, period },
|
||||
});
|
||||
|
||||
|
||||
maturityData.value[period] = response.data;
|
||||
dataCache.set(cacheKey, response.data);
|
||||
|
||||
|
||||
return { success: true, data: response.data };
|
||||
} catch (err) {
|
||||
console.error('Failed to load maturity data:', err);
|
||||
console.error("Failed to load maturity data:", err);
|
||||
return { success: false, error: err.message };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const loadCurrentPeriod = async (companyId) => {
|
||||
try {
|
||||
const response = await apiService.get('/dashboard/current-period', {
|
||||
params: { company: companyId }
|
||||
const response = await apiService.get("/dashboard/current-period", {
|
||||
params: { company: companyId },
|
||||
});
|
||||
|
||||
currentPeriod.value = response.data;
|
||||
return { success: true, data: response.data };
|
||||
} catch (err) {
|
||||
console.error('Failed to load current period:', err);
|
||||
console.error("Failed to load current period:", err);
|
||||
// Fallback to current date if API fails
|
||||
const now = new Date();
|
||||
const fallbackPeriod = {
|
||||
year: now.getFullYear(),
|
||||
month: now.getMonth() + 1,
|
||||
period: `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
|
||||
period: `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`,
|
||||
};
|
||||
currentPeriod.value = fallbackPeriod;
|
||||
return { success: false, error: err.message, data: fallbackPeriod };
|
||||
@@ -368,6 +503,6 @@ export const useDashboardStore = defineStore("dashboard", () => {
|
||||
clearCache,
|
||||
|
||||
// Detailed data pagination
|
||||
detailedDataTotal
|
||||
detailedDataTotal,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user