add waitlist skipper

This commit is contained in:
Paul Miller
2023-02-21 12:40:05 -06:00
parent b4fc2a2a6f
commit edadb56f26
15 changed files with 184 additions and 151 deletions

7
package-lock.json generated
View File

@@ -19,6 +19,7 @@
"react-router-dom": "^6.8.0"
},
"devDependencies": {
"@types/node": "^18.14.0",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"@types/react-linkify": "^1.0.1",
@@ -2427,9 +2428,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "18.13.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz",
"integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==",
"version": "18.14.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz",
"integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==",
"dev": true
},
"node_modules/@types/prop-types": {

View File

@@ -20,6 +20,7 @@
"react-router-dom": "^6.8.0"
},
"devDependencies": {
"@types/node": "^18.14.0",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"@types/react-linkify": "^1.0.1",

View File

@@ -1,9 +1,12 @@
import { Routes, Route } from "react-router-dom";
import Join from "./Join";
import Layout from "./components/Layout";
import Join from "@/routes/Join";
import Layout from "@/components/Layout";
import SecretWaitlistSkipper from "@/routes/SecretWaitlistSkipper";
import Home from "@/routes/Home";
function App() {
let active = localStorage.getItem('active') || "";
return (
<div className="App">
@@ -12,7 +15,8 @@ function App() {
<Routes>
{/* <Route path="/" element={<Home />} /> */}
<Route path="/" element={<Layout />}>
<Route index element={<Join />} />
<Route index element={active === "true" ? <Home /> : <Join />} />
<Route path="secretwaitlistskipper" element={<SecretWaitlistSkipper />} />
</Route>
</Routes>
</div>

View File

@@ -1,115 +0,0 @@
import Sheet from 'react-modal-sheet';
import { useState } from 'react';
import logo from './assets/mutiny-logo.svg';
import mutiny_m from './assets/m.svg';
import scan from './assets/scan.svg';
import settings from './assets/settings.svg';
import send from './assets/send.svg';
function ActivityItem() {
return (
<div className="flex flex-row border-b border-gray-500 gap-4 py-2">
<img src={send} className="App-logo" alt="logo" />
<div className='flex flex-col flex-1'>
<h1>Bitcoin Beefsteak</h1>
<h2>-1,441,851 SAT</h2>
<h3 className='text-sm text-gray-500'>Jul 24</h3>
</div>
<div className='text-sm font-semibold uppercase text-[#E23A5E]'>SEND</div>
</div>
)
}
function App() {
const [isOpen, setOpen] = useState(false);
return (
<div className="safe-top safe-left safe-right safe-bottom">
<div className="disable-scrollbars max-h-screen h-full overflow-y-scroll mx-4">
<main className='flex flex-col gap-4 py-8'>
<header>
<img src={logo} className="App-logo" alt="logo" />
</header>
<div className='border border-white rounded-xl border-b-4 p-4 flex flex-col gap-2'>
<header className='text-sm font-semibold uppercase'>
Balance
</header>
<div>
<h1 className='text-4xl font-light'>
69,420 <span className='text-xl'>SAT</span>
</h1>
</div>
<div className="flex gap-2 py-4">
<button onClick={() => setOpen(true)} className='bg-[#1EA67F] p-4 flex-1 rounded-xl text-xl font-semibold '><span className="drop-shadow-sm shadow-black">Send</span></button>
<button className='bg-[#3B6CCC] p-4 flex-1 rounded-xl text-xl font-semibold '><span className="drop-shadow-sm shadow-black">Receive</span></button>
</div>
</div>
<div className='rounded-xl p-4 flex flex-col gap-2 bg-[rgba(0,0,0,0.5)]'>
<header className='text-sm font-semibold uppercase'>
Activity
</header>
<ActivityItem />
<ActivityItem />
<ActivityItem />
<ActivityItem />
<ActivityItem />
<ActivityItem />
<ActivityItem />
<div className='flex justify-end py-4'>
<a href="#" className='underline text-sm'>
MORE
</a>
</div>
</div>
{/* safety div */}
<div className="h-32" />
</main>
</div>
<Sheet isOpen={isOpen} onClose={() => setOpen(false)}>
<Sheet.Container>
<Sheet.Header />
<Sheet.Content>
<div className='p-4 flex flex-col gap-2'>
<header className='text-sm font-semibold uppercase'>
Activity
</header>
<ActivityItem />
<h1 className='text-4xl font-light'>
It's a sheet! Like a modal, but a sheet.
</h1>
</div>
</Sheet.Content>
</Sheet.Container>
<Sheet.Backdrop />
</Sheet>
<nav className='bg-black fixed bottom-0 shadow-lg z-40 w-full safe-bottom'>
<ul className='h-16 flex justify-between px-16 items-center'>
<li className='h-full border-t-2 border-b-2 border-b-black flex flex-col justify-center'>
<img src={mutiny_m} className="App-logo" alt="logo" />
</li>
<li>
<img src={scan} className="App-logo" alt="logo" />
</li>
<li>
<img src={settings} className="App-logo" alt="logo" />
</li>
{/* <li>home</li> */}
{/* <li>scan</li> */}
{/* <li>settings</li> */}
</ul>
</nav>
</div >
)
}
export default App

View File

@@ -1,19 +0,0 @@
import { Link } from "react-router-dom";
import { motion } from "framer-motion";
function Receive() {
const pageMotion = {
initial: { opacity: 0, x: 0 },
animate: { opacity: 1, x: 50, transition: { duration: 2 } },
exit: { opacity: 0, x: 0, transition: { duration: 2 } }
};
return (
<div className="about">
<motion.div initial="initial" animate="animate" exit="exit" variants={pageMotion}>about page</motion.div>
<Link to="/">Go to home page</Link>
</div>
)
}
export default Receive

View File

@@ -18,9 +18,9 @@ function Note({ e }: { e: NostrEvent }) {
}
return (
<div className="flex gap-4 border-b border-faint-white py-6 items-start">
<img className="bg-black rounded-xl" src="../180.png" width={45} height={45} />
<div className="flex flex-col gap-2 max-w-sm">
<div className="flex gap-4 border-b border-faint-white py-6 items-start w-full">
<img className="bg-black rounded-xl flex-0" src="../180.png" width={45} height={45} />
<div className="flex flex-col gap-2 flex-1">
{/* <p>{JSON.stringify(e, null, 2)}</p> */}
<p className="break-words">
<Linkify>

View File

@@ -1,5 +1,6 @@
import Notes from "./Notes";
import { NostrProvider } from "nostr-react";
import { useState } from "react";
const relayUrls = [
"wss://nostr.zebedee.cloud",
@@ -12,18 +13,28 @@ const relayUrls = [
]
export function WaitlistAlreadyIn() {
const [skipCount, setSkipCount] = useState(0);
function skipCounter() {
setSkipCount(skipCount + 1);
if (skipCount >= 6) {
window.location.href = "/secretwaitlistskipper";
}
}
return (
<main className='flex flex-col gap-4 py-8 max-w-xl mx-auto items-center drop-shadow-blue-glow'>
<main className='flex flex-col gap-2 sm:gap-4 py-8 px-4 max-w-xl mx-auto items-center drop-shadow-blue-glow'>
<h1 className="text-4xl font-bold">You're on a list!</h1>
<h2 className="text-xl">
We'll message you when Mutiny Wallet is ready.
</h2>
<div className="p-8 rounded-xl bg-half-black">
<div className="px-4 sm:px-8 py-8 rounded-xl bg-half-black">
<h2 className="text-sm font-semibold uppercase">Recent Updates</h2>
<NostrProvider relayUrls={relayUrls} debug={true}>
<Notes />
</NostrProvider>
</div>
<button className="opacity-0" onClick={skipCounter}>Skip</button>
</main>
);
}

View File

@@ -1,5 +1,5 @@
import { useState } from "react";
import button from "./button";
import button from "@/styles/button";
const INPUT = "w-full mb-4 p-2 rounded-lg text-black"
@@ -73,7 +73,7 @@ export default function WaitlistForm() {
}
return (
<main className='flex flex-col gap-4 py-8 max-w-xl mx-auto drop-shadow-blue-glow'>
<main className='flex flex-col gap-4 py-8 px-4 max-w-xl mx-auto drop-shadow-blue-glow'>
<h1 className='text-4xl font-bold'>Join Waitlist</h1>
{/* HTML form with three inputs: nostr pubkey (text), email (text), and a textarea for comments */}
<h2 className="text-xl">

View File

@@ -1,4 +1,3 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'

112
src/routes/Home.tsx Normal file
View File

@@ -0,0 +1,112 @@
import Sheet from 'react-modal-sheet';
import { useState } from 'react';
import logo from '@/assets/mutiny-logo.svg';
import mutiny_m from '@/assets/m.svg';
import scan from '@/assets/scan.svg';
import settings from '@/assets/settings.svg';
import send from '@/assets/send.svg';
function ActivityItem() {
return (
<div className="flex flex-row border-b border-gray-500 gap-4 py-2">
<img src={send} className="App-logo" alt="logo" />
<div className='flex flex-col flex-1'>
<h1>Bitcoin Beefsteak</h1>
<h2>-1,441,851 SAT</h2>
<h3 className='text-sm text-gray-500'>Jul 24</h3>
</div>
<div className='text-sm font-semibold uppercase text-[#E23A5E]'>SEND</div>
</div>
)
}
function App() {
const [isOpen, setOpen] = useState(false);
return (
<>
<main className='flex flex-col gap-4 py-8 px-4'>
<header>
<img src={logo} className="App-logo" alt="logo" />
</header>
<div className='border border-white rounded-xl border-b-4 p-4 flex flex-col gap-2'>
<header className='text-sm font-semibold uppercase'>
Balance
</header>
<div>
<h1 className='text-4xl font-light'>
69,420 <span className='text-xl'>SAT</span>
</h1>
</div>
<div className="flex gap-2 py-4">
<button onClick={() => setOpen(true)} className='bg-[#1EA67F] p-4 flex-1 rounded-xl text-xl font-semibold '><span className="drop-shadow-sm shadow-black">Send</span></button>
<button className='bg-[#3B6CCC] p-4 flex-1 rounded-xl text-xl font-semibold '><span className="drop-shadow-sm shadow-black">Receive</span></button>
</div>
</div>
<div className='rounded-xl p-4 flex flex-col gap-2 bg-[rgba(0,0,0,0.5)]'>
<header className='text-sm font-semibold uppercase'>
Activity
</header>
<ActivityItem />
<ActivityItem />
<ActivityItem />
<ActivityItem />
<ActivityItem />
<ActivityItem />
<ActivityItem />
<div className='flex justify-end py-4'>
<a href="#" className='underline text-sm'>
MORE
</a>
</div>
</div>
{/* safety div */}
<div className="h-32" />
</main>
<Sheet isOpen={isOpen} onClose={() => setOpen(false)}>
<Sheet.Container>
<Sheet.Header />
<Sheet.Content>
<div className='p-4 flex flex-col gap-2'>
<header className='text-sm font-semibold uppercase'>
Activity
</header>
<ActivityItem />
<h1 className='text-4xl font-light'>
It's a sheet! Like a modal, but a sheet.
</h1>
</div>
</Sheet.Content>
</Sheet.Container>
<Sheet.Backdrop />
</Sheet>
<nav className='bg-black fixed bottom-0 shadow-lg z-40 w-full safe-bottom'>
<ul className='h-16 flex justify-between px-16 items-center'>
<li className='h-full border-t-2 border-b-2 border-b-black flex flex-col justify-center'>
<img src={mutiny_m} className="App-logo" alt="logo" />
</li>
<li>
<img src={scan} className="App-logo" alt="logo" />
</li>
<li>
<img src={settings} className="App-logo" alt="logo" />
</li>
{/* <li>home</li> */}
{/* <li>scan</li> */}
{/* <li>settings</li> */}
</ul>
</nav>
</>
)
}
export default App

View File

@@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
import WaitlistForm from "./components/WaitlistForm";
import { WaitlistAlreadyIn } from "./components/WaitlistAlreadyIn";
import WaitlistForm from "@/components/WaitlistForm";
import { WaitlistAlreadyIn } from "@/components/WaitlistAlreadyIn";
export default function Join() {
// On load, check if the user is already on the waitlist

View File

@@ -0,0 +1,30 @@
import button from "@/styles/button";
import { useState } from "react";
export default function SecretWaitlistSkipper() {
const [active] = useState(localStorage.getItem('active') || "");
function toggleSkipWaitlist() {
// If active in localstorage is true, set to false, otherwie set to true
if (active === "true") {
localStorage.setItem("active", "false");
} else {
localStorage.setItem("active", "true");
}
// Redirect to index
window.location.href = "/";
}
return (
<div className="w-full h-screen flex flex-col items-center justify-center">
<div className="flex-0">
{active === "true" &&
<button className={button({ intent: "active" })} onClick={toggleSkipWaitlist}><span className="drop-shadow-sm shadow-black">I love waiting, hate cheating</span></button>
}
{active !== "true" &&
<button className={button({ intent: "active" })} onClick={toggleSkipWaitlist}><span className="drop-shadow-sm shadow-black">I hate waiting, love cheating</span></button>
}
</div>
</div>
)
}

View File

@@ -14,7 +14,11 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
"jsx": "react-jsx",
"types": ["node"],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]

View File

@@ -2,6 +2,8 @@ import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { VitePWA } from 'vite-plugin-pwa'
import * as path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
@@ -29,4 +31,7 @@ export default defineConfig({
enabled: true
}
})],
resolve: {
alias: [{ find: '@', replacement: path.resolve(__dirname, './src') }]
}
})