Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(friends): Allow quick add friend from link #906

Open
wants to merge 25 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a4c0a9c
allow quick add friend from link
Flemmli97 Dec 3, 2024
7cbb8b0
Merge branch 'dev' into add_friend_link
luisecm Dec 3, 2024
730d098
Merge branch 'dev' into add_friend_link
luisecm Dec 3, 2024
cfb2061
add url copy on did button
Flemmli97 Dec 4, 2024
01e74ad
make param optional. solving prerender problem
Flemmli97 Dec 4, 2024
d8a06d5
Merge branch 'dev' into add_friend_link
Flemmli97 Dec 4, 2024
e0ca90b
fix blocked tab
Flemmli97 Dec 4, 2024
04d49b2
Merge branch 'dev' into add_friend_link
Flemmli97 Dec 5, 2024
24e64d4
Merge branch 'dev' into add_friend_link
stavares843 Dec 5, 2024
2f4d66f
Merge branch 'dev' into add_friend_link
phillsatellite Dec 5, 2024
a69c026
Merge branch 'dev' into add_friend_link
stavares843 Dec 5, 2024
c107e74
Merge branch 'dev' into add_friend_link
phillsatellite Dec 6, 2024
c51178b
Merge branch 'dev' into add_friend_link
Flemmli97 Dec 6, 2024
280c04d
Merge branch 'dev' into add_friend_link
Flemmli97 Dec 9, 2024
192afdc
Merge branch 'dev' into add_friend_link
phillsatellite Dec 9, 2024
4eb5fc9
Merge branch 'dev' into add_friend_link
luisecm Dec 12, 2024
f95a5f7
Merge branch 'dev' into add_friend_link
Flemmli97 Dec 13, 2024
2f4200b
Merge branch 'dev' into add_friend_link
luisecm Dec 13, 2024
b73cce7
Merge branch 'dev' into add_friend_link
tooshel Dec 15, 2024
8de0f32
Merge branch 'dev' into add_friend_link
stavares843 Dec 17, 2024
eec8117
Merge branch 'dev' into add_friend_link
luisecm Dec 18, 2024
6727c9d
Merge branch 'dev' into add_friend_link
Flemmli97 Dec 20, 2024
82f45b3
Merge branch 'dev' into add_friend_link
luisecm Dec 30, 2024
a4bb549
Merge branch 'dev' into add_friend_link
stavares843 Dec 31, 2024
d74441d
Merge branch 'dev' into add_friend_link
stavares843 Jan 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions src/lib/components/friends/AddFriendPopup.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<script lang="ts">
import { Icon, Label, Text } from "$lib/elements"
import Button from "$lib/elements/Button.svelte"
import { Store } from "$lib/state/Store"
import { createEventDispatcher } from "svelte"
import { _ } from "svelte-i18n"
import ProfilePicture from "../profile/ProfilePicture.svelte"
import { Appearance, Shape, Size } from "$lib/enums"
import { MultipassStoreInstance } from "$lib/wasm/MultipassStore"
import type { WarpError } from "$lib/wasm/HandleWarpErrors"
import { ToastMessage } from "$lib/state/ui/toast"

export let friend: string
$: user = Store.getUser(friend)

const dispatcher = createEventDispatcher()

function close() {
dispatcher("close")
}

async function add() {
let res = await MultipassStoreInstance.sendFriendRequest(friend)
res.fold(
(e: WarpError) => {
Store.addToastNotification(new ToastMessage("", e, 3, Shape.XMark, Appearance.Error))
},
() => {
Store.addToastNotification(new ToastMessage("", `Your request is making it's way!`, 3, Shape.CheckMark, Appearance.Success))
}
)
close()
}
</script>

<div class="add-friend-popup">
<Label hook="label-create-group-name" text={$_("settings.profile.addFriend")} />
<div class="user">
<ProfilePicture id={$user.key} image={$user.profile.photo.image} noIndicator size={Size.Medium} loading={$user.key === "0x0"} />
<div class="username">
<Text singleLine class="username">{$user.name}</Text>
<Text singleLine class="status">{$user.profile.status_message}</Text>
</div>
</div>
<div class="button-group">
<Button text={$_("generic.add")} appearance={Appearance.Default} on:click={add}>
<Icon icon={Shape.Plus} />
</Button>
<Button text={$_("generic.cancel")} appearance={Appearance.Default} on:click={close}>
<Icon icon={Shape.NoSymbol} />
</Button>
</div>
</div>

<style lang="scss">
.add-friend-popup {
display: flex;
flex-direction: column;
padding: var(--padding);
border-radius: var(--border-radius);
gap: var(--gap);
.user {
display: flex;
width: 100%;
gap: var(--gap);
}
.button-group {
justify-content: center;
display: flex;
gap: var(--gap);
margin-top: var(--padding-less);
}
}
</style>
1 change: 1 addition & 0 deletions src/lib/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@
"update": "Profile Updated!",
"copy_id": "Copy ID",
"copy_did": "Copy DID",
"copy_did_link": "URL",
"integration": {
"title": "Accounts",
"description": "Share more ways for others to connect and contribute to you. Link your accounts below and they will display on your profile card.",
Expand Down
17 changes: 17 additions & 0 deletions src/lib/state/page/PageStates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { writable, type Writable } from "svelte/store"

export enum FriendPage {
ALL,
ACTIVE,
BLOCKED,
}

export type PageStateStruct = {
friends: Writable<FriendPage>
addFriend: Writable<string>
}

export const PageState: PageStateStruct = {
friends: writable(FriendPage.ALL),
addFriend: writable(""),
}
99 changes: 64 additions & 35 deletions src/routes/friends/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import Fuse from "fuse.js"
import Friend from "$lib/components/friends/Friend.svelte"
import { Store } from "$lib/state/Store"
import { FriendPage, PageState, type PageStateStruct } from "$lib/state/page/PageStates"
import { get } from "svelte/store"
import { goto } from "$app/navigation"
import { UIStore } from "$lib/state/ui"
Expand All @@ -19,10 +20,17 @@
import { ToastMessage } from "$lib/state/ui/toast"
import { CommonInputRules } from "$lib/utils/CommonInputRules"
import CreateGroup from "$lib/components/group/CreateGroup.svelte"
import AddFriendPopup from "$lib/components/friends/AddFriendPopup.svelte"
import { onDestroy } from "svelte"

import { Clipboard } from "@capacitor/clipboard"

enum DIDCopy {
DEFAULT,
SHORT,
LINK,
}

let loading: boolean = false
$: sidebarOpen = UIStore.state.sidebarOpen
$: friends = Store.getUsers(Store.state.friends)
Expand All @@ -33,20 +41,9 @@
let isValidFriendDid: boolean = false
let newGroup: boolean = false

let tab: "all" | "active" | "blocked" = "all"

let unsub = Store.state.pageState.subscribe(s => {
function isTab(value: string): value is "all" | "active" | "blocked" {
return value === "all" || value === "active" || value === "blocked"
}
if (isTab(s)) {
tab = s
}
})

onDestroy(() => {
unsub()
})
$: console.log("tab ", $tab)
$: tab = PageState.friends
$: addFriend = PageState.addFriend

function toggleSidebar(): void {
UIStore.toggleSidebar()
Expand Down Expand Up @@ -159,18 +156,43 @@
})
}

async function copy_did(short: boolean) {
async function copy_did(conf: DIDCopy) {
let user = get(Store.state.user)
if (short) {
await writeToClipboard(`${user.name}#${user.id.short}`)
} else {
const updatedKey = user.key.replace("did:key:", "")
await writeToClipboard(updatedKey)
switch (conf) {
case DIDCopy.DEFAULT: {
const updatedKey = user.key.replace("did:key:", "")
await writeToClipboard(updatedKey)
break
}
case DIDCopy.SHORT: {
await writeToClipboard(`${user.name}#${user.id.short}`)
break
}
case DIDCopy.LINK: {
const updatedKey = user.key.replace("did:key:", "")
await writeToClipboard(`${window.location.origin}/friends/add/${updatedKey}`)
}
}
}

function validDid(did: string) {
return did !== get(Store.state.user).key.replace("did:key:", "")
}
</script>

<div id="page">
{#if $addFriend && validDid($addFriend)}
<Modal
on:close={_ => {
$addFriend = ""
}}>
<AddFriendPopup
friend={$addFriend}
on:close={_ => {
$addFriend = ""
}}></AddFriendPopup>
</Modal>
{/if}
<Sidebar loading={loading} on:toggle={toggleSidebar} open={$sidebarOpen} activeRoute={Route.Friends}>
<!--
<Button hook="button-marketplace" outline appearance={Appearance.Alt} text={$_("market.market")}>
Expand Down Expand Up @@ -214,38 +236,38 @@
<div class="content">
<Topbar>
<svelte:fragment slot="controls">
{#if tab === "all"}
<Button hook="button-friends-all" appearance={Appearance.Alt} text={$_("friends.all")} on:click={_ => (tab = "all")}>
{#if $tab === FriendPage.ALL}
<Button hook="button-friends-all" appearance={Appearance.Alt} text={$_("friends.all")} on:click={_ => ($tab = FriendPage.ALL)}>
<Icon icon={Shape.Users} alt />
</Button>
{:else}
<Button hook="button-friends-all" appearance={Appearance.Alt} text={$_("friends.all")} on:click={_ => (tab = "all")}>
<Button hook="button-friends-all" appearance={Appearance.Alt} text={$_("friends.all")} on:click={_ => ($tab = FriendPage.ALL)}>
<Icon icon={Shape.Users} />
</Button>
{/if}
{#if tab === "active"}
<Button badge={incomingRequests.length} hook="button-friends-active" appearance={Appearance.Primary} text={$_("friends.active")} on:click={_ => (tab = "active")} hideTextOnMobile>
{#if $tab === FriendPage.ACTIVE}
<Button badge={incomingRequests.length} hook="button-friends-active" appearance={Appearance.Primary} text={$_("friends.active")} on:click={_ => ($tab = FriendPage.ACTIVE)} hideTextOnMobile>
<Icon icon={Shape.ArrowsLeftRight} alt />
</Button>
{:else}
<Button badge={incomingRequests.length} hook="button-friends-active" appearance={Appearance.Alt} text={$_("friends.active")} on:click={_ => (tab = "active")} hideTextOnMobile>
<Button badge={incomingRequests.length} hook="button-friends-active" appearance={Appearance.Alt} text={$_("friends.active")} on:click={_ => ($tab = FriendPage.ACTIVE)} hideTextOnMobile>
<Icon icon={Shape.ArrowsLeftRight} />
</Button>
{/if}
{#if tab === "blocked"}
<Button hook="button-friends-blocked" appearance={Appearance.Primary} text={$_("friends.blocked")} on:click={_ => (tab = "blocked")} hideTextOnMobile>
{#if $tab === FriendPage.BLOCKED}
<Button hook="button-friends-blocked" appearance={Appearance.Primary} text={$_("friends.blocked")} on:click={_ => ($tab = FriendPage.BLOCKED)} hideTextOnMobile>
<Icon icon={Shape.NoSymbol} alt />
</Button>
{:else}
<Button hook="button-friends-blocked" appearance={Appearance.Alt} text={$_("friends.blocked")} on:click={_ => (tab = "blocked")} hideTextOnMobile>
<Button hook="button-friends-blocked" appearance={Appearance.Alt} text={$_("friends.blocked")} on:click={_ => ($tab = FriendPage.BLOCKED)} hideTextOnMobile>
<Icon icon={Shape.NoSymbol} />
</Button>
{/if}
</svelte:fragment>
</Topbar>

<div class="body">
{#if tab === "all"}
{#if $tab === FriendPage.ALL}
<Label hook="label-add-someone" text={$_("friends.add_someone")} />
<div class="section" data-cy="friends-section-all">
<Input
Expand Down Expand Up @@ -273,17 +295,24 @@
icon: Shape.Users,
text: $_("settings.profile.copy_id"),
appearance: Appearance.Default,
onClick: async () => await copy_did(true),
onClick: async () => await copy_did(DIDCopy.SHORT),
},
{
id: "copy-did",
icon: Shape.Clipboard,
text: $_("settings.profile.copy_did"),
appearance: Appearance.Default,
onClick: async () => await copy_did(false),
onClick: async () => await copy_did(DIDCopy.DEFAULT),
},
{
id: "copy-link",
icon: Shape.Clipboard,
text: $_("settings.profile.copy_did_link"),
appearance: Appearance.Default,
onClick: async () => await copy_did(DIDCopy.LINK),
},
]}>
<Button hook="button-copy-id" slot="content" appearance={Appearance.Alt} text={$_("friends.copy")} tooltip={$_("friends.copy_did")} let:open on:contextmenu={open} on:click={async _ => await copy_did(false)}>
<Button hook="button-copy-id" slot="content" appearance={Appearance.Alt} icon tooltip={$_("friends.copy_did")} let:open on:contextmenu={open} on:click={async _ => await copy_did(DIDCopy.DEFAULT)}>
<Icon icon={Shape.Clipboard} />
</Button>
</ContextMenu>
Expand Down Expand Up @@ -407,7 +436,7 @@
{/each}
</div>
</div>
{:else if tab === "active"}
{:else if $tab === FriendPage.ACTIVE}
<div class="section column" data-cy="friends-section-requests">
<Label hook="label-outgoing-requests" text={$_("friends.outgoing_requests")} />
{#each outgoingRequests as request}
Expand Down Expand Up @@ -439,7 +468,7 @@
<Text hook="text-no-incoming-requests">{$_("friends.noIncoming")}</Text>
{/if}
</div>
{:else if tab === "blocked"}
{:else if $tab === FriendPage.BLOCKED}
<div class="section column" data-cy="friends-section-blocked">
<Label hook="label-blocked-users" text={$_("friends.blocked_users")} />
{#each $blocked as user}
Expand Down
19 changes: 19 additions & 0 deletions src/routes/friends/add/[[user]]/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script lang="ts">
import { goto } from "$app/navigation"
import { page } from "$app/stores"
import { Route } from "$lib/enums"
import { PageState } from "$lib/state/page/PageStates"
import { onMount } from "svelte"

let { user } = $page.params

onMount(() => {
PageState.addFriend.set(user)
goto(Route.Friends)
})
</script>

<div></div>

<style lang="scss">
</style>
41 changes: 32 additions & 9 deletions src/routes/settings/profile/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
Missing,
}

enum DIDCopy {
DEFAULT,
SHORT,
LINK,
}

let loading = true
let isValidUsernameToUpdate = false
let isValidStatusMessageToUpdate = true
Expand Down Expand Up @@ -252,12 +258,22 @@
let unsavedChanges: boolean
let profile_update_txt = $_("settings.profile.update")

async function copy_did(short: boolean) {
if (short) {
await navigator.clipboard.writeText(`${userReference.name}#${userReference.id.short}`)
} else {
const updatedKey = userReference.key.replace("did:key:", "")
await navigator.clipboard.writeText(updatedKey)
async function copy_did(conf: DIDCopy) {
let user = get(Store.state.user)
switch (conf) {
case DIDCopy.DEFAULT: {
const updatedKey = userReference.key.replace("did:key:", "")
await navigator.clipboard.writeText(updatedKey)
break
}
case DIDCopy.SHORT: {
await navigator.clipboard.writeText(`${userReference.name}#${userReference.id.short}`)
break
}
case DIDCopy.LINK: {
const updatedKey = user.key.replace("did:key:", "")
await navigator.clipboard.writeText(`${window.location.origin}/friends/add/${updatedKey}`)
}
}
}

Expand Down Expand Up @@ -476,17 +492,24 @@
icon: Shape.Users,
text: $_("settings.profile.copy_id"),
appearance: Appearance.Default,
onClick: async () => await copy_did(true),
onClick: async () => await copy_did(DIDCopy.SHORT),
},
{
id: "copy-did",
icon: Shape.Clipboard,
text: $_("settings.profile.copy_did"),
appearance: Appearance.Default,
onClick: async () => await copy_did(false),
onClick: async () => await copy_did(DIDCopy.DEFAULT),
},
{
id: "copy-link",
icon: Shape.Clipboard,
text: $_("settings.profile.copy_did_link"),
appearance: Appearance.Default,
onClick: async () => await copy_did(DIDCopy.LINK),
},
]}>
<div slot="content" class="short-id" role="presentation" let:open on:contextmenu={open} on:click={async _ => await copy_did(false)}>
<div slot="content" class="short-id" role="presentation" let:open on:contextmenu={open} on:click={async _ => await copy_did(DIDCopy.DEFAULT)}>
<Input hook="input-settings-profile-short-id" alt value={$user.id.short} disabled copyOnInteract>
<Icon icon={Shape.Hashtag} alt muted />
</Input>
Expand Down
Loading