diff --git a/app/profile/settings/page.tsx b/app/profile/settings/page.tsx
index f73c86a..d61e00d 100644
--- a/app/profile/settings/page.tsx
+++ b/app/profile/settings/page.tsx
@@ -10,7 +10,6 @@ export default function ProfileSettingsPage() {
document.title = `Settings | LUMINA`;
}, []);
-
let pubkey = null;
if (typeof window !== 'undefined') {
pubkey = window.localStorage.getItem('pubkey');
@@ -23,10 +22,20 @@ export default function ProfileSettingsPage() {
}
return (
- <>
-
-
+
+
+
+
Profile Settings
+
+ Update your profile information that will be visible to others on the Nostr network
+
+
+
- >
+
);
}
\ No newline at end of file
diff --git a/components/UpdateProfileForm.tsx b/components/UpdateProfileForm.tsx
index 816b452..ccecdc1 100644
--- a/components/UpdateProfileForm.tsx
+++ b/components/UpdateProfileForm.tsx
@@ -1,6 +1,6 @@
'use client';
-import React, { useState } from 'react';
+import React, { useEffect, useState } from 'react';
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { nip19 } from "nostr-tools"
@@ -10,10 +10,16 @@ import { verifyEvent } from 'nostr-tools/pure'
import { hexToBytes } from '@noble/hashes/utils'
import { useNostr, useProfile } from 'nostr-react';
import { signEvent } from '@/utils/utils';
+import { Card, CardContent } from "@/components/ui/card";
+import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
+import { Loader2, Globe, Image, ImageIcon, BadgeCheck, Zap } from "lucide-react";
+import { Skeleton } from "@/components/ui/skeleton";
export function UpdateProfileForm() {
-
const { publish } = useNostr();
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [isSaved, setIsSaved] = useState(false);
+ const [isDataLoaded, setIsDataLoaded] = useState(false);
let npub = '';
let pubkey = '';
@@ -34,77 +40,326 @@ export function UpdateProfileForm() {
}
}
- let { data: userData } = useProfile({
+ const { data: userData, isLoading: isUserDataLoading } = useProfile({
pubkey,
});
- const [username, setUsername] = useState(userData?.name);
- const [displayName, setDisplayName] = useState(userData?.display_name);
- const [bio, setBio] = useState(userData?.about);
+ const [username, setUsername] = useState
('');
+ const [displayName, setDisplayName] = useState('');
+ const [bio, setBio] = useState('');
+ const [picture, setPicture] = useState('');
+ const [banner, setBanner] = useState('');
+ const [nip05, setNip05] = useState('');
+ const [lud16, setLud16] = useState('');
+ const [website, setWebsite] = useState('');
+ // Update form data when userData changes
+ useEffect(() => {
+ if (userData && !isDataLoaded) {
+ setUsername(userData.name);
+ setDisplayName(userData.display_name);
+ setBio(userData.about);
+ setPicture(userData.picture);
+ setBanner(userData.banner);
+ setNip05(userData.nip05);
+ setLud16(userData.lud16);
+ setWebsite(userData.website);
+ setIsDataLoaded(true);
+ }
+ }, [userData, isDataLoaded]);
+
+ // Field change handlers
const handleUsernameChange = (event: React.ChangeEvent) => {
setUsername(event.target.value);
+ setIsSaved(false);
};
+
const handleDisplayNameChange = (event: React.ChangeEvent) => {
setDisplayName(event.target.value);
+ setIsSaved(false);
};
+
const handleBioChange = (event: React.ChangeEvent) => {
setBio(event.target.value);
+ setIsSaved(false);
+ };
+
+ const handlePictureChange = (event: React.ChangeEvent) => {
+ setPicture(event.target.value);
+ setIsSaved(false);
+ };
+
+ const handleBannerChange = (event: React.ChangeEvent) => {
+ setBanner(event.target.value);
+ setIsSaved(false);
+ };
+
+ const handleNip05Change = (event: React.ChangeEvent) => {
+ setNip05(event.target.value);
+ setIsSaved(false);
+ };
+
+ const handleLud16Change = (event: React.ChangeEvent) => {
+ setLud16(event.target.value);
+ setIsSaved(false);
+ };
+
+ const handleWebsiteChange = (event: React.ChangeEvent) => {
+ setWebsite(event.target.value);
+ setIsSaved(false);
};
async function handleProfileUpdate() {
- const username = (document.getElementById('username') as HTMLInputElement).value;
- const bio = (document.getElementById('bio') as HTMLInputElement).value;
- const displayname = (document.getElementById('displayname') as HTMLInputElement).value;
+ setIsSubmitting(true);
+ setIsSaved(false);
if (loginType) {
- let event = {
- kind: 0,
- created_at: Math.floor(Date.now() / 1000),
- tags: [],
- content: `{"name": "${username}", "about": "${bio}"}`,
- pubkey: pubkey,
- id: "",
- sig: "",
- };
+ try {
+ let event = {
+ kind: 0,
+ created_at: Math.floor(Date.now() / 1000),
+ tags: [],
+ content: JSON.stringify({
+ name: username,
+ display_name: displayName,
+ about: bio,
+ picture: picture,
+ banner: banner,
+ nip05: nip05,
+ lud16: lud16,
+ website: website,
+ }),
+ pubkey: pubkey,
+ id: "",
+ sig: "",
+ };
- let signedEvent = await signEvent(loginType, event);
+ let signedEvent = await signEvent(loginType, event);
- if (signedEvent === null) {
- alert('Failed to sign the event. Please check your connection and try again.');
- return;
- }
+ if (signedEvent === null) {
+ throw new Error('Failed to sign the event');
+ }
- let isGood = verifyEvent(signedEvent);
+ let isGood = verifyEvent(signedEvent);
- if (isGood) {
- publish(signedEvent);
- window.location.href = `/profile/${npub}`;
+ if (isGood) {
+ publish(signedEvent);
+ setIsSaved(true);
+ setTimeout(() => {
+ window.location.href = `/profile/${npub}`;
+ }, 1000);
+ }
+ } catch (error) {
+ console.error("Error updating profile:", error);
+ alert('Failed to update profile. Please check your connection and try again.');
+ } finally {
+ setIsSubmitting(false);
}
}
}
+ if (isUserDataLoading && !isDataLoaded) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+
return (
-
-
+
+
+
+
+
+ {username?.charAt(0) || "U"}
+
+
-
-
+
{displayName || username || "Your Profile"}
+
{nip05 || npub}
-
-
-
-
-
-
-
-
-
-
- {/* */}
-
-
-
+
+
+
+
+
+
+
+
Your public identity on the Nostr network
+
+
+
+
+
+
+
Your unique username on the network
+
+
+
+
+
+
How your name appears to others
+
+
+
+
+
+
+
A short description about yourself
+
+
+
+
+
+
+
URL to your profile image
+
+
+
+
+
+
URL to your profile banner image
+
+
+
+
+
+
+
+
Your verified Nostr identifier
+
+
+
+
+
+
Your Lightning address for receiving payments
+
+
+
+
+
+
+
Your personal website or social media link
+
+
+
+
+
+
+
)