Skip to content

Commit

Permalink
UI improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
luloxi committed Oct 19, 2024
1 parent c66280e commit 7a5aa01
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 130 deletions.
46 changes: 19 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
A social dapp where interactions are free, and mints are monetized 💰, allowing users to earn through engaging with their community 🫂.
A social dapp where interactions are monetized 💰, allowing users to earn through engaging with their community 🫂.

# 🤘 Features

- 🤹‍♂️ **Post types**: Posts can have text, image, audio, video, links and polls
- 💰 **Monetization of Posts**: Users can mint each other posts as NFTs while paying to the original creator.
- 🥇 **First minter incentive**: First minters of a post, if not the creator, earn a share of the earnings from succesive mints.
- 💰 **Social monetization**: Likes, comments, shares and follows send USDC to the user on the other end
- 📈 **Revenue dashboard**: Users can track and analyze their earnings
- 🔔 **Notifications**: Receive alerts on activity
- 💌 **Messaging**: Direct messaging and group chat features
- 🎨 **Profile customization**: Users can customize their profile and post collections
- 📱 **Web 2.5 login**: Social login options with Web2 platforms (Google, Twitter, etc.)
- 🌐 **Multi-chain support**: Interact with the platform on multiple chains
- 🌐 **Multi-chain support**: Bridge your posts as NFTs to Avalanche L0 and other chains to access NFT markets
- 🎧 **Accessibility support**: ARIA compliant for screen readers and other assistive technologies

# 🤘 Roadmap
Expand All @@ -19,37 +18,31 @@ A social dapp where interactions are free, and mints are monetized 💰, allowin

-**Create PunkPosts contract**
-**Create PunkProfile contract to register users info and socials**
-**PunkSociety contract:** Social interactions
-**Post creation tool**
-**User profile page**

## 👥 Phase 2 (Social Activity and Indexing)

-**PunkSociety contract:** Social interactions
-**Search**: By address or username
- ✅ Enable options for sharing on other platforms
- **Incentive model**: Social interactions send $ to the user that posted
- **Revenue Model**: PunkSociety collects fees from interactions
- Enable following users, liking, commenting and sharing posts on frontend
- **Notification system**
- **USDC payment method:** Bridge USDC from Avalanche to PunkSociety L1 and use it as native gas and payment method for social interactions (Reference: [Create an Avalanche L1](https://docs.avax.network/tooling/create-deploy-avalanche-l1s/create-avalanche-l1))
- **Multi-chain support**: Allow users to bridge their posts as NFTs to other chains (Reference: [Interchain Token Transfer](https://academy.avax.network/course/interchain-token-transfer/02-avalanche-starter-kit/01-avalanche-starter-kit) | [Chainlink CCIP Cross Chain Tokens](https://docs.chain.link/ccip/tutorials/cross-chain-tokens))
- **Individual post viewer**
- **Integrate The Graph to index activity** and save RPC calls (Reference: [Bootstrap a Full Stack Modern dapp using the Scaffold-ETH CLI and Subgraph Extension](https://siddhantk08.hashnode.dev/bootstrap-a-full-stack-modern-dapp-using-the-scaffold-eth-cli-and-subgraph-extension) | [The Graph tool for creating a subgraph](https://thegraph.com/docs/en/developing/creating-a-subgraph/))

## 💌 Phase 3 (Direct messages)

- **Direct messages:** Allow users to send private messages to each other
## 👥 Phase 2 (Indexing and Bridging)

## ✍️ Phase 4 (Gasless activity)

- **Signatures:** Interact with the platform without paying gas fees
- **Database:** To store and retrieve EIP 712 signatures (Reference: [SE-2 firebase-auth-extension](https://github.com/ByteAtATime/firebase-auth-extension))
- **Built-in bridge manager**: Built-in simple tool for bridging USDC and NFTs to Avalanche L0 and other EVM chains
- **Easy onramp tool**: Easy USDC buying and bridging tool for onboarding new users. (Reference:[FundButton from Coinbase](https://onchainkit.xyz/fund/fund-button) | [OnchainKit extension for Scaffold-ETH 2](https://github.com/scaffold-eth/create-eth-extensions/tree/onchainkit))
- **Integrate The Graph to index activity** and save RPC calls (Reference: [Bootstrap a Full Stack Modern dapp using the Scaffold-ETH CLI and Subgraph Extension](https://siddhantk08.hashnode.dev/bootstrap-a-full-stack-modern-dapp-using-the-scaffold-eth-cli-and-subgraph-extension) | [The Graph tool for creating a subgraph](https://thegraph.com/docs/en/developing/creating-a-subgraph/))
- **Dashboard Insights**: Track and analyze revenue
- **Notification system**

## 🍀 Phase 5 (Incentivized socials)
## 💌 Phase 3 (Direct messages)

- **Incentive model**: Post mints send $ to the user that posted
- **Multiple payment methods:** Pay with native gas or with `$USDC`, and also with `$PUNKS` for a discount. (Reference: [Easy2Pay](https://github.com/luloxi/Easy2Pay))
- **Built-in wallet manager**: Built-in simple wallet for sending supported tokens and receiving funds, generating and scanning QR, buying gas, etc (Reference: [PunkWallet](https://app.buidlguidl.com/build/mTKhXMLEOCQEgPgG57R9) | [FundButton from Coinbase](https://onchainkit.xyz/fund/fund-button) [OnchainKit extension for Scaffold-ETH 2](https://github.com/scaffold-eth/create-eth-extensions/tree/onchainkit))
- **Dashboard Insights**: Track and analyze revenue
- **Revenue Model**: PunkSociety collects fees from mints
- **Direct messages:** Allow users to send private messages to each other (Reference [Push Protocol](https://push.org/))

## 💬 Phase 6 (Social enhancement)
## 💬 Phase 4 (Social enhancement)

- Enable audio, video and links with preview type of posts
- **Polls**: Allow users to create polls
Expand All @@ -58,12 +51,11 @@ A social dapp where interactions are free, and mints are monetized 💰, allowin
- **Groups**: Allow users to create and join groups with custom chat and newfeed
- **Categories**: Allow users to categorize their posts, filter by category and search by category

## 👨‍🦽 Phase 7 (Ease of use)
## 👨‍🦽 Phase 5 (Ease of use)

- **Account abstraction**: Interact with the platform without flooding your NFT collections with social posts or having to sign for every interaction.
- **Multi-chain support**: Allow users to interact with the platform on multiple chains
- **Accesibility support**: For the hearing and visually impaired, the app should be ARIA compliant to support screen readers and other assistive technologies (Reference: [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA))
- **Web 2.5 social login:** Sign up and log in with Google, Twitter, Instagram, etc
- **Account abstraction**: Interact with the platform without flooding your NFT collections with social posts or having to sign for every interaction.
- **Multi-language support**: Switch between languages
- **Educational Content**: Include onboarding tutorials and step-by-step guides to help users understand NFTs and Web3 concepts

Expand Down
24 changes: 6 additions & 18 deletions packages/nextjs/app/profile/[address]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import ProfilePictureUpload from "../_components/ProfilePictureUpload";
import { NextPage } from "next";
import { useAccount } from "wagmi";
import { PencilIcon } from "@heroicons/react/24/outline";
import { Address, RainbowKitCustomConnectButton } from "~~/components/scaffold-eth";
import { Address } from "~~/components/scaffold-eth";
import { InputBase } from "~~/components/scaffold-eth";
import { useScaffoldEventHistory, useScaffoldReadContract, useScaffoldWriteContract } from "~~/hooks/scaffold-eth";
import { notification } from "~~/utils/scaffold-eth";
Expand Down Expand Up @@ -217,21 +217,9 @@ const ProfilePage: NextPage = () => {
{bio && <p className="text-base-content">{bio}</p>}

<div className="mt-2">
{address == connectedAddress ? (
<div className="flex flex-col md:flex-row items-center justify-center gap-3">
<div>
<RainbowKitCustomConnectButton />
</div>

<button className="btn btn-primary bg-red-600 hover:bg-red-700 text-white border-0">
+ Add funds
</button>
</div>
) : (
<div className="text-base-content">
<Address address={address} />
</div>
)}
<div className="text-base-content">
<Address address={address} />
</div>
</div>
</>
)}
Expand Down Expand Up @@ -287,13 +275,13 @@ const ProfilePage: NextPage = () => {
Featured
</button>
<button className={`tab ${activeTab === "Minted" ? "active" : ""}`} onClick={() => handleTabClick("Minted")}>
Minted
Shared
</button>
<button
className={`tab text-red-600 ${activeTab === "Shared" ? "active" : ""}`}
onClick={() => handleTabClick("Shared")}
>
Shared
Liked
</button>
<button
className={`tab text-red-600 ${activeTab === "Revenue" ? "active" : ""}`}
Expand Down
8 changes: 4 additions & 4 deletions packages/nextjs/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const Header = () => {
}`}
>
<div className="flex flex-row items-center justify-center gap-2">
<HomeIcon className="h-6 w-6" />
<HomeIcon className="h-6 w-6" /> Home
</div>
</button>
</Link>
Expand All @@ -66,7 +66,7 @@ export const Header = () => {
}`}
>
<div className="flex flex-row items-center justify-center gap-2">
<MagnifyingGlassIcon className="h-6 w-6" />
<MagnifyingGlassIcon className="h-6 w-6" /> Search
</div>
</button>
</Link>
Expand All @@ -78,7 +78,7 @@ export const Header = () => {
}`}
>
<div className="flex flex-row items-center justify-center gap-2">
<BellIcon className="h-6 w-6" />
<BellIcon className="h-6 w-6" /> Notifications
</div>
</button>
</Link>
Expand All @@ -90,7 +90,7 @@ export const Header = () => {
}`}
>
<div className="flex flex-row items-center justify-center gap-2">
<EnvelopeIcon className="h-6 w-6" />
<EnvelopeIcon className="h-6 w-6" /> Messages
</div>
</button>
</Link>
Expand Down
9 changes: 2 additions & 7 deletions packages/nextjs/components/punk-society/PostCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
ChatBubbleLeftIcon,
MagnifyingGlassPlusIcon,
ShareIcon,
ShoppingCartIcon,
XMarkIcon,
} from "@heroicons/react/24/outline";
import { ChatBubbleLeftIcon as ChatBubbleLeftSolidIcon } from "@heroicons/react/24/solid";
Expand Down Expand Up @@ -110,14 +109,10 @@ export const PostCard = ({ post, isGrid }: { post: Post; isGrid: boolean }) => {
<button className="icon-button">
<ArrowPathRoundedSquareIcon className="repost-icon text-red-600" />
</button>
<button onClick={handleShare} className="icon-button">
<ShareIcon className="repost-icon " />
</button>
</div>
<div className="flex items-center gap-3">
<button className="px-4 py-2 rounded-lg bg-red-600 text-white">Mint</button>
<button className="p-2 rounded-full bg-red-600 text-white">
<ShoppingCartIcon className="h-5 w-5" />
<button onClick={handleShare} className="icon-button">
<ShareIcon className="repost-icon " />
</button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import CopyToClipboard from "react-copy-to-clipboard";
import { getAddress } from "viem";
import { Address } from "viem";
import { useDisconnect } from "wagmi";
import { KeyIcon, LanguageIcon } from "@heroicons/react/20/solid";
import {
ArrowLeftOnRectangleIcon,
ArrowTopRightOnSquareIcon,
Expand Down Expand Up @@ -98,6 +99,12 @@ export const AddressInfoDropdown = ({
<span className="whitespace-nowrap">View QR Code</span>
</label>
</li>
<li className={selectingNetwork ? "hidden" : ""}>
<label htmlFor="private-key-modal" className="btn-sm !rounded-xl flex gap-3 py-3">
<KeyIcon className="h-6 w-4 ml-2 sm:ml-0" />
<span className="whitespace-nowrap">View Private Key</span>
</label>
</li>
<li className={selectingNetwork ? "hidden" : ""}>
<button className="menu-item btn-sm !rounded-xl flex gap-3 py-3" type="button">
<ArrowTopRightOnSquareIcon className="h-6 w-4 ml-2 sm:ml-0" />
Expand All @@ -111,6 +118,12 @@ export const AddressInfoDropdown = ({
</a>
</button>
</li>
<li className={selectingNetwork ? "hidden" : ""}>
<label htmlFor="switch-language-modal" className="btn-sm !rounded-xl flex gap-3 py-3">
<LanguageIcon className="h-6 w-4 ml-2 sm:ml-0" />
<span className="whitespace-nowrap">Switch languages</span>
</label>
</li>
{allowedNetworks.length > 1 ? (
<li className={selectingNetwork ? "hidden" : ""}>
<button
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useEffect, useState } from "react";
import { notification } from "~~/utils/scaffold-eth";

type AddressQRCodeModalProps = {
modalId: string;
};

export const PrivateKeyModal = ({ modalId }: AddressQRCodeModalProps) => {
const [privateKey, setPrivateKey] = useState<string | null>(null);

useEffect(() => {
const storedPrivateKey = localStorage.getItem("burnerWallet.pk");
setPrivateKey(storedPrivateKey);
}, []);

const handleCopy = () => {
if (privateKey) {
navigator.clipboard
.writeText(privateKey)
.then(() => {
notification.success("Private key copied to clipboard");
// alert("Private key copied to clipboard");
})
.catch(err => {
notification.error("Failed to copy private key: ", err);
});
}
};

return (
<>
<div>
<input type="checkbox" id={`${modalId}`} className="modal-toggle" />
<label htmlFor={`${modalId}`} className="modal cursor-pointer">
<label className="modal-box relative" htmlFor="">
<div className="flex flex-col justify-center items-center text-center">
<h2 className="text-xl font-bold mb-4">Your Private Key</h2>
<div className="break-words whitespace-pre-wrap text-red-600 font-bold text-center w-full">
Save this into a safe place and don&apos;t share it with anyone.
</div>
<div className="break-words whitespace-pre-wrap text-red-600 font-bold mt-4 text-center w-full">
This is the only way to recover your account and funds, and it can&apos;t be changed or retrieved by
PunkSociety team.
</div>
<div className="break-words whitespace-pre-wrap mt-4 text-left w-full">{privateKey}</div>
<button
onClick={handleCopy}
className="btn btn-primary bg-green-600 hover:bg-green-500 active:bg-green-500 mt-4"
>
Copy Private Key
</button>
</div>
<label
htmlFor={`${modalId}`}
className="btn text-xl rounded-full bg-red-600 hover:bg-red-500 btn-ghost btn-sm btn-circle absolute right-3 top-3"
>
</label>
</label>
</label>
</div>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Image from "next/image";

type AddressQRCodeModalProps = {
modalId: string;
};

export const SwitchLanguageModal = ({ modalId }: AddressQRCodeModalProps) => {
const handleLearnEnglishClick = () => {
window.open("https://www.duolingo.com/", "_blank");
};
return (
<>
<div>
<input type="checkbox" id={`${modalId}`} className="modal-toggle" />
<label htmlFor={`${modalId}`} className="modal cursor-pointer">
<label className="modal-box relative" htmlFor="">
<div className="flex flex-col justify-center items-center text-center">
<h2 className="text-xl font-bold mb-4 text-red-600">Sorry, we don&apos;t have other languages yet.</h2>
<button
onClick={handleLearnEnglishClick}
className="btn btn-primary border-0 flex items-center hover:bg-green-600 active:bg-green-600"
>
<Image src="/duolingo.gif" alt="Duolingo" width={60} height={60} className="mr-2" />
Learn English in Duolingo!
</button>
<label
htmlFor={`${modalId}`}
className="btn text-xl rounded-full bg-red-600 hover:bg-red-500 btn-ghost btn-sm btn-circle absolute right-3 top-3"
>
</label>
</div>
</label>
</label>
</div>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// @refresh reset
import { AddressInfoDropdown } from "./AddressInfoDropdown";
import { AddressQRCodeModal } from "./AddressQRCodeModal";
import { PrivateKeyModal } from "./PrivateKeyModal";
import { SwitchLanguageModal } from "./SwitchLanguageModal";
import { WrongNetworkDropdown } from "./WrongNetworkDropdown";
import { ConnectButton } from "@rainbow-me/rainbowkit";
import { Address } from "viem";
Expand Down Expand Up @@ -53,6 +55,8 @@ export const PunkConnectButton = () => {
blockExplorerAddressLink={blockExplorerAddressLink}
/>
<AddressQRCodeModal address={account.address as Address} modalId="qrcode-modal" />
<PrivateKeyModal modalId="private-key-modal" />
<SwitchLanguageModal modalId="switch-language-modal" />
</>
);
})()}
Expand Down
Binary file added packages/nextjs/public/duolingo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 7a5aa01

Please sign in to comment.