diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1ef5d469..5c3cb797 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix: Display "unconfirmed" label for contacts that have not yet joined their private conversation.
- Fix: In public converastion invitations, use the cell name as the conversation title when convesation config is not available.
- Fix: Open external links in message content in system default browser or mail client.
+- Feat: Delete a contact by clicking the "Delete Contact" button on their page.
## [0.7.5] - 2025-01-10
diff --git a/ui/src/lib/Dialog.svelte b/ui/src/lib/Dialog.svelte
new file mode 100644
index 00000000..ec022675
--- /dev/null
+++ b/ui/src/lib/Dialog.svelte
@@ -0,0 +1,58 @@
+
+
+{#if open}
+
+
e.key === "Enter" && handleCancel()}
+ />
+
+
{title}
+
+
+
+
+
+
+
+
+
+{/if}
diff --git a/ui/src/lib/svgIcons.ts b/ui/src/lib/svgIcons.ts
index d0e6aa6c..adc5c4ac 100644
--- a/ui/src/lib/svgIcons.ts
+++ b/ui/src/lib/svgIcons.ts
@@ -7,7 +7,8 @@
* Before adding an svg string here you MUST complete the following steps:
* 1. Ensure the svg string does NOT contain the properties: "fill", "stroke", "width", or "height"
* If it does, delete them.
- * 2. Add the following properties to the svg element: fill="currentColor" width="100%" height="100%"
+ * 2. For fill based icons, add the following properties to the svg element: fill="currentColor" width="100%" height="100%"
+ * 3. For stroke based icons, add the following properties to the svg element: stroke="currentColor" width="100%" height="100%"
*/
export const svgIcons: { [key: string]: string } = {
@@ -90,4 +91,5 @@ export const svgIcons: { [key: string]: string } = {
pdf: '',
fileClip:
'',
+ delete: '',
};
diff --git a/ui/src/routes/contacts/[id]/+page.svelte b/ui/src/routes/contacts/[id]/+page.svelte
index d8673280..d454d03c 100644
--- a/ui/src/routes/contacts/[id]/+page.svelte
+++ b/ui/src/routes/contacts/[id]/+page.svelte
@@ -3,10 +3,8 @@
import { page } from "$app/stores";
import Button from "$lib/Button.svelte";
import ButtonIconBare from "$lib/ButtonIconBare.svelte";
- import ButtonsCopyShare from "$lib/ButtonsCopyShare.svelte";
import ButtonsCopyShareIcon from "$lib/ButtonsCopyShareIcon.svelte";
import Header from "$lib/Header.svelte";
- import SvgIcon from "$lib/SvgIcon.svelte";
import { deriveAgentContactStore, type ContactStore } from "$store/ContactStore";
import { getContext, onDestroy, onMount } from "svelte";
import { t } from "$translations";
@@ -21,6 +19,8 @@
import type { AgentPubKeyB64 } from "@holochain/client";
import { POLLING_INTERVAL_SLOW } from "$config";
import NoticeContactNotJoined from "$lib/NoticeContactNotJoined.svelte";
+ import Dialog from "$lib/Dialog.svelte";
+ import toast from "svelte-french-toast";
const contactStore = getContext<{ getStore: () => ContactStore }>("contactStore").getStore();
const conversationStore = getContext<{ getStore: () => ConversationStore }>(
@@ -33,7 +33,8 @@
const myPubKeyB64 = getContext<{ getMyPubKeyB64: () => AgentPubKeyB64 }>(
"myPubKey",
).getMyPubKeyB64();
- $: myProfile = $provisionedRelayCellProfileStore.data[myPubKeyB64];
+
+ let isDeletingContact = false;
let contact = deriveAgentContactStore(contactStore, $page.params.id);
let conversation =
@@ -45,9 +46,12 @@
? deriveCellProfileStore(profileStore, encodeCellIdToBase64($contact.cellId))
: undefined;
+ let showDeleteDialog = false;
+
let pollInterval: NodeJS.Timeout;
$: hasAgentJoinedDht =
profiles !== undefined &&
+ $contact !== undefined &&
$profiles?.list.find(([key]) => key === $contact.publicKeyB64) !== undefined;
async function loadProfiles() {
@@ -61,57 +65,92 @@
}
}
+ async function handleDeleteContact() {
+ if (isDeletingContact) return;
+
+ isDeletingContact = true;
+ try {
+ await contact.delete();
+ toast.success($t("common.delete_contact_success"));
+ await goto("/create");
+ showDeleteDialog = false;
+ } catch (err) {
+ console.error("Error deleting contact:", err);
+ toast.error($t("common.delete_contact_error"));
+ }
+ isDeletingContact = false;
+ }
+
onMount(() => {
loadProfiles();
});
- onDestroy(() => clearInterval(pollInterval));
+
+ onDestroy(() => {
+ clearInterval(pollInterval);
+ });
-