From 725a21b02721f92ed0420ed3f807ee921de77992 Mon Sep 17 00:00:00 2001
From: tobi <31960611+tsmethurst@users.noreply.github.com>
Date: Wed, 1 May 2024 15:11:22 +0200
Subject: [feature] Page through accounts as moderator (#2881)

* [feature] Page through accounts as moderator

* aaaaa

* use COLLATE "C" for Postgres to ensure same ordering as SQLite

* fix typo, test paging up

* don't show moderation / info for our instance acct
---
 web/source/settings/components/pageable-list.tsx | 113 +++++++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 web/source/settings/components/pageable-list.tsx

(limited to 'web/source/settings/components/pageable-list.tsx')

diff --git a/web/source/settings/components/pageable-list.tsx b/web/source/settings/components/pageable-list.tsx
new file mode 100644
index 000000000..918103ead
--- /dev/null
+++ b/web/source/settings/components/pageable-list.tsx
@@ -0,0 +1,113 @@
+/*
+	GoToSocial
+	Copyright (C) GoToSocial Authors admin@gotosocial.org
+	SPDX-License-Identifier: AGPL-3.0-or-later
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU Affero General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU Affero General Public License for more details.
+
+	You should have received a copy of the GNU Affero General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React, { ReactNode } from "react";
+import { useLocation } from "wouter";
+import { Error } from "./error";
+import { SerializedError } from "@reduxjs/toolkit";
+import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
+import { Links } from "parse-link-header";
+import Loading from "./loading";
+
+export interface PageableListProps<T> {
+	isSuccess: boolean;
+	items?: T[];
+	itemToEntry: (_item: T) => ReactNode;
+	isLoading: boolean;
+	isFetching: boolean;
+	isError: boolean;
+	error: FetchBaseQueryError | SerializedError | undefined;
+	emptyMessage: string;
+	prevNextLinks?: Links | null | undefined;
+}
+
+export function PageableList<T>({
+	isLoading,
+	isFetching,
+	isSuccess,
+	items,
+	itemToEntry,
+	isError,
+	error,
+	emptyMessage,
+	prevNextLinks,
+}: PageableListProps<T>) {
+	const [ location, setLocation ] = useLocation();
+	
+	if (!(isSuccess || isError)) {
+		// Hasn't been called yet.
+		return null;
+	}
+
+	if (isLoading || isFetching) {
+		return <Loading />;
+	}
+
+	if (error) {
+		return <Error error={error} />;
+	}
+
+	// Map response to items if possible.
+	let content: ReactNode;
+	if (items == undefined || items.length == 0) {
+		content = <b>{emptyMessage}</b>;
+	} else {
+		content = (
+			<div className="entries">
+				{items.map(item => itemToEntry(item))}
+			</div>
+		);
+	}
+
+	// If it's possible to page to next and previous
+	// pages, instantiate button handlers for this.
+	let prevClick: (() => void) | undefined;
+	let nextClick: (() => void) | undefined;
+	if (prevNextLinks) {
+		const prev = prevNextLinks["prev"];
+		if (prev) {
+			const prevUrl = new URL(prev.url);
+			const prevParams = prevUrl.search;
+			prevClick = () => {
+				setLocation(location + prevParams.toString());
+			};
+		}
+
+		const next = prevNextLinks["next"];
+		if (next) {
+			const nextUrl = new URL(next.url);
+			const nextParams = nextUrl.search;
+			nextClick = () => {
+				setLocation(location + nextParams.toString());
+			};
+		}
+	}
+
+	return (
+		<div className="list pageable-list">
+			{ content }
+			{ prevNextLinks &&
+				<div className="prev-next">
+					{ prevClick && <button onClick={prevClick}>Previous page</button> }
+					{ nextClick && <button onClick={nextClick}>Next page</button> }
+				</div>
+			}
+		</div>
+	);
+}
-- 
cgit v1.2.3

