diff --git a/src/shared/utils/teamTaskState.ts b/src/shared/utils/teamTaskState.ts index b3d059a8..c5afb481 100644 --- a/src/shared/utils/teamTaskState.ts +++ b/src/shared/utils/teamTaskState.ts @@ -7,78 +7,73 @@ export interface TeamTaskStateLike { export type TeamTaskWorkflowColumn = 'review' | 'approved'; -export function isTeamTaskApproved(task: TeamTaskStateLike): boolean { - if (isTeamTaskDeleted(task) || task.status === 'pending') { - return false; - } - - if (task.kanbanColumn === 'approved') { - return true; - } - - if (task.kanbanColumn === 'review') { - return false; - } - - return task.reviewState === 'approved'; +interface CachedTeamTaskState { + status: TeamTaskStateLike['status']; + reviewState: TeamTaskStateLike['reviewState']; + kanbanColumn: TeamTaskStateLike['kanbanColumn']; + deletedAt: TeamTaskStateLike['deletedAt']; + deleted: boolean; + approved: boolean; + workflowColumn: TeamTaskWorkflowColumn | undefined; + needsFixActionable: boolean; + finishedForDependency: boolean; + terminalForActionableWork: boolean; } -export function isTeamTaskDeleted(task: TeamTaskStateLike): boolean { - return task.status === 'deleted' || Boolean(task.deletedAt); -} +const teamTaskStateCache = new WeakMap(); -export function isTeamTaskActivelyWorked(task: TeamTaskStateLike): boolean { - return ( - task.status === 'in_progress' && - getTeamTaskWorkflowColumn(task) !== 'review' && - !isTeamTaskApproved(task) && - !isTeamTaskDeleted(task) - ); -} - -export function isTeamTaskNeedsFixActionable(task: TeamTaskStateLike): boolean { - return ( - task.reviewState === 'needsFix' && - !isTeamTaskDeleted(task) && - getTeamTaskWorkflowColumn(task) === undefined - ); -} - -export function isTeamTaskFinishedForDependency(task: TeamTaskStateLike): boolean { - const workflowColumn = getTeamTaskWorkflowColumn(task); - if (workflowColumn === 'approved') { - return true; - } - if (workflowColumn === 'review' || isTeamTaskNeedsFixActionable(task)) { - return false; - } - return task.status === 'completed'; -} - -export function isTeamTaskTerminalForActionableWork(task: TeamTaskStateLike): boolean { - if (isTeamTaskDeleted(task)) { - return true; +function getCachedTeamTaskState(task: TeamTaskStateLike): CachedTeamTaskState { + const cached = teamTaskStateCache.get(task); + if ( + cached && + cached.status === task.status && + cached.reviewState === task.reviewState && + cached.kanbanColumn === task.kanbanColumn && + cached.deletedAt === task.deletedAt + ) { + return cached; } - const workflowColumn = getTeamTaskWorkflowColumn(task); - if (workflowColumn === 'approved') { - return true; - } - - if (workflowColumn === 'review' || isTeamTaskNeedsFixActionable(task)) { - return false; - } - return task.status === 'completed'; + const deleted = task.status === 'deleted' || Boolean(task.deletedAt); + const workflowColumn = resolveTeamTaskWorkflowColumn(task, deleted); + const approved = + !deleted && + task.status !== 'pending' && + (task.kanbanColumn === 'approved' || + (task.kanbanColumn !== 'review' && task.reviewState === 'approved')); + const needsFixActionable = + task.reviewState === 'needsFix' && !deleted && workflowColumn === undefined; + const finishedForDependency = + workflowColumn === 'approved' + ? true + : workflowColumn === 'review' || needsFixActionable + ? false + : task.status === 'completed'; + const terminalForActionableWork = + deleted || + workflowColumn === 'approved' || + (workflowColumn !== 'review' && !needsFixActionable && task.status === 'completed'); + const next: CachedTeamTaskState = { + status: task.status, + reviewState: task.reviewState, + kanbanColumn: task.kanbanColumn, + deletedAt: task.deletedAt, + deleted, + approved, + workflowColumn, + needsFixActionable, + finishedForDependency, + terminalForActionableWork, + }; + teamTaskStateCache.set(task, next); + return next; } -export function isTeamTaskFinalForCompletionNotification(task: TeamTaskStateLike): boolean { - return isTeamTaskTerminalForActionableWork(task); -} - -export function getTeamTaskWorkflowColumn( - task: TeamTaskStateLike +function resolveTeamTaskWorkflowColumn( + task: TeamTaskStateLike, + deleted: boolean ): TeamTaskWorkflowColumn | undefined { - if (isTeamTaskDeleted(task) || task.status === 'pending') { + if (deleted || task.status === 'pending') { return undefined; } @@ -100,3 +95,43 @@ export function getTeamTaskWorkflowColumn( return undefined; } + +export function isTeamTaskApproved(task: TeamTaskStateLike): boolean { + return getCachedTeamTaskState(task).approved; +} + +export function isTeamTaskDeleted(task: TeamTaskStateLike): boolean { + return getCachedTeamTaskState(task).deleted; +} + +export function isTeamTaskActivelyWorked(task: TeamTaskStateLike): boolean { + const cached = getCachedTeamTaskState(task); + return ( + task.status === 'in_progress' && + cached.workflowColumn !== 'review' && + !cached.approved && + !cached.deleted + ); +} + +export function isTeamTaskNeedsFixActionable(task: TeamTaskStateLike): boolean { + return getCachedTeamTaskState(task).needsFixActionable; +} + +export function isTeamTaskFinishedForDependency(task: TeamTaskStateLike): boolean { + return getCachedTeamTaskState(task).finishedForDependency; +} + +export function isTeamTaskTerminalForActionableWork(task: TeamTaskStateLike): boolean { + return getCachedTeamTaskState(task).terminalForActionableWork; +} + +export function isTeamTaskFinalForCompletionNotification(task: TeamTaskStateLike): boolean { + return isTeamTaskTerminalForActionableWork(task); +} + +export function getTeamTaskWorkflowColumn( + task: TeamTaskStateLike +): TeamTaskWorkflowColumn | undefined { + return getCachedTeamTaskState(task).workflowColumn; +}