From 8bd4561ba851504498e2c722f7e41a1e6a1038cc Mon Sep 17 00:00:00 2001 From: Lulox Date: Tue, 10 Dec 2024 13:18:58 -0300 Subject: [PATCH] Added modal to profile edit and improved about --- packages/nextjs/app/about/About.tsx | 42 ++-- packages/nextjs/app/create/Create.tsx | 11 +- .../nextjs/app/profile/[address]/page.tsx | 184 +++++++----------- .../app/profile/_components/EditProfile.tsx | 83 ++++++++ packages/nextjs/app/roadmap/Roadmap.tsx | 6 +- packages/nextjs/components/Footer.tsx | 2 +- packages/nextjs/components/Header.tsx | 4 +- .../punk-society}/ImageUploader.tsx | 0 .../punk-society}/Modal.tsx | 0 .../punk-society}/TextInput.tsx | 4 +- 10 files changed, 183 insertions(+), 153 deletions(-) create mode 100644 packages/nextjs/app/profile/_components/EditProfile.tsx rename packages/nextjs/{app/create/_components => components/punk-society}/ImageUploader.tsx (100%) rename packages/nextjs/{app/create => components/punk-society}/Modal.tsx (100%) rename packages/nextjs/{app/create/_components => components/punk-society}/TextInput.tsx (94%) diff --git a/packages/nextjs/app/about/About.tsx b/packages/nextjs/app/about/About.tsx index fc0d9d5..b1d5875 100644 --- a/packages/nextjs/app/about/About.tsx +++ b/packages/nextjs/app/about/About.tsx @@ -275,6 +275,27 @@ export const About = () => {
+
+
+ Scaffold-ETH 2 logo +

Scaffold-ETH 2

+

+ Built with{" "} + + Scaffold-ETH 2 + Scaffold-ETH 2 logo + {" "} + , using the latest tech stack to build web3 dApps. +

+
+
+
USDC logo @@ -319,27 +340,6 @@ export const About = () => {

- -
-
- Scaffold-ETH 2 logo -

Scaffold-ETH 2

-

- Built with{" "} - - Scaffold-ETH 2 - Scaffold-ETH 2 logo - {" "} - , using the latest tech stack to build web3 dApps. -

-
-
diff --git a/packages/nextjs/app/create/Create.tsx b/packages/nextjs/app/create/Create.tsx index 3e817d0..638382b 100644 --- a/packages/nextjs/app/create/Create.tsx +++ b/packages/nextjs/app/create/Create.tsx @@ -1,12 +1,10 @@ "use client"; import { useEffect, useState } from "react"; -import { ImageUploader } from "./_components/ImageUploader"; import { MintingButtons } from "./_components/MintingButtons"; -import { TextInput } from "./_components/TextInput"; import generateTokenURI from "./_components/generateTokenURI"; - -// import type { NextPage } from "next"; +import { ImageUploader } from "~~/components/punk-society/ImageUploader"; +import { TextInput } from "~~/components/punk-society/TextInput"; const Create = ({ onClose }: { onClose: any }) => { const [description, setDescription] = useState(""); @@ -53,13 +51,10 @@ const Create = ({ onClose }: { onClose: any }) => { />
- +
- {/* JSON Viewer */} - {/* */} - { date?: string; } -const defaultProfilePicture = "/guest-profile.jpg"; - const ProfilePage: NextPage = () => { - const [username, setUsername] = useState(""); - const [bio, setBio] = useState(""); - const [profilePicture, setProfilePicture] = useState(""); - const [isEditing, setIsEditing] = useState(false); // New state for edit mode const [posts, setPosts] = useState([]); const [loading, setLoading] = useState(true); const [loadingMore, setLoadingMore] = useState(true); const [page, setPage] = useState(1); // Start from page 1 to get the last post first - const [loadingProfile, setLoadingProfile] = useState(true); const [activeTab, setActiveTab] = useState("Minted"); + const [isEditing, setIsEditing] = useState(false); // New state for edit mode + const [isAnimating, setIsAnimating] = useState(false); + + const closeModal = () => { + setIsAnimating(true); + setTimeout(() => { + setIsAnimating(false); + setIsEditing(false); + }, 300); // Adjust the timeout to match your animation duration + }; const handleTabClick = (tab: any) => { setActiveTab(tab); @@ -43,6 +47,8 @@ const ProfilePage: NextPage = () => { const observer = useRef(null); + const defaultProfilePicture = "/guest-profile.jpg"; + const { address: connectedAddress } = useAccount(); const pathname = usePathname(); @@ -55,8 +61,6 @@ const ProfilePage: NextPage = () => { watch: true, }); - const { writeContractAsync: punkProfileWriteAsync } = useScaffoldWriteContract("PunkProfile"); - const { data: createEvents, // isLoading: createIsLoadingEvents, @@ -68,29 +72,6 @@ const ProfilePage: NextPage = () => { watch: true, }); - const handleEditProfile = async () => { - try { - // Check if the current profile picture is the default one - if (profilePicture === defaultProfilePicture) { - // Unset the current profile picture before editing the profile - setProfilePicture(""); - } - - await punkProfileWriteAsync({ - functionName: "setProfile", - args: [username, bio, profilePicture], - }); - - notification.success("Profile Edited Successfully"); - setIsEditing(false); - } catch (error) { - console.error("Error during editing profile:", error); - - // Log the error and notify the user - notification.error("Editing profile, please try again."); - } - }; - const fetchPosts = useCallback( async (page: number) => { if (!createEvents) return; @@ -164,15 +145,6 @@ const ProfilePage: NextPage = () => { [loadingMore], ); - useEffect(() => { - if (!isEditing && punkProfile) { - setUsername(punkProfile[0] || ""); - setBio(punkProfile[1] || ""); - setProfilePicture(punkProfile[2] ? punkProfile[2] : defaultProfilePicture); - setLoadingProfile(false); - } - }, [punkProfile, isEditing]); - // Ensure the address is available before rendering the component if (!address) { return

Inexistent address, try again...

; @@ -190,83 +162,65 @@ const ProfilePage: NextPage = () => { <>
{/* User Profile Section */} - {loadingProfile ? ( -
-
- -
-
- ) : ( -
- {/* Profile Picture */} -
- + {/* Profile Picture */} +
+ {/* -
- {/* User Info Section */} -
- {isEditing ? ( - - ) : ( - <> -

{username || "Guest user"}

- - {bio &&

{bio}

} - -
-
-
-
- Balance: - -
-
-
- - )} -
- {/* Div to align info in the center */} -
- {/* User Bio */}{" "} - {isEditing ? ( -
- <> - - -
- ) : ( - <> + /> */} + Profile Picture +
+ {/* User Info Section */} +
+ {(isEditing || isAnimating) && ( + + + )} - {/* Edit/Cancel Button */} - {address === connectedAddress && ( - <> - {isEditing ? ( - - ) : ( - - )} - {isEditing && ( -
- + + <> +

{punkProfile?.[0] || "Guest user"}

+ + {punkProfile?.[1] &&

{punkProfile?.[1]}

} + +
+
+
+
+ Balance: +
- )} - - )} +
+
+
- )} +
+ + {/* Edit/Cancel Button */} + {address === connectedAddress && ( + <> + {isEditing ? ( + + ) : ( + + )} + {isEditing &&
} + + )} +
{/* {loading && } */} diff --git a/packages/nextjs/app/profile/_components/EditProfile.tsx b/packages/nextjs/app/profile/_components/EditProfile.tsx new file mode 100644 index 0000000..507ebcc --- /dev/null +++ b/packages/nextjs/app/profile/_components/EditProfile.tsx @@ -0,0 +1,83 @@ +"use client"; + +import { useEffect, useState } from "react"; +import ProfilePictureUpload from "./ProfilePictureUpload"; +import { useAccount } from "wagmi"; +import { TextInput } from "~~/components/punk-society/TextInput"; +import { InputBase } from "~~/components/scaffold-eth"; +import { useScaffoldReadContract, useScaffoldWriteContract } from "~~/hooks/scaffold-eth"; +import { notification } from "~~/utils/scaffold-eth"; + +const EditProfile = () => { + const [username, setUsername] = useState(""); + const [bio, setBio] = useState(""); + const [profilePicture, setProfilePicture] = useState(""); + + const defaultProfilePicture = "/guest-profile.jpg"; + + const { address: connectedAddress } = useAccount(); + + const { writeContractAsync: punkProfileWriteAsync } = useScaffoldWriteContract("PunkProfile"); + + const { data: punkProfile } = useScaffoldReadContract({ + contractName: "PunkProfile", + functionName: "profiles", + args: [connectedAddress], + watch: true, + }); + + useEffect(() => { + if (punkProfile) { + setUsername(punkProfile?.[0] ? punkProfile?.[0] : ""); + setBio(punkProfile?.[1] ? punkProfile?.[1] : ""); + setProfilePicture(punkProfile?.[2] ? punkProfile?.[2] : ""); + } + }, [punkProfile]); + + const handleEditProfile = async () => { + try { + // Check if the current profile picture is the default one + if (profilePicture === defaultProfilePicture) { + // Unset the current profile picture before editing the profile + setProfilePicture(""); + } + + await punkProfileWriteAsync({ + functionName: "setProfile", + args: [username, bio, profilePicture], + }); + + notification.success("Profile Edited Successfully"); + window.location.reload(); + } catch (error) { + console.error("Error during editing profile:", error); + + // Log the error and notify the user + notification.error("Editing profile, please try again."); + } + }; + + return ( + <> +
+
+
+

Edit your profile info

+ + + + +
+
+
+ + ); +}; + +export default EditProfile; diff --git a/packages/nextjs/app/roadmap/Roadmap.tsx b/packages/nextjs/app/roadmap/Roadmap.tsx index 74f3e2c..3a154bf 100644 --- a/packages/nextjs/app/roadmap/Roadmap.tsx +++ b/packages/nextjs/app/roadmap/Roadmap.tsx @@ -89,10 +89,8 @@ export const Roadmap = () => { Enable following users, liking, commenting and sharing posts
  • - Incentive model: Likes and comments send $ to the user on the other end -
  • -
  • - Posting and interactions send a fee to PunkSociety + Incentive model: Likes and comments send $ to the user on the other end. Posting sends + $ to PunkSociety's deployer.
  • Dynamic page to view individual posts diff --git a/packages/nextjs/components/Footer.tsx b/packages/nextjs/components/Footer.tsx index de49010..2bf2703 100644 --- a/packages/nextjs/components/Footer.tsx +++ b/packages/nextjs/components/Footer.tsx @@ -2,10 +2,10 @@ import React, { useEffect, useState } from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import Create from "../app/create/Create"; -import Modal from "../app/create/Modal"; import { useAccount } from "wagmi"; import { HeartIcon } from "@heroicons/react/24/outline"; import { BellIcon, EnvelopeIcon, HomeIcon, MagnifyingGlassIcon, PlusIcon } from "@heroicons/react/24/solid"; +import Modal from "~~/components/punk-society/Modal"; import { useScaffoldReadContract } from "~~/hooks/scaffold-eth"; export const Footer = () => { diff --git a/packages/nextjs/components/Header.tsx b/packages/nextjs/components/Header.tsx index 74c7086..4fac4b8 100644 --- a/packages/nextjs/components/Header.tsx +++ b/packages/nextjs/components/Header.tsx @@ -110,9 +110,7 @@ export const Header = () => {
  • - {/*
    */} - -
    +
    diff --git a/packages/nextjs/app/create/_components/ImageUploader.tsx b/packages/nextjs/components/punk-society/ImageUploader.tsx similarity index 100% rename from packages/nextjs/app/create/_components/ImageUploader.tsx rename to packages/nextjs/components/punk-society/ImageUploader.tsx diff --git a/packages/nextjs/app/create/Modal.tsx b/packages/nextjs/components/punk-society/Modal.tsx similarity index 100% rename from packages/nextjs/app/create/Modal.tsx rename to packages/nextjs/components/punk-society/Modal.tsx diff --git a/packages/nextjs/app/create/_components/TextInput.tsx b/packages/nextjs/components/punk-society/TextInput.tsx similarity index 94% rename from packages/nextjs/app/create/_components/TextInput.tsx rename to packages/nextjs/components/punk-society/TextInput.tsx index cb4483d..4070e14 100644 --- a/packages/nextjs/app/create/_components/TextInput.tsx +++ b/packages/nextjs/components/punk-society/TextInput.tsx @@ -2,6 +2,7 @@ import { ChangeEvent, FocusEvent, ReactNode, useCallback, useEffect, useRef } fr interface TextInputProps { description: string; + placeholder: string; setDescription: (desc: string) => void; error?: boolean; prefix?: ReactNode; @@ -10,6 +11,7 @@ interface TextInputProps { } export const TextInput: React.FC = ({ + placeholder, description, setDescription, error, @@ -47,7 +49,7 @@ export const TextInput: React.FC = ({ {prefix}