Skip to content

Commit cd7a3d5

Browse files
committed
Added features from PunkSOciety and improved README
1 parent 1ce5fa5 commit cd7a3d5

20 files changed

+630
-79
lines changed

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ E-commerce dApp to sell products without intermediaries 💰
1515

1616
## 🐣 Phase 1 (MVP)
1717

18+
-**Integrate OnchainKit for Basenames and FundButton** (Reference: [OnchainKit](https://onchainkit.xyz/) | [OnchainKit extension for Scaffold-ETH 2](https://github.com/scaffold-eth/create-eth-extensions/tree/onchainkit))
1819
-**BasedArticles contract:** To register articles info
1920
-**BasedProfile contract:** To register users bio and email
2021
-**BasedShop contract:** To manage products and sales
@@ -23,11 +24,10 @@ E-commerce dApp to sell products without intermediaries 💰
2324
- ✅ Enable options for sharing on other platforms
2425
- ✅ Enable bookmarking articles
2526
-**Search**: By address, ENS or basename
26-
-**Integrate OnchainKit** (Reference: [OnchainKit](https://onchainkit.xyz/)
27-
- **Individual article viewer**
2827

2928
## 💰 Phase 2 (Shop features)
3029

30+
- **Individual article viewer**
3131
- **Escrow system**: Hold funds until the buyer confirms the purchase
3232
- **Dashboard Insights**: Track and analyze revenue
3333
- **Stablecoin payment methods:** Pay with native gas or with `$USDC`. (Reference: [Easy2Pay](https://github.com/luloxi/Easy2Pay))
@@ -66,11 +66,15 @@ E-commerce dApp to sell products without intermediaries 💰
6666

6767
## 🛠️ Technical details
6868

69-
⚙️ Built using Foundry, NextJS, RainbowKit, Wagmi, Viem, and Typescript,
69+
⚙️ Currently built using [Scaffold-ETH 2](https://scaffoldeth.io/), [Foundry](https://book.getfoundry.sh/), [OnchainKit](https://onchainkit.xyz/), [Pinata](https://pinata.cloud/), [Vercel](https://vercel.com/), [NextJS](https://nextjs.org/), [RainbowKit](https://rainbowkit.com/), [Wagmi](https://wagmi.sh/), [Viem](https://viem.sh/), and [Typescript](https://www.typescriptlang.org/).
70+
71+
🏦 Considering using protocols: [Circle USDC](https://www.circle.com/) as preferredd ERC20 payment method, [The Graph](https://thegraph.com/) for indexing events, [Chainlink](https://chain.link/) for price oracles, [Push Protocol](https://push.org/) for notifications and messages.
72+
73+
📜 Considering using contracts: [ERC20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/) and [ERC721](https://ethereum.org/en/developers/docs/standards/tokens/erc-721/), [Ownable](https://docs.openzeppelin.com/contracts/2.x/access-control) and [Upgradeable](https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable) from [OpenZeppelin](https://www.openzeppelin.com/) or [Solady](https://github.com/Vectorized/solady) for contract ownership. [EIP712 Signatures](https://eips.ethereum.org/EIPS/eip-712) for gasless stuff.
7074

71-
🔗 To be deployed on Base and/or EVM compatible chains
75+
🔗 To be deployed on Base
7276

73-
📥 To see current development tasks, [see here](https://lulox.notion.site/BasedShop-11e13362a5748056b5bfe8bc5d4ff260?pvs=4)
77+
📥 To see current development tasks, [see here](https://trello.com/b/j1HVwxL7/basedshop)
7478

7579
## 📚 Prerequisites
7680

packages/nextjs/app/search/Search.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const Search = () => {
2121

2222
const handleSearch = async () => {
2323
if (!searchQuery) {
24-
setError("Please enter an address or username.");
24+
setError("Please enter an address, ENS or basename.");
2525
return;
2626
}
2727

@@ -45,13 +45,21 @@ export const Search = () => {
4545
}
4646
};
4747

48+
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
49+
if (event.key === "Enter") {
50+
handleSearch();
51+
}
52+
};
53+
4854
return (
4955
<div className="flex flex-col items-center justify-center min-h-screen gap-3">
50-
<AddressInput
51-
value={searchQuery}
52-
onChange={value => setSearchQuery(value.toLowerCase())}
53-
placeholder="username, ENS or address"
54-
/>
56+
<div onKeyDown={handleKeyDown}>
57+
<AddressInput
58+
value={searchQuery}
59+
onChange={value => setSearchQuery(value.toLowerCase())}
60+
placeholder="basename, ENS or address"
61+
/>
62+
</div>
5563
<button onClick={handleSearch} disabled={loading} className="btn btn-primary px-6">
5664
{loading ? <LoadingBars /> : "Go"}
5765
</button>

packages/nextjs/components/Header.tsx

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,16 @@ import React from "react";
44
import Link from "next/link";
55
import { usePathname } from "next/navigation";
66
import { SwitchTheme } from "./SwitchTheme";
7-
import { PunkBalance } from "./punk-society/PunkBalance";
8-
import { PunkConnectButton } from "./punk-society/PunkConnectButton";
7+
import { PunkConnectButton } from "./punk-society/BasedConnectButton";
8+
import { ConfigMenu } from "./punk-society/ConfigMenu";
99
import { FaucetButton } from "./scaffold-eth";
10-
import { useAccount } from "wagmi";
1110
import { ShoppingCartIcon } from "@heroicons/react/24/outline";
12-
import { BellIcon, HomeIcon, MagnifyingGlassIcon } from "@heroicons/react/24/solid";
11+
import { BellIcon, EnvelopeIcon, HomeIcon, MagnifyingGlassIcon } from "@heroicons/react/24/solid";
1312

1413
/**
1514
* Site header
1615
*/
1716
export const Header = () => {
18-
const { address: connectedAddress } = useAccount();
19-
2017
const pathname = usePathname();
2118

2219
return (
@@ -38,36 +35,48 @@ export const Header = () => {
3835
<div className="flex flex-row gap-3 ">
3936
<Link href="/" passHref>
4037
<button
41-
className={`bg-transparent hover:bg-base-200 border-none hidden lg:flex flex-row items-center justify-center text-xl ${
38+
className={`bg-transparent hover:bg-transparent border-none hidden lg:flex flex-row items-center justify-center text-xl ${
4239
pathname === "/" ? "text-blue-600" : ""
4340
}`}
4441
>
4542
<div className="flex flex-row items-center justify-center gap-2">
46-
<HomeIcon className="h-6 w-6" />
43+
<HomeIcon className="h-6 w-6" /> Home
4744
</div>
4845
</button>
4946
</Link>
5047

5148
<Link href="/search" passHref>
5249
<button
53-
className={`bg-transparent hover:bg-base-200 border-none hidden lg:flex flex-row items-center justify-center text-xl ${
50+
className={`bg-transparent hover:bg-bg-transparent border-none hidden lg:flex flex-row items-center justify-center text-xl ${
5451
pathname === "/search" ? "text-blue-600" : ""
5552
}`}
5653
>
5754
<div className="flex flex-row items-center justify-center gap-2">
58-
<MagnifyingGlassIcon className="h-6 w-6" />
55+
<MagnifyingGlassIcon className="h-6 w-6" /> Search
5956
</div>
6057
</button>
6158
</Link>
6259

6360
<Link href="/not-found" passHref>
6461
<button
65-
className={`bg-transparent text-red-600 hover:bg-base-200 border-none hidden lg:flex flex-row items-center justify-center text-xl ${
62+
className={`bg-transparent text-red-600 hover:bg-transparent border-none hidden lg:flex flex-row items-center justify-center text-xl ${
6663
pathname === "/notifications" ? "text-blue-600" : ""
6764
}`}
6865
>
6966
<div className="flex flex-row items-center justify-center gap-2">
70-
<BellIcon className="h-6 w-6" />
67+
<BellIcon className="h-6 w-6" /> Notifications
68+
</div>
69+
</button>
70+
</Link>
71+
72+
<Link href="/not-found" passHref>
73+
<button
74+
className={`bg-transparent text-red-600 hover:bg-transparent border-none hidden lg:flex flex-row items-center justify-center text-xl ${
75+
pathname === "/messages" ? "text-blue-600" : ""
76+
}`}
77+
>
78+
<div className="flex flex-row items-center justify-center gap-2">
79+
<EnvelopeIcon className="h-6 w-6" /> Messages
7180
</div>
7281
</button>
7382
</Link>
@@ -105,9 +114,9 @@ export const Header = () => {
105114
</button>
106115
</Link>
107116
</div>
108-
<div className="hidden md:flex">
117+
{/* <div className="hidden md:flex">
109118
<PunkBalance address={connectedAddress} />
110-
</div>
119+
</div> */}
111120

112121
<div className="flex items-center justify-center">
113122
<PunkConnectButton />
@@ -118,6 +127,9 @@ export const Header = () => {
118127
</div>
119128
</div>
120129
<div className="flex flex-row items-center justify-center gap-3">
130+
<div className="">
131+
<ConfigMenu />
132+
</div>
121133
<div className="hidden lg:flex ">
122134
<SwitchTheme />
123135
</div>

packages/nextjs/components/punk-society/PunkConnectButton/AddressInfoDropdown.tsx renamed to packages/nextjs/components/punk-society/BasedConnectButton/AddressInfoDropdown.tsx

Lines changed: 11 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
import { useRef, useState } from "react";
22
import Link from "next/link";
3+
import { PunkBalance } from "../PunkBalance";
34
import { NetworkOptions } from "./NetworkOptions";
45
import { FundButton, getOnrampBuyUrl } from "@coinbase/onchainkit/fund";
56
import { Avatar, Badge, Identity, Name } from "@coinbase/onchainkit/identity";
6-
import CopyToClipboard from "react-copy-to-clipboard";
7-
import { getAddress } from "viem";
87
import { Address } from "viem";
98
import { useAccount, useDisconnect } from "wagmi";
109
import {
1110
ArrowDownLeftIcon,
1211
ArrowLeftOnRectangleIcon,
13-
ArrowTopRightOnSquareIcon,
1412
ArrowUpRightIcon,
1513
ArrowsRightLeftIcon,
16-
CheckCircleIcon,
17-
DocumentDuplicateIcon,
1814
UserIcon,
1915
} from "@heroicons/react/24/outline";
2016
import { useOutsideClick } from "~~/hooks/scaffold-eth";
@@ -29,12 +25,9 @@ type AddressInfoDropdownProps = {
2925
ensAvatar?: string;
3026
};
3127

32-
export const AddressInfoDropdown = ({ address, blockExplorerAddressLink }: AddressInfoDropdownProps) => {
28+
export const AddressInfoDropdown = ({ address }: AddressInfoDropdownProps) => {
3329
const { disconnect } = useDisconnect();
3430
const { address: connectedAddress } = useAccount();
35-
const checkSumAddress = getAddress(address);
36-
37-
const [addressCopied, setAddressCopied] = useState(false);
3831

3932
const [selectingNetwork, setSelectingNetwork] = useState(false);
4033

@@ -86,6 +79,9 @@ export const AddressInfoDropdown = ({ address, blockExplorerAddressLink }: Addre
8679
className="dropdown-content menu z-[2] p-2 mt-2 shadow-center shadow-accent bg-base-200 rounded-box gap-1"
8780
>
8881
<NetworkOptions hidden={!selectingNetwork} />
82+
<div className={selectingNetwork ? "hidden" : ""}>
83+
<PunkBalance address={connectedAddress} />
84+
</div>
8985
<li className={selectingNetwork ? "hidden" : ""}>
9086
<Link className="p-0 flex items-center justify-center" href={`/profile/${connectedAddress}`} passHref>
9187
<div className="btn-sm w-full !rounded-xl flex items-center justify-start gap-2 py-3 text-white bg-orange-600 hover:bg-orange-500 active:bg-orange-500">
@@ -97,10 +93,15 @@ export const AddressInfoDropdown = ({ address, blockExplorerAddressLink }: Addre
9793
</div>
9894
</Link>
9995
</li>
96+
10097
<FundButton
10198
text="Add funds"
10299
fundingUrl={onrampBuyUrl}
103-
className="py-1 px-6 md:px-3.5 gap-0.5 md:gap-1 text-md rounded-xl bg-[#4338CA] hover:bg-[#4f46e5] active:bg-[#4f46e5] justify-start font-normal "
100+
className={
101+
selectingNetwork
102+
? "hidden"
103+
: "py-1 px-6 md:px-3.5 gap-0.5 md:gap-1 text-md rounded-xl bg-[#4338CA] hover:bg-[#4f46e5] active:bg-[#4f46e5] justify-start font-normal "
104+
}
104105
/>
105106
<li className={selectingNetwork ? "hidden" : ""}>
106107
<button
@@ -133,49 +134,6 @@ export const AddressInfoDropdown = ({ address, blockExplorerAddressLink }: Addre
133134
</button>
134135
</li>
135136

136-
<li className={selectingNetwork ? "hidden" : ""}>
137-
{addressCopied ? (
138-
<div className="btn-sm !rounded-xl flex gap-3 py-3">
139-
<CheckCircleIcon
140-
className="text-xl font-normal h-6 w-4 cursor-pointer ml-2 sm:ml-0"
141-
aria-hidden="true"
142-
/>
143-
<span className=" whitespace-nowrap">Copy address</span>
144-
</div>
145-
) : (
146-
<CopyToClipboard
147-
text={checkSumAddress}
148-
onCopy={() => {
149-
setAddressCopied(true);
150-
setTimeout(() => {
151-
setAddressCopied(false);
152-
}, 800);
153-
}}
154-
>
155-
<div className="btn-sm !rounded-xl flex gap-3 py-3">
156-
<DocumentDuplicateIcon
157-
className="text-xl font-normal h-6 w-4 cursor-pointer ml-2 sm:ml-0"
158-
aria-hidden="true"
159-
/>
160-
<span className=" whitespace-nowrap">Copy address</span>
161-
</div>
162-
</CopyToClipboard>
163-
)}
164-
</li>
165-
166-
<li className={selectingNetwork ? "hidden" : ""}>
167-
<button className="menu-item btn-sm !rounded-xl flex gap-3 py-3" type="button">
168-
<ArrowTopRightOnSquareIcon className="h-6 w-4 ml-2 sm:ml-0" />
169-
<a
170-
target="_blank"
171-
href={blockExplorerAddressLink}
172-
rel="noopener noreferrer"
173-
className="whitespace-nowrap"
174-
>
175-
View on Block Explorer
176-
</a>
177-
</button>
178-
</li>
179137
{allowedNetworks.length > 1 ? (
180138
<li className={selectingNetwork ? "hidden" : ""}>
181139
<button
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { useRef, useState } from "react";
2+
import { NetworkOptions } from "./NetworkOptions";
3+
import { Address } from "viem";
4+
import { useDisconnect } from "wagmi";
5+
import { Cog6ToothIcon } from "@heroicons/react/20/solid";
6+
import {
7+
ArrowLeftOnRectangleIcon,
8+
ArrowTopRightOnSquareIcon,
9+
ArrowsRightLeftIcon,
10+
QrCodeIcon,
11+
} from "@heroicons/react/24/outline";
12+
import { LanguageIcon } from "@heroicons/react/24/solid";
13+
import { useOutsideClick } from "~~/hooks/scaffold-eth";
14+
import { getTargetNetworks } from "~~/utils/scaffold-eth";
15+
16+
const allowedNetworks = getTargetNetworks();
17+
18+
type AddressInfoDropdownProps = {
19+
address: Address;
20+
blockExplorerAddressLink: string | undefined;
21+
displayName: string;
22+
ensAvatar?: string;
23+
};
24+
25+
export const AddressInfoDropdown = ({ blockExplorerAddressLink }: AddressInfoDropdownProps) => {
26+
const [selectingNetwork, setSelectingNetwork] = useState(false);
27+
28+
const { disconnect } = useDisconnect();
29+
30+
const dropdownRef = useRef<HTMLDetailsElement>(null);
31+
const closeDropdown = () => {
32+
setSelectingNetwork(false);
33+
dropdownRef.current?.removeAttribute("open");
34+
};
35+
useOutsideClick(dropdownRef, closeDropdown);
36+
37+
return (
38+
<>
39+
<details ref={dropdownRef} className="dropdown dropdown-end leading-3">
40+
<summary
41+
tabIndex={0}
42+
className="flex items-center justify-center hover:cursor-pointer p-2 shadow-none bg-transparent border-0 btn-sm dropdown-toggle gap-0 !h-auto"
43+
>
44+
<Cog6ToothIcon className="h-5 w-5 ml-2 sm:ml-0" />
45+
</summary>
46+
<ul
47+
tabIndex={0}
48+
className="dropdown-content menu z-[2] p-2 mt-2 shadow-center shadow-accent bg-base-200 rounded-box gap-1"
49+
>
50+
<NetworkOptions hidden={!selectingNetwork} />
51+
52+
<li className={selectingNetwork ? "hidden" : ""}>
53+
<label
54+
htmlFor="qrcode-modal"
55+
className="text-white bg-orange-600 hover:bg-orange-500 active:bg-orange-500 btn-sm !rounded-xl flex gap-3 py-3"
56+
>
57+
<QrCodeIcon className="h-6 w-4 ml-2 sm:ml-0" />
58+
<span className="whitespace-nowrap">View your address</span>
59+
</label>
60+
</li>
61+
62+
{allowedNetworks.length > 1 ? (
63+
<li className={selectingNetwork ? "hidden" : ""}>
64+
<button
65+
className="btn-sm !rounded-xl flex gap-3 py-3"
66+
type="button"
67+
onClick={() => {
68+
setSelectingNetwork(true);
69+
}}
70+
>
71+
<ArrowsRightLeftIcon className="h-4 w-4 ml-2 sm:ml-0" /> <span>Switch Network</span>
72+
</button>
73+
</li>
74+
) : null}
75+
<li className={selectingNetwork ? "hidden" : ""}>
76+
<label htmlFor="switch-language-modal" className="btn-sm !rounded-xl flex gap-3 py-3">
77+
<LanguageIcon className="h-6 w-4 ml-2 sm:ml-0" />
78+
<span className="whitespace-nowrap">Switch languages</span>
79+
</label>
80+
</li>
81+
82+
<li className={selectingNetwork ? "hidden" : ""}>
83+
<button className="menu-item btn-sm !rounded-xl flex gap-3 py-3" type="button">
84+
<ArrowTopRightOnSquareIcon className="h-6 w-4 ml-2 sm:ml-0" />
85+
<a
86+
target="_blank"
87+
href={blockExplorerAddressLink}
88+
rel="noopener noreferrer"
89+
className="whitespace-nowrap"
90+
>
91+
View on Block Explorer
92+
</a>
93+
</button>
94+
</li>
95+
96+
<li className={selectingNetwork ? "hidden" : ""}>
97+
<button
98+
className="menu-item text-red-600 dark:text-red-500 btn-sm !rounded-xl flex gap-3 py-3"
99+
type="button"
100+
onClick={() => disconnect()}
101+
>
102+
<ArrowLeftOnRectangleIcon className="h-6 w-4 ml-2 sm:ml-0" /> <span>Disconnect</span>
103+
</button>
104+
</li>
105+
</ul>
106+
</details>
107+
</>
108+
);
109+
};

0 commit comments

Comments
 (0)