diff --git a/src/components/daily/DailyCheckboxItem.tsx b/src/components/daily/DailyCheckboxItem.tsx
index 6dc50a7..e1da1ef 100644
--- a/src/components/daily/DailyCheckboxItem.tsx
+++ b/src/components/daily/DailyCheckboxItem.tsx
@@ -5,6 +5,8 @@ import Link from 'next/link';
import { DailyCheckbox, DailyCheckboxType } from '@/lib/types';
import { Input } from '@/components/ui/Input';
import { EditCheckboxModal } from './EditCheckboxModal';
+import { getTaskEmoji } from '@/lib/task-emoji';
+import { Emoji } from '@/components/ui/Emoji';
interface DailyCheckboxItemProps {
checkbox: DailyCheckbox;
@@ -129,6 +131,11 @@ export function DailyCheckboxItem({
// Vérifier si la tâche est archivée
const isArchived = checkbox.isArchived;
+ // Obtenir l'emoji de la tâche associée si elle existe
+ const taskEmoji = checkbox.task
+ ? getTaskEmoji(checkbox.task, undefined)
+ : null;
+
return (
<>
) : (
-
+
+ {/* Emoji de la tâche associée */}
+ {taskEmoji && (
+
+
+
+ )}
+
{/* Texte cliquable pour édition inline */}
{
// Variants
@@ -216,35 +217,22 @@ const TaskCard = forwardRef(
return colors[priority as keyof typeof colors] || colors.medium;
};
- // Fonction pour extraire les emojis avec la lib emoji-regex
- const extractEmojis = (text: string): string[] => {
- const regex = emojiRegex();
- return text.match(regex) || [];
- };
-
- const titleEmojis = extractEmojis(title);
+ // Utiliser getTaskEmoji avec les propriétés de la tâche disponibles
+ const taskEmoji = getTaskEmoji(
+ {
+ title,
+ tags: tags || [],
+ primaryTagId,
+ tagDetails: availableTags?.filter((tag) => tags?.includes(tag.name)),
+ primaryTag: primaryTagId
+ ? availableTags?.find((tag) => tag.id === primaryTagId)
+ : undefined,
+ },
+ availableTags
+ );
+ const displayEmojis: string[] = taskEmoji ? [taskEmoji] : [];
const titleWithoutEmojis = title.replace(emojiRegex(), '').trim();
- // Si pas d'emoji dans le titre, utiliser l'emoji du tag prioritaire ou du premier tag
- let displayEmojis: string[] = titleEmojis;
- if (displayEmojis.length === 0 && tags && tags.length > 0) {
- // Priorité au tag prioritaire, sinon premier tag
- let tagToUse = null;
- if (primaryTagId && availableTags) {
- tagToUse = availableTags.find((tag) => tag.id === primaryTagId);
- }
- if (!tagToUse) {
- tagToUse = availableTags.find((tag) => tag.name === tags[0]);
- }
-
- if (tagToUse) {
- const tagEmojis = extractEmojis(tagToUse.name);
- if (tagEmojis.length > 0) {
- displayEmojis = [tagEmojis[0]]; // Prendre seulement le premier emoji du tag
- }
- }
- }
-
const sourceStyles = getSourceStyles();
const priorityColor = getPriorityColor(priority);
diff --git a/src/lib/task-emoji.ts b/src/lib/task-emoji.ts
new file mode 100644
index 0000000..43b6b2a
--- /dev/null
+++ b/src/lib/task-emoji.ts
@@ -0,0 +1,96 @@
+import emojiRegex from 'emoji-regex';
+import { Task, Tag } from './types';
+
+/**
+ * Extrait les emojis d'un texte
+ */
+export function extractEmojis(text: string): string[] {
+ const regex = emojiRegex();
+ return text.match(regex) || [];
+}
+
+/**
+ * Type pour représenter une tâche partielle avec les propriétés nécessaires pour extraire l'emoji
+ */
+type TaskForEmoji = Pick &
+ Partial>;
+
+/**
+ * Extrait l'emoji principal d'une tâche en suivant la logique du TaskCard:
+ * 1. D'abord, cherche les emojis dans le titre de la tâche
+ * 2. Si pas trouvé, cherche dans le tag prioritaire (primaryTag)
+ * 3. Si pas trouvé, cherche dans le premier tag disponible
+ *
+ * @param task La tâche (complète ou partielle) à partir de laquelle extraire l'emoji
+ * @param availableTags Les tags disponibles (optionnel, pour la recherche par tag)
+ * @returns Le premier emoji trouvé, ou null si aucun emoji n'est trouvé
+ */
+export function getTaskEmoji(
+ task: TaskForEmoji | Task | null | undefined,
+ availableTags?: Tag[]
+): string | null {
+ if (!task || !task.title) {
+ return null;
+ }
+
+ // 1. Chercher les emojis dans le titre
+ const titleEmojis = extractEmojis(task.title);
+ if (titleEmojis.length > 0) {
+ return titleEmojis[0]; // Prendre seulement le premier emoji
+ }
+
+ // 2. Si pas d'emoji dans le titre, utiliser l'emoji du tag prioritaire ou du premier tag
+ if (task.tags && task.tags.length > 0 && availableTags) {
+ // Priorité au tag prioritaire, sinon premier tag
+ let tagToUse: Tag | null = null;
+
+ if (task.primaryTagId) {
+ tagToUse =
+ availableTags.find((tag) => tag.id === task.primaryTagId) || null;
+ }
+
+ if (!tagToUse && task.primaryTag) {
+ tagToUse = task.primaryTag;
+ }
+
+ if (!tagToUse) {
+ // Chercher par nom du premier tag
+ const firstTagName = task.tags[0];
+ tagToUse = availableTags.find((tag) => tag.name === firstTagName) || null;
+ }
+
+ if (tagToUse) {
+ const tagEmojis = extractEmojis(tagToUse.name);
+ if (tagEmojis.length > 0) {
+ return tagEmojis[0]; // Prendre seulement le premier emoji du tag
+ }
+ }
+ }
+
+ // 3. Si la tâche a tagDetails directement (sans avoir besoin de availableTags)
+ if (task.tagDetails && task.tagDetails.length > 0) {
+ let tagToUse: Tag | null = null;
+
+ if (task.primaryTagId) {
+ tagToUse =
+ task.tagDetails.find((tag) => tag.id === task.primaryTagId) || null;
+ }
+
+ if (!tagToUse && task.primaryTag) {
+ tagToUse = task.primaryTag;
+ }
+
+ if (!tagToUse) {
+ tagToUse = task.tagDetails[0];
+ }
+
+ if (tagToUse) {
+ const tagEmojis = extractEmojis(tagToUse.name);
+ if (tagEmojis.length > 0) {
+ return tagEmojis[0];
+ }
+ }
+ }
+
+ return null;
+}
diff --git a/src/services/task-management/daily.ts b/src/services/task-management/daily.ts
index 84e8ee8..c013f57 100644
--- a/src/services/task-management/daily.ts
+++ b/src/services/task-management/daily.ts
@@ -61,7 +61,19 @@ export class DailyService {
date: normalizedDate,
userId: userId,
},
- include: { task: true, user: true },
+ include: {
+ task: {
+ include: {
+ taskTags: {
+ include: {
+ tag: true,
+ },
+ },
+ primaryTag: true,
+ },
+ },
+ user: true,
+ },
orderBy: { order: 'asc' },
});
@@ -93,7 +105,19 @@ export class DailyService {
order,
isChecked: data.isChecked ?? false,
},
- include: { task: true, user: true },
+ include: {
+ task: {
+ include: {
+ taskTags: {
+ include: {
+ tag: true,
+ },
+ },
+ primaryTag: true,
+ },
+ },
+ user: true,
+ },
});
return this.mapPrismaCheckbox(checkbox);
@@ -124,7 +148,19 @@ export class DailyService {
const checkbox = await prisma.dailyCheckbox.update({
where: { id: checkboxId },
data: updateData,
- include: { task: true, user: true },
+ include: {
+ task: {
+ include: {
+ taskTags: {
+ include: {
+ tag: true,
+ },
+ },
+ primaryTag: true,
+ },
+ },
+ user: true,
+ },
});
return this.mapPrismaCheckbox(checkbox);
@@ -145,7 +181,19 @@ export class DailyService {
const updated = await prisma.dailyCheckbox.update({
where: { id: checkboxId },
data: { isChecked: !existing.isChecked, updatedAt: new Date() },
- include: { task: true, user: true },
+ include: {
+ task: {
+ include: {
+ taskTags: {
+ include: {
+ tag: true,
+ },
+ },
+ primaryTag: true,
+ },
+ },
+ user: true,
+ },
});
return this.mapPrismaCheckbox(updated);
@@ -195,7 +243,19 @@ export class DailyService {
contains: query,
},
},
- include: { task: true, user: true },
+ include: {
+ task: {
+ include: {
+ taskTags: {
+ include: {
+ tag: true,
+ },
+ },
+ primaryTag: true,
+ },
+ },
+ user: true,
+ },
orderBy: { date: 'desc' },
take: limit,
});
@@ -271,12 +331,76 @@ export class DailyService {
/**
* Mappe une checkbox Prisma vers notre interface
+ * Accepte les checkboxes avec ou sans les relations taskTags et primaryTag
*/
private mapPrismaCheckbox(
checkbox: Prisma.DailyCheckboxGetPayload<{
- include: { task: true; user: true };
+ include: {
+ task:
+ | true
+ | {
+ include: {
+ taskTags: {
+ include: {
+ tag: true;
+ };
+ };
+ primaryTag: true;
+ };
+ };
+ user: true;
+ };
}>
): DailyCheckbox {
+ // Extraire les tags de la tâche si elle existe
+ let taskTags: string[] = [];
+ let taskTagDetails:
+ | Array<{ id: string; name: string; color: string; isPinned?: boolean }>
+ | undefined = undefined;
+ let taskPrimaryTag:
+ | { id: string; name: string; color: string; isPinned?: boolean }
+ | undefined = undefined;
+
+ if (checkbox.task) {
+ // Vérifier si taskTags est disponible (peut être true ou un objet avec include)
+ const taskWithTags = checkbox.task as unknown as {
+ taskTags?: Array<{
+ tag: { id: string; name: string; color: string; isPinned: boolean };
+ }>;
+ primaryTag?: {
+ id: string;
+ name: string;
+ color: string;
+ isPinned: boolean;
+ } | null;
+ };
+
+ if (
+ 'taskTags' in taskWithTags &&
+ taskWithTags.taskTags &&
+ Array.isArray(taskWithTags.taskTags)
+ ) {
+ // Utiliser les relations Prisma pour récupérer les noms et détails des tags
+ taskTags = taskWithTags.taskTags.map((tt) => tt.tag.name);
+ taskTagDetails = taskWithTags.taskTags.map((tt) => ({
+ id: tt.tag.id,
+ name: tt.tag.name,
+ color: tt.tag.color,
+ isPinned: tt.tag.isPinned,
+ }));
+ }
+
+ // Extraire le primaryTag si disponible
+ if ('primaryTag' in taskWithTags && taskWithTags.primaryTag) {
+ taskPrimaryTag = {
+ id: taskWithTags.primaryTag.id,
+ name: taskWithTags.primaryTag.name,
+ color: taskWithTags.primaryTag.color,
+ isPinned: taskWithTags.primaryTag.isPinned,
+ };
+ }
+ }
+
return {
id: checkbox.id,
date: checkbox.date,
@@ -295,7 +419,10 @@ export class DailyService {
priority: checkbox.task.priority as TaskPriority,
source: checkbox.task.source as TaskSource,
sourceId: checkbox.task.sourceId || undefined,
- tags: [], // Les tags seront chargés séparément si nécessaire
+ tags: taskTags,
+ tagDetails: taskTagDetails,
+ primaryTagId: checkbox.task.primaryTagId || undefined,
+ primaryTag: taskPrimaryTag,
dueDate: checkbox.task.dueDate || undefined,
completedAt: checkbox.task.completedAt || undefined,
createdAt: checkbox.task.createdAt,
@@ -384,7 +511,19 @@ export class DailyService {
const checkboxes = await prisma.dailyCheckbox.findMany({
where: whereConditions,
- include: { task: true, user: true },
+ include: {
+ task: {
+ include: {
+ taskTags: {
+ include: {
+ tag: true,
+ },
+ },
+ primaryTag: true,
+ },
+ },
+ user: true,
+ },
orderBy: [{ date: 'desc' }, { order: 'asc' }],
...(options?.limit ? { take: options.limit } : {}),
});
@@ -406,7 +545,19 @@ export class DailyService {
?.text + ' [ARCHIVÉ]',
updatedAt: new Date(),
},
- include: { task: true, user: true },
+ include: {
+ task: {
+ include: {
+ taskTags: {
+ include: {
+ tag: true,
+ },
+ },
+ primaryTag: true,
+ },
+ },
+ user: true,
+ },
});
return this.mapPrismaCheckbox(checkbox);
@@ -450,7 +601,19 @@ export class DailyService {
order: newOrder,
updatedAt: new Date(),
},
- include: { task: true, user: true },
+ include: {
+ task: {
+ include: {
+ taskTags: {
+ include: {
+ tag: true,
+ },
+ },
+ primaryTag: true,
+ },
+ },
+ user: true,
+ },
});
return this.mapPrismaCheckbox(updatedCheckbox);