diff --git a/apps/web/app/hooks/useInfinityFetch.ts b/apps/web/app/hooks/useInfinityFetch.ts index e85ace888..ae3ea3856 100644 --- a/apps/web/app/hooks/useInfinityFetch.ts +++ b/apps/web/app/hooks/useInfinityFetch.ts @@ -5,21 +5,22 @@ import React from 'react'; export const getPartData = ({ offset = 0, limit = 10, arr = [] }: { offset?: number; limit?: number; arr: any[] }) => arr.slice(0, offset * limit + limit); -export const useInfinityScrolling = (arr: any) => { +export const useInfinityScrolling = (arr: T[], lim?: number) => { + const limit = lim ?? 10; const [offset, setOffset] = React.useState(0); - const [data, setData] = React.useState(arr); + const [data, setData] = React.useState(arr); const getSomeTasks = React.useCallback( (offset: number) => { - setData(getPartData({ arr, limit: 10, offset })); + setData(getPartData({ arr, limit, offset })); }, - [arr] + [arr, limit] ); const nextOffset = React.useCallback(() => { setOffset((prev) => prev + 1); - setData((prev) => getPartData({ arr: prev, limit: 10, offset })); - }, [offset]); + setData((prev) => getPartData({ arr: prev, limit, offset })); + }, [limit, offset]); React.useEffect(() => { console.log({ offset }); diff --git a/apps/web/components/shared/Observer/index.tsx b/apps/web/components/shared/Observer/index.tsx index 7f6f10d0d..bcdbaf35e 100644 --- a/apps/web/components/shared/Observer/index.tsx +++ b/apps/web/components/shared/Observer/index.tsx @@ -1,22 +1,61 @@ import React from 'react'; -export const ObserverComponent = ({ isLast, getNextData }: { isLast: boolean; getNextData: () => any }) => { +export const ObserverComponent = ({ + isLast, + getNextData +}: { + root?: JSX.Element; + isLast: boolean; + getNextData: () => any; +}) => { const cardRef = React.useRef(); React.useEffect(() => { if (!cardRef?.current) return; - const observer = new IntersectionObserver(([entry]) => { - if (isLast && entry.isIntersecting) { - // fetch with new Entry - console.log('IN OBSERVER'); - getNextData(); - observer.unobserve(entry.target); + const observer = new IntersectionObserver( + ([entry]) => { + if (isLast && entry.isIntersecting) { + // fetch with new Entry + console.log('IN OBSERVER'); + getNextData(); + observer.unobserve(entry.target); + } + }, + { + threshold: 1.0 } - }); + ); observer.observe(cardRef.current); + + return () => { + // eslint-disable-next-line react-hooks/exhaustive-deps + cardRef.current && observer.unobserve(cardRef.current); + }; }, [isLast, getNextData]); // @ts-expect-error return
; }; + +export const useElementOnScreen = (options: IntersectionObserverInit | undefined) => { + const containerRef = React.useRef(); + const [isVisible, setIsVisible] = React.useState(); + + const cbFunction = (entries: any[]) => { + const [entry] = entries; + setIsVisible(entry.isIntersecting); + }; + + React.useEffect(() => { + const observer = new IntersectionObserver(cbFunction, options); + if (containerRef.current) observer.observe(containerRef.current); + + return () => { + // eslint-disable-next-line react-hooks/exhaustive-deps + if (containerRef.current) observer.unobserve(containerRef.current); + }; + }, [containerRef, options]); + + return [isVisible, containerRef]; +}; diff --git a/apps/web/lib/features/task/task-input.tsx b/apps/web/lib/features/task/task-input.tsx index 43228528a..dedab1012 100644 --- a/apps/web/lib/features/task/task-input.tsx +++ b/apps/web/lib/features/task/task-input.tsx @@ -26,6 +26,8 @@ import { TaskItem } from './task-item'; import { TaskLabels } from './task-labels'; import { ActiveTaskPropertiesDropdown, ActiveTaskSizesDropdown, ActiveTaskStatusDropdown } from './task-status'; import { useTranslations } from 'next-intl'; +import { useInfinityScrolling } from '@app/hooks/useInfinityFetch'; +import { ObserverComponent } from '@components/shared/Observer'; type Props = { task?: Nullable; @@ -419,6 +421,7 @@ function TaskCard({ const { taskLabels: taskLabelsData } = useTaskLabels(); const { taskStatus, taskPriority, taskSize, taskLabels, taskDescription } = datas; + const { nextOffset, data } = useInfinityScrolling(updatedTaskList ?? [], 5); useEffect(() => { if (datas.editMode) { @@ -437,139 +440,142 @@ function TaskCard({ shadow="custom" className={clsxm( 'rounded-xl md:px-4 md:py-4', - 'overflow-auto', + 'overflow-hidden', !cardWithoutShadow && ['shadow-xlcard'], fullWidth ? ['w-full'] : ['md:w-[500px]'], fullHeight ? 'h-full' : 'max-h-96' )} > {inputField} - {/* Create team button */} -
- {datas.hasCreateForm && ( -
- { - if (taskDescription) { - taskDescription.current = e.target.value; - } - }} - className={'dark:bg-[#1B1D22]'} - /> - -
- { - if (v && taskStatus) { - taskStatus.current = v; +
+ {/* Create team button */} +
+ {datas.hasCreateForm && ( +
+ { + if (taskDescription) { + taskDescription.current = e.target.value; } }} - defaultValue={taskStatus?.current as ITaskStatus} - task={null} + className={'dark:bg-[#1B1D22]'} /> - { - if (v && taskPriority) { - taskPriority.current = v; - } - }} - defaultValue={taskPriority?.current as ITaskPriority} - task={null} - /> +
+ { + if (v && taskStatus) { + taskStatus.current = v; + } + }} + defaultValue={taskStatus?.current as ITaskStatus} + task={null} + /> - { - if (v && taskSize) { - taskSize.current = v; - } - }} - defaultValue={taskSize?.current as ITaskSize} - task={null} - /> + { + if (v && taskPriority) { + taskPriority.current = v; + } + }} + defaultValue={taskPriority?.current as ITaskPriority} + task={null} + /> - { - taskLabelsData.filter((tag) => (tag.name ? values?.includes(tag.name) : false)); + { + if (v && taskSize) { + taskSize.current = v; + } + }} + defaultValue={taskSize?.current as ITaskSize} + task={null} + /> - if (taskLabels && values?.length) { - taskLabels.current = taskLabelsData.filter((tag) => + { + taskLabelsData.filter((tag) => tag.name ? values?.includes(tag.name) : false ); - } - }} - task={datas.inputTask} - /> + + if (taskLabels && values?.length) { + taskLabels.current = taskLabelsData.filter((tag) => + tag.name ? values?.includes(tag.name) : false + ); + } + }} + task={datas.inputTask} + /> +
-
- )} + )} - - - -
- - {/* Task filter buttons */} -
- datas.setFilter && datas.setFilter('open')} - > -
- + {!datas.createLoading && } + {t('common.CREATE_TASK')} + + +
+ + {/* Task filter buttons */} +
+ datas.setFilter && datas.setFilter('open')} > - {datas.openTaskCount || 0} {t('common.OPEN')} - - - - datas.setFilter && datas.setFilter('closed')} - > - - + + {datas.openTaskCount || 0} {t('common.OPEN')} + + + + datas.setFilter && datas.setFilter('closed')} > - {datas.closedTaskCount || 0} {t('common.CLOSED')} - - + + + {datas.closedTaskCount || 0} {t('common.CLOSED')} + + +
- {/* Task list */} -
    +
      {forParentChildRelationship && - updatedTaskList?.map((task, i) => { + data?.map((task, i) => { const last = (datas.filteredTasks?.length || 0) - 1 === i; const active = datas.inputTask === task; @@ -581,7 +587,7 @@ function TaskCard({ onClick={onItemClick} className="cursor-pointer" /> - + {!last && } ); @@ -606,7 +612,7 @@ function TaskCard({ })} {(forParentChildRelationship && updatedTaskList && updatedTaskList.length === 0) || - (!forParentChildRelationship && datas?.filteredTasks && datas.filteredTasks.length === 0 && ( + (!forParentChildRelationship && datas.filteredTasks && datas.filteredTasks.length === 0 && (
      {t('common.NO_TASKS')}
      ))}