Skip to content

Commit

Permalink
to fix AccountProfile
Browse files Browse the repository at this point in the history
  • Loading branch information
scobru committed Oct 12, 2024
1 parent af14b61 commit a024d80
Show file tree
Hide file tree
Showing 11 changed files with 1,182 additions and 54 deletions.
4 changes: 4 additions & 0 deletions packages/svelte/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@sveltejs/adapter-auto": "^3.2.4",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.7",
"@types/color-hash": "^2",
"@types/d3": "^7",
"@types/dompurify": "^3",
"@types/eslint": "^8.56.0",
Expand Down Expand Up @@ -58,13 +59,15 @@
"abitype": "^1.0.2",
"blo": "^1.1.1",
"buffer": "^6.0.3",
"color-hash": "^2.0.2",
"d3": "^7.9.0",
"dompurify": "^3.1.6",
"dotenv": "^16.4.5",
"ethers": "^6.13.2",
"express": "^4.21.0",
"express-rate-limit": "^7.4.0",
"gun": "^0.2020.1240",
"gun-avatar": "^1.9.4",
"gun-eth": "^1.2.13",
"ip": "^2.0.1",
"js-sha256": "^0.11.0",
Expand All @@ -74,6 +77,7 @@
"self-adjusting-interval": "^1.0.0",
"svelte-wagmi": "^1.0.7",
"tiny-secp256k1": "^2.2.3",
"url-regex": "^5.0.0",
"viem": "^2.21.7",
"vis-network": "^9.1.9",
"vite-plugin-svelte": "^3.0.1"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<script lang="ts">
import { useAvatar } from '$lib/gun/avatar';
import { useUser } from '$lib/gun/user';
import { onMount } from 'svelte';
export let pub: string = '';
export let size: number = 42;
export let border: number = 2;
const { user } = useUser();
let isOwnAvatar = false;
let fileInput: HTMLInputElement;
$: ({ avatar, blink, uploadAvatar, uploadStatus } = useAvatar(pub, size));
onMount(() => {
isOwnAvatar = $user.pub === pub;
console.log("isOwnAvatar:", isOwnAvatar, "$user.pub:", $user.pub, "pub:", pub);
});
async function handleFileChange(event: Event) {
const file = (event.target as HTMLInputElement).files?.[0];
if (file) await uploadAvatar(file);
}
</script>

<div class="flex flex-col items-center justify-center relative my-10 w-fit mx-auto">
{#if pub}
<img
class="border rounded-full overflow-hidden transition duration-500 ease-out"
style="border-color: {$blink ? 'accent' : 'transparent'}; border-width: {border}px;"
width={size}
height={size}
src={$avatar}
alt="Avatar"
/>
{#if isOwnAvatar}
<button
class="absolute bottom-0 right-0 bg-accent text-white rounded-full p-1 hover:bg-accent/80"
on:click={() => fileInput.click()}
>
<div class="i-la-camera" style="font-size: {size / 3}px;"></div>
</button>
<input
bind:this={fileInput}
type="file"
accept="image/*"
on:change={handleFileChange}
class="hidden"
/>
{#if $uploadStatus}
<div class="mt-2 text-sm text-gray-600">{$uploadStatus}</div>
{/if}
{/if}
{:else}
<div class="pb-2 px-1" style="font-size: {size}px;">
<div class="i-la-user"></div>
</div>
{/if}
<slot></slot>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<script lang="ts">
import { useAccount } from "$lib/gun/account";
import { onMount } from "svelte";
import urlRegex from "url-regex";
export let pub: string | undefined = "URlViuNviAEET30fV4QgPDmGB6DMk4ZxGr-MDBVaPM4.5KaWNBz8Nvq5_yUcmJvQc6E2miOnu-z4uL7TLXbpsaw";
const { account } = useAccount(pub);
function isLink(text: string): boolean {
return urlRegex({ exact: true }).test(text);
}
let lastPulse = 0;
$: if ($account && $account.pulse !== lastPulse) {
lastPulse = $account.pulse;
console.log("Pulse updated:", $account.pulse);
}
onMount(() => {
console.log("AccountProfile mounted", $account);
});
</script>

{#if $account}
<div class="flex flex-col break-all">
<h2 class="text-xl font-bold mb-2">Account Information</h2>
{#each ['pub', 'Color', 'pulse', 'Blink', 'lastSeen'] as field}
<div class="p-2 flex items-center">
<div class="mr-2 font-bold" style="flex: 1 1 60px">{field}</div>
<div class="flex items-center ml-1" style="flex: 1 1 180px">
{#if field === 'Color'}
<div class="p-0" style="background-color: {$account.color}; width: 20px; height: 20px; border-radius: 50%;"></div>
<span class="ml-2">{$account.color}</span>
{:else if field === 'Blink'}
<div class="p-0">{$account.blink ? 'Yes' : 'No'}</div>
{:else}
<div class="p-0 break-all">{$account[field.toLowerCase().replace(' ', '')]}</div>
{/if}
</div>
</div>
{/each}

<h2 class="text-xl font-bold mt-4 mb-2">Profile</h2>
{#if $account.profile}
{#each Object.entries($account.profile) as [field, content]}
<div class="p-2 flex items-center">
<div class="mr-2 font-bold" style="flex: 1 1 60px">{field}</div>
<div class="flex items-center ml-1" style="flex: 1 1 180px">
{#if !isLink(content as string)}
<div class="p-0">{content}</div>
{:else}
<a class="font-bold underline" href={content as string} target="_blank">
{content}
</a>
{/if}
</div>
</div>
{/each}
{:else}
<p>Nessun dato del profilo disponibile.</p>
{/if}
</div>
{:else}
<p>Caricamento account...</p>
{/if}
191 changes: 191 additions & 0 deletions packages/svelte/src/lib/gun/account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import { writable, derived, get } from "svelte/store";
import ms from "ms";
import { useGun } from "./gun";
import { useUser } from "./user";
import SEA from "gun/sea";
import { useColor } from "./colors";

const TIMEOUT = 10000;
const colorDeep = useColor("deep");

interface Profile {
name?: string;
first_name?: string;
last_name?: string;
birth_day?: string;
}

interface Account {
pub?: string;
color?: string;
pulse?: number;
blink?: boolean;
profile?: Profile;
petname?: string;
db?: any;
lastSeen?: string | number;
}

export function useAccount(pubKey: string) {
console.log("useAccount called with:", pubKey);
const gun = useGun();
const { user } = useUser();
console.log("user store:", user);
const pub = writable(pubKey);

const accountStore = writable<Account>({
pub: pubKey,
color: colorDeep.hex(pubKey),
profile: { name: "" },
pulse: 0,
blink: false,
db: gun.user(pubKey),
lastSeen: "offline",
});

const pulseStore = writable(0);

const calculateLastSeen = (pulse: number) => {
if (!pulse) return "offline";
const timeDiff = Date.now() - pulse;
if (timeDiff <= TIMEOUT) return "online";
return ms(timeDiff);
};



// Aggiorna lastSeen ogni secondo
const lastSeenInterval = setInterval(() => {
accountStore.update(acc => ({
...acc,
lastSeen: calculateLastSeen(get(pulseStore)),
}));
}, 1000);

const account = derived([pub, user, accountStore, pulseStore], ([$pub, $user, $account, $pulse]) => {
if (!$pub || !$user) return $account;

gun
.user($pub)
.get("pulse")
.on(d => {
pulseStore.set(d);
accountStore.update(acc => ({ ...acc, blink: !acc.blink, pulse: d }));
});

if ($user.is) {
gun
.user()
.get("petnames")
.get($pub)
.on(async d => {
const decrypted = await $user.decrypt(d);
accountStore.update(acc => ({ ...acc, petname: decrypted }));
});
}

gun
.user($pub)
.get("profile")
.map()
.on((data, key) => {
accountStore.update(acc => ({
...acc,
profile: { ...acc.profile, [key]: data },
}));
});

return $account;
});

return {
account,
setPetname,
destroy: () => clearInterval(lastSeenInterval), // Funzione per pulire l'intervallo
};
}

export async function setPetname(pub: string, name: string): Promise<void> {
const { user } = useUser();
if (!get(user).is) return;
const gun = useGun();
const enc = await get(user).encrypt(name);
gun.user().get("petnames").get(pub).put(enc);
}

export function useAvatar(pub: string, size: number) {
const gun = useGun();
const { user } = useUser();
const avatar = writable("");
const blink = writable(false);
const uploadStatus = writable("");

const updateAvatar = () => {
console.log("Updating avatar for pub:", pub);
gun
.user(pub)
.get("avatar")
.once(data => {
console.log("Avatar data:", data);
if (data) {
avatar.set(data);
} else {
avatar.set(`https://avatars.dicebear.com/api/identicon/${pub}.svg?size=${size}`);
}
});
};

updateAvatar();

gun
.user(pub)
.get("pulse")
.on(() => {
blink.update(b => !b);
});

const uploadAvatar = async (file: File) => {
console.log("Starting avatar upload");
uploadStatus.set("Iniziando il caricamento...");

const currentUser = get(user);
if (!currentUser || !currentUser.is || currentUser.pub !== pub) {
console.error("Utente non autenticato o non autorizzato");
uploadStatus.set("Errore: Utente non autenticato o non autorizzato");
return;
}

try {
const reader = new FileReader();
reader.onload = async e => {
const base64 = e.target?.result as string;
uploadStatus.set("Salvando avatar...");

gun
.user()
.get("avatar")
.put(base64, ack => {
if (ack.err) {
console.error("Errore nel salvare l'avatar:", ack.err);
uploadStatus.set("Errore nel salvare l'avatar");
} else {
console.log("Avatar salvato con successo");
uploadStatus.set("Avatar caricato con successo");
updateAvatar();
}
});
};
reader.readAsDataURL(file);
} catch (error) {
console.error("Errore durante il caricamento dell'avatar:", error);
uploadStatus.set("Errore durante il caricamento. Riprova.");
}
};

return {
avatar: derived(avatar, $a => $a),
blink: derived(blink, $b => $b),
uploadAvatar,
uploadStatus: derived(uploadStatus, $s => $s),
};
}
Loading

0 comments on commit a024d80

Please sign in to comment.