From 7c2931b2c813ea10412c859c5d8bb765f5462921 Mon Sep 17 00:00:00 2001 From: admin-valentin Date: Fri, 31 Jul 2026 19:26:45 +0000 Subject: [PATCH] =?UTF-8?q?feat(cc-049):=20Priorities=20=E2=80=94=20smart?= =?UTF-8?q?=20focus=20list=20from=20tasks,=20goals,=20decisions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/dashboard/priorities/page.tsx | 234 ++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 src/app/dashboard/priorities/page.tsx diff --git a/src/app/dashboard/priorities/page.tsx b/src/app/dashboard/priorities/page.tsx new file mode 100644 index 0000000..b4a3711 --- /dev/null +++ b/src/app/dashboard/priorities/page.tsx @@ -0,0 +1,234 @@ +'use client'; + +import Link from 'next/link'; +import { useQuery } from '@tanstack/react-query'; +import { apiFetch, type Goal, type Decision } from '../../../lib/api'; +import { useSession } from '../../../components/session-provider'; + +interface Task { + id: string; + title: string; + status: string; + dueDate?: string; +} + +export default function PrioritiesPage() { + const { activeTenant } = useSession(); + const tenantId = activeTenant?.tenantId ?? ''; + + const { data: tasks = [] } = useQuery({ + queryKey: ['tasks-prio', tenantId], + queryFn: () => apiFetch('/v1/tasks', { tenantId }), + enabled: Boolean(tenantId), + }); + + const { data: goals = [] } = useQuery({ + queryKey: ['goals-prio', tenantId], + queryFn: () => apiFetch('/v1/goals', { tenantId }), + enabled: Boolean(tenantId), + }); + + const { data: decisions = [] } = useQuery({ + queryKey: ['decisions-prio', tenantId], + queryFn: () => apiFetch('/v1/decisions', { tenantId }), + enabled: Boolean(tenantId), + }); + + const now = new Date(); + const in7Days = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); + + const activeTasks = tasks.filter((t) => t.status !== 'done'); + const overdueTasks = activeTasks.filter((t) => t.dueDate && new Date(t.dueDate) < now); + const urgentTasks = activeTasks.filter( + (t) => + t.dueDate && + new Date(t.dueDate) >= now && + new Date(t.dueDate) <= in7Days && + !overdueTasks.includes(t), + ); + const inProgressTasks = activeTasks.filter( + (t) => t.status === 'in_progress' && !overdueTasks.includes(t) && !urgentTasks.includes(t), + ); + + const riskyGoals = goals.filter((g) => g.status === 'at_risk'); + const overdueReviews = decisions.filter( + (d) => d.selectedOption && d.reviewDueAt && new Date(d.reviewDueAt) < now, + ); + const pendingDecisions = decisions.filter((d) => !d.selectedOption); + + const allClear = + overdueTasks.length === 0 && + urgentTasks.length === 0 && + riskyGoals.length === 0 && + overdueReviews.length === 0; + + return ( +
+
+

Priorități

+

+ Focus list generat automat din sarcini, obiective și decizii. +

+
+ + {allClear && ( +
+

✓ Totul este în regulă

+

+ Nu există sarcini restante, obiective la risc sau decizii blocate. +

+
+ )} + + {overdueTasks.length > 0 && ( +
+

+ + Urgente — Restante ({overdueTasks.length}) +

+
    + {overdueTasks.map((t) => ( +
  • +
    +

    {t.title}

    + {t.dueDate && ( +

    + Limită: {new Date(t.dueDate).toLocaleDateString('ro-RO')} +

    + )} +
    + + Gestionează + +
  • + ))} +
+
+ )} + + {urgentTasks.length > 0 && ( +
+

+ + Scadente în 7 zile ({urgentTasks.length}) +

+
    + {urgentTasks.map((t) => ( +
  • +
    +

    {t.title}

    + {t.dueDate && ( +

    + Limită: {new Date(t.dueDate).toLocaleDateString('ro-RO')} +

    + )} +
    +
  • + ))} +
+
+ )} + + {inProgressTasks.length > 0 && ( +
+

+ + În lucru ({inProgressTasks.length}) +

+
    + {inProgressTasks.slice(0, 5).map((t) => ( +
  • +

    {t.title}

    +
  • + ))} +
+
+ )} + + {riskyGoals.length > 0 && ( +
+

+ + Obiective la risc ({riskyGoals.length}) +

+
    + {riskyGoals.map((g) => ( +
  • +
    +

    {g.metric}

    +

    + Target: {g.target} · {g.horizon} +

    +
    + + Actualizează + +
  • + ))} +
+
+ )} + + {overdueReviews.length > 0 && ( +
+

+ + Review decizii întârziate ({overdueReviews.length}) +

+
    + {overdueReviews.map((d) => ( +
  • +
    +

    {d.context}

    +

    + Review due: {new Date(d.reviewDueAt!).toLocaleDateString('ro-RO')} +

    +
    + + Revizuiește + +
  • + ))} +
+
+ )} + + {pendingDecisions.length > 0 && ( +
+

+ + Decizii fără opțiune aleasă ({pendingDecisions.length}) +

+
    + {pendingDecisions.slice(0, 5).map((d) => ( +
  • +

    {d.context}

    + + Decide + +
  • + ))} +
+
+ )} +
+ ); +}