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>
46 lines
1.3 KiB
TypeScript
46 lines
1.3 KiB
TypeScript
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,
|
|
}))
|
|
}
|