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 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | 1x 1x 10x 10x 10x 10x 10x 10x 1x 1x 10x 1x 1x 10x 1x 1x 10x 1x 1x 6x 10x 7x 7x 7x 7x 7x 4x 4x 3x 3x 7x 3x 3x 3x 3x 3x 7x 6x 10x 1x 1x 5x 5x 5x 5x 5x 5x 5x 5x 5x 1x 8x 8x 8x 8x 8x 8x 1x 7x 8x 8x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x 5x 5x 5x 5x 5x 5x 5x 5x 5x 1x 5x 7x 7x 4x 4x 4x 4x 4x 4x 4x 4x 5x 5x | import { tagService } from '@common/services';
import { Tag } from '@common/types';
/**
* Updates tags for a newsletter using TagService
* @param newsletterId - The ID of the newsletter to update
* @param tagIds - Array of tag IDs to set for the newsletter
* @param currentTagIds - Current tag IDs for the newsletter
* @param userId - The ID of the current user
* @returns Object containing update results
*/
export const updateNewsletterTags = async (
newsletterId: string,
tagIds: string[],
currentTagIds: string[],
userId: string
) => {
// Validate inputs
if (!newsletterId) {
throw new Error('Newsletter ID is required');
}
if (!userId) {
throw new Error('User ID is required');
}
if (!Array.isArray(tagIds)) {
throw new Error('tagIds must be an array');
}
if (!Array.isArray(currentTagIds)) {
throw new Error('currentTagIds must be an array');
}
// Process tag IDs or names through the service
const processedTagIds: string[] = [];
for (const tagIdOrName of tagIds) {
// Check if it's a UUID (existing tag)
const isUuid =
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
tagIdOrName
);
if (isUuid) {
// It's a UUID, verify it exists
const existingTag = await tagService.getTag(tagIdOrName);
if (existingTag) {
processedTagIds.push(tagIdOrName);
}
} else {
// It's a tag name, get or create through service
const result = await tagService.getOrCreateTag(tagIdOrName.trim());
if (result.success && result.tag) {
processedTagIds.push(result.tag.id);
}
}
}
// Update newsletter tags using the service
const updateResult = await tagService.updateNewsletterTagsWithIds(newsletterId, processedTagIds);
if (!updateResult.success) {
throw new Error(updateResult.error || 'Failed to update newsletter tags');
}
// Get updated tags for the newsletter
const updatedTags = await tagService.getTagsForNewsletter(newsletterId);
return {
newsletterId,
tagIds: updatedTags.map((tag) => tag.id),
added: processedTagIds.filter((id) => !currentTagIds.includes(id)).length,
removed: currentTagIds.filter((id) => !processedTagIds.includes(id)).length,
tags: updatedTags,
};
};
/**
* Toggles a tag filter in the list of selected tag IDs
* @param tag - The tag to toggle (can be a tag ID or Tag object)
* @param currentTagIds - Currently selected tag IDs
* @returns Updated array of selected tag IDs or null if no tags are selected
*/
export const toggleTagFilter = <T extends { id: string }>(
tag: string | T,
currentTagIds: string[] | null
): string[] => {
const tagId = typeof tag === 'string' ? tag : tag.id;
const currentTags = currentTagIds || [];
const updatedTagIds = currentTags.includes(tagId)
? currentTags.filter((id) => id !== tagId)
: [...currentTags, tagId];
return updatedTagIds;
};
/**
* Handles tag click events
* @param tag - The tag that was clicked (can be a tag ID or Tag object)
* @param currentTagIds - Currently selected tag IDs
* @param setTagIds - State setter function for updating selected tag IDs
* @param event - Optional React mouse event to stop propagation
*/
export const handleTagClick = <T extends { id: string }>(
tag: string | T,
currentTagIds: string[] | null,
setTagIds: (ids: string[]) => void,
event?: React.MouseEvent
): void => {
event?.stopPropagation();
const newTagIds = toggleTagFilter(tag, currentTagIds);
setTagIds(newTagIds);
};
/**
* Handles tag click with navigation to a specific route
* @param tag - The tag that was clicked (can be a tag ID or Tag object)
* @param navigate - Navigation function from react-router
* @param basePath - Base path to navigate to (e.g., '/inbox')
* @param event - Mouse event to stop propagation
*/
export const handleTagClickWithNavigation = <T extends { id: string }>(
tag: string | T,
navigate: (to: string) => void,
basePath: string = '/inbox',
event?: React.MouseEvent
): void => {
event?.stopPropagation();
const tagId = typeof tag === 'string' ? tag : tag.id;
navigate(`${basePath}?tags=${tagId}`);
};
/**
* Gets optimistic tags for immediate UI updates
* @param tagIds - Array of tag IDs
* @param userId - The ID of the current user
* @param allTags - Array of all available tags for fallback
* @returns Array of Tag objects with optimistic data
*/
export const getOptimisticTags = (tagIds: string[], userId: string, allTags: Tag[]): Tag[] => {
return tagIds.map((tagId) => {
const existingTag = allTags.find((t) => t.id === tagId);
if (existingTag) return existingTag;
// Fallback with minimal tag data if not found in allTags
return {
id: tagId,
name: '',
color: '#808080', // Default gray color
user_id: userId,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
};
});
};
|