'use client'; import { useState } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { apiFetch, type Goal, type GoalStatus } from '../../../lib/api'; import { useSession } from '../../../components/session-provider'; const GOAL_STATUS_LABELS: Record = { not_started: 'Neînceput', on_track: 'Pe track', at_risk: 'La risc', achieved: 'Atins', abandoned: 'Abandonat', }; const STATUS_COLORS: Record = { not_started: 'text-ink-faint', on_track: 'text-signal-ok', at_risk: 'text-signal-warn', achieved: 'text-bronze-deep', abandoned: 'text-ink-line', }; const createGoalSchema = z.object({ horizon: z.string().min(1, 'Orizontul este obligatoriu').max(500), metric: z.string().min(1, 'Metrica este obligatorie').max(500), target: z.string().min(1, 'Ținta este obligatorie').max(1000), }); type CreateGoalForm = z.infer; export default function GoalsPage() { const { activeTenant } = useSession(); const tenantId = activeTenant?.tenantId ?? ''; const queryClient = useQueryClient(); const [isFormOpen, setIsFormOpen] = useState(false); const [statusFilter, setStatusFilter] = useState(''); const { data: goals = [], isLoading } = useQuery({ queryKey: ['goals', tenantId, statusFilter], queryFn: () => apiFetch( `/v1/goals${statusFilter ? `?status=${statusFilter}` : ''}`, { tenantId }, ), enabled: Boolean(tenantId), }); const { register, handleSubmit, reset, formState: { errors, isSubmitting } } = useForm({ resolver: zodResolver(createGoalSchema), }); const createGoal = useMutation({ mutationFn: (values: CreateGoalForm) => apiFetch('/v1/goals', { method: 'POST', tenantId, body: values }), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ['goals', tenantId] }); reset(); setIsFormOpen(false); }, }); const updateStatus = useMutation({ mutationFn: ({ id, status }: { id: string; status: GoalStatus }) => apiFetch(`/v1/goals/${id}`, { method: 'PATCH', tenantId, body: { status } }), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ['goals', tenantId] }); }, }); const deleteGoal = useMutation({ mutationFn: (id: string) => apiFetch<{ deleted: boolean }>(`/v1/goals/${id}`, { method: 'DELETE', tenantId }), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ['goals', tenantId] }); }, }); return (

Obiective

Obiectivele strategice urmărite în acest workspace.

{isFormOpen && (
createGoal.mutate(values))} noValidate className="card mb-6 space-y-4 p-5" >
{errors.horizon &&

{errors.horizon.message}

}
{errors.metric &&

{errors.metric.message}

}
{errors.target &&

{errors.target.message}

}
{createGoal.isError && (

{createGoal.error instanceof Error ? createGoal.error.message : 'Eroare la creare'}

)}
)}
{(Object.keys(GOAL_STATUS_LABELS) as GoalStatus[]).map((status) => ( ))}
{isLoading &&

Se încarcă…

} {!isLoading && goals.length === 0 && (

{statusFilter ? `Niciun obiectiv cu statusul "${GOAL_STATUS_LABELS[statusFilter]}".` : 'Niciun obiectiv încă. Adaugă primul mai sus.'}

)}
    {goals.map((goal) => (
  • {goal.horizon}

    {goal.metric}

    {goal.target}

  • ))}
); }