feat: follow requests
This commit is contained in:
		
							parent
							
								
									563541d0e6
								
							
						
					
					
						commit
						e3586f4eec
					
				
					 4 changed files with 179 additions and 3 deletions
				
			
		|  | @ -38,6 +38,10 @@ | |||
|         "back": "Back" | ||||
|     }, | ||||
| 
 | ||||
|     "follow_requests": { | ||||
|         "none": "no follow requests to action right now!" | ||||
|     }, | ||||
| 
 | ||||
|     "timeline": { | ||||
|         "home": "Home", | ||||
|         "local": "Local", | ||||
|  |  | |||
|  | @ -202,6 +202,40 @@ export async function getFollowRequests(host, token, since_id, max_id, limit) { | |||
|     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. | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ 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(); | ||||
|  | @ -20,5 +21,8 @@ export async function fetchFollowRequests(force) { | |||
|         get(app).token | ||||
|     ); | ||||
| 
 | ||||
|     // parse accounts
 | ||||
|     newReqs = newReqs.map((r) => parseAccount(r)); | ||||
| 
 | ||||
|     followRequests.set(newReqs); | ||||
| } | ||||
|  | @ -1,10 +1,144 @@ | |||
| <script> | ||||
|     import { followRequests } from '$lib/followRequests.js'; | ||||
|     import PageHeader from '../../lib/ui/core/PageHeader.svelte'; | ||||
|     import Lang from '$lib/lang'; | ||||
|     import {server} from '$lib/client/server'; | ||||
|     import {app} from '$lib/client/app'; | ||||
|     import Button from '../../lib/ui/Button.svelte'; | ||||
|     import * as api from '$lib/api' | ||||
| 
 | ||||
|     import TickIcon from '../../img/icons/tick.svg' | ||||
|     import CrossIcon from '../../img/icons/cross.svg' | ||||
|     import { get } from 'svelte/store'; | ||||
| 
 | ||||
|     const lang = Lang('en_GB'); | ||||
| 
 | ||||
|     async function actionRequest(account_id, approved) { | ||||
|         // remove item from array first - this updates the ui and | ||||
|         // makes the interaction more seamless | ||||
|         $followRequests.splice( | ||||
|             $followRequests.indexOf( | ||||
|                 $followRequests.find(r => r.id) | ||||
|             ), | ||||
|             1 | ||||
|         ); | ||||
| 
 | ||||
|         // hack: force the state to update now that we just spliced the array | ||||
|         $followRequests = $followRequests | ||||
| 
 | ||||
|         if(approved) { | ||||
|             await api.acceptFollowRequest( | ||||
|                 get(server).host, | ||||
|                 get(app).token, | ||||
|                 account_id | ||||
|             ) | ||||
|         } else { | ||||
|             await api.rejectFollowRequest( | ||||
|                 get(server).host, | ||||
|                 get(app).token, | ||||
|                 account_id | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     // aliases | ||||
|     const acceptRequest = (id) => actionRequest(id, true); | ||||
|     const denyRequest = (id) => actionRequest(id, false); | ||||
| </script> | ||||
| 
 | ||||
| <div> | ||||
| <PageHeader title={lang.string('navigation.follow_requests')}/> | ||||
| 
 | ||||
| {#if $followRequests.length < 1} | ||||
| <p class="request-zero">{lang.string('follow_requests.none')}</p> | ||||
| {/if} | ||||
| 
 | ||||
| {#each $followRequests as req} | ||||
|     <div class="request"> | ||||
|         <a href="/{$server.host}/@{req.fqn}" class="request-avatar-container" on:mouseup|stopPropagation> | ||||
|             <img src={req.avatar_url} alt="" width="48" height="48" class="post-avatar" loading="lazy" decoding="async"> | ||||
|         </a> | ||||
|         <div class="info"> | ||||
|             <div class="request-user-info"> | ||||
|                 <a href="/{$server.host}/@{req.fqn}" class="name">{@html req.rich_name}</a> | ||||
|                 <span class="username">{req.mention}</span> | ||||
|             </div> | ||||
|         </div> | ||||
|         <div class="request-options"> | ||||
|             <Button filled title="Yes" on:click={() => acceptRequest(req.id)}> | ||||
|                 <TickIcon width="24px"/> | ||||
|             </Button> | ||||
|             <Button title="No" on:click={() => denyRequest(req.id)}> | ||||
|                 <CrossIcon width="24px"/> | ||||
|             </Button> | ||||
|         </div> | ||||
|     </div> | ||||
| {/each} | ||||
| 
 | ||||
| <style></style> | ||||
| <style> | ||||
|     .request { | ||||
|         width: 100%; | ||||
|         display: flex; | ||||
|         flex-direction: row; | ||||
| 
 | ||||
|         background: var(--bg-900); | ||||
|         padding: .5rem; | ||||
|         border-radius: 8px; | ||||
|     } | ||||
| 
 | ||||
|     .request a, | ||||
|     .request a:visited { | ||||
|         color: inherit; | ||||
|         text-decoration: none; | ||||
|     } | ||||
|     .request a:hover { | ||||
|         text-decoration: underline; | ||||
|     } | ||||
| 
 | ||||
|     .request-avatar-container { | ||||
|         margin-right: 12px; | ||||
|         display: flex; | ||||
|     } | ||||
| 
 | ||||
|     .post-avatar { | ||||
|         border-radius: 8px; | ||||
|     } | ||||
| 
 | ||||
|     .info { | ||||
|         display: flex; | ||||
|         flex-grow: 1; | ||||
|         flex-direction: row; | ||||
|     } | ||||
| 
 | ||||
|     .request-user-info { | ||||
|         margin-top: -2px; | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         justify-content: center; | ||||
|     } | ||||
| 
 | ||||
|     .request-user-info a { | ||||
|         display: block; | ||||
|     } | ||||
| 
 | ||||
|     .request-user-info .username { | ||||
|         opacity: .8; | ||||
|         font-size: .9em; | ||||
|     } | ||||
| 
 | ||||
|     .request-options { | ||||
|         display: flex; | ||||
|         gap: 8px; | ||||
|     } | ||||
| 
 | ||||
|     .request-options :global(button) { | ||||
|         width: fit-content; | ||||
|         height: 100%; | ||||
|     } | ||||
| 
 | ||||
|     .request-zero { | ||||
|         opacity: 0.8; | ||||
|         font-size: 0.95rem; | ||||
|         text-align: center; | ||||
|     } | ||||
| </style> | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue