diff --git a/src-tauri/src/commands/accounts.rs b/src-tauri/src/commands/accounts.rs index c5ff008..18043f1 100644 --- a/src-tauri/src/commands/accounts.rs +++ b/src-tauri/src/commands/accounts.rs @@ -6,6 +6,7 @@ use tauri::{AppHandle, Manager}; #[serde(rename_all = "camelCase")] pub struct Account { pub display_name: String, + pub avatar: Option, pub private_key: String, } diff --git a/src/app/app.ts b/src/app/app.ts index 8eb46a6..62f033d 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -5,7 +5,7 @@ import { sha512 } from "@noble/hashes/sha2.js"; import { base58 } from "@scure/base"; import axios from "axios"; -import { AccountsFile, getAccounts } from "@/lib/accounts"; +import { Account, AccountsFile, getAccounts } from "@/lib/accounts"; ed.hashes.sha512 = sha512; @@ -38,6 +38,10 @@ export default class Enclave { this.accounts = await getAccounts(); } + public getAccount(): Account | null { + return this.accounts?.accounts[this.accounts.activeAccount] || null; + } + public async connectToServer(hostname: string, isSecure: boolean) { if (this.server) { this.server.disconnect(); @@ -87,7 +91,7 @@ export default class Enclave { public getClientSecretKey() { if (!this.accounts) return null; - const account = this.accounts?.accounts[this.accounts.activeAccount]; + const account = this.getAccount(); return account ? base58.decode(account.privateKey) : null; } diff --git a/src/components/view/NewProfileView.tsx b/src/components/view/NewProfileView.tsx index 49dba06..a5c06d8 100644 --- a/src/components/view/NewProfileView.tsx +++ b/src/components/view/NewProfileView.tsx @@ -7,6 +7,16 @@ import { Label } from "@/components/ui/label"; import { Button } from "@/components/ui/button"; import { saveAccounts } from "@/lib/accounts"; import Enclave from "@/app/app"; +import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar"; + +function readFileAsDataUrl(file: File): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result as string); + reader.onerror = () => reject(new Error("Failed to read image")); + reader.readAsDataURL(file); + }); +} export function NewProfilePage({ appRef, @@ -14,9 +24,28 @@ export function NewProfilePage({ appRef: React.RefObject; }) { const [displayName, setDisplayName] = useState(""); + const [avatar, setAvatar] = useState(null); const [error, setError] = useState(null); const [submitting, setSubmitting] = useState(false); + async function handleAvatarChange(e: React.ChangeEvent) { + const file = e.target.files?.[0]; + if (!file) return; + + if (!file.type.startsWith("image/")) { + setError("Please select an image file"); + return; + } + + try { + const dataUrl = await readFileAsDataUrl(file); + setAvatar(dataUrl); + setError(null); + } catch { + setError("Failed to load image"); + } + } + async function handleCreate() { const name = displayName.trim(); if (!name) { @@ -42,6 +71,7 @@ export function NewProfilePage({ const newAccount = { displayName: name, privateKey: base58.encode(secretKey), + avatar: avatar ?? undefined, }; appRef.current.accounts.activeAccount = @@ -54,11 +84,13 @@ export function NewProfilePage({ setError(e instanceof Error ? e.message : "Failed to create profile"); } finally { setSubmitting(false); + + window.location.reload(); } } return ( -
+

Create your profile

@@ -68,6 +100,24 @@ export function NewProfilePage({

+
+ + +
+
; }) { + const account = appRef.current?.getAccount(); + return (
{appRef.current?.server?.meta && ( @@ -74,24 +76,27 @@ export default function Sidebar({ )} -
- -
- - - -
- Klesti Selimaj - Online + {account && ( +
+ +
+ + + {account.displayName[0]} + +
+ {account.displayName} + Online +
-
-
- -
- -
+
+ +
+ +
+ )}
); } diff --git a/src/components/view/serverList.tsx b/src/components/view/serverList.tsx index 2624c7b..ae84df4 100644 --- a/src/components/view/serverList.tsx +++ b/src/components/view/serverList.tsx @@ -10,7 +10,7 @@ export default function ServerList({ if (!appRef.current) return null; return ( -