diff --git a/packages/frontend/src/routes/Pieces.tsx b/packages/frontend/src/routes/Pieces.tsx
index e81e2e5..bfc4661 100644
--- a/packages/frontend/src/routes/Pieces.tsx
+++ b/packages/frontend/src/routes/Pieces.tsx
@@ -14,32 +14,27 @@ import clsx from "clsx";
import { PieceId, Updater } from "common";
import * as Body from "common/Body";
import { getMediaTypeForFilename } from "common/MediaType";
-import { Array, Cause, Effect, Fiber, Iterable, Match, Option, Order, pipe, Predicate, Scope, SortedMap } from "effect";
-import { Import, Loader2, Plus } from "lucide-react";
-import { DragEventHandler, FormEventHandler, useId, useRef, useState } from "react";
+import { Array, Effect, Fiber, Iterable, Match, Option, Order, pipe, Predicate, Scope, SortedMap } from "effect";
+import { Import, Loader2, Plus, RefreshCwIcon } from "lucide-react";
+import { DragEventHandler, FormEventHandler, RefObject, useCallback, useId, useImperativeHandle, useRef, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
+const LIMIT = 100;
+
export function Pieces() {
const name = useStore(state => state.pieceQueryName);
const author = useStore(state => state.pieceQueryAuthor);
const [importDialogOpen, setImportDialogOpen] = useState(false);
+ const [refresh, setRefresh] = useState(Effect.void);
const debounce = useRef(Effect.void);
const breakpoint = useBreakpoint();
- const columns = breakpoint ? 4 : 1;
- const { isLoading, error, data: pieceIds, refresh } = useLoading(Effect.gen(function* () {
- yield* debounce.current;
- const data = yield* client.queryPieces({
- name: name !== "" ? Option.some(name) : Option.none(),
- author: author !== "" ? Option.some(author) : Option.none(),
- offset: 0,
- limit: 100,
- });
- return data;
- }), [name, author]);
+ const queryRef = useCallback((ref: Query.Ref | null) => {
+ setRefresh(ref !== null ? ref.refresh : Effect.void);
+ }, []);
return (
@@ -93,30 +88,98 @@ export function Pieces() {
)}
- {isLoading ? (
-
-
-
-
- Ładowanie…
-
-
-
- ) : error !== null ? (
-
-
- {Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${JSON.stringify(error)}`}
-
-
- ) : (
- pieceIds.map((pieceId) => )
- )}
+
);
}
+namespace Query {
+ export interface Props {
+ readonly offset: number;
+ readonly debounce?: RefObject> | undefined;
+ readonly ref?: React.Ref[ | undefined;
+ }
+
+ export interface Ref {
+ readonly refresh: Effect.Effect;
+ }
+}
+
+function Query({
+ offset,
+ debounce,
+ ref,
+}: Query.Props) {
+
+ const name = useStore(state => state.pieceQueryName);
+ const author = useStore(state => state.pieceQueryAuthor);
+
+ const breakpoint = useBreakpoint();
+ const columns = breakpoint ? 4 : 1;
+
+ const [continuationOpen, setContinuationOpen] = useState(false);
+
+ const { isLoading, error, data: pieceIds, refresh } = useLoading(Effect.gen(function* () {
+ setContinuationOpen(false);
+ if (debounce !== undefined) {
+ yield* debounce.current;
+ }
+
+ const data = yield* client.queryPieces({
+ name: name !== "" ? Option.some(name) : Option.none(),
+ author: author !== "" ? Option.some(author) : Option.none(),
+ offset,
+ limit: LIMIT,
+ });
+ return data;
+ }), [name, author, offset]);
+
+ useImperativeHandle(ref, () => Object.freeze({
+ refresh,
+ }), [refresh]);
+
+ return isLoading ? (
+
+
+ ]
+
+ Ładowanie…
+
+
+
+ ) : error !== null ? (
+
+
+ Wystąpił błąd: {Match.value(error).pipe(
+ Match.tag("FetchError", () => "Nie można połączyć się z serwerem"),
+ Match.tag("Unauthenticated", () => "Zaloguj się, aby kontynuować"),
+ Match.tag("Unauthorized", () => "Nie posiadasz uprawnień"),
+ Match.exhaustive,
+ )}
+
+
+ ) : (<>
+ {pieceIds.map((pieceId) => )}
+ {continuationOpen ? (
+
+ ) : pieceIds.length >= LIMIT ? (
+
+
+
+
+
+ ) : null}
+ >);
+}
+
namespace PieceRow {
export interface Props {
readonly pieceId: PieceId;