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}

-
- - -
-
- - -
-
- - {/* */} -