diff --git a/client/src/components/task-center/task-center.component.jsx b/client/src/components/task-center/task-center.component.jsx index 1b8587623..da4ebaf52 100644 --- a/client/src/components/task-center/task-center.component.jsx +++ b/client/src/components/task-center/task-center.component.jsx @@ -8,11 +8,10 @@ import "./task-center.styles.scss"; const { Text, Title } = Typography; -const TaskCenterComponent = forwardRef(({ visible, tasks, loading, onTaskClick }, ref) => { +const TaskCenterComponent = forwardRef(({ visible, tasks, loading, onTaskClick, onLoadMore, totalTasks }, ref) => { const { t } = useTranslation(); const virtuosoRef = useRef(null); - // Organize tasks into sections const sections = useMemo(() => { const now = day(); const today = now.startOf("day"); @@ -80,6 +79,11 @@ const TaskCenterComponent = forwardRef(({ visible, tasks, loading, onTaskClick } totalCount={sections.length} itemContent={(index, section) => renderSection(section, index)} /> + {tasks.length < totalTasks && ( + + )} ); }); diff --git a/client/src/components/task-center/task-center.container.jsx b/client/src/components/task-center/task-center.container.jsx index cfecedf75..e51cce810 100644 --- a/client/src/components/task-center/task-center.container.jsx +++ b/client/src/components/task-center/task-center.container.jsx @@ -5,10 +5,10 @@ import { createStructuredSelector } from "reselect"; import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors"; import { useSocket } from "../../contexts/SocketIO/useSocket"; import { useIsEmployee } from "../../utils/useIsEmployee"; -import { QUERY_MY_TASKS_PAGINATED } from "../../graphql/tasks.queries"; import TaskCenterComponent from "./task-center.component"; import dayjs from "../../utils/day"; import { setModalContext } from "../../redux/modals/modals.actions"; +import { QUERY_MY_ACTIVE_TASKS_PAGINATED } from "../../graphql/tasks.queries"; const POLL_INTERVAL = 60; // seconds @@ -23,47 +23,29 @@ const mapDispatchToProps = (dispatch) => ({ const TaskCenterContainer = ({ visible, onClose, bodyshop, currentUser, setTaskUpsertContext }) => { const [tasks, setTasks] = useState([]); - const [loading, setLoading] = useState(false); const { isConnected } = useSocket(); const isEmployee = useIsEmployee(bodyshop, currentUser); - // Compute assignedToId with useMemo to ensure stability const assignedToId = useMemo(() => { const employee = bodyshop?.employees?.find((e) => e.user_email === currentUser?.email); - if (employee?.id) { - console.log("AssignedToId computed:", employee.id); // Debug log - return employee.id; - } - return null; + return employee?.id || null; }, [bodyshop, currentUser]); - const where = useMemo( - () => ({ - assigned_to: { _eq: assignedToId }, - deleted: { _eq: false }, - completed: { _eq: false } - }), - [assignedToId] - ); - const { data, loading: queryLoading, - refetch - } = useQuery(QUERY_MY_TASKS_PAGINATED, { + fetchMore + } = useQuery(QUERY_MY_ACTIVE_TASKS_PAGINATED, { variables: { bodyshop: bodyshop?.id, assigned_to: assignedToId, - where, offset: 0, limit: 50, order: [{ due_date: "asc_nulls_last" }, { created_at: "desc" }] }, - // Skip query if any required data is missing skip: !bodyshop?.id || !assignedToId || !isEmployee || !currentUser?.email, fetchPolicy: "cache-and-network", pollInterval: isConnected ? 0 : dayjs.duration(POLL_INTERVAL, "seconds").asMilliseconds(), - // Log errors for debugging onError: (error) => { console.error("Query error:", error); } @@ -75,14 +57,28 @@ const TaskCenterContainer = ({ visible, onClose, bodyshop, currentUser, setTaskU } }, [data]); + const handleLoadMore = () => { + fetchMore({ + variables: { + offset: tasks.length + }, + updateQuery: (prev, { fetchMoreResult }) => { + if (!fetchMoreResult) return prev; + return { + ...prev, + tasks: [...prev.tasks, ...fetchMoreResult.tasks] + }; + } + }); + }; + const handleTaskClick = useCallback( (id) => { const task = tasks.find((t) => t.id === id); if (task) { setTaskUpsertContext({ context: { - taskId: task.id, - view: true + existingTask: task } }); } @@ -95,10 +91,11 @@ const TaskCenterContainer = ({ visible, onClose, bodyshop, currentUser, setTaskU visible={visible} onClose={onClose} tasks={tasks} - loading={loading || queryLoading} + loading={queryLoading} onTaskClick={handleTaskClick} + onLoadMore={handleLoadMore} + totalTasks={data?.tasks_aggregate?.aggregate?.count} /> ); }; - export default connect(mapStateToProps, mapDispatchToProps)(TaskCenterContainer); diff --git a/client/src/components/task-upsert-modal/task-upsert-modal.component.jsx b/client/src/components/task-upsert-modal/task-upsert-modal.component.jsx index 6e1f8209b..0c6482c9d 100644 --- a/client/src/components/task-upsert-modal/task-upsert-modal.component.jsx +++ b/client/src/components/task-upsert-modal/task-upsert-modal.component.jsx @@ -7,6 +7,7 @@ import { connect } from "react-redux"; import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component.jsx"; import JobSearchSelectComponent from "../job-search-select/job-search-select.component.jsx"; import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx"; +import { Link } from "react-router-dom"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -41,7 +42,7 @@ export function TaskUpsertModalComponent({ ]; const generatePresets = (job) => { - if (!job || !selectedJobDetails) return datePickerPresets; // return default presets if no job selected + if (!job || !selectedJobDetails) return datePickerPresets; const relativePresets = []; if (selectedJobDetails?.scheduled_completion) { @@ -96,13 +97,8 @@ export function TaskUpsertModalComponent({ }); }; - /** - * Change the selected job id - * @param jobId - */ const changeJobId = (jobId) => { setSelectedJobId(jobId || null); - // Reset the form fields when selectedJobId changes clearRelations(); }; @@ -162,6 +158,13 @@ export function TaskUpsertModalComponent({ required: true } ]} + extra={ + existingTask && selectedJobId ? ( +