Add business Finance hub with invoices and templates.

Ship invoice issue/list/templates under Finance, fix tenant theme reset and owner role badge, and show customers-joined charts by Persian months.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-11 15:17:03 +03:30
co-authored by Cursor
parent 722933dda9
commit 917b840ee5
44 changed files with 5136 additions and 105 deletions
@@ -0,0 +1,45 @@
import type { DailyActivityPoint } from '../services/dailyActivityService'
import { buildLast12MonthKeys, formatMonthLabel } from './productActivity'
export interface MonthActivityPoint {
monthKey: string
label: string
primary: number
secondary: number
}
function toMonthKey(dateKey: string): string {
return dateKey.slice(0, 7)
}
/** Roll daily dual series into the last 12 calendar months. */
export function aggregateDailyActivityByMonth(
primaryItems: DailyActivityPoint[],
secondaryItems: DailyActivityPoint[],
locale: string,
): MonthActivityPoint[] {
const monthKeys = buildLast12MonthKeys()
const primaryByMonth = new Map(monthKeys.map((key) => [key, 0]))
const secondaryByMonth = new Map(monthKeys.map((key) => [key, 0]))
for (const item of primaryItems) {
const key = toMonthKey(item.date)
if (primaryByMonth.has(key)) {
primaryByMonth.set(key, (primaryByMonth.get(key) ?? 0) + item.count)
}
}
for (const item of secondaryItems) {
const key = toMonthKey(item.date)
if (secondaryByMonth.has(key)) {
secondaryByMonth.set(key, (secondaryByMonth.get(key) ?? 0) + item.count)
}
}
return monthKeys.map((monthKey) => ({
monthKey,
label: formatMonthLabel(monthKey, locale),
primary: primaryByMonth.get(monthKey) ?? 0,
secondary: secondaryByMonth.get(monthKey) ?? 0,
}))
}