* feat: Add infrastructure for no-show audit integration - Add Prisma migrations for SYSTEM source and NO_SHOW_UPDATED audit action - Add NoShowUpdatedAuditActionService with array-based attendeesNoShow schema - Update BookingAuditActionServiceRegistry to include NO_SHOW_UPDATED - Update BookingAuditTaskConsumer and BookingAuditViewerService - Add AttendeeRepository methods for no-show queries - Update IAuditActionService interface with values array support - Update locales with no-show audit translation keys Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Add NO_SHOW_UPDATED to BookingAuditAction and SYSTEM to ActionSource types Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Remove HOST_NO_SHOW_UPDATED and ATTENDEE_NO_SHOW_UPDATED from BookingAuditAction type to match Prisma schema Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Update BookingAuditActionSchema to use NO_SHOW_UPDATED instead of HOST_NO_SHOW_UPDATED and ATTENDEE_NO_SHOW_UPDATED Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * refactor: Remove deprecated no-show audit services and unify to NoShowUpdatedAuditActionService - Delete HostNoShowUpdatedAuditActionService and AttendeeNoShowUpdatedAuditActionService - Update BookingAuditProducerService.interface.ts to use queueNoShowUpdatedAudit - Update BookingAuditTaskerProducerService.ts to use queueNoShowUpdatedAudit - Update BookingEventHandlerService.ts to use onNoShowUpdated - Add integration tests for NoShowUpdatedAuditActionService Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Add data migration step for deprecated no-show enum values Addresses Cubic AI review feedback (confidence 9/10): The migration now includes an UPDATE statement to convert existing records using the deprecated 'host_no_show_updated' or 'attendee_no_show_updated' enum values to the new unified 'no_show_updated' value before the type cast. This prevents migration failures if any existing data uses the old values. Co-Authored-By: unknown <> * fix: Use CASE expression in USING clause for enum migration Fixes PostgreSQL error 'unsafe use of new value of enum type' by avoiding the ADD VALUE statement and instead using a CASE expression in the ALTER TABLE USING clause to convert deprecated enum values (host_no_show_updated, attendee_no_show_updated) to the new unified value (no_show_updated) during the type conversion. Co-Authored-By: unknown <> * fix: Replace hardcoded color with semantic text-success class Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Remove color class completely from display fields Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * feat: Add valuesWithParams support for translatable complex field values Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * refactor(booking-audit): use discriminated union for displayFields and update consumers Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: add explicit return type to getBookingHistoryHandler to bust stale tRPC build cache Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * refactor: replace $t() nested interpolation with separate translation keys and add translationsWithParams tests Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
159 lines
5.5 KiB
TypeScript
159 lines
5.5 KiB
TypeScript
/**
|
|
* Represents a component that can be interpolated into translations
|
|
* Used with react-i18next Trans component for proper i18n support (RTL, word order, etc.)
|
|
*/
|
|
export type TranslationComponent = {
|
|
type: "link";
|
|
href: string;
|
|
};
|
|
|
|
/**
|
|
* Represents a translation key with optional interpolation params and components
|
|
* Used for dynamic display titles that need to be translated with context
|
|
* Components are used for clickable links within translations (e.g., "Rescheduled to <1>New Booking</1>")
|
|
*/
|
|
export type TranslationWithParams = {
|
|
key: string;
|
|
params?: Record<string, string | number>;
|
|
components?: TranslationComponent[];
|
|
};
|
|
|
|
import type { EnrichmentDataStore, DataRequirements } from "../service/EnrichmentDataStore";
|
|
|
|
/**
|
|
* This is agnostic of the action and is common for all actions
|
|
*/
|
|
export type BaseStoredAuditData = {
|
|
version: number;
|
|
fields: Record<string, unknown>;
|
|
};
|
|
|
|
export type GetDisplayJsonParams = {
|
|
storedData: BaseStoredAuditData;
|
|
userTimeZone: string;
|
|
};
|
|
|
|
export type GetDisplayTitleParams = {
|
|
storedData: BaseStoredAuditData;
|
|
userTimeZone: string;
|
|
dbStore: EnrichmentDataStore;
|
|
};
|
|
|
|
export type GetDisplayFieldsParams = {
|
|
storedData: BaseStoredAuditData;
|
|
dbStore: EnrichmentDataStore;
|
|
};
|
|
|
|
/**
|
|
* Discriminated union for display field values
|
|
* Each variant represents a different way to render the field value
|
|
*/
|
|
export type DisplayFieldValue =
|
|
| { type: "translationKey"; valueKey: string }
|
|
| { type: "rawValue"; value: string }
|
|
| { type: "rawValues"; values: string[] }
|
|
| { type: "translationsWithParams"; valuesWithParams: TranslationWithParams[] };
|
|
|
|
export type DisplayField = {
|
|
labelKey: string;
|
|
fieldValue: DisplayFieldValue;
|
|
};
|
|
|
|
/**
|
|
* Interface for Audit Action Services
|
|
*
|
|
* Defines the contract that all audit action services must implement.
|
|
* Uses composition with AuditActionServiceHelper to provide common functionality
|
|
* while maintaining runtime type safety through Zod schema validation.
|
|
*
|
|
* All methods use common base types at the interface level, while implementations
|
|
* validate to their specific schemas internally.
|
|
*/
|
|
export interface IAuditActionService {
|
|
/**
|
|
* Current version number for this action type
|
|
*/
|
|
readonly VERSION: number;
|
|
|
|
/**
|
|
* Parse given fields against latest schema and wrap with version
|
|
* @param fields - Raw input fields (just the audit fields)
|
|
* @returns Parsed data with version wrapper { version, fields }
|
|
*/
|
|
getVersionedData(fields: unknown): BaseStoredAuditData;
|
|
|
|
/**
|
|
* Parse stored audit record (includes version wrapper)
|
|
* Accepts data from ANY supported version (not just latest) for backward compatibility
|
|
* @param data - Stored data from database (can be any version)
|
|
* @returns Parsed stored data { version, fields } - version may differ from current VERSION
|
|
*/
|
|
parseStored(data: unknown): BaseStoredAuditData;
|
|
|
|
/**
|
|
* Extract version number from stored data
|
|
* @param data - Stored data from database
|
|
* @returns Version number
|
|
*/
|
|
getVersion(data: unknown): number;
|
|
|
|
/**
|
|
* Get flattened JSON data for display (fields only, no version wrapper)
|
|
* Optional - implement only if custom display formatting is needed
|
|
* @param params - Object containing storedData and userTimeZone
|
|
* @param params.storedData - Parsed stored data { version, fields }
|
|
* @param params.userTimeZone - User's timezone for datetime formatting (required)
|
|
* @returns The fields object without version wrapper and we decide what fields to show to the client
|
|
*/
|
|
getDisplayJson?(params: GetDisplayJsonParams): Record<string, unknown>;
|
|
|
|
/**
|
|
* Declare what data this action needs from DB
|
|
* Returns identifiers to be bulk-fetched before enrichment
|
|
* @param storedData - Parsed stored data { version, fields }
|
|
* @returns Data requirements with arrays of identifiers to fetch
|
|
*/
|
|
getDataRequirements(storedData: BaseStoredAuditData): DataRequirements;
|
|
|
|
/**
|
|
* Get the display title for the audit action
|
|
* Returns a translation key with optional interpolation params for dynamic titles
|
|
* (e.g., "Booking reassigned to John Doe" instead of just "Reassignment")
|
|
* @param params - Object containing storedData and userTimeZone
|
|
* @param params.storedData - Parsed stored data { version, fields }
|
|
* @param params.userTimeZone - User's timezone for date formatting (required)
|
|
* @returns Translation key with optional interpolation params
|
|
*/
|
|
getDisplayTitle(params: GetDisplayTitleParams): Promise<TranslationWithParams>;
|
|
|
|
/**
|
|
* Returns additional display fields with translation keys for frontend rendering
|
|
* Optional - implement only if custom display fields are needed
|
|
* @param params - Object containing storedData
|
|
* @param params.storedData - Parsed stored data { version, fields }
|
|
* @returns Promise of array of DisplayField objects with label and discriminated value type
|
|
*/
|
|
getDisplayFields?(params: GetDisplayFieldsParams): Promise<DisplayField[]>;
|
|
|
|
/**
|
|
* Migrate old version data to latest version
|
|
*
|
|
* Required method that validates and migrates data to latest schema version.
|
|
* For V1-only actions, simply validates and returns with isMigrated=false.
|
|
* For multi-version actions, checks version and transforms if needed.
|
|
*
|
|
* @param data - Data from task payload (any supported version)
|
|
* @returns Migration result with status and latest data
|
|
*/
|
|
migrateToLatest(data: unknown): {
|
|
/**
|
|
* True if migration was performed, false if already latest
|
|
*/
|
|
isMigrated: boolean;
|
|
/**
|
|
* Always set, either migrated or original
|
|
*/
|
|
latestData: Record<string, unknown>;
|
|
};
|
|
}
|