All files / src/common/utils newsletterUtils.ts

63.63% Statements 35/55
57.14% Branches 8/14
66.66% Functions 2/3
63.63% Lines 35/55

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82        1x 174x   174x 174x 174x 174x 174x 174x 174x 174x 174x 174x 174x 174x   174x   174x 93x 93x 16x     16x                                 16x                 16x   16x 16x 93x 77x 77x 93x   174x 174x                       1x 88x 88x 82x 82x  
// Utility to normalize newsletter filter keys from snake_case to camelCase
// NOTE: No module-level memoization – callers (hooks) already wrap this in useMemo,
// so a shared cache would be silently stale when multiple hook instances are active.
 
export function normalizeNewsletterFilter(filter: any): any {
  if (!filter) return filter;
 
  const mapping: Record<string, string> = {
    is_liked: 'isLiked',
    is_archived: 'isArchived',
    is_read: 'isRead',
    tag_ids: 'tagIds',
    source_id: 'sourceIds',
    date_from: 'dateFrom',
    date_to: 'dateTo',
    order_by: 'orderBy',
    order_direction: 'orderDirection',
    group_id: 'groupIds',
  };
 
  const result: any = {};
 
  for (const key in filter) {
    const value = filter[key];
    if (mapping[key]) {
      const newKey = mapping[key];
 
      // Handle special cases for array fields
      if (newKey === 'sourceIds' && value !== undefined) {
        // Convert single source_id to array format
        if (typeof value === 'string') {
          // Validate UUID format
          if (isValidUUID(value)) {
            result[newKey] = [value];
          } else {
            // Skip invalid UUIDs
            continue;
          }
        } else if (Array.isArray(value)) {
          // Filter out invalid UUIDs from arrays
          result[newKey] = value.filter((id) => isValidUUID(id));
        } else {
          // Skip non-string, non-array values
          continue;
        }
      } else if (newKey === 'tagIds' && value !== undefined) {
        // Handle tag IDs array
        if (Array.isArray(value)) {
          // Filter out invalid UUIDs from arrays
          result[newKey] = value.filter((id) => isValidUUID(id));
        } else {
          // Skip non-array values
          continue;
        }
      } else {
        // For other fields, just copy the value
        result[newKey] = value;
      }
    } else {
      result[key] = filter[key];
    }
  }
 
  return result;
}
 
// Helper function to validate UUID format
function isValidUUID(uuid: string): boolean {
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
  return uuidRegex.test(uuid);
}
 
/**
 * Format estimated read time for display. Avoids showing "1 min" when content
 * is empty or very short (word count 0 or &lt; ~50 words).
 */
export function formatReadTime(estimatedReadTime: number, wordCount: number): string {
  if (wordCount === 0) return '< 1 min';
  if (estimatedReadTime <= 1 && wordCount < 50) return '< 1 min';
  return `${estimatedReadTime} min`;
}