wip
ya funciona la busqueda de asignaturas, pero ocurre un bug en la insercion de la asignatura clonada
This commit is contained in:
@@ -4,6 +4,7 @@ import { useEffect, useMemo } from 'react'
|
||||
import { useDebounce } from 'use-debounce'
|
||||
|
||||
import type { NewSubjectWizardState } from '@/features/asignaturas/nueva/types'
|
||||
import type { Database } from '@/types/supabase'
|
||||
|
||||
import Pagination03 from '@/components/shadcn-studio/pagination/pagination-03'
|
||||
import { Button } from '@/components/ui/button'
|
||||
@@ -28,12 +29,13 @@ type SourceSubjectRow = {
|
||||
tipo: any
|
||||
plan_estudio_id: string
|
||||
estructura_id: string | null
|
||||
rank?: number
|
||||
}
|
||||
|
||||
const ALL = '__all__'
|
||||
|
||||
const normalizeLikeTerm = (term: string) =>
|
||||
term.trim().replace(/[(),]/g, ' ').replace(/\s+/g, ' ')
|
||||
type SearchAsignaturasRow =
|
||||
Database['public']['Functions']['search_asignaturas']['Returns'][number]
|
||||
|
||||
export function PasoFuenteClonadoInterno({
|
||||
wizard,
|
||||
@@ -95,41 +97,146 @@ export function PasoFuenteClonadoInterno({
|
||||
const from = (page - 1) * pageSize
|
||||
const to = from + pageSize - 1
|
||||
|
||||
let q = supabase
|
||||
.from('asignaturas')
|
||||
.select(
|
||||
'id,nombre,codigo,creditos,tipo,plan_estudio_id,estructura_id',
|
||||
{
|
||||
count: 'exact',
|
||||
},
|
||||
)
|
||||
.order('nombre', { ascending: true })
|
||||
const term = debouncedSearch.trim()
|
||||
|
||||
// Full text search (tsvector) para el campo Buscar.
|
||||
// Si no hay término, conservamos el listado base por nombre.
|
||||
if (term) {
|
||||
const mapRow = (r: SearchAsignaturasRow): SourceSubjectRow => ({
|
||||
id: r.id,
|
||||
nombre: r.nombre,
|
||||
codigo: r.codigo,
|
||||
creditos: Number(r.creditos),
|
||||
tipo: r.tipo,
|
||||
plan_estudio_id: r.plan_estudio_id,
|
||||
estructura_id: null,
|
||||
rank: r.rank,
|
||||
})
|
||||
|
||||
if (planOrigenId) {
|
||||
q = q.eq('plan_estudio_id', planOrigenId)
|
||||
} else if (needPlansForFilter) {
|
||||
const args: Database['public']['Functions']['search_asignaturas']['Args'] =
|
||||
{
|
||||
p_search: term,
|
||||
p_plan_estudio_id: planOrigenId,
|
||||
p_limit: pageSize,
|
||||
p_offset: from,
|
||||
}
|
||||
|
||||
const { data, error, count } = await supabase.rpc(
|
||||
'search_asignaturas',
|
||||
args,
|
||||
{ count: 'exact' },
|
||||
)
|
||||
if (error) throw new Error(error.message)
|
||||
|
||||
return {
|
||||
data: data.map(mapRow),
|
||||
count: count ?? 0,
|
||||
}
|
||||
}
|
||||
|
||||
if (needPlansForFilter) {
|
||||
const planIds = plansForFilter.map((p) => p.id)
|
||||
if (!planIds.length) {
|
||||
return { data: [] as Array<SourceSubjectRow>, count: 0 }
|
||||
}
|
||||
q = q.in('plan_estudio_id', planIds)
|
||||
|
||||
const perPlanLimit = pageSize * page
|
||||
|
||||
const perPlan = await Promise.all(
|
||||
planIds.map(async (planId) => {
|
||||
const args: Database['public']['Functions']['search_asignaturas']['Args'] =
|
||||
{
|
||||
p_search: term,
|
||||
p_plan_estudio_id: planId,
|
||||
p_limit: perPlanLimit,
|
||||
p_offset: 0,
|
||||
}
|
||||
|
||||
const term = normalizeLikeTerm(debouncedSearch)
|
||||
if (term) {
|
||||
// PostgREST OR syntax
|
||||
q = q.or(`nombre.ilike.%${term}%,codigo.ilike.%${term}%`)
|
||||
}
|
||||
|
||||
q = q.range(from, to)
|
||||
|
||||
const { data, error, count } = await q
|
||||
const { data, error, count } = await supabase.rpc(
|
||||
'search_asignaturas',
|
||||
args,
|
||||
{ count: 'exact' },
|
||||
)
|
||||
if (error) throw new Error(error.message)
|
||||
|
||||
return {
|
||||
data: data as unknown as Array<SourceSubjectRow>,
|
||||
data,
|
||||
count: count ?? 0,
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
const merged = perPlan
|
||||
.flatMap((p) => p.data)
|
||||
.map(mapRow)
|
||||
.sort((a, b) => {
|
||||
const ar = a.rank ?? 0
|
||||
const br = b.rank ?? 0
|
||||
if (br !== ar) return br - ar
|
||||
const byName = a.nombre.localeCompare(b.nombre, 'es')
|
||||
if (byName !== 0) return byName
|
||||
return String(a.id).localeCompare(String(b.id))
|
||||
})
|
||||
|
||||
const pageData = merged.slice(from, to + 1)
|
||||
const totalCount = perPlan.reduce((acc, p) => acc + p.count, 0)
|
||||
|
||||
return {
|
||||
data: pageData,
|
||||
count: totalCount,
|
||||
}
|
||||
}
|
||||
|
||||
const args: Database['public']['Functions']['search_asignaturas']['Args'] =
|
||||
{
|
||||
p_search: term,
|
||||
p_limit: pageSize,
|
||||
p_offset: from,
|
||||
}
|
||||
|
||||
const { data, error, count } = await supabase.rpc(
|
||||
'search_asignaturas',
|
||||
args,
|
||||
{ count: 'exact' },
|
||||
)
|
||||
if (error) throw new Error(error.message)
|
||||
|
||||
return {
|
||||
data: data.map(mapRow),
|
||||
count: count ?? 0,
|
||||
}
|
||||
}
|
||||
|
||||
// let q = supabase
|
||||
// .from('asignaturas')
|
||||
// .select(
|
||||
// 'id,nombre,codigo,creditos,tipo,plan_estudio_id,estructura_id',
|
||||
// {
|
||||
// count: 'exact',
|
||||
// },
|
||||
// )
|
||||
// .order('nombre', { ascending: true })
|
||||
|
||||
// if (planOrigenId) {
|
||||
// q = q.eq('plan_estudio_id', planOrigenId)
|
||||
// } else if (needPlansForFilter) {
|
||||
// const planIds = plansForFilter.map((p) => p.id)
|
||||
// if (!planIds.length) {
|
||||
// return { data: [] as Array<SourceSubjectRow>, count: 0 }
|
||||
// }
|
||||
// q = q.in('plan_estudio_id', planIds)
|
||||
// }
|
||||
|
||||
// q = q.range(from, to)
|
||||
|
||||
// const { data, error, count } = await q
|
||||
// if (error) throw new Error(error.message)
|
||||
|
||||
// return {
|
||||
// data: data as unknown as Array<SourceSubjectRow>,
|
||||
// count: count ?? 0,
|
||||
// }
|
||||
},
|
||||
})
|
||||
|
||||
@@ -188,7 +295,7 @@ export function PasoFuenteClonadoInterno({
|
||||
resetSelection()
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger className="w-full min-w-0 [&>span]:block! [&>span]:truncate!">
|
||||
<SelectValue placeholder="Todas" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -217,7 +324,7 @@ export function PasoFuenteClonadoInterno({
|
||||
}}
|
||||
disabled={!facultadId}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger className="w-full min-w-0 [&>span]:block! [&>span]:truncate!">
|
||||
<SelectValue
|
||||
placeholder={facultadId ? 'Todas' : 'Selecciona facultad'}
|
||||
/>
|
||||
@@ -243,7 +350,10 @@ export function PasoFuenteClonadoInterno({
|
||||
resetSelection()
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger
|
||||
className="w-full min-w-0 [&>span]:block! [&>span]:truncate!"
|
||||
disabled={!carreraId && !facultadId}
|
||||
>
|
||||
<SelectValue placeholder="Todos" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
||||
@@ -257,6 +257,8 @@ export function WizardControls({
|
||||
null,
|
||||
}
|
||||
|
||||
console.log('payload:', payload)
|
||||
|
||||
const { data: inserted, error: insertError } = await supabase
|
||||
.from('asignaturas')
|
||||
.insert(payload)
|
||||
|
||||
@@ -155,6 +155,7 @@ export type Database = {
|
||||
orden_celda: number | null
|
||||
plan_estudio_id: string
|
||||
prerrequisito_asignatura_id: string | null
|
||||
search_vector: unknown
|
||||
tipo: Database['public']['Enums']['tipo_asignatura']
|
||||
tipo_origen: Database['public']['Enums']['tipo_origen'] | null
|
||||
}
|
||||
@@ -181,6 +182,7 @@ export type Database = {
|
||||
orden_celda?: number | null
|
||||
plan_estudio_id: string
|
||||
prerrequisito_asignatura_id?: string | null
|
||||
search_vector?: unknown
|
||||
tipo?: Database['public']['Enums']['tipo_asignatura']
|
||||
tipo_origen?: Database['public']['Enums']['tipo_origen'] | null
|
||||
}
|
||||
@@ -207,6 +209,7 @@ export type Database = {
|
||||
orden_celda?: number | null
|
||||
plan_estudio_id?: string
|
||||
prerrequisito_asignatura_id?: string | null
|
||||
search_vector?: unknown
|
||||
tipo?: Database['public']['Enums']['tipo_asignatura']
|
||||
tipo_origen?: Database['public']['Enums']['tipo_origen'] | null
|
||||
}
|
||||
@@ -1393,6 +1396,31 @@ export type Database = {
|
||||
Args: { p_append: Json; p_id: string }
|
||||
Returns: undefined
|
||||
}
|
||||
build_asignaturas_prefix_tsquery: {
|
||||
Args: { p_search: string }
|
||||
Returns: unknown
|
||||
}
|
||||
search_asignaturas: {
|
||||
Args: {
|
||||
p_limit?: number
|
||||
p_offset?: number
|
||||
p_plan_estudio_id?: string
|
||||
p_search: string
|
||||
}
|
||||
Returns: Array<{
|
||||
codigo: string
|
||||
contenido_tematico: Json
|
||||
creditos: number
|
||||
datos: Json
|
||||
estado: Database['public']['Enums']['estado_asignatura']
|
||||
id: string
|
||||
nombre: string
|
||||
numero_ciclo: number
|
||||
plan_estudio_id: string
|
||||
rank: number
|
||||
tipo: Database['public']['Enums']['tipo_asignatura']
|
||||
}>
|
||||
}
|
||||
suma_porcentajes: { Args: { '': Json }; Returns: number }
|
||||
unaccent: { Args: { '': string }; Returns: string }
|
||||
unaccent_immutable: { Args: { '': string }; Returns: string }
|
||||
|
||||
Reference in New Issue
Block a user