Create form for adding aliases

This commit is contained in:
silverpill 2023-04-03 22:16:31 +00:00
parent 12df3fe955
commit 2d164cdd19
5 changed files with 119 additions and 10 deletions

View file

@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added ### Added
- Added "Aliases" page. - Added "Aliases" page.
- Form for adding aliases.
## [1.19.0] - 2023-03-30 ## [1.19.0] - 2023-03-30

View file

@ -29,12 +29,16 @@ export async function getSearchResults(
} }
export async function searchProfilesByAcct( export async function searchProfilesByAcct(
authToken: string | null,
acct: string, acct: string,
resolve: boolean = false,
limit = 40,
): Promise<Profile[]> { ): Promise<Profile[]> {
const url = `${BACKEND_URL}/api/v1/accounts/search` const url = `${BACKEND_URL}/api/v1/accounts/search`
const response = await http(url, { const response = await http(url, {
method: "GET", method: "GET",
queryParams: { q: acct }, queryParams: { q: acct, resolve, limit },
authToken,
}) })
const data = await response.json() const data = await response.json()
if (response.status !== 200) { if (response.status !== 200) {

View file

@ -1,6 +1,6 @@
import { BACKEND_URL } from "@/constants" import { BACKEND_URL } from "@/constants"
import { http } from "./common" import { http } from "./common"
import { User } from "./users" import { Aliases, User } from "./users"
export async function changePassword( export async function changePassword(
authToken: string, authToken: string,
@ -20,6 +20,24 @@ export async function changePassword(
} }
} }
export async function addAlias(
authToken: string,
acct: string,
): Promise<Aliases> {
const url = `${BACKEND_URL}/api/v1/settings/aliases`
const response = await http(url, {
method: "POST",
json: { acct: acct },
authToken,
})
const data = await response.json()
if (response.status !== 200) {
throw new Error(data.error_description)
} else {
return data
}
}
async function downloadBlob(blob: Blob, name: string) { async function downloadBlob(blob: Blob, name: string) {
const fileUrl = window.URL.createObjectURL(blob) const fileUrl = window.URL.createObjectURL(blob)
const hiddenLink = document.createElement("a") const hiddenLink = document.createElement("a")

View file

@ -194,7 +194,7 @@ async function identifySender() {
return return
} }
isLoading = true isLoading = true
const profiles = await searchProfilesByAcct(senderAcct) const profiles = await searchProfilesByAcct(null, senderAcct)
if (profiles.length > 1) { if (profiles.length > 1) {
senderError = "Please provide full address" senderError = "Please provide full address"
} else { } else {

View file

@ -22,9 +22,40 @@
<profile-list-item :profile="profile"></profile-list-item> <profile-list-item :profile="profile"></profile-list-item>
</router-link> </router-link>
</section> </section>
<div class="not-found" v-if="isEmpty() && !isLoading"> <section>
No aliases found <h2>Add alias</h2>
</div> <form @submit.prevent="onAddAlias()">
<div class="input-group">
<input
id="alias"
type="text"
v-model="newAlias"
placeholder="Fediverse address"
@input="newAliasSuggestions = []; newAliasError = null"
>
<div class="suggestions" v-if="newAliasSuggestions.length > 0">
<button
class="suggestion"
v-for="profile in newAliasSuggestions"
:key="profile.id"
@click="newAlias = profile.acct; newAliasSuggestions = []"
>
{{ profile.acct }}
</button>
</div>
</div>
<button
type="submit"
class="btn"
:disabled="!canAddAlias()"
>
Add
</button>
<div class="error-message" v-if="newAliasError">
{{ newAliasError }}
</div>
</form>
</section>
<loader v-if="isLoading"></loader> <loader v-if="isLoading"></loader>
</template> </template>
</sidebar-layout> </sidebar-layout>
@ -34,16 +65,21 @@
import { onMounted } from "vue" import { onMounted } from "vue"
import { $, $ref } from "vue/macros" import { $, $ref } from "vue/macros"
import { getAliases, Aliases } from "@/api/users" import { searchProfilesByAcct } from "@/api/search"
import { addAlias } from "@/api/settings"
import { getAliases, Aliases, Profile } from "@/api/users"
import SidebarLayout from "@/components/SidebarLayout.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import Loader from "@/components/Loader.vue" import Loader from "@/components/Loader.vue"
import ProfileListItem from "@/components/ProfileListItem.vue" import ProfileListItem from "@/components/ProfileListItem.vue"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"
const { ensureCurrentUser } = $(useCurrentUser()) const { ensureCurrentUser, ensureAuthToken } = $(useCurrentUser())
let aliases = $ref<Aliases>({ declared: [], verified: [] }) let aliases = $ref<Aliases>({ declared: [], verified: [] })
let isLoading = $ref(false) let isLoading = $ref(false)
let newAlias = $ref<string>("")
let newAliasSuggestions = $ref<Profile[]>([])
let newAliasError = $ref<string | null>(null)
onMounted(async () => { onMounted(async () => {
isLoading = true isLoading = true
@ -51,13 +87,37 @@ onMounted(async () => {
isLoading = false isLoading = false
}) })
function isEmpty(): boolean { function canAddAlias(): boolean {
return aliases.declared.length === 0 && aliases.verified.length === 0 return newAlias.length > 0 && newAliasError === null
}
async function onAddAlias() {
isLoading = true
const profiles = await searchProfilesByAcct(
ensureAuthToken(),
newAlias,
true,
5,
)
if (profiles.length === 0) {
newAliasError = "Profile not found"
isLoading = false
return
}
if (profiles.length === 1 && profiles[0].acct === newAlias) {
aliases = await addAlias(ensureAuthToken(), newAlias)
newAlias = ""
} else {
newAliasSuggestions = profiles
}
isLoading = false
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "../styles/layout"; @import "../styles/layout";
@import "../styles/mixins";
@import "../styles/theme";
section { section {
margin-bottom: $block-outer-padding; margin-bottom: $block-outer-padding;
@ -67,6 +127,32 @@ section {
margin-bottom: $block-outer-padding; margin-bottom: $block-outer-padding;
} }
form {
@include content-form;
.suggestions {
background-color: var(--block-background-color);
border-radius: $btn-border-radius;
display: flex;
flex-direction: column;
margin-top: 1px;
.suggestion {
padding: calc($input-padding / 2) $input-padding;
text-align: left;
word-wrap: break-word;
&:first-child {
padding-top: $input-padding;
}
&:last-child {
padding-bottom: $input-padding;
}
}
}
}
.loader { .loader {
margin: $block-outer-padding auto; margin: $block-outer-padding auto;
} }