import { COABalance, COABalanceTimeFrame, ID, ReportID, User, UserPayload } from '@zeniai/client-epic-state'; import { ReportTreeNode } from '../../reportTree/reportTreeTypes'; import { CompanyNameWithId, LiveBlocksCompany, LiveBlocksUser, ThreadMetadata } from './CollaborationTypes'; export declare const getLiveBlocksUsersByUserIds: (users: User[], userId: ID[]) => LiveBlocksUser[]; export declare const getCompanyByCompanyIds: (companies: CompanyNameWithId[], roomIds: ID[]) => LiveBlocksCompany[]; export declare const getCompanyIdFromRoomId: (roomId: ID) => ID | undefined; export declare const getUsersByUserIdsUserPayload: (users: UserPayload[], userId: ID[]) => LiveBlocksUser[]; export declare const mapUsersPayloadToUsers: (usersPayloadList: UserPayload[], userIds: ID[]) => User[]; /** * Merge a freshly-fetched LiveBlocksUser list into an existing cache by * userId. Primed entries must survive: a blind replace erases the * internal-teammate IDs that `primeCommentingUsers` injected, and the * mention picker falls back to "Zeni Team" until the next prime cycle. */ export declare const mergeLiveBlocksUsers: (existing: LiveBlocksUser[], fetched: LiveBlocksUser[]) => LiveBlocksUser[]; export declare const toLiveBlocksUsers: (users: UserPayload[]) => LiveBlocksUser[]; export declare const getUsersByUserIdsFromLiveBlockUsers: (users: LiveBlocksUser[], userIds: ID[]) => LiveBlocksUser[]; export declare const filterAndReturnUserIds: (users: LiveBlocksUser[], text: string) => ID[]; /** * Expense Automation row entityType bases that share a comment pool with the * transaction detail page (Transactions / Receipts tabs). Newer threads * append the transaction type as a final segment. */ export declare const EA_TRANSACTION_ROW_ENTITY_TYPE_BASES: string[]; /** * Field-level transaction detail threads (`transaction.details.`, e.g. * `transaction.details.memo`). These anchor to a specific field on the * transaction detail page: they open inline there, and are excluded from the * Expense Automation list drawers (which aggregate only transaction-level * comments). Page-level `transaction.details` (exact) is NOT a field thread — * it has no trailing segment, so it does not match this prefix. */ export declare const TRANSACTION_DETAIL_FIELD_ENTITY_TYPE_PREFIX = "transaction.details."; export declare const isTransactionDetailFieldEntityType: (entityType: string) => boolean; /** * Derives a stable column key from a COABalance for per-cell comment targeting. * * Regular period columns use `startDate_endDate` formatted with the shared * analytics `YYYY-MM-DD` format — a timezone-independent machine identifier * (not display copy), so the same month always yields the same key regardless * of the viewer's timezone or DST. Calculated columns (YTD, Change %, etc.) * use the balance type enum string. * * The `_` between startDate and endDate is a parsing contract: * parseReportColumnPeriod splits on the FIRST underscore (the `YYYY-MM-DD` * dates use `-`, never `_`) — any new serialization must keep that property. * Legacy comments serialized the dates as a timezone-dependent ZeniDate * toString (`Sun, 01 Mar 2026 05:00:00 GMT`); canonicalizeColumnKey normalizes * those to this form on read so they still resolve. * Returns undefined for null balances so callers can skip commenting on empty cells. */ export declare const toColumnKey: (balance: COABalance | null) => string | undefined; /** * Builds a per-cell entityId by combining a row-level stable ID with a column key. * Returns undefined if either part is missing (commenting should be disabled for that cell). */ export declare const toCellEntityId: (rowStableId: string | undefined, balance: COABalance | null) => string | undefined; /** * Normalizes a column key to its canonical, timezone-independent form. * Date-pair keys become `YYYY-MM-DD_YYYY-MM-DD`; calculated-column keys * (ytd_total, …) and anything that isn't a date pair pass through unchanged. * Legacy keys serialized from a ZeniDate (`Sun, 01 Mar 2026 05:00:00 GMT_…`) * normalize to the same string toColumnKey now produces, so comments created * before the canonical format still resolve to their cell. */ export declare const canonicalizeColumnKey: (columnKey: string) => string; /** * Normalizes a per-cell entityId (`{rowStableId}:{columnKey}`) by canonicalizing * its column key. entityIds without a `:` column suffix (non-report threads) * and cells whose column key isn't a date pair are returned unchanged. Used on * read so legacy comments match freshly-rendered canonical cells. */ export declare const canonicalizeCellEntityId: (entityId: string) => string; export interface ReportThreadTarget { accountId: string; cellEntityId: string; columnKey: string; reportId: ReportID; } /** * Parses thread metadata into structured navigation coordinates for report cells. * * entityType format: `{tab}.details.{reportId}` (e.g. `standard_report.details.profit_and_loss`) * entityId format: `{accountId}:{columnKey}` where columnKey is either a * calculated balance type (e.g. `ytd_total`) or canonical `{startDate}_{endDate}` * in `YYYY-MM-DD` form (e.g. `account_1a2b:2026-06-01_2026-06-30`). Legacy * comments used a timezone-dependent ZeniDate toString * (`account_1a2b:Mon, 01 Jun 2026 07:00:00 GMT_Tue, 30 Jun 2026 07:00:00 GMT`); * canonicalizeColumnKey normalizes those on read. The split below uses the * FIRST colon, which is why the time-of-day colons in legacy dates are safe. */ export declare const parseReportThreadTarget: (metadata: ThreadMetadata | undefined) => ReportThreadTarget | null; export interface ReportColumnPeriod { endDate: Date; startDate: Date; } /** * Parses a `startDate_endDate` column key (see toColumnKey) back into dates. * Returns null for calculated-column keys (e.g. `ytd_total`) and anything * else that isn't a valid date pair. */ export declare const parseReportColumnPeriod: (columnKey: string) => ReportColumnPeriod | null; /** * Derives the "View Columns By" granularity a report column belongs to from * its period span. Only returns the granularities the reports filter bar * offers (month / quarter / year); anything else (weeks, free ranges) maps * to null so callers skip the timeframe switch. */ export declare const deriveReportColumnTimeframe: (period: ReportColumnPeriod) => COABalanceTimeFrame | null; export interface TreeNodeLookupResult { ancestorIds: string[]; targetNodeId: string; } /** * Walks a report tree and returns the chain of ancestor node IDs leading * to the node whose `reportElementData.element.data` has a matching `accountId`, * plus the target node's own ID (needed for react-vtree scrollToItem). * Returns null when the account is not found anywhere in the tree. */ export declare const findAncestorNodeIds: (rootNodes: ReportTreeNode[], targetAccountId: string) => TreeNodeLookupResult | null;