feat(reports): add daily rate to report tables and exports

This commit is contained in:
2026-04-28 20:26:21 +03:30
parent 3efa04094d
commit 2b5ee2abf1
5 changed files with 30 additions and 11 deletions

View File

@@ -58,6 +58,7 @@ export interface DailyReportRow {
billable_duration: string;
non_billable_duration: string;
total_duration: string;
latest_hourly_rate: CurrencyTotal | null;
income_totals: CurrencyTotal[];
}

View File

@@ -43,6 +43,14 @@ const formatMoneyTotals = (totals: { currency: string; amount: string }[], lang:
return totals.map((item) => `${formatAmount(item.amount, lang)} ${currencyLabel(item.currency, lang)}`).join(" | ");
};
const formatHourlyRate = (
rate: { currency: string; amount: string } | null,
lang: "en" | "fa",
) => {
if (!rate) return "-";
return `${formatAmount(rate.amount, lang)} ${currencyLabel(rate.currency, lang)}`;
};
const formatDisplayDate = (value: string, lang: "en" | "fa") => {
const parsed = new Date(`${value}T00:00:00`);
return new Intl.DateTimeFormat(lang === "fa" ? "fa-IR" : "en-US", {
@@ -209,6 +217,10 @@ export function ReportsTablePanel({
<div className="mb-1 text-[11px] uppercase tracking-[0.12em] text-slate-400 dark:text-slate-500">{labels.nonBillableHours}</div>
<div className="font-medium">{localizeDigits(day.non_billable_duration, lang)}</div>
</div>
<div>
<div className="mb-1 text-[11px] uppercase tracking-[0.12em] text-slate-400 dark:text-slate-500">{labels.hourlyRate}</div>
<div className="font-medium">{formatHourlyRate(day.latest_hourly_rate, lang)}</div>
</div>
<div className="col-span-2">
<div className="mb-1 text-[11px] uppercase tracking-[0.12em] text-slate-400 dark:text-slate-500">{labels.totalIncome}</div>
<div className="font-medium">{formatMoneyTotals(day.income_totals, lang)}</div>
@@ -249,9 +261,10 @@ export function ReportsTablePanel({
<thead>
<tr className="border-b border-slate-200 text-slate-500 dark:border-slate-800 dark:text-slate-400">
<th className="w-[18%] px-3 py-3 text-start font-medium">{labels.date}</th>
<th className="w-[16%] px-3 py-3 text-start font-medium">{labels.billableHours}</th>
<th className="w-[20%] px-3 py-3 text-start font-medium">{labels.nonBillableHours}</th>
<th className="w-[36%] px-3 py-3 text-start font-medium">{labels.totalIncome}</th>
<th className="w-[14%] px-3 py-3 text-start font-medium">{labels.billableHours}</th>
<th className="w-[14%] px-3 py-3 text-start font-medium">{labels.nonBillableHours}</th>
<th className="w-[18%] px-3 py-3 text-start font-medium">{labels.hourlyRate}</th>
<th className="w-[26%] px-3 py-3 text-start font-medium">{labels.totalIncome}</th>
<th className="w-[10%] px-3 py-3 text-start font-medium">{labels.details}</th>
</tr>
</thead>
@@ -264,6 +277,7 @@ export function ReportsTablePanel({
<td className="px-3 py-3 font-medium text-slate-900 dark:text-slate-100">{formatDisplayDate(day.date, lang)}</td>
<td className="px-3 py-3 text-slate-700 dark:text-slate-300">{localizeDigits(day.billable_duration, lang)}</td>
<td className="px-3 py-3 text-slate-700 dark:text-slate-300">{localizeDigits(day.non_billable_duration, lang)}</td>
<td className="px-3 py-3 text-slate-700 dark:text-slate-300">{formatHourlyRate(day.latest_hourly_rate, lang)}</td>
<td className="px-3 py-3 text-slate-700 dark:text-slate-300">{formatMoneyTotals(day.income_totals, lang)}</td>
<td className="px-3 py-3">
<button
@@ -300,6 +314,7 @@ export function ReportsTablePanel({
<td className="px-3 py-3">{labels.total}</td>
<td className="px-3 py-3">{localizeDigits(data.summary.billable_duration, lang)}</td>
<td className="px-3 py-3">{localizeDigits(data.summary.non_billable_duration, lang)}</td>
<td className="px-3 py-3">-</td>
<td className="px-3 py-3">{formatMoneyTotals(data.summary.income_totals, lang)}</td>
<td className="px-3 py-3" />
</tr>

View File

@@ -471,6 +471,7 @@ export const en = {
totalHours: "Total hours",
billableHours: "Billable hours",
nonBillableHours: "Non-billable hours",
hourlyRate: "Hourly rate",
totalIncome: "Total income",
chartTitle: "Activity chart",
totalSeconds: "Total seconds",

View File

@@ -467,6 +467,7 @@ export const fa = {
totalHours: "مجموع ساعت",
billableHours: "ساعات کاری",
nonBillableHours: "ساعات غیر کاری",
hourlyRate: "نرخ ساعتی",
totalIncome: "مجموع درآمد",
chartTitle: "نمودار فعالیت",
totalSeconds: "مجموع ثانیه",

View File

@@ -381,6 +381,7 @@ export default function Reports() {
billableHours: t.reports?.billableHours || "Billable hours",
nonBillableHours: t.reports?.nonBillableHours || "Non-billable hours",
totalHours: t.reports?.totalHours || "Total hours",
hourlyRate: t.reports?.hourlyRate || "Hourly rate",
totalIncome: t.reports?.totalIncome || "Total income",
details: t.reports?.details || "Details",
total: t.reports?.total || "Total",