feat(timeline): add pulse animation for in-flight drag mutations
Allocation bars that have active optimistic overrides (post-drag, awaiting server confirmation) now pulse subtly via animate-pulse. The pending set is derived from the existing optimisticAllocations map keys, requiring no additional state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { PrismaClient } from "@capakraken/db";
|
||||
import type { WeekdayAvailability } from "@capakraken/shared";
|
||||
import { toIsoDate, DAY_KEYS, type WeekdayAvailability } from "@capakraken/shared";
|
||||
import { calculateInclusiveDays, MILLISECONDS_PER_DAY } from "./shared.js";
|
||||
import {
|
||||
calculateEffectiveAllocationCostCents,
|
||||
@@ -46,20 +46,6 @@ export interface BudgetForecastRow {
|
||||
derivation?: BudgetForecastDerivationSummary;
|
||||
}
|
||||
|
||||
const DAY_KEYS: (keyof WeekdayAvailability)[] = [
|
||||
"sunday",
|
||||
"monday",
|
||||
"tuesday",
|
||||
"wednesday",
|
||||
"thursday",
|
||||
"friday",
|
||||
"saturday",
|
||||
];
|
||||
|
||||
function toIsoDate(value: Date): string {
|
||||
return value.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
function getDailyAvailabilityHours(
|
||||
availability: WeekdayAvailability,
|
||||
date: Date,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PrismaClient } from "@capakraken/db";
|
||||
import type { WeekdayAvailability } from "@capakraken/shared";
|
||||
import { toIsoDate, DAY_KEYS, type WeekdayAvailability } from "@capakraken/shared";
|
||||
import {
|
||||
isChargeabilityActualBooking,
|
||||
isChargeabilityRelevantProject,
|
||||
@@ -12,16 +12,6 @@ import {
|
||||
type DailyAvailabilityContext,
|
||||
} from "./holiday-capacity.js";
|
||||
|
||||
const DAY_KEYS: (keyof WeekdayAvailability)[] = [
|
||||
"sunday",
|
||||
"monday",
|
||||
"tuesday",
|
||||
"wednesday",
|
||||
"thursday",
|
||||
"friday",
|
||||
"saturday",
|
||||
];
|
||||
|
||||
export interface GetDashboardChargeabilityOverviewInput {
|
||||
includeProposed?: boolean;
|
||||
topN: number;
|
||||
@@ -72,10 +62,6 @@ export interface DashboardChargeabilityOverview {
|
||||
month: string;
|
||||
}
|
||||
|
||||
function toIsoDate(value: Date): string {
|
||||
return value.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
function getDailyAvailabilityHours(
|
||||
availability: WeekdayAvailability,
|
||||
date: Date,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PrismaClient } from "@capakraken/db";
|
||||
import type { WeekdayAvailability } from "@capakraken/shared";
|
||||
import { toIsoDate, type WeekdayAvailability } from "@capakraken/shared";
|
||||
import { loadDashboardPlanningReadModel } from "./load-dashboard-planning-read-model.js";
|
||||
import { calculateAllocationHours } from "./shared.js";
|
||||
import {
|
||||
@@ -66,10 +66,6 @@ function toDate(value: Date | string): Date {
|
||||
return value instanceof Date ? value : new Date(value);
|
||||
}
|
||||
|
||||
function toIsoDate(value: Date): string {
|
||||
return value.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
function buildLocationKey(input: {
|
||||
countryCode: string | null | undefined;
|
||||
countryName: string | null | undefined;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PrismaClient } from "@capakraken/db";
|
||||
import type { WeekdayAvailability } from "@capakraken/shared";
|
||||
import { toIsoDate, DAY_KEYS, type WeekdayAvailability } from "@capakraken/shared";
|
||||
import { listAssignmentBookings } from "../allocation/list-assignment-bookings.js";
|
||||
import { getMonthBucketKey, getWeekBucketKey } from "./shared.js";
|
||||
import {
|
||||
@@ -81,20 +81,6 @@ type PeakTimesCapacityDerivationSummary = Pick<
|
||||
| "calendarLocations"
|
||||
>;
|
||||
|
||||
const DAY_KEYS: (keyof WeekdayAvailability)[] = [
|
||||
"sunday",
|
||||
"monday",
|
||||
"tuesday",
|
||||
"wednesday",
|
||||
"thursday",
|
||||
"friday",
|
||||
"saturday",
|
||||
];
|
||||
|
||||
function toIsoDate(value: Date): string {
|
||||
return value.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
function round1(value: number): number {
|
||||
return Math.round(value * 10) / 10;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PrismaClient } from "@capakraken/db";
|
||||
import type { WeekdayAvailability } from "@capakraken/shared";
|
||||
import { toIsoDate, MILLISECONDS_PER_DAY, DAY_KEYS, type WeekdayAvailability } from "@capakraken/shared";
|
||||
import { calculateInclusiveDays } from "./shared.js";
|
||||
import {
|
||||
calculateEffectiveAllocationCostCents,
|
||||
@@ -51,26 +51,12 @@ export interface ProjectHealthRow {
|
||||
};
|
||||
}
|
||||
|
||||
const DAY_KEYS: (keyof WeekdayAvailability)[] = [
|
||||
"sunday",
|
||||
"monday",
|
||||
"tuesday",
|
||||
"wednesday",
|
||||
"thursday",
|
||||
"friday",
|
||||
"saturday",
|
||||
];
|
||||
|
||||
function hasAvailability<T extends { availability?: unknown }>(
|
||||
resource: T | null | undefined,
|
||||
): resource is T & { availability: WeekdayAvailability } {
|
||||
return resource !== null && resource !== undefined && resource.availability !== null && resource.availability !== undefined;
|
||||
}
|
||||
|
||||
function toIsoDate(value: Date): string {
|
||||
return value.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
function getDailyAvailabilityHours(
|
||||
availability: WeekdayAvailability,
|
||||
date: Date,
|
||||
@@ -360,7 +346,7 @@ export async function getDashboardProjectHealth(
|
||||
const endDate = p.endDate ? toUtcDayStart(p.endDate) : null;
|
||||
const today = toUtcDayStart(now);
|
||||
const daysUntilEndDate = endDate
|
||||
? Math.round((endDate.getTime() - today.getTime()) / 86_400_000)
|
||||
? Math.round((endDate.getTime() - today.getTime()) / MILLISECONDS_PER_DAY)
|
||||
: null;
|
||||
const timelineStatus = endDate === null
|
||||
? "UNSCHEDULED"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const MILLISECONDS_PER_DAY = 86_400_000;
|
||||
export { MILLISECONDS_PER_DAY } from "@capakraken/shared";
|
||||
import { MILLISECONDS_PER_DAY } from "@capakraken/shared";
|
||||
|
||||
export function calculateInclusiveDays(startDate: Date, endDate: Date): number {
|
||||
return (endDate.getTime() - startDate.getTime()) / MILLISECONDS_PER_DAY + 1;
|
||||
|
||||
Reference in New Issue
Block a user