forked from denoland/std
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat:
<ItemsList />
with cursor-based pagination (denoland#445)
This change contains a few changes that affect interdependent features. Changes include: - Add `<ItemsList />` with cursor-based pagination - Remove now unused code for the previous pagination solution - Fix and rework voting functionality relating to denoland#427 - Tweak REST API endpoints return signature to be more generic, using a `values` field - `fetchValues()` - Simplify and optimise `<VoteButton />` - New `DELETE/GET /api/items/[id]/vote` endpoint - New `GET /api/me/votes` endpoint - Other various cleanups Note: The migration script has been tested successfully locally. Closes denoland#427 Closes denoland#414 Towards denoland#439
- Loading branch information
Showing
27 changed files
with
423 additions
and
561 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// Copyright 2023 the Deno authors. All rights reserved. MIT license. | ||
import { useComputed, useSignal } from "@preact/signals"; | ||
import { useEffect } from "preact/hooks"; | ||
import type { Item } from "@/utils/db.ts"; | ||
import { LINK_STYLES } from "@/utils/constants.ts"; | ||
import IconInfo from "tabler_icons_tsx/info-circle.tsx"; | ||
import ItemSummary from "@/components/ItemSummary.tsx"; | ||
import { fetchValues } from "@/utils/http.ts"; | ||
|
||
async function fetchVotedItems() { | ||
const url = "/api/me/votes"; | ||
const resp = await fetch(url); | ||
if (!resp.ok) throw new Error(`Request failed: GET ${url}`); | ||
return await resp.json() as Item[]; | ||
} | ||
|
||
function EmptyItemsList() { | ||
return ( | ||
<> | ||
<div class="flex flex-col justify-center items-center gap-2"> | ||
<div class="flex flex-col items-center gap-2 pt-16"> | ||
<IconInfo class="w-10 h-10 text-gray-400 dark:text-gray-600" /> | ||
<p class="text-center font-medium">No items found</p> | ||
</div> | ||
|
||
<a | ||
href="/submit" | ||
class="inline-flex items-center justify-center gap-2 rounded-md px-3 py-2 text-primary hover:underline" | ||
> | ||
Submit your project | ||
</a> | ||
</div> | ||
</> | ||
); | ||
} | ||
|
||
export default function ItemsList(props: { endpoint: string }) { | ||
const itemsSig = useSignal<Item[]>([]); | ||
const votedItemsIdsSig = useSignal<string[]>([]); | ||
const cursorSig = useSignal(""); | ||
const isLoadingSig = useSignal(false); | ||
const itemsAreVotedSig = useComputed(() => | ||
itemsSig.value.map((item) => votedItemsIdsSig.value.includes(item.id)) | ||
); | ||
|
||
async function loadMoreItems() { | ||
isLoadingSig.value = true; | ||
try { | ||
const { values, cursor } = await fetchValues<Item>( | ||
props.endpoint, | ||
cursorSig.value, | ||
); | ||
itemsSig.value = [...itemsSig.value, ...values]; | ||
cursorSig.value = cursor; | ||
} catch (error) { | ||
console.error(error.message); | ||
} finally { | ||
isLoadingSig.value = false; | ||
} | ||
} | ||
|
||
useEffect(() => { | ||
fetchVotedItems() | ||
.then((votedItems) => | ||
votedItemsIdsSig.value = votedItems.map(({ id }) => id) | ||
) | ||
.then(() => loadMoreItems()); | ||
}, []); | ||
|
||
return ( | ||
<div> | ||
{itemsSig.value.length | ||
? itemsSig.value.map((item, id) => { | ||
return ( | ||
<ItemSummary | ||
key={item.id} | ||
item={item} | ||
isVoted={itemsAreVotedSig.value[id]} | ||
/> | ||
); | ||
}) | ||
: <EmptyItemsList />} | ||
{cursorSig.value !== "" && !isLoadingSig.value && ( | ||
<button onClick={loadMoreItems} class={LINK_STYLES}> | ||
Load more | ||
</button> | ||
)} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.