.claude/skills/create-hook/SKILL.md
Cuando necesites crear un custom hook para fetch (useQuery), mutaciones (useMutation) o suscripciones realtime con Supabase.
npx skillsauth add placidovenegas/kiyoko-AI create-hookInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
// src/hooks/useNombreRecurso.ts
'use client';
import { useQuery } from '@tanstack/react-query';
import { createBrowserClient } from '@/lib/supabase/client';
import { queryKeys } from '@/lib/query/keys';
export function useNombreRecurso(parentId: string) {
const supabase = createBrowserClient();
return useQuery({
queryKey: queryKeys.recurso.byParent(parentId),
queryFn: async () => {
const { data, error } = await supabase
.from('tabla')
.select('*')
.eq('parent_id', parentId)
.order('sort_order');
if (error) throw error;
return data;
},
enabled: !!parentId, // No ejecutar si no hay ID
});
}
// src/hooks/useUpdateNombreRecurso.ts
'use client';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { createBrowserClient } from '@/lib/supabase/client';
import { queryKeys } from '@/lib/query/keys';
export function useUpdateNombreRecurso() {
const supabase = createBrowserClient();
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ id, data }: { id: string; data: Partial<Recurso> }) => {
const { error } = await supabase.from('tabla').update(data).eq('id', id);
if (error) throw error;
},
onMutate: async ({ id, data }) => {
const key = queryKeys.recurso.byParent(parentId);
await qc.cancelQueries({ queryKey: key });
const prev = qc.getQueryData(key);
qc.setQueryData(key, (old: any[]) =>
old?.map(item => item.id === id ? { ...item, ...data } : item)
);
return { prev };
},
onError: (_err, _vars, ctx) => {
if (ctx?.prev) qc.setQueryData(queryKeys.recurso.byParent(parentId), ctx.prev);
},
onSettled: () => {
qc.invalidateQueries({ queryKey: queryKeys.recurso.byParent(parentId) });
},
});
}
export function useCreateNombreRecurso(parentId: string) {
const supabase = createBrowserClient();
const qc = useQueryClient();
return useMutation({
mutationFn: async (data: NewRecurso) => {
const { data: created, error } = await supabase
.from('tabla')
.insert({ ...data, parent_id: parentId })
.select()
.single();
if (error) throw error;
return created;
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: queryKeys.recurso.byParent(parentId) });
},
});
}
export function useDeleteNombreRecurso(parentId: string) {
const supabase = createBrowserClient();
const qc = useQueryClient();
return useMutation({
mutationFn: async (id: string) => {
const { error } = await supabase.from('tabla').delete().eq('id', id);
if (error) throw error;
},
onMutate: async (id) => {
const key = queryKeys.recurso.byParent(parentId);
await qc.cancelQueries({ queryKey: key });
const prev = qc.getQueryData(key);
qc.setQueryData(key, (old: any[]) => old?.filter(item => item.id !== id));
return { prev };
},
onError: (_err, _vars, ctx) => {
if (ctx?.prev) qc.setQueryData(queryKeys.recurso.byParent(parentId), ctx.prev);
},
onSettled: () => {
qc.invalidateQueries({ queryKey: queryKeys.recurso.byParent(parentId) });
},
});
}
@/lib/query/keys.ts, no hardcodear strings.enabled: !!parentId para evitar queries con undefined.prev para rollback en onError.onSettled (no onSuccess) para invalidar: se ejecuta tanto en éxito como en error.testing
Auditar componentes UI para consistencia visual, compliance con design system, accesibilidad y patrones Notion/Supabase. Usar cuando se quiera verificar calidad visual del proyecto.
data-ai
Postgres performance optimization and best practices from Supabase. Use this skill when writing, reviewing, or optimizing Postgres queries, schema designs, or database configurations.
tools
Cuando necesites crear, modificar o borrar tablas, enums, indices, RLS policies o seeds en Supabase. También para ejecutar SQL vía MCP.
testing
Motor de escenas de Kiyoko AI. Usar cuando se trabaje con escenas, prompts de imagen/video, timeline, camara, o generacion de contenido audiovisual. Referencia completa en docs/v6/MY DOCUMENT/kiyoko-motor-escenas-spec.md