From 6f446fd8718b6dc847173577473913cd3ae4518b Mon Sep 17 00:00:00 2001 From: mae taylor Date: Mon, 14 Jul 2025 17:42:20 +0100 Subject: [PATCH] feat: follow requests in sidebar --- src/lang/en_GB.json | 1 + src/lib/api.js | 26 +++++++++++++++++++ src/lib/followRequests.js | 24 +++++++++++++++++ src/lib/ui/Navigation.svelte | 25 +++++++++++++++--- src/lib/ui/core/PageHeader.svelte | 34 +++++++++++++++++++++++++ src/routes/follow-requests/+page.svelte | 10 ++++++++ 6 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 src/lib/followRequests.js create mode 100644 src/lib/ui/core/PageHeader.svelte create mode 100644 src/routes/follow-requests/+page.svelte diff --git a/src/lang/en_GB.json b/src/lang/en_GB.json index cf52f3e..25b8e4d 100644 --- a/src/lang/en_GB.json +++ b/src/lang/en_GB.json @@ -23,6 +23,7 @@ "navigation": { "timeline": "Timeline", "notifications": "Notifications", + "follow_requests": "Follow requests", "explore": "Explore", "lists": "Lists", diff --git a/src/lib/api.js b/src/lib/api.js index d5cfbb8..ee6c913 100644 --- a/src/lib/api.js +++ b/src/lib/api.js @@ -176,6 +176,32 @@ export async function getNotifications(host, token, min_id, max_id, limit, types return data; } +/** + * GET /api/v1/follow_requests + * @param {string} host - The domain of the target server. + * @param {string} token - The application token. + * @param {string} min_id - If provided, only shows follow requests since this ID. + * @param {string} max_id - If provided, only shows follow requests before this ID. + * @param {string} limit - The maximum number of follow requests to retrieve (default 40, max 80). + */ +export async function getFollowRequests(host, token, since_id, max_id, limit) { + let url = `https://${host}/api/v1/follow_requests`; + + let params = new URLSearchParams(); + if (since_id) params.append("since_id", since_id); + if (max_id) params.append("max_id", max_id); + if (limit) params.append("limit", limit); + const params_string = params.toString(); + if (params_string) url += '?' + params_string; + + const data = await fetch(url, { + method: 'GET', + headers: { "Authorization": "Bearer " + token } + }).then(res => res.json()); + + return data; +} + /** * GET /api/v1/timelines/{timeline} * @param {string} host - The domain of the target server. diff --git a/src/lib/followRequests.js b/src/lib/followRequests.js new file mode 100644 index 0000000..38aa77c --- /dev/null +++ b/src/lib/followRequests.js @@ -0,0 +1,24 @@ +import { server } from './client/server.js'; +import { writable } from "svelte/store"; +import * as api from "./api.js"; +import { app } from './client/app.js'; +import { get } from 'svelte/store'; + +// Cache for all requests +export let followRequests = writable(); + +/** + * Gets all follow requests + * @param {boolean} force + */ +export async function fetchFollowRequests(force) { + // if already cached, return for now + if(!get(followRequests) && !force) return; + + let newReqs = await api.getFollowRequests( + get(server).host, + get(app).token + ); + + followRequests.set(newReqs); +} \ No newline at end of file diff --git a/src/lib/ui/Navigation.svelte b/src/lib/ui/Navigation.svelte index d67f391..41b2f8e 100644 --- a/src/lib/ui/Navigation.svelte +++ b/src/lib/ui/Navigation.svelte @@ -6,8 +6,9 @@ import { playSound } from '$lib/sound.js'; import { goto } from '$app/navigation'; import { page } from '$app/stores'; - import { createEventDispatcher } from 'svelte'; + import { createEventDispatcher, onMount } from 'svelte'; import { unread_notif_count } from '$lib/notifications.js'; + import { fetchFollowRequests, followRequests } from '$lib/followRequests.js' import Lang from '$lib/lang'; import Logo from '$lib/../img/campfire-logo.svg'; @@ -24,6 +25,7 @@ import InfoIcon from '../../img/icons/info.svg'; import SettingsIcon from '../../img/icons/settings.svg'; import LogoutIcon from '../../img/icons/logout.svg'; + import FollowersIcon from '../../img/icons/followers.svg'; const VERSION = APP_VERSION; const lang = Lang('en_GB'); @@ -40,7 +42,7 @@ goto(`/${$server.host}/${$account.username}`); } - async function log_out() { + async function logOut() { if (!confirm("This will log you out. Are you sure?")) return; const res = await api.revokeToken( @@ -59,6 +61,10 @@ goto("/"); } + + onMount(async () => { + await fetchFollowRequests(true) + })