feat: pagination in nav

This commit is contained in:
Wentao Lyu 2023-03-15 04:05:14 +08:00
parent 71fc86b9a6
commit 8289558d94
8 changed files with 84 additions and 46 deletions

View file

@ -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 && (
<button
onClick={clickHandler}
className="btn btn-dark btn-small m-auto mb-2 flex justify-center gap-2"
>
Show more
</button>
)}
<div className="m-auto mt-4 mb-2 flex justify-center items-center gap-2">
<button
onClick={clickHandler(previousPage)}
className={"flex btn btn-small transition bg-transition dark:text-white disabled:text-gray-300 dark:disabled:text-gray-400 m-auto gap-2 hover:bg-gray-800" + (pageNumber<=1?" hidden-visibility":"")}
disabled={pageNumber<=1}
>
&lt;&lt;
</button>
<span className="flex-none text-gray-400">
{pageNumber} / {pages}
</span>
<button
onClick={clickHandler(nextPage)}
className={"flex btn btn-small transition bg-transition dark:text-white disabled:text-gray-300 dark:disabled:text-gray-400 m-auto gap-2 hover:bg-gray-800" + (pageNumber>=pages?" hidden-visibility":"")}
disabled={pageNumber>=pages}
>
&gt;&gt;
</button>
</div>
</>
);
}

View file

@ -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 (
<div className="sticky top-0 z-10 flex items-center border-b border-white/20 bg-gray-800 pl-1 pt-1 text-gray-200 sm:pl-3 md:hidden">
<button
@ -64,7 +62,7 @@ export default function MobileNav({ setNavVisible }) {
/>
</svg>
</button>
<h1 className="flex-1 text-center text-base font-normal">{title}</h1>
<h1 className="flex-1 text-center text-base font-normal">{title || 'New Chat'}</h1>
<button
type="button"
className="px-3"

View file

@ -6,37 +6,53 @@ import NavLinks from './NavLinks';
import useDidMountEffect from '~/hooks/useDidMountEffect';
import { swr } from '~/utils/fetchers';
import { useDispatch, useSelector } from 'react-redux';
import { incrementPage, setConvos } from '~/store/convoSlice';
import { increasePage, decreasePage, setPage, setConvos, setPages } from '~/store/convoSlice';
export default function Nav({ navVisible, setNavVisible }) {
const dispatch = useDispatch();
const [isHovering, setIsHovering] = useState(false);
const { conversationId, convos, pageNumber, refreshConvoHint } = useSelector((state) => state.convo);
const { conversationId, convos, pages, pageNumber, refreshConvoHint } = useSelector((state) => state.convo);
const onSuccess = (data) => {
dispatch(setConvos(data));
const { conversations, pages } = data;
if (pageNumber > pages)
dispatch(setPage(pages));
else
dispatch(setConvos(conversations));
dispatch(setPages(pages));
};
const { data, isLoading, mutate } = swr(
`/api/convos?pageNumber=${pageNumber}`,
onSuccess
onSuccess,
{revalidateOnMount: false}
);
const containerRef = useRef(null);
const scrollPositionRef = useRef(null);
const showMore = async (increment = true) => {
const moveToTop = () => {
const container = containerRef.current;
if (container) {
scrollPositionRef.current = container.scrollTop;
}
}
if (increment) {
dispatch(incrementPage());
await mutate();
}
const nextPage = async () => {
moveToTop()
dispatch(increasePage());
await mutate();
};
useDidMountEffect(() => mutate(), [conversationId, refreshConvoHint]);
const previousPage = async () => {
moveToTop()
dispatch(decreasePage());
await mutate();
};
useEffect(() => {mutate()}, [pageNumber, conversationId, refreshConvoHint]);
useEffect(() => {
const container = containerRef.current;
@ -86,8 +102,11 @@ export default function Nav({ navVisible, setNavVisible }) {
<Conversations
conversations={convos}
conversationId={conversationId}
showMore={showMore}
nextPage={nextPage}
previousPage={previousPage}
moveToTop={moveToTop}
pageNumber={pageNumber}
pages={pages}
/>
)}
</div>

View file

@ -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;

View file

@ -1876,3 +1876,6 @@ button.scroll-convo {
background-color:hsla(0,0%,100%,.4)
}
}
.hidden-visibility {
visibility: hidden;
}

View file

@ -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) {