diff --git a/README.md b/README.md index d42d522..747b456 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,26 @@ -# web3getter -Stitch, share and combine your web3 data into a beautiful, customisable dashboard. +# My Room + +My Room enables people to collect, share, and utilize their NFTs in a secure a manner with an intuitive and sleek UI built for the mainstream user. Let's unlock your NFT potential. + +## Our use of Sponsors + +### Lens Protocol. +My Room relies on Lens Protocol to integrate the lens profiles for each My Room page. The Lens Handle is prominently atop the dashboard and we use that handle to check if Users have created a room or not. Users can search for their friend's rooms by resolving to their Lens handles and they can follow each other using the Lens follow integration. My Room's entire social element runs on those fundamental features of Lens but adds the personalized dashboard for each user. We believe the intuitive and sleek UI of My Room will enable web3 to have a better social web3 experience and encourage non-web3 users to socially utilize their NFTs. + +### WalletConnect. +My Room is a deployed Dapp that integrates Wallet Connect to provide a convenient user experience for onboarding mainstream people into web3. We place a themed wallet connect button on the home page of the dapp to immprove the user interface. We rely extensively on Wallet Connect to provide quick access to multiple wallets across multiple chains. The wallet connect themed QR pop-up emphasizes the importance of connecting a wallet but relaxes the user with the use of the orange color. + +### Magic. +We aim to use My Room to transform millions of owners of NFTs into millions of users of NFTs. My Room will help onboard more owners and users of NFTs through improvements in UX. The Magic Wallet SDK was crucial to the building of our Dapp. Authentication enabled users to login with their email address to access their dashboard. Such an improvement in UX is important to ensure that mainstream users can access My Room without sacrificing any of their security. + +### Base. +Our target user are mainstream users who are unfamiliar with web3. Deploying on Base means that users can enter the convenient ecosystem of Coinbase and potentially begin to use Coinbase's financial services and NFT marketplace because of their use of My Room. Each profile is a mintable ERC-721 contract. Each profile resolves to the minter's address. We deployed the ERC-721 contract on Base testnet because we wanted to enable the user to resolve to their addresses. The ERC-721 is an easy and fast way for users to share their room profiles and to save the content of their room profiles to the token URI. Our target user are mainstream users who are unfamiliar with web3. + +### Scroll. +The dapp we built needs speed and cheap transaction fees to ensure the best UX. Scroll delivers both. Each profile is a mintable ERC-721 contract. Each profile resolves to the minter's address. We deployed the ERC-721 contract on Scroll testnet because we wanted to enable the user to resolve to their addresses. The ERC-721 is an easy and fast way for users to share their room profiles and to save the content of their room profiles to the token URI. + +### Polygon. +The dapp we built needs speed and cheap transaction fees to ensure the best UX. Polygon delivers both. Each profile is a mintable ERC-721 contract. Each profile resolves to the minter's address. We deployed the ERC-721 contract on Polygon testnet because we wanted to enable the user to resolve to their addresses. The ERC-721 is an easy and fast way for users to share their room profiles and to save the content of their room profiles to the token URI. Our dashboard pulls NFT data across wallets, across chains, which means that user experience with NFTs has vastly improved. Our dashboard will enable millions of owners of NFTs to analyze their own NFT and others without viewing the junk or uninteresting NFTs owned by each individual. + +### Infura. +Our social web3 app uses Infura along with Lens Protocol to provide a cross-chain, cross-wallet experience. Built with Truffle, our dapp enables user to follow and post using their Lens profiles. diff --git a/apps/dashkit/.gitignore b/apps/dashkit/.gitignore index c87c9b3..de2a148 100644 --- a/apps/dashkit/.gitignore +++ b/apps/dashkit/.gitignore @@ -34,3 +34,5 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +.yarn \ No newline at end of file diff --git a/apps/dashkit/package.json b/apps/dashkit/package.json index 3febb4e..76a66ee 100644 --- a/apps/dashkit/package.json +++ b/apps/dashkit/package.json @@ -11,6 +11,8 @@ "dependencies": { "@apollo/client": "^3.7.9", "@dnd-kit/core": "^6.0.8", + "@dnd-kit/sortable": "^7.0.2", + "@rive-app/react-canvas": "^3.0.38", "@types/node": "18.14.1", "@types/react": "18.0.28", "@types/react-dom": "18.0.11", @@ -21,6 +23,7 @@ "ethers": "<6", "framer-motion": "^10.0.0", "graphql": "^16.6.0", + "magic-sdk": "^13.5.0", "next": "13.2.1", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/apps/dashkit/public/ani/myroom.riv b/apps/dashkit/public/ani/myroom.riv new file mode 100644 index 0000000..9051a52 Binary files /dev/null and b/apps/dashkit/public/ani/myroom.riv differ diff --git a/apps/dashkit/public/img/Unknown-2.jpg b/apps/dashkit/public/img/Unknown-2.jpg new file mode 100644 index 0000000..d94d442 Binary files /dev/null and b/apps/dashkit/public/img/Unknown-2.jpg differ diff --git a/apps/dashkit/public/img/Unknown-3.jpg b/apps/dashkit/public/img/Unknown-3.jpg new file mode 100644 index 0000000..351e47b Binary files /dev/null and b/apps/dashkit/public/img/Unknown-3.jpg differ diff --git a/apps/dashkit/public/img/Unknown-4.jpg b/apps/dashkit/public/img/Unknown-4.jpg new file mode 100644 index 0000000..dd41eac Binary files /dev/null and b/apps/dashkit/public/img/Unknown-4.jpg differ diff --git a/apps/dashkit/public/img/Unknown.jpg b/apps/dashkit/public/img/Unknown.jpg new file mode 100644 index 0000000..a08cd9c Binary files /dev/null and b/apps/dashkit/public/img/Unknown.jpg differ diff --git a/apps/dashkit/src/components/Button.tsx b/apps/dashkit/src/components/Button.tsx index 29347cc..c80ed64 100644 --- a/apps/dashkit/src/components/Button.tsx +++ b/apps/dashkit/src/components/Button.tsx @@ -16,8 +16,9 @@ function Button({ as = "button", className, ...props }: BaseButtonProps) { const Component = as; return ( diff --git a/apps/dashkit/src/components/DragGrid.tsx b/apps/dashkit/src/components/DragGrid.tsx index ecc53da..1107b81 100644 --- a/apps/dashkit/src/components/DragGrid.tsx +++ b/apps/dashkit/src/components/DragGrid.tsx @@ -1,7 +1,52 @@ import { - -} from "@dnd-kit/core" + DndContext, + PointerSensor, + TouchSensor, + useSensor, + useSensors, + closestCenter, +} from '@dnd-kit/core'; +import { SortableContext } from '@dnd-kit/sortable'; +import { Showcase } from '@/components'; +import BaseWidget from './widgets/BaseWidget'; -export const DragGrid = () => { - return <> -} \ No newline at end of file +const DragGrid = () => { + const sensors = useSensors( + useSensor(PointerSensor), + useSensor(TouchSensor) + ); + + return ( +
+ + + +
+ + + + + + + + + + +
+
+
+
+ ); +}; + +export default DragGrid; diff --git a/apps/dashkit/src/components/Greeter.tsx b/apps/dashkit/src/components/Greeter.tsx new file mode 100644 index 0000000..189045c --- /dev/null +++ b/apps/dashkit/src/components/Greeter.tsx @@ -0,0 +1,20 @@ +type GreeterProps = { + me?: boolean, + name: string +} + +const Greeter = ({me, name}: GreeterProps) => { + return ( +
+ {me ? "Welcome home " : "This room belongs to "} + {name} +
+ ) +} +export default Greeter \ No newline at end of file diff --git a/apps/dashkit/src/components/IconButton.tsx b/apps/dashkit/src/components/IconButton.tsx new file mode 100644 index 0000000..c85ee07 --- /dev/null +++ b/apps/dashkit/src/components/IconButton.tsx @@ -0,0 +1,29 @@ +import { HTMLAttributes, ReactElement, ReactNode } from "react"; + +type BaseButtonProps = { + className?: string; + as?: "a" | "button"; + icon?: ReactNode; +}; + +type LinkButtonProps = BaseButtonProps & HTMLAttributes; + +type ButtonProps = BaseButtonProps & HTMLAttributes; + +function IconButton(props: LinkButtonProps): ReactElement; +function IconButton(props: ButtonProps): ReactElement; +function IconButton({ as = "button", className, ...props }: BaseButtonProps) { + const Component = as; + return ( + + {props.icon} + + ); +} + +export default IconButton; diff --git a/apps/dashkit/src/components/MagicPopup.tsx b/apps/dashkit/src/components/MagicPopup.tsx new file mode 100644 index 0000000..2fea839 --- /dev/null +++ b/apps/dashkit/src/components/MagicPopup.tsx @@ -0,0 +1,109 @@ +import React, { useState, ChangeEvent, FormEvent, useEffect } from 'react'; +import { Magic } from "magic-sdk"; +import { ethers } from "ethers"; +import { useRouter } from "next/router"; + + +type MagicPopupModalProps = { + children: React.ReactNode; + className?: string; +} + +export default function MagicPopup() { + const [showModal, setShowModal] = useState(false); + const [email, setEmail] = useState(""); + const [address, setAddress] = useState(null); + + const handleChange = (event: FormEvent) => { + setEmail(event.currentTarget.value); + }; + const router = useRouter() + const handleSignIn = async (event: FormEvent) => { + event.preventDefault(); + console.log("boo ") + + const magic = new Magic(process.env.NEXT_PUBLIC_MAGIC_PUBLISHABLE_KEY as string); + console.log("🚀 ~ file: MagicPopup.tsx:25 ~ handleSignIn ~ magic:", magic) + + const didToken = magic.auth.loginWithMagicLink({ + email + }); + // // 🌐 Send didToken to your backend API + + const provider = new ethers.providers.Web3Provider(magic.rpcProvider as any); + + const signer = provider.getSigner(); + const address = await signer.getAddress(); + + setAddress(address as any); + if (address) { + router.push("/rooms/me") + } + + } + + + + + const openModal = () => { + setShowModal(true); + console.log("opened") + } + + const closeModal = () => { + setShowModal(false); + console.log("closed") + } + + return ( + <> + + {showModal && ( +
+ {/*
+ {address && ( +

+ {address} +

+ )} +
*/} + +
+
+
+
+
+ +
+
+ +
+ + +
+
+ + +
+
+
+ )} + + ); +}; \ No newline at end of file diff --git a/apps/dashkit/src/components/Navigation.tsx b/apps/dashkit/src/components/Navigation.tsx index 42fed56..bf0ad64 100644 --- a/apps/dashkit/src/components/Navigation.tsx +++ b/apps/dashkit/src/components/Navigation.tsx @@ -1,13 +1,35 @@ +import IconButton from '@/components/IconButton'; +import MyRoomLogo from '@/svg/logo.svg'; +import { + HiMagnifyingGlass, + HiQrCode, + HiWrench, +} from 'react-icons/hi2'; +import Image from 'next/image'; + const Navigation = () => { - return <> - - ; + return ( + <> + + + ); }; -export default Navigation; \ No newline at end of file +export default Navigation; diff --git a/apps/dashkit/src/components/Showcase.tsx b/apps/dashkit/src/components/Showcase.tsx new file mode 100644 index 0000000..131bf66 --- /dev/null +++ b/apps/dashkit/src/components/Showcase.tsx @@ -0,0 +1,19 @@ +type ShowcaseProps = { + data: any; +}; + +const Showcase = ({ + data +}: ShowcaseProps) => { + return ( +
+
+

+ Test +

+
+
+ ); +} + +export default Showcase; \ No newline at end of file diff --git a/apps/dashkit/src/components/index.tsx b/apps/dashkit/src/components/index.tsx index 48d953d..b6b0a59 100644 --- a/apps/dashkit/src/components/index.tsx +++ b/apps/dashkit/src/components/index.tsx @@ -1,4 +1,8 @@ import Button from './Button'; import Navigation from './Navigation'; +import IconButton from './IconButton'; +import Showcase from './Showcase'; +import Greeter from './Greeter'; +import DragGrid from './DragGrid'; -export { Button, Navigation }; \ No newline at end of file +export { Button, Navigation, IconButton, Showcase, Greeter, DragGrid }; \ No newline at end of file diff --git a/apps/dashkit/src/components/widgets/BaseWidget.tsx b/apps/dashkit/src/components/widgets/BaseWidget.tsx new file mode 100644 index 0000000..65b978c --- /dev/null +++ b/apps/dashkit/src/components/widgets/BaseWidget.tsx @@ -0,0 +1,57 @@ +import { useDraggable } from "@dnd-kit/core"; + +import {CSS} from '@dnd-kit/utilities'; +import { motion } from "framer-motion"; +import { CSSProperties } from "react"; + +const variants: { + [key: string]: CSSProperties +} = { + small: { + aspectRatio: 1 / 1, + width: "1fr" + }, + big: { + aspectRatio: 1 / 1, + gridRow: "span 2", + gridColumn: "span 2", + }, + doubleWide: { + aspectRatio: 2 / 1, + gridColumn: "span 2", + }, + doubleTall: { + aspectRatio: 1 / 2, + gridRow: "span 2", + }, + tripleWide: { + aspectRatio: 3 / 1, + gridColumn: "span 3", + }, +} + +const BaseWidget = (props: any) => { + const { className, size, children, id } = props; + const { listeners, attributes, transform, isDragging, setNodeRef } = useDraggable({ + id, + }); + + return ( +
+
+ {children} +
+
+ ); +}; + +export default BaseWidget; \ No newline at end of file diff --git a/apps/dashkit/src/pages/_app.tsx b/apps/dashkit/src/pages/_app.tsx index f033ccb..26c6a0a 100644 --- a/apps/dashkit/src/pages/_app.tsx +++ b/apps/dashkit/src/pages/_app.tsx @@ -2,7 +2,6 @@ import '@/styles/globals.css' import type { AppProps } from 'next/app' import { EthereumClient, modalConnectors, walletConnectProvider } from '@web3modal/ethereum' import { Web3Modal } from '@web3modal/react' -import { useEffect, useState } from 'react' import { configureChains, createClient, WagmiConfig } from 'wagmi' import { arbitrum, avalanche, goerli, mainnet, optimism, polygon, zkSyncTestnet } from 'wagmi/chains' import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client"; diff --git a/apps/dashkit/src/pages/index.tsx b/apps/dashkit/src/pages/index.tsx index d6e2a45..0d1a9ed 100644 --- a/apps/dashkit/src/pages/index.tsx +++ b/apps/dashkit/src/pages/index.tsx @@ -4,11 +4,14 @@ import { useEffect } from "react"; import { Web3Button } from "@web3modal/react"; import { useRouter } from "next/router"; import { useAccount } from "wagmi"; +import MagicPopup from "@/components/MagicPopup" + +import Rive, { Layout, Alignment, Fit } from '@rive-app/react-canvas'; export default function Home() { const router = useRouter() const { isConnected } = useAccount() - + useEffect(() => { if (isConnected) router.push("/rooms/me") @@ -29,20 +32,32 @@ export default function Home() { color: "var(--color-primary-contrast)", }} > -

+ + +

- My Room + my room

+ +
+ +

- +

diff --git a/apps/dashkit/src/pages/rooms/[ref].tsx b/apps/dashkit/src/pages/rooms/[ref].tsx index 4e612cb..5343eb0 100644 --- a/apps/dashkit/src/pages/rooms/[ref].tsx +++ b/apps/dashkit/src/pages/rooms/[ref].tsx @@ -27,6 +27,13 @@ const RoomWithRef: NextPage = () => { This is a Lens Protocol user

} +

+ My Room - © 2023 +
+ Made with ♥ for ETHDenver #BUIDLathon 2023 +
+ By Dino, Liang, Geoffrey and Josh. +

} diff --git a/apps/dashkit/src/pages/rooms/me.tsx b/apps/dashkit/src/pages/rooms/me.tsx index 4ac3340..2c0f1d2 100644 --- a/apps/dashkit/src/pages/rooms/me.tsx +++ b/apps/dashkit/src/pages/rooms/me.tsx @@ -3,43 +3,54 @@ import { useRouter } from "next/router"; import { useAccount } from "wagmi"; import { useDefaultOnHydration, useUniversalResolver } from "@/utils"; -import { Button, Navigation } from "@/components"; +import { Button, Navigation, DragGrid, Greeter } from "@/components"; import { HiPaperAirplane } from "react-icons/hi2"; import { NextPage } from "next"; - const RoomOfAccount: NextPage = () => { - const { isConnected, address: _address } = useAccount(); + const { status, address: _address } = useAccount(); const { name: _name, isLens } = useUniversalResolver(_address as string); - const { name, address } = useDefaultOnHydration( - { - name: _name, - address: _address, - }, - // Default - { - name: "unknown", - address: "unknown", - } - ); + const name = useDefaultOnHydration(_name, "unknown"); + const address = useDefaultOnHydration(_address as string, "unknown"); const router = useRouter(); - useEffect(() => { - if (!isConnected) { + if (status !== "connected") { router.push("/"); } - }, [isConnected, router]); + }, [status, router]); return ( <> +
+
+ + {isLens && ( + + )} +
+ + +
+

+ My Room - © 2023 +
+ Made with ♥ for ETHDenver #BUIDLathon 2023 +
+ By Dino, Liang, Geoffrey and Josh. +

Welcome{" "} - {name ?? `${address?.slice(0, 8) ?? "unknown"}...`}! + {name ?? `${address?.slice(0, 8) ?? "let's create a room"}!!!`}!

{isLens && (