feat(reports): add daily rate to report tables and exports
This commit is contained in:
@@ -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[];
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -468,10 +468,11 @@ export const en = {
|
||||
name: "Name",
|
||||
clear: "Clear",
|
||||
apply: "Apply",
|
||||
totalHours: "Total hours",
|
||||
billableHours: "Billable hours",
|
||||
nonBillableHours: "Non-billable hours",
|
||||
totalIncome: "Total income",
|
||||
totalHours: "Total hours",
|
||||
billableHours: "Billable hours",
|
||||
nonBillableHours: "Non-billable hours",
|
||||
hourlyRate: "Hourly rate",
|
||||
totalIncome: "Total income",
|
||||
chartTitle: "Activity chart",
|
||||
totalSeconds: "Total seconds",
|
||||
exportExcel: "Export Excel",
|
||||
|
||||
@@ -464,10 +464,11 @@ export const fa = {
|
||||
name: "نام",
|
||||
clear: "پاک کردن",
|
||||
apply: "اعمال",
|
||||
totalHours: "مجموع ساعت",
|
||||
billableHours: "ساعات کاری",
|
||||
nonBillableHours: "ساعات غیر کاری",
|
||||
totalIncome: "مجموع درآمد",
|
||||
totalHours: "مجموع ساعت",
|
||||
billableHours: "ساعات کاری",
|
||||
nonBillableHours: "ساعات غیر کاری",
|
||||
hourlyRate: "نرخ ساعتی",
|
||||
totalIncome: "مجموع درآمد",
|
||||
chartTitle: "نمودار فعالیت",
|
||||
totalSeconds: "مجموع ثانیه",
|
||||
exportExcel: "خروجی Excel",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user