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 < ~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`;
}
|