From 8289558d94b613ff58645dc74ca5f85b333979c9 Mon Sep 17 00:00:00 2001 From: Wentao Lyu <35-wentao.lyu@users.noreply.git.stereye.tech> Date: Wed, 15 Mar 2023 04:05:14 +0800 Subject: [PATCH] feat: pagination in nav --- api/models/Conversation.js | 14 +++---- api/server/routes/convos.js | 4 +- client/src/components/Conversations/index.jsx | 35 ++++++++++------ client/src/components/Nav/MobileNav.jsx | 6 +-- client/src/components/Nav/index.jsx | 41 ++++++++++++++----- client/src/store/convoSlice.js | 19 ++++++--- client/src/style.css | 3 ++ client/src/utils/fetchers.js | 8 ++-- 8 files changed, 84 insertions(+), 46 deletions(-) diff --git a/api/models/Conversation.js b/api/models/Conversation.js index a32bc3e7a4..6e3c646c64 100644 --- a/api/models/Conversation.js +++ b/api/models/Conversation.js @@ -91,19 +91,17 @@ module.exports = { } }, // getConvos: async () => await Conversation.find({}).sort({ createdAt: -1 }).exec(), - getConvos: async (pageNumber = 1, pageSize = 12) => { + getConvosByPage: async (pageNumber = 1, pageSize = 12) => { try { - const skip = (pageNumber - 1) * pageSize; - // const limit = pageNumber * pageSize; - - const conversations = await Conversation.find({}) + const totalConvos = await Conversation.countDocuments(); + const totalPages = Math.ceil(totalConvos / pageSize); + const convos = await Conversation.find() .sort({ createdAt: -1 }) - .skip(skip) - // .limit(limit) + .skip((pageNumber - 1) * pageSize) .limit(pageSize) .exec(); - return conversations; + return { conversations: convos, pages: totalPages, pageNumber, pageSize }; } catch (error) { console.log(error); return { message: 'Error getting conversations' }; diff --git a/api/server/routes/convos.js b/api/server/routes/convos.js index bfe3bc2d56..9a5f71cee3 100644 --- a/api/server/routes/convos.js +++ b/api/server/routes/convos.js @@ -2,12 +2,12 @@ const express = require('express'); const router = express.Router(); const { titleConvo } = require('../../app/'); const { getConvo, saveConvo, getConvoTitle } = require('../../models'); -const { getConvos, deleteConvos, updateConvo } = require('../../models/Conversation'); +const { getConvosByPage, deleteConvos, updateConvo } = require('../../models/Conversation'); const { getMessages } = require('../../models/Message'); router.get('/', async (req, res) => { const pageNumber = req.query.pageNumber || 1; - res.status(200).send(await getConvos(pageNumber)); + res.status(200).send(await getConvosByPage(pageNumber)); }); router.post('/gen_title', async (req, res) => { diff --git a/client/src/components/Conversations/index.jsx b/client/src/components/Conversations/index.jsx index d3ab1ffd0b..4142cb8ed1 100644 --- a/client/src/components/Conversations/index.jsx +++ b/client/src/components/Conversations/index.jsx @@ -1,10 +1,10 @@ import React from 'react'; import Conversation from './Conversation'; -export default function Conversations({ conversations, conversationId, showMore }) { - const clickHandler = async (e) => { +export default function Conversations({ conversations, conversationId, pageNumber, pages, nextPage, previousPage, moveToTop }) { + const clickHandler = (func) => async (e) => { e.preventDefault(); - await showMore(); + await func(); }; return ( @@ -33,18 +33,29 @@ export default function Conversations({ conversations, conversationId, showMore chatGptLabel={convo.chatGptLabel} promptPrefix={convo.promptPrefix} bingData={bingData} - retainView={showMore.bind(null, false)} + retainView={moveToTop} /> ); })} - {conversations?.length >= 12 && ( - - )} +
+ + + {pageNumber} / {pages} + + +
); } diff --git a/client/src/components/Nav/MobileNav.jsx b/client/src/components/Nav/MobileNav.jsx index e4107e9ac6..0c846524fc 100644 --- a/client/src/components/Nav/MobileNav.jsx +++ b/client/src/components/Nav/MobileNav.jsx @@ -7,7 +7,7 @@ import { setText } from '~/store/textSlice'; export default function MobileNav({ setNavVisible }) { const dispatch = useDispatch(); - const { conversationId, convos } = useSelector((state) => state.convo); + const { conversationId, convos, title } = useSelector((state) => state.convo); const toggleNavVisible = () => { setNavVisible((prev) => { @@ -22,8 +22,6 @@ export default function MobileNav({ setNavVisible }) { dispatch(setSubmission({})); } - const title = convos?.find(element => element?.conversationId == conversationId)?.title || 'New Chat'; - return (
-

{title}

+

{title || 'New Chat'}

diff --git a/client/src/store/convoSlice.js b/client/src/store/convoSlice.js index 258de84e70..c862a8e1e7 100644 --- a/client/src/store/convoSlice.js +++ b/client/src/store/convoSlice.js @@ -13,8 +13,9 @@ const initialState = { promptPrefix: null, convosLoading: false, pageNumber: 1, + pages: 1, refreshConvoHint: 0, - convos: [] + convos: [], }; const currentSlice = createSlice({ @@ -30,12 +31,18 @@ const currentSlice = createSlice({ setError: (state, action) => { state.error = action.payload; }, - incrementPage: (state) => { + increasePage: (state) => { state.pageNumber = state.pageNumber + 1; }, + decreasePage: (state) => { + state.pageNumber = state.pageNumber - 1; + }, + setPage: (state, action) => { + state.pageNumber = action.payload; + }, setNewConvo: (state) => { state.error = false; - state.title = 'New Chat'; + state.title = 'ChatGPT Clone'; state.conversationId = null; state.parentMessageId = null; state.jailbreakConversationId = null; @@ -45,13 +52,15 @@ const currentSlice = createSlice({ state.chatGptLabel = null; state.promptPrefix = null; state.convosLoading = false; - state.pageNumber = 1; }, setConvos: (state, action) => { state.convos = action.payload.sort( (a, b) => new Date(b.createdAt) - new Date(a.createdAt) ); }, + setPages: (state, action) => { + state.pages = action.payload; + }, removeConvo: (state, action) => { state.convos = state.convos.filter((convo) => convo.conversationId !== action.payload); }, @@ -61,7 +70,7 @@ const currentSlice = createSlice({ } }); -export const { refreshConversation, setConversation, setConvos, setNewConvo, setError, incrementPage, removeConvo, removeAll } = +export const { refreshConversation, setConversation, setPages, setConvos, setNewConvo, setError, increasePage, decreasePage, setPage, removeConvo, removeAll } = currentSlice.actions; export default currentSlice.reducer; diff --git a/client/src/style.css b/client/src/style.css index 6b17c388e2..c4a03408b7 100644 --- a/client/src/style.css +++ b/client/src/style.css @@ -1876,3 +1876,6 @@ button.scroll-convo { background-color:hsla(0,0%,100%,.4) } } +.hidden-visibility { + visibility: hidden; +} \ No newline at end of file diff --git a/client/src/utils/fetchers.js b/client/src/utils/fetchers.js index 9faa211d4e..d9cfa54116 100644 --- a/client/src/utils/fetchers.js +++ b/client/src/utils/fetchers.js @@ -9,14 +9,14 @@ const postRequest = async (url, { arg }) => { return await axios.post(url, { arg }); }; -export const swr = (path, successCallback) => { - const options = {}; +export const swr = (path, successCallback, options) => { + const _options = {...options}; if (successCallback) { - options.onSuccess = successCallback; + _options.onSuccess = successCallback; } - return useSWR(path, fetcher, options); + return useSWR(path, fetcher, _options); } export default function manualSWR(path, type, successCallback) {