feat: add subjects and tasks API, hooks, and related types
- Implemented subjects API with functions for creating, updating, and retrieving subjects, including history and bibliography. - Added tasks API for managing user tasks, including listing and marking tasks as completed. - Created hooks for managing AI interactions, authentication, subjects, tasks, and metadata queries. - Established query keys for caching and managing query states. - Introduced Supabase client and environment variable management for better configuration. - Defined types for database and domain models to ensure type safety across the application.
This commit is contained in:
28
src/data/hooks/useAI.ts
Normal file
28
src/data/hooks/useAI.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import {
|
||||
ai_plan_chat,
|
||||
ai_plan_improve,
|
||||
ai_subject_chat,
|
||||
ai_subject_improve,
|
||||
library_search,
|
||||
} from "../api/ai.api";
|
||||
|
||||
export function useAIPlanImprove() {
|
||||
return useMutation({ mutationFn: ai_plan_improve });
|
||||
}
|
||||
|
||||
export function useAIPlanChat() {
|
||||
return useMutation({ mutationFn: ai_plan_chat });
|
||||
}
|
||||
|
||||
export function useAISubjectImprove() {
|
||||
return useMutation({ mutationFn: ai_subject_improve });
|
||||
}
|
||||
|
||||
export function useAISubjectChat() {
|
||||
return useMutation({ mutationFn: ai_subject_chat });
|
||||
}
|
||||
|
||||
export function useLibrarySearch() {
|
||||
return useMutation({ mutationFn: library_search });
|
||||
}
|
||||
59
src/data/hooks/useAuth.ts
Normal file
59
src/data/hooks/useAuth.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { useEffect } from "react";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { supabaseBrowser } from "../supabase/client";
|
||||
import { qk } from "../query/keys";
|
||||
import { throwIfError } from "../api/_helpers";
|
||||
|
||||
export function useSession() {
|
||||
const supabase = supabaseBrowser();
|
||||
const qc = useQueryClient();
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: qk.session(),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await supabase.auth.getSession();
|
||||
throwIfError(error);
|
||||
return data.session ?? null;
|
||||
},
|
||||
staleTime: Infinity,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const { data } = supabase.auth.onAuthStateChange(() => {
|
||||
qc.invalidateQueries({ queryKey: qk.session() });
|
||||
qc.invalidateQueries({ queryKey: qk.meProfile() });
|
||||
qc.invalidateQueries({ queryKey: qk.auth });
|
||||
});
|
||||
|
||||
return () => data.subscription.unsubscribe();
|
||||
}, [supabase, qc]);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
export function useMeProfile() {
|
||||
const supabase = supabaseBrowser();
|
||||
|
||||
return useQuery({
|
||||
queryKey: qk.meProfile(),
|
||||
queryFn: async () => {
|
||||
const { data: u, error: uErr } = await supabase.auth.getUser();
|
||||
throwIfError(uErr);
|
||||
const userId = u.user?.id;
|
||||
if (!userId) return null;
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from("usuarios_app")
|
||||
.select("id,nombre_completo,email,externo,creado_en,actualizado_en")
|
||||
.eq("id", userId)
|
||||
.single();
|
||||
|
||||
// si aún no existe perfil en usuarios_app, permite null (tu seed/trigger puede crearlo)
|
||||
if (error && (error as any).code === "PGRST116") return null;
|
||||
|
||||
throwIfError(error);
|
||||
return data ?? null;
|
||||
},
|
||||
staleTime: 60_000,
|
||||
});
|
||||
}
|
||||
49
src/data/hooks/useMeta.ts
Normal file
49
src/data/hooks/useMeta.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { qk } from "../query/keys";
|
||||
import {
|
||||
carreras_list,
|
||||
estados_plan_list,
|
||||
estructuras_asignatura_list,
|
||||
estructuras_plan_list,
|
||||
facultades_list,
|
||||
} from "../api/meta.api";
|
||||
|
||||
export function useFacultades() {
|
||||
return useQuery({
|
||||
queryKey: qk.facultades(),
|
||||
queryFn: facultades_list,
|
||||
staleTime: 5 * 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
export function useCarreras(params?: { facultadId?: string | null }) {
|
||||
return useQuery({
|
||||
queryKey: qk.carreras(params?.facultadId ?? null),
|
||||
queryFn: () => carreras_list(params),
|
||||
staleTime: 5 * 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
export function useEstructurasPlan(params?: { nivel?: string | null }) {
|
||||
return useQuery({
|
||||
queryKey: qk.estructurasPlan(params?.nivel ?? null),
|
||||
queryFn: () => estructuras_plan_list(params),
|
||||
staleTime: 10 * 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
export function useEstructurasAsignatura() {
|
||||
return useQuery({
|
||||
queryKey: qk.estructurasAsignatura(),
|
||||
queryFn: estructuras_asignatura_list,
|
||||
staleTime: 10 * 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
export function useEstadosPlan() {
|
||||
return useQuery({
|
||||
queryKey: qk.estadosPlan(),
|
||||
queryFn: estados_plan_list,
|
||||
staleTime: 10 * 60_000,
|
||||
});
|
||||
}
|
||||
49
src/data/hooks/useNotifications.ts
Normal file
49
src/data/hooks/useNotifications.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { useEffect } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { qk } from "../query/keys";
|
||||
import { notificaciones_marcar_leida, notificaciones_mias_list } from "../api/notifications.api";
|
||||
import { supabaseBrowser } from "../supabase/client";
|
||||
|
||||
export function useMisNotificaciones() {
|
||||
return useQuery({
|
||||
queryKey: qk.notificaciones(),
|
||||
queryFn: notificaciones_mias_list,
|
||||
staleTime: 10_000,
|
||||
});
|
||||
}
|
||||
|
||||
/** 🔥 Opcional: realtime (si tienes Realtime habilitado) */
|
||||
export function useRealtimeNotificaciones(enable = true) {
|
||||
const supabase = supabaseBrowser();
|
||||
const qc = useQueryClient();
|
||||
|
||||
useEffect(() => {
|
||||
if (!enable) return;
|
||||
|
||||
const channel = supabase
|
||||
.channel("rt-notificaciones")
|
||||
.on(
|
||||
"postgres_changes",
|
||||
{ event: "*", schema: "public", table: "notificaciones" },
|
||||
() => {
|
||||
qc.invalidateQueries({ queryKey: qk.notificaciones() });
|
||||
}
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
return () => {
|
||||
supabase.removeChannel(channel);
|
||||
};
|
||||
}, [enable, supabase, qc]);
|
||||
}
|
||||
|
||||
export function useMarcarNotificacionLeida() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: notificaciones_marcar_leida,
|
||||
onSuccess: () => {
|
||||
qc.invalidateQueries({ queryKey: qk.notificaciones() });
|
||||
},
|
||||
});
|
||||
}
|
||||
210
src/data/hooks/usePlans.ts
Normal file
210
src/data/hooks/usePlans.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { qk } from "../query/keys";
|
||||
import type { PlanEstudio, UUID } from "../types/domain";
|
||||
import type { PlanListFilters, PlanMapOperation, PlansCreateManualInput, PlansUpdateFieldsPatch } from "../api/plans.api";
|
||||
import {
|
||||
ai_generate_plan,
|
||||
plan_asignaturas_list,
|
||||
plan_lineas_list,
|
||||
plans_clone_from_existing,
|
||||
plans_create_manual,
|
||||
plans_generate_document,
|
||||
plans_get,
|
||||
plans_get_document,
|
||||
plans_history,
|
||||
plans_import_from_files,
|
||||
plans_list,
|
||||
plans_persist_from_ai,
|
||||
plans_transition_state,
|
||||
plans_update_fields,
|
||||
plans_update_map,
|
||||
} from "../api/plans.api";
|
||||
|
||||
export function usePlanes(filters: PlanListFilters) {
|
||||
// 🧠 Tip: memoiza "filters" (useMemo) para que queryKey sea estable.
|
||||
return useQuery({
|
||||
queryKey: qk.planesList(filters),
|
||||
queryFn: () => plans_list(filters),
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
}
|
||||
|
||||
export function usePlan(planId: UUID | null | undefined) {
|
||||
return useQuery({
|
||||
queryKey: planId ? qk.plan(planId) : ["planes", "detail", null],
|
||||
queryFn: () => plans_get(planId as UUID),
|
||||
enabled: Boolean(planId),
|
||||
});
|
||||
}
|
||||
|
||||
export function usePlanLineas(planId: UUID | null | undefined) {
|
||||
return useQuery({
|
||||
queryKey: planId ? qk.planLineas(planId) : ["planes", "lineas", null],
|
||||
queryFn: () => plan_lineas_list(planId as UUID),
|
||||
enabled: Boolean(planId),
|
||||
});
|
||||
}
|
||||
|
||||
export function usePlanAsignaturas(planId: UUID | null | undefined) {
|
||||
return useQuery({
|
||||
queryKey: planId ? qk.planAsignaturas(planId) : ["planes", "asignaturas", null],
|
||||
queryFn: () => plan_asignaturas_list(planId as UUID),
|
||||
enabled: Boolean(planId),
|
||||
});
|
||||
}
|
||||
|
||||
export function usePlanHistorial(planId: UUID | null | undefined) {
|
||||
return useQuery({
|
||||
queryKey: planId ? qk.planHistorial(planId) : ["planes", "historial", null],
|
||||
queryFn: () => plans_history(planId as UUID),
|
||||
enabled: Boolean(planId),
|
||||
});
|
||||
}
|
||||
|
||||
export function usePlanDocumento(planId: UUID | null | undefined) {
|
||||
return useQuery({
|
||||
queryKey: planId ? qk.planDocumento(planId) : ["planes", "documento", null],
|
||||
queryFn: () => plans_get_document(planId as UUID),
|
||||
enabled: Boolean(planId),
|
||||
staleTime: 30_000,
|
||||
});
|
||||
}
|
||||
|
||||
/* ------------------ Mutations ------------------ */
|
||||
|
||||
export function useCreatePlanManual() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (input: PlansCreateManualInput) => plans_create_manual(input),
|
||||
onSuccess: (plan) => {
|
||||
qc.invalidateQueries({ queryKey: ["planes", "list"] });
|
||||
qc.setQueryData(qk.plan(plan.id), plan);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useGeneratePlanAI() {
|
||||
return useMutation({
|
||||
mutationFn: ai_generate_plan,
|
||||
});
|
||||
}
|
||||
|
||||
export function usePersistPlanFromAI() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (payload: { jsonPlan: any }) => plans_persist_from_ai(payload),
|
||||
onSuccess: (plan) => {
|
||||
qc.invalidateQueries({ queryKey: ["planes", "list"] });
|
||||
qc.setQueryData(qk.plan(plan.id), plan);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useClonePlan() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: plans_clone_from_existing,
|
||||
onSuccess: (plan) => {
|
||||
qc.invalidateQueries({ queryKey: ["planes", "list"] });
|
||||
qc.setQueryData(qk.plan(plan.id), plan);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useImportPlanFromFiles() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: plans_import_from_files,
|
||||
onSuccess: (plan) => {
|
||||
qc.invalidateQueries({ queryKey: ["planes", "list"] });
|
||||
qc.setQueryData(qk.plan(plan.id), plan);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdatePlanFields() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (vars: { planId: UUID; patch: PlansUpdateFieldsPatch }) =>
|
||||
plans_update_fields(vars.planId, vars.patch),
|
||||
onSuccess: (updated) => {
|
||||
qc.setQueryData(qk.plan(updated.id), updated);
|
||||
qc.invalidateQueries({ queryKey: ["planes", "list"] });
|
||||
qc.invalidateQueries({ queryKey: qk.planHistorial(updated.id) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdatePlanMapa() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (vars: { planId: UUID; ops: PlanMapOperation[] }) => plans_update_map(vars.planId, vars.ops),
|
||||
|
||||
// ✅ Optimista (rápida) para el caso MOVE_ASIGNATURA
|
||||
onMutate: async (vars) => {
|
||||
await qc.cancelQueries({ queryKey: qk.planAsignaturas(vars.planId) });
|
||||
const prev = qc.getQueryData<any>(qk.planAsignaturas(vars.planId));
|
||||
|
||||
// solo optimizamos MOVEs simples
|
||||
const moves = vars.ops.filter((x) => x.op === "MOVE_ASIGNATURA") as Array<
|
||||
Extract<PlanMapOperation, { op: "MOVE_ASIGNATURA" }>
|
||||
>;
|
||||
|
||||
if (prev && Array.isArray(prev) && moves.length) {
|
||||
const next = prev.map((a: any) => {
|
||||
const m = moves.find((x) => x.asignaturaId === a.id);
|
||||
if (!m) return a;
|
||||
return {
|
||||
...a,
|
||||
numero_ciclo: m.numero_ciclo,
|
||||
linea_plan_id: m.linea_plan_id,
|
||||
orden_celda: m.orden_celda ?? a.orden_celda,
|
||||
};
|
||||
});
|
||||
qc.setQueryData(qk.planAsignaturas(vars.planId), next);
|
||||
}
|
||||
|
||||
return { prev };
|
||||
},
|
||||
|
||||
onError: (_err, vars, ctx) => {
|
||||
if (ctx?.prev) qc.setQueryData(qk.planAsignaturas(vars.planId), ctx.prev);
|
||||
},
|
||||
|
||||
onSuccess: (_ok, vars) => {
|
||||
qc.invalidateQueries({ queryKey: qk.planAsignaturas(vars.planId) });
|
||||
qc.invalidateQueries({ queryKey: qk.planHistorial(vars.planId) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useTransitionPlanEstado() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: plans_transition_state,
|
||||
onSuccess: (_ok, vars) => {
|
||||
qc.invalidateQueries({ queryKey: qk.plan(vars.planId) });
|
||||
qc.invalidateQueries({ queryKey: qk.planHistorial(vars.planId) });
|
||||
qc.invalidateQueries({ queryKey: ["planes", "list"] });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useGeneratePlanDocumento() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (planId: UUID) => plans_generate_document(planId),
|
||||
onSuccess: (_doc, planId) => {
|
||||
qc.invalidateQueries({ queryKey: qk.planDocumento(planId) });
|
||||
qc.invalidateQueries({ queryKey: qk.planHistorial(planId) });
|
||||
},
|
||||
});
|
||||
}
|
||||
166
src/data/hooks/useSubjects.ts
Normal file
166
src/data/hooks/useSubjects.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { qk } from "../query/keys";
|
||||
import type { UUID } from "../types/domain";
|
||||
import type {
|
||||
BibliografiaUpsertInput,
|
||||
SubjectsCreateManualInput,
|
||||
SubjectsUpdateFieldsPatch,
|
||||
} from "../api/subjects.api";
|
||||
import {
|
||||
ai_generate_subject,
|
||||
subjects_bibliografia_list,
|
||||
subjects_clone_from_existing,
|
||||
subjects_create_manual,
|
||||
subjects_generate_document,
|
||||
subjects_get,
|
||||
subjects_get_document,
|
||||
subjects_history,
|
||||
subjects_import_from_file,
|
||||
subjects_persist_from_ai,
|
||||
subjects_update_bibliografia,
|
||||
subjects_update_contenido,
|
||||
subjects_update_fields,
|
||||
} from "../api/subjects.api";
|
||||
|
||||
export function useSubject(subjectId: UUID | null | undefined) {
|
||||
return useQuery({
|
||||
queryKey: subjectId ? qk.asignatura(subjectId) : ["asignaturas", "detail", null],
|
||||
queryFn: () => subjects_get(subjectId as UUID),
|
||||
enabled: Boolean(subjectId),
|
||||
});
|
||||
}
|
||||
|
||||
export function useSubjectBibliografia(subjectId: UUID | null | undefined) {
|
||||
return useQuery({
|
||||
queryKey: subjectId ? qk.asignaturaBibliografia(subjectId) : ["asignaturas", "bibliografia", null],
|
||||
queryFn: () => subjects_bibliografia_list(subjectId as UUID),
|
||||
enabled: Boolean(subjectId),
|
||||
});
|
||||
}
|
||||
|
||||
export function useSubjectHistorial(subjectId: UUID | null | undefined) {
|
||||
return useQuery({
|
||||
queryKey: subjectId ? qk.asignaturaHistorial(subjectId) : ["asignaturas", "historial", null],
|
||||
queryFn: () => subjects_history(subjectId as UUID),
|
||||
enabled: Boolean(subjectId),
|
||||
});
|
||||
}
|
||||
|
||||
export function useSubjectDocumento(subjectId: UUID | null | undefined) {
|
||||
return useQuery({
|
||||
queryKey: subjectId ? qk.asignaturaDocumento(subjectId) : ["asignaturas", "documento", null],
|
||||
queryFn: () => subjects_get_document(subjectId as UUID),
|
||||
enabled: Boolean(subjectId),
|
||||
staleTime: 30_000,
|
||||
});
|
||||
}
|
||||
|
||||
/* ------------------ Mutations ------------------ */
|
||||
|
||||
export function useCreateSubjectManual() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (payload: SubjectsCreateManualInput) => subjects_create_manual(payload),
|
||||
onSuccess: (subject) => {
|
||||
qc.setQueryData(qk.asignatura(subject.id), subject);
|
||||
qc.invalidateQueries({ queryKey: qk.planAsignaturas(subject.plan_estudio_id) });
|
||||
qc.invalidateQueries({ queryKey: qk.planHistorial(subject.plan_estudio_id) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useGenerateSubjectAI() {
|
||||
return useMutation({ mutationFn: ai_generate_subject });
|
||||
}
|
||||
|
||||
export function usePersistSubjectFromAI() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (payload: { planId: UUID; jsonMateria: any }) => subjects_persist_from_ai(payload),
|
||||
onSuccess: (subject) => {
|
||||
qc.setQueryData(qk.asignatura(subject.id), subject);
|
||||
qc.invalidateQueries({ queryKey: qk.planAsignaturas(subject.plan_estudio_id) });
|
||||
qc.invalidateQueries({ queryKey: qk.planHistorial(subject.plan_estudio_id) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useCloneSubject() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: subjects_clone_from_existing,
|
||||
onSuccess: (subject) => {
|
||||
qc.setQueryData(qk.asignatura(subject.id), subject);
|
||||
qc.invalidateQueries({ queryKey: qk.planAsignaturas(subject.plan_estudio_id) });
|
||||
qc.invalidateQueries({ queryKey: qk.planHistorial(subject.plan_estudio_id) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useImportSubjectFromFile() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: subjects_import_from_file,
|
||||
onSuccess: (subject) => {
|
||||
qc.setQueryData(qk.asignatura(subject.id), subject);
|
||||
qc.invalidateQueries({ queryKey: qk.planAsignaturas(subject.plan_estudio_id) });
|
||||
qc.invalidateQueries({ queryKey: qk.planHistorial(subject.plan_estudio_id) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateSubjectFields() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (vars: { subjectId: UUID; patch: SubjectsUpdateFieldsPatch }) =>
|
||||
subjects_update_fields(vars.subjectId, vars.patch),
|
||||
onSuccess: (updated) => {
|
||||
qc.setQueryData(qk.asignatura(updated.id), updated);
|
||||
qc.invalidateQueries({ queryKey: qk.planAsignaturas(updated.plan_estudio_id) });
|
||||
qc.invalidateQueries({ queryKey: qk.asignaturaHistorial(updated.id) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateSubjectContenido() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (vars: { subjectId: UUID; unidades: any[] }) =>
|
||||
subjects_update_contenido(vars.subjectId, vars.unidades),
|
||||
onSuccess: (updated) => {
|
||||
qc.setQueryData(qk.asignatura(updated.id), updated);
|
||||
qc.invalidateQueries({ queryKey: qk.asignaturaHistorial(updated.id) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateSubjectBibliografia() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (vars: { subjectId: UUID; entries: BibliografiaUpsertInput }) =>
|
||||
subjects_update_bibliografia(vars.subjectId, vars.entries),
|
||||
onSuccess: (_ok, vars) => {
|
||||
qc.invalidateQueries({ queryKey: qk.asignaturaBibliografia(vars.subjectId) });
|
||||
qc.invalidateQueries({ queryKey: qk.asignaturaHistorial(vars.subjectId) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useGenerateSubjectDocumento() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (subjectId: UUID) => subjects_generate_document(subjectId),
|
||||
onSuccess: (_doc, subjectId) => {
|
||||
qc.invalidateQueries({ queryKey: qk.asignaturaDocumento(subjectId) });
|
||||
qc.invalidateQueries({ queryKey: qk.asignaturaHistorial(subjectId) });
|
||||
},
|
||||
});
|
||||
}
|
||||
22
src/data/hooks/useTasks.ts
Normal file
22
src/data/hooks/useTasks.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { qk } from "../query/keys";
|
||||
import { tareas_marcar_completada, tareas_mias_list } from "../api/tasks.api";
|
||||
|
||||
export function useMisTareas() {
|
||||
return useQuery({
|
||||
queryKey: qk.tareas(),
|
||||
queryFn: tareas_mias_list,
|
||||
staleTime: 15_000,
|
||||
});
|
||||
}
|
||||
|
||||
export function useMarcarTareaCompletada() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: tareas_marcar_completada,
|
||||
onSuccess: () => {
|
||||
qc.invalidateQueries({ queryKey: qk.tareas() });
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user