Files
plspace/src/components/profile/ContactBox.svelte
T

146 lines
4.7 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts">
/**
* "Contacting Tom" — the two-column action list.
*
* Follow state comes from `/api/v1/accounts/relationships`, which is only
* available when signed in; logged out, the actions become sign-in prompts
* rather than disappearing, so the box keeps its shape.
*/
import type { Account, Relationship } from '$lib/api/types'
import { useAppServices } from '$lib/app-services'
import { displayNameOf } from '$lib/util/profile'
import Module from '../common/Module.svelte'
import EmojiText from '../common/EmojiText.svelte'
interface Props {
account: Account
relationship: Relationship | null
onrelationship?: (relationship: Relationship) => void
}
let { account, relationship, onrelationship }: Props = $props()
const { endpoints, session } = useAppServices()
let busy = $state(false)
let error = $state<string | null>(null)
const firstName = $derived(displayNameOf(account).split(/\s+/)[0])
const isSelf = $derived(session.me?.id === account.id)
const following = $derived(relationship?.following ?? false)
const requested = $derived(relationship?.requested ?? false)
const blocking = $derived(relationship?.blocking ?? false)
const followLabel = $derived(
blocking
? 'Unblock User'
: following
? 'Remove from Friends'
: requested
? 'Cancel Friend Request'
: account.locked
? 'Request to Add'
: 'Add to Friends',
)
async function run(action: () => Promise<Relationship>): Promise<void> {
if (busy) return
busy = true
error = null
try {
onrelationship?.(await action())
} catch (cause) {
error = cause instanceof Error ? cause.message : 'That didnt work.'
} finally {
busy = false
}
}
function toggleFollow(): void {
if (blocking) {
void run(() => endpoints.unblockAccount(session.api, account.id))
} else if (following || requested) {
void run(() => endpoints.unfollowAccount(session.api, account.id))
} else {
void run(() => endpoints.followAccount(session.api, account.id))
}
}
function toggleBlock(): void {
void run(() =>
blocking
? endpoints.unblockAccount(session.api, account.id)
: endpoints.blockAccount(session.api, account.id),
)
}
</script>
<Module title={`Contacting ${firstName}`} titleEmojis={account.emojis}>
{#if error}
<p class="error-note" role="alert">{error}</p>
{/if}
<ul class="action-list">
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true"></span>
{#if session.signedIn}
<a class="action-list-label" href={`#/compose?to=${encodeURIComponent(account.acct)}`}>Send Message</a>
{:else}
<a class="action-list-label" href="#/login">Send Message</a>
{/if}
</li>
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true">👤</span>
{#if isSelf}
<span class="action-list-label muted">This is you</span>
{:else if session.signedIn}
<button
type="button"
class="link-button action-list-label"
disabled={busy}
aria-pressed={following ? 'true' : 'false'}
onclick={toggleFollow}
>
{followLabel}
</button>
{:else}
<a class="action-list-label" href="#/login">Add to Friends</a>
{/if}
</li>
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true"></span>
<a class="action-list-label" href={account.url} target="_blank" rel="noopener noreferrer">
View on {account.acct.includes('@') ? account.acct.split('@')[1] : session.host}
</a>
</li>
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true"></span>
<a class="action-list-label" href={`#/@${account.acct}/friends`}>Forward to Friend</a>
</li>
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true">💬</span>
<a class="action-list-label" href={`#/@${account.acct}/blog`}>Instant Message</a>
</li>
<li class="action-list-item">
<span class="action-list-icon" aria-hidden="true"></span>
{#if isSelf || !session.signedIn}
<span class="action-list-label muted">Block User</span>
{:else}
<button type="button" class="link-button action-list-label" disabled={busy} onclick={toggleBlock}>
{blocking ? 'Unblock User' : 'Block User'}
</button>
{/if}
</li>
</ul>
{#if relationship?.followed_by && !isSelf}
<p class="contact-note muted">
<EmojiText text={firstName} emojis={account.emojis} /> has you on their friends list.
</p>
{/if}
</Module>