diff --git a/src/img/icons/cross.svg b/src/img/icons/cross.svg new file mode 100644 index 0000000..c94691d --- /dev/null +++ b/src/img/icons/cross.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/img/icons/tick.svg b/src/img/icons/tick.svg new file mode 100644 index 0000000..89657e6 --- /dev/null +++ b/src/img/icons/tick.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/lang/en_GB.json b/src/lang/en_GB.json index cf52f3e..52db85b 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", @@ -37,6 +38,10 @@ "back": "Back" }, + "follow_requests": { + "none": "no follow requests to action right now!" + }, + "timeline": { "home": "Home", "local": "Local", diff --git a/src/lib/api.js b/src/lib/api.js index d5cfbb8..07644a3 100644 --- a/src/lib/api.js +++ b/src/lib/api.js @@ -176,6 +176,66 @@ 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; +} + +/** + * POST /api/v1/follow_requests/:account_id/authorize + * @param {string} host - The domain of the target server. + * @param {string} token - The application token. + * @param {string} account_id - The account ID of the follow request to accept + */ +export async function acceptFollowRequest(host, token, account_id) { + let url = `https://${host}/api/v1/follow_requests/${account_id}/authorize`; + + const data = await fetch(url, { + method: 'POST', + headers: { "Authorization": "Bearer " + token } + }).then(res => res.json()); + + return data; +} + +/** + * POST /api/v1/follow_requests/:account_id/reject + * @param {string} host - The domain of the target server. + * @param {string} token - The application token. + * @param {string} account_id - The account ID of the follow request to reject + */ +export async function rejectFollowRequest(host, token, account_id) { + let url = `https://${host}/api/v1/follow_requests/${account_id}/reject`; + + const data = await fetch(url, { + method: 'POST', + 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..38a4e2d --- /dev/null +++ b/src/lib/followRequests.js @@ -0,0 +1,28 @@ +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'; +import { parseAccount } from './account.js'; + +// 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 + ); + + // parse accounts + newReqs = newReqs.map((r) => parseAccount(r)); + + followRequests.set(newReqs); +} \ No newline at end of file diff --git a/src/lib/ui/Button.svelte b/src/lib/ui/Button.svelte index b6b63f4..cc720c8 100644 --- a/src/lib/ui/Button.svelte +++ b/src/lib/ui/Button.svelte @@ -154,8 +154,7 @@ a.disabled, button.disabled { color: var(--text); - opacity: .5; - background: transparent; + opacity: .35; border-color: transparent; cursor: not-allowed; } 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) + })