Skip to content

Commit

Permalink
style: restyle song component. add link to temp page for song compone…
Browse files Browse the repository at this point in the history
…nt (link to artist profile in future)
  • Loading branch information
RafaelCaso committed Sep 19, 2024
1 parent eae5ccd commit 4f3a8c8
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 45 deletions.
64 changes: 44 additions & 20 deletions packages/nextjs/app/listen/_components/Song.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { useEffect, useRef, useState } from "react";
import { useRouter } from "next/navigation";
import { Howl } from "howler";
import { Address } from "~~/components/scaffold-eth";
import { Avatar } from "~~/components/scaffold-eth/Avatar";

interface SongProps {
songCID: string;
Expand All @@ -8,19 +11,17 @@ interface SongProps {

const Song: React.FC<SongProps> = ({ songCID, metadataCID }) => {
const [isPlaying, setIsPlaying] = useState(false);
const [metadata, setMetadata] = useState<{ title?: string; artist?: string; genre?: string; uploadTime?: string }>(
{},
);
const [metadata, setMetadata] = useState<{
title?: string;
artist?: string;
genre?: string;
uploadTime?: string;
artistAddress?: string;
}>({});
const howlerRef = useRef<Howl | null>(null);
const router = useRouter();

// const testTime = 1726665533;
// const testDate = new Date(testTime * 1000);
// const formattedDate = testDate.toString();
// console.log(formattedDate);

// Using useEffect to initialize the song and Howler.js
useEffect(() => {
// Since `metadataCID` is already an object, parse and set metadata directly
const meta = JSON.parse(metadataCID);
const humanReadableTime = new Date(meta.uploadTime * 1000).toString();
meta.uploadTime = humanReadableTime;
Expand Down Expand Up @@ -49,32 +50,55 @@ const Song: React.FC<SongProps> = ({ songCID, metadataCID }) => {
}
};

const handleClick = () => {
router.push("/");
};

return (
<div className="flex items-center bg-gray-800 text-white p-4 rounded-lg shadow-lg my-4 w-2/3 mx-auto">
<div
onClick={handleClick}
className="flex items-center bg-gray-800 text-white p-4 rounded-lg shadow-lg my-4 w-2/3 mx-auto transition-transform duration-300 transform hover:scale-105 hover:bg-gray-700 cursor-pointer"
>
{/* Play/Pause Button */}
<button
onClick={togglePlay}
onClick={e => {
e.stopPropagation();
togglePlay();
}}
className="w-10 h-10 bg-gray-600 rounded-full flex items-center justify-center focus:outline-none mr-4"
>
{isPlaying ? <span className="material-icons">pause</span> : <span className="material-icons">play</span>}
</button>

{/* Song Info */}
<div className="flex-1">
{/* Use title, artist, and genre from the metadata */}
<p className="text-lg font-semibold">{metadata.title || "Unknown Track"}</p>
<p className="text-sm">{metadata.artist || "Unknown Artist"}</p>
<p className="text-sm italic">{metadata.genre || "Unknown Genre"}</p>
<p className="text-sm italic">{metadata.uploadTime || "Unknown Date"}</p>
{/* Title */}
<div className="flex items-center">
<p className="text-lg font-semibold">{metadata.title || "Unknown Track"}</p>
</div>

{/* Genre and Upload Time */}
<div className="flex flex-col mt-2">
<p className="text-sm italic">{metadata.genre || "Unknown Genre"}</p>
<p className="text-sm italic">{metadata.uploadTime || "Unknown Date"}</p>
</div>

{/* Placeholder for waveform visualization */}
<div className="relative mt-2 w-full h-2 bg-gray-700 rounded-full overflow-hidden">
<div className="absolute top-0 left-0 h-full bg-orange-500" style={{ width: "50%" }}></div>
</div>
</div>

{/* Graphic or album art placeholder */}
<div className="w-12 h-12 bg-gray-700 rounded-lg ml-4"></div>
<div className="flex flex-col items-center justify-center">
{/* Artist Name */}
<p className="text-lg font-semibold">{metadata.artist || "Unknown Artist"}</p>

{/* Avatar */}
<Avatar address={metadata.artistAddress} size="10xl" />

<div className="mt-2">
<Address address={metadata.artistAddress} />
</div>
</div>
</div>
);
};
Expand Down
3 changes: 0 additions & 3 deletions packages/nextjs/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ const Home: NextPage = () => {
functionName: "registerAccount",
args: [artistName],
});

console.log(txHash);
};

if (!isRegisteredError) {
Expand Down Expand Up @@ -94,7 +92,6 @@ const Home: NextPage = () => {
Register
</button>
</div>
<Link href="/listen">Listen</Link>
</div>
)}
</>
Expand Down
1 change: 1 addition & 0 deletions packages/nextjs/app/upload/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ const UploadMusic: React.FC = () => {
genre: genre.toLowerCase(),
fileUrl: fileIpfsUrl,
uploadTime: unixTimeStamp,
artistAddress: connectedAddress,
};

// Upload metadata to IPFS
Expand Down
40 changes: 18 additions & 22 deletions packages/nextjs/components/scaffold-eth/Address.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
"use client";

import { useEffect, useState } from "react";
import Link from "next/link";
import { CopyToClipboard } from "react-copy-to-clipboard";
Expand Down Expand Up @@ -29,9 +27,6 @@ const blockieSizeMap = {
"3xl": 15,
};

/**
* Displays an address (or ENS) with a Blockie image and option to copy address.
*/
export const Address = ({ address, disableAddressLink, format, size = "base" }: AddressProps) => {
const [ens, setEns] = useState<string | null>();
const [ensAvatar, setEnsAvatar] = useState<string | null>();
Expand All @@ -47,6 +42,7 @@ export const Address = ({ address, disableAddressLink, format, size = "base" }:
enabled: isAddress(checkSumAddress ?? ""),
},
});

const { data: fetchedEnsAvatar } = useEnsAvatar({
name: fetchedEns ? normalize(fetchedEns) : undefined,
chainId: 1,
Expand All @@ -56,7 +52,6 @@ export const Address = ({ address, disableAddressLink, format, size = "base" }:
},
});

// We need to apply this pattern to avoid Hydration errors.
useEffect(() => {
setEns(fetchedEns);
}, [fetchedEns]);
Expand All @@ -65,10 +60,9 @@ export const Address = ({ address, disableAddressLink, format, size = "base" }:
setEnsAvatar(fetchedEnsAvatar);
}, [fetchedEnsAvatar]);

// Skeleton UI
if (!checkSumAddress) {
return (
<div className="animate-pulse flex space-x-4">
<div className="animate-pulse flex space-x-4 mt-2">
<div className="rounded-md bg-slate-300 h-6 w-6"></div>
<div className="flex items-center space-y-6">
<div className="h-2 w-28 bg-slate-300 rounded"></div>
Expand All @@ -90,6 +84,14 @@ export const Address = ({ address, disableAddressLink, format, size = "base" }:
displayAddress = checkSumAddress;
}

const handleCopyClick = (e: React.MouseEvent) => {
e.stopPropagation(); // Prevent navigation
setAddressCopied(true);
setTimeout(() => {
setAddressCopied(false);
}, 800);
};

return (
<div className="flex items-center flex-shrink-0">
<div className="flex-shrink-0">
Expand Down Expand Up @@ -121,20 +123,14 @@ export const Address = ({ address, disableAddressLink, format, size = "base" }:
aria-hidden="true"
/>
) : (
<CopyToClipboard
text={checkSumAddress}
onCopy={() => {
setAddressCopied(true);
setTimeout(() => {
setAddressCopied(false);
}, 800);
}}
>
<DocumentDuplicateIcon
className="ml-1.5 text-xl font-normal text-sky-600 h-5 w-5 cursor-pointer flex-shrink-0"
aria-hidden="true"
/>
</CopyToClipboard>
<span onClick={handleCopyClick}>
<CopyToClipboard text={checkSumAddress}>
<DocumentDuplicateIcon
className="ml-1.5 text-xl font-normal text-sky-600 h-5 w-5 cursor-pointer flex-shrink-0"
aria-hidden="true"
/>
</CopyToClipboard>
</span>
)}
</div>
);
Expand Down
75 changes: 75 additions & 0 deletions packages/nextjs/components/scaffold-eth/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { useEffect, useState } from "react";
import { getAddress } from "viem";
import { useEnsAvatar, useEnsName } from "wagmi";
import { BlockieAvatar } from "~~/components/scaffold-eth";

type AvatarProps = {
address?: string;
size?: "xs" | "sm" | "base" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl" | "7xl" | "8xl" | "9xl" | "10xl";
};

const blockieSizeMap = {
xs: 6,
sm: 7,
base: 8,
lg: 9,
xl: 10,
"2xl": 12,
"3xl": 15,
"4xl": 18,
"5xl": 21,
"6xl": 24,
"7xl": 27,
"8xl": 30,
"9xl": 33,
"10xl": 40,
};
export const Avatar = ({ address, size = "base" }: AvatarProps) => {
if (!address) {
return <div className="w-12 h-12 bg-gray-700 rounded-lg" />;
}

const [ensName, setEnsName] = useState<string | null>(null);
const [ensAvatar, setEnsAvatar] = useState<string | null>(null);
const checkSumAddress = getAddress(address);

// Fetch ENS name associated with the address
const { data: fetchedEnsName } = useEnsName({
address: checkSumAddress,
chainId: 1, // Mainnet for ENS lookups
});

// Fetch ENS avatar using the ENS name
const { data: fetchedEnsAvatar } = useEnsAvatar({
name: fetchedEnsName || undefined, // Pass ENS name to get avatar
chainId: 1,
});

// Update the ENS name and avatar when fetched
useEffect(() => {
setEnsName(fetchedEnsName ?? null);
}, [fetchedEnsName]);

useEffect(() => {
setEnsAvatar(fetchedEnsAvatar ?? null);
}, [fetchedEnsAvatar]);

return (
<div className="flex items-center">
{/* Display ENS avatar if available, otherwise fallback to blockie */}
{ensAvatar ? (
<img
src={ensAvatar}
alt="ENS Avatar"
className="rounded-full w-12 h-12"
style={{
width: `${(blockieSizeMap[size] * 24) / blockieSizeMap["base"]}px`,
height: `${(blockieSizeMap[size] * 24) / blockieSizeMap["base"]}px`,
}}
/>
) : (
<BlockieAvatar address={checkSumAddress} size={(blockieSizeMap[size] * 24) / blockieSizeMap["base"]} />
)}
</div>
);
};

0 comments on commit 4f3a8c8

Please sign in to comment.