1616 :value =" item.id"
1717 />
1818 <el-option
19- v-if =" loading && collections.length > 0 "
19+ v-if =" isFetchingNextPage || isPending "
2020 :key =" 'loading'"
2121 label =" Loading..."
2222 value =" "
2727</template >
2828
2929<script setup lang="ts">
30- import { debounce } from ' lodash' ;
3130import {
32- nextTick , onBeforeUnmount , onMounted , reactive , ref ,
31+ computed ,
32+ nextTick ,
33+ onBeforeUnmount ,
34+ onMounted ,
35+ reactive ,
36+ ref ,
37+ watch ,
3338} from ' vue' ;
34- import { CollectionsService } from ' @/modules/admin/modules/collections/services/collections.service' ;
39+ import {
40+ COLLECTIONS_SERVICE ,
41+ } from ' @/modules/admin/modules/collections/services/collections.service' ;
3542import Message from ' @/shared/message/message' ;
36- import { CollectionModel } from ' ../../../collections/models/collection.model' ;
43+ import { TanstackKey } from ' @/shared/types/tanstack' ;
44+ import { QueryFunction , useInfiniteQuery } from ' @tanstack/vue-query' ;
45+ import { Pagination } from ' @/shared/types/Pagination' ;
46+ import { debounce } from ' lodash' ;
3747import { InsightsProjectAddFormModel } from ' ../../models/insights-project-add-form.model' ;
48+ import { CollectionModel } from ' ../../../collections/models/collection.model' ;
3849
3950const props = defineProps <{
4051 form: InsightsProjectAddFormModel ;
4152}>();
4253
4354const cForm = reactive (props .form );
4455
45- const loading = ref (false );
46- const collections = ref <CollectionModel []>([]);
47- const page = ref (0 );
48- const pageSize = 20 ;
49- const noMoreData = ref (false );
5056const searchQuery = ref (' ' );
5157let scrollContainer: HTMLElement | null = null ;
5258
53- // Your API service method
54- function fetchCollections(query = ' ' , pageNum = 0 ) {
55- loading .value = true ;
56- CollectionsService .list ({
57- filter: query
58- ? {
59- name: {
60- like: ` %${query }% ` ,
61- },
62- }
63- : {},
64- offset: pageNum * pageSize ,
65- limit: pageSize ,
66- })
67- .then ((res : { rows: CollectionModel [], total: string }) => {
68- const { rows } = res ;
69- const selectedItems = cForm .collections ;
70- if (pageNum === 0 ) {
71- collections .value = [... selectedItems , ... rows ].reduce ((acc , item ) => {
72- if (! acc .find ((i ) => i .id === item .id )) acc .push (item );
73- return acc ;
74- }, [] as CollectionModel []);
75- } else {
76- collections .value = [... collections .value , ... rows ].reduce ((acc , item ) => {
77- if (! acc .find ((i ) => i .id === item .id )) acc .push (item );
78- return acc ;
79- }, [] as CollectionModel []);
80- }
81-
82- noMoreData .value = collections .value .length >= + res .total ;
83- })
84- .catch (() => {
85- Message .closeAll ();
86- Message .error (' Failed to load collections' );
87- })
88- .finally (() => {
89- loading .value = false ;
90- });
91- }
59+ const queryKey = computed (() => [
60+ TanstackKey .ADMIN_COLLECTIONS ,
61+ searchQuery .value ,
62+ ]);
63+ const queryFn = COLLECTIONS_SERVICE .query (() => ({
64+ filter: searchQuery .value
65+ ? {
66+ name: {
67+ like: ` %${searchQuery .value }% ` ,
68+ },
69+ }
70+ : {},
71+ offset: 0 ,
72+ limit: 20 ,
73+ })) as QueryFunction <Pagination <CollectionModel >, readonly unknown [], unknown >;
74+
75+ const {
76+ data,
77+ isPending,
78+ isFetchingNextPage,
79+ fetchNextPage,
80+ hasNextPage,
81+ isSuccess,
82+ error,
83+ } = useInfiniteQuery <Pagination <CollectionModel >, Error >({
84+ queryKey ,
85+ queryFn ,
86+ getNextPageParam : (lastPage ) => {
87+ const nextPage = lastPage .offset + lastPage .limit ;
88+ const totalRows = lastPage .total || lastPage .count ;
89+ return nextPage < totalRows ? nextPage : undefined ;
90+ },
91+ initialPageParam: 0 ,
92+ });
93+
94+ const collections = computed ((): CollectionModel [] => {
95+ if (isSuccess .value && data .value ) {
96+ const selectedItems = cForm .collections ;
97+ const rows = data .value .pages .reduce (
98+ (acc , page ) => acc .concat (page .rows ),
99+ [] as CollectionModel [],
100+ );
101+ return [... selectedItems , ... rows ].reduce ((acc , item ) => {
102+ if (! acc .find ((i ) => i .id === item .id )) acc .push (item );
103+ return acc ;
104+ }, [] as CollectionModel []);
105+ }
106+ return [];
107+ });
108+
109+ watch (error , (err ) => {
110+ if (err ) {
111+ Message .error (' Something went wrong while fetching collections' );
112+ }
113+ });
92114
93115// Debounced search input handler
94116const debouncedSearch = debounce ((query : string ) => {
95- page .value = 0 ;
96- noMoreData .value = false ;
97- fetchCollections (query , page .value );
117+ searchQuery .value = query ;
98118}, 300 );
99119
100120function onSearchInput(query : string ) {
@@ -109,18 +129,16 @@ function onScroll(e: Event) {
109129
110130 const target = e .target as HTMLElement ;
111131 if (
112- ! loading .value
113- && ! noMoreData .value
132+ ! isFetchingNextPage .value
133+ && hasNextPage .value
114134 && target .scrollHeight - target .scrollTop - target .clientHeight < threshold
115135 ) {
116- page .value += 1 ;
117- fetchCollections (searchQuery .value , page .value );
136+ fetchNextPage ();
118137 }
119138}
120139
121140// Attach scroll listener after dropdown renders
122141onMounted (() => {
123- fetchCollections (' ' , 0 );
124142 nextTick (() => {
125143 scrollContainer = document .querySelector (
126144 ' .collection-infinite-select-dropdown .el-select-dropdown__wrap' ,
@@ -145,9 +163,18 @@ export default {
145163 </script >
146164
147165<style >
148-
149166.collection-infinite-select-dropdown .el-select-dropdown__wrap {
150167 max-height : 200px ;
151168 overflow : auto ;
152169}
170+
171+ .collection-infinite-select-dropdown .el-select-dropdown__item span {
172+ max-width : 100% ;
173+ text-overflow : ellipsis ;
174+ overflow : hidden ;
175+ }
176+
177+ .el-select-dropdown {
178+ max-width : 552px ;
179+ }
153180 </style >
0 commit comments