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 { useDebounce } from 'use-debounce'
|
||||||
|
|
||||||
import type { NewSubjectWizardState } from '@/features/asignaturas/nueva/types'
|
import type { NewSubjectWizardState } from '@/features/asignaturas/nueva/types'
|
||||||
|
import type { Database } from '@/types/supabase'
|
||||||
|
|
||||||
import Pagination03 from '@/components/shadcn-studio/pagination/pagination-03'
|
import Pagination03 from '@/components/shadcn-studio/pagination/pagination-03'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
@@ -28,12 +29,13 @@ type SourceSubjectRow = {
|
|||||||
tipo: any
|
tipo: any
|
||||||
plan_estudio_id: string
|
plan_estudio_id: string
|
||||||
estructura_id: string | null
|
estructura_id: string | null
|
||||||
|
rank?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const ALL = '__all__'
|
const ALL = '__all__'
|
||||||
|
|
||||||
const normalizeLikeTerm = (term: string) =>
|
type SearchAsignaturasRow =
|
||||||
term.trim().replace(/[(),]/g, ' ').replace(/\s+/g, ' ')
|
Database['public']['Functions']['search_asignaturas']['Returns'][number]
|
||||||
|
|
||||||
export function PasoFuenteClonadoInterno({
|
export function PasoFuenteClonadoInterno({
|
||||||
wizard,
|
wizard,
|
||||||
@@ -95,41 +97,146 @@ export function PasoFuenteClonadoInterno({
|
|||||||
const from = (page - 1) * pageSize
|
const from = (page - 1) * pageSize
|
||||||
const to = from + pageSize - 1
|
const to = from + pageSize - 1
|
||||||
|
|
||||||
let q = supabase
|
const term = debouncedSearch.trim()
|
||||||
.from('asignaturas')
|
|
||||||
.select(
|
|
||||||
'id,nombre,codigo,creditos,tipo,plan_estudio_id,estructura_id',
|
|
||||||
{
|
|
||||||
count: 'exact',
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.order('nombre', { ascending: true })
|
|
||||||
|
|
||||||
if (planOrigenId) {
|
// Full text search (tsvector) para el campo Buscar.
|
||||||
q = q.eq('plan_estudio_id', planOrigenId)
|
// Si no hay término, conservamos el listado base por nombre.
|
||||||
} 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
const term = normalizeLikeTerm(debouncedSearch)
|
|
||||||
if (term) {
|
if (term) {
|
||||||
// PostgREST OR syntax
|
const mapRow = (r: SearchAsignaturasRow): SourceSubjectRow => ({
|
||||||
q = q.or(`nombre.ilike.%${term}%,codigo.ilike.%${term}%`)
|
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) {
|
||||||
|
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 }
|
||||||
|
}
|
||||||
|
|
||||||
|
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 { data, error, count } = await supabase.rpc(
|
||||||
|
'search_asignaturas',
|
||||||
|
args,
|
||||||
|
{ count: 'exact' },
|
||||||
|
)
|
||||||
|
if (error) throw new Error(error.message)
|
||||||
|
|
||||||
|
return {
|
||||||
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
q = q.range(from, to)
|
// let q = supabase
|
||||||
|
// .from('asignaturas')
|
||||||
|
// .select(
|
||||||
|
// 'id,nombre,codigo,creditos,tipo,plan_estudio_id,estructura_id',
|
||||||
|
// {
|
||||||
|
// count: 'exact',
|
||||||
|
// },
|
||||||
|
// )
|
||||||
|
// .order('nombre', { ascending: true })
|
||||||
|
|
||||||
const { data, error, count } = await q
|
// if (planOrigenId) {
|
||||||
if (error) throw new Error(error.message)
|
// 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)
|
||||||
|
// }
|
||||||
|
|
||||||
return {
|
// q = q.range(from, to)
|
||||||
data: data as unknown as Array<SourceSubjectRow>,
|
|
||||||
count: count ?? 0,
|
// 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()
|
resetSelection()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger className="w-full min-w-0 [&>span]:block! [&>span]:truncate!">
|
||||||
<SelectValue placeholder="Todas" />
|
<SelectValue placeholder="Todas" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -217,7 +324,7 @@ export function PasoFuenteClonadoInterno({
|
|||||||
}}
|
}}
|
||||||
disabled={!facultadId}
|
disabled={!facultadId}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger className="w-full min-w-0 [&>span]:block! [&>span]:truncate!">
|
||||||
<SelectValue
|
<SelectValue
|
||||||
placeholder={facultadId ? 'Todas' : 'Selecciona facultad'}
|
placeholder={facultadId ? 'Todas' : 'Selecciona facultad'}
|
||||||
/>
|
/>
|
||||||
@@ -243,7 +350,10 @@ export function PasoFuenteClonadoInterno({
|
|||||||
resetSelection()
|
resetSelection()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger
|
||||||
|
className="w-full min-w-0 [&>span]:block! [&>span]:truncate!"
|
||||||
|
disabled={!carreraId && !facultadId}
|
||||||
|
>
|
||||||
<SelectValue placeholder="Todos" />
|
<SelectValue placeholder="Todos" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
|
|||||||
@@ -257,6 +257,8 @@ export function WizardControls({
|
|||||||
null,
|
null,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('payload:', payload)
|
||||||
|
|
||||||
const { data: inserted, error: insertError } = await supabase
|
const { data: inserted, error: insertError } = await supabase
|
||||||
.from('asignaturas')
|
.from('asignaturas')
|
||||||
.insert(payload)
|
.insert(payload)
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ export type Database = {
|
|||||||
orden_celda: number | null
|
orden_celda: number | null
|
||||||
plan_estudio_id: string
|
plan_estudio_id: string
|
||||||
prerrequisito_asignatura_id: string | null
|
prerrequisito_asignatura_id: string | null
|
||||||
|
search_vector: unknown
|
||||||
tipo: Database['public']['Enums']['tipo_asignatura']
|
tipo: Database['public']['Enums']['tipo_asignatura']
|
||||||
tipo_origen: Database['public']['Enums']['tipo_origen'] | null
|
tipo_origen: Database['public']['Enums']['tipo_origen'] | null
|
||||||
}
|
}
|
||||||
@@ -181,6 +182,7 @@ export type Database = {
|
|||||||
orden_celda?: number | null
|
orden_celda?: number | null
|
||||||
plan_estudio_id: string
|
plan_estudio_id: string
|
||||||
prerrequisito_asignatura_id?: string | null
|
prerrequisito_asignatura_id?: string | null
|
||||||
|
search_vector?: unknown
|
||||||
tipo?: Database['public']['Enums']['tipo_asignatura']
|
tipo?: Database['public']['Enums']['tipo_asignatura']
|
||||||
tipo_origen?: Database['public']['Enums']['tipo_origen'] | null
|
tipo_origen?: Database['public']['Enums']['tipo_origen'] | null
|
||||||
}
|
}
|
||||||
@@ -207,6 +209,7 @@ export type Database = {
|
|||||||
orden_celda?: number | null
|
orden_celda?: number | null
|
||||||
plan_estudio_id?: string
|
plan_estudio_id?: string
|
||||||
prerrequisito_asignatura_id?: string | null
|
prerrequisito_asignatura_id?: string | null
|
||||||
|
search_vector?: unknown
|
||||||
tipo?: Database['public']['Enums']['tipo_asignatura']
|
tipo?: Database['public']['Enums']['tipo_asignatura']
|
||||||
tipo_origen?: Database['public']['Enums']['tipo_origen'] | null
|
tipo_origen?: Database['public']['Enums']['tipo_origen'] | null
|
||||||
}
|
}
|
||||||
@@ -1393,6 +1396,31 @@ export type Database = {
|
|||||||
Args: { p_append: Json; p_id: string }
|
Args: { p_append: Json; p_id: string }
|
||||||
Returns: undefined
|
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 }
|
suma_porcentajes: { Args: { '': Json }; Returns: number }
|
||||||
unaccent: { Args: { '': string }; Returns: string }
|
unaccent: { Args: { '': string }; Returns: string }
|
||||||
unaccent_immutable: { Args: { '': string }; Returns: string }
|
unaccent_immutable: { Args: { '': string }; Returns: string }
|
||||||
|
|||||||
Reference in New Issue
Block a user