diff options
| author | secondl1ght <[email protected]> | 2022-10-25 18:01:56 -0600 |
|---|---|---|
| committer | secondl1ght <[email protected]> | 2022-10-25 18:01:56 -0600 |
| commit | a67b375473f1f40e1c0febfac16d7e36e0d72561 (patch) | |
| tree | 10a5fa750f2ccb53cff3510ab8fbbce108a35eb6 /src/routes/launch | |
| parent | aa6debcd83c0b4067e0f8ce9a11d9c9ac02476ad (diff) | |
| parent | 5a5ea3ccc327ff52fb1c313998d90e4bfefea90a (diff) | |
| download | coinos-ui-a67b375473f1f40e1c0febfac16d7e36e0d72561.tar.gz coinos-ui-a67b375473f1f40e1c0febfac16d7e36e0d72561.zip | |
Merge branch 'master' of github.com:coinos/coinos-ui-v2
Diffstat (limited to 'src/routes/launch')
| -rw-r--r-- | src/routes/launch/+page.server.js | 6 | ||||
| -rw-r--r-- | src/routes/launch/+page.svelte | 91 | ||||
| -rw-r--r-- | src/routes/launch/purchase/+page.server.js | 45 | ||||
| -rw-r--r-- | src/routes/launch/purchase/+page.svelte | 91 | ||||
| -rw-r--r-- | src/routes/launch/purchase/card/+page.server.js | 44 | ||||
| -rw-r--r-- | src/routes/launch/purchase/card/+page.svelte | 77 | ||||
| -rw-r--r-- | src/routes/launch/thanks/[asset]/+page.server.js | 1 | ||||
| -rw-r--r-- | src/routes/launch/thanks/[asset]/+page.svelte | 29 | ||||
| -rw-r--r-- | src/routes/launch/ticket/+page.server.js | 9 | ||||
| -rw-r--r-- | src/routes/launch/ticket/+page.svelte | 35 |
10 files changed, 351 insertions, 77 deletions
diff --git a/src/routes/launch/+page.server.js b/src/routes/launch/+page.server.js new file mode 100644 index 00000000..2b44dfae --- /dev/null +++ b/src/routes/launch/+page.server.js @@ -0,0 +1,6 @@ +import { auth, get } from '$lib/utils'; + +export const load = async ({ parent }) => { + let tickets = await get('/tickets'); + return { ...(await parent()), tickets }; +}; diff --git a/src/routes/launch/+page.svelte b/src/routes/launch/+page.svelte index 04f53086..6faf492d 100644 --- a/src/routes/launch/+page.svelte +++ b/src/routes/launch/+page.svelte @@ -1,48 +1,99 @@ <script> - import { redirect } from '$lib/store'; + import { LandingHeader } from '$comp'; + import { loginRedirect } from '$lib/store'; import { beforeNavigate } from '$app/navigation'; import { info } from '$lib/utils'; + import { Icon } from '$comp'; + import { t } from '$lib/translations'; + import { goto } from '$app/navigation'; + import { scroll } from '$lib/utils'; export let data; - let { user } = data; - $: link = user ? '/launch/purchase' : '/register'; - $redirect = '/launch/purchase'; + let { user, tickets } = data; + $loginRedirect = '/launch/purchase'; + + let hasTicket = !!user?.accounts.find((a) => tickets.includes(a.asset)); + $: link = hasTicket ? '/launch/ticket' : user ? $loginRedirect : '/register'; + $: text = (hasTicket ? 'View' : 'Purchase') + ' Ticket'; beforeNavigate(({ to }) => { - console.log(link); - if (link === '/register') info('Please sign in so we can get you a ticket'); + if (to?.routeId === 'register') info('Please sign in so we can get you a ticket'); }); + + let showMobileMenu = false; + const mobileMenuButtonClick = (section) => { + showMobileMenu = false; + scroll(section); + }; </script> -<div class="flex mt-20 px-8"> - <img src="/images/ticket.webp" class="mb-8 md:max-w-xl mx-auto border border-gray-400" /> -</div> -<div class="mx-auto flex items-center justify-center px-8"> - <div class="flex flex-col w-full bg-white rounded shadow-lg sm:w-3/4 md:w-1/2 lg:w-3/5"> +<header class="w-full lg:w-5/6 py-5 mx-auto fixed md:sticky z-10 top-0 bg-white/90"> + <nav class="block xl:flex flex-wrap justify-between items-center"> + <div class="flex justify-start md:justify-center items-center md:space-x-10"> + <a href="/" class="hidden md:block"> + <Icon icon="logo" style="mb-5 xl:mb-0" /> + </a> + <Icon icon="logo" style="block md:hidden ml-5 w-48" /> + </div> + </nav> +</header> + +<div class="mx-auto flex items-center justify-center px-8 mt-20"> + <div class="flex flex-col w-full bg-white rounded shadow-lg sm:w-3/4 lg:w-3/5"> <div class="flex flex-col w-full md:flex-row"> <div class="flex flex-row justify-around p-4 font-bold leading-none text-gray-800 uppercase bg-gray-400 rounded md:flex-col md:items-center md:justify-center md:w-1/4" > <div class="md:text-3xl">Oct</div> - <div class="md:text-6xl">5</div> + <div class="md:text-6xl">26</div> <div class="md:text-xl">6 pm</div> </div> - <div class="p-4 font-normal text-gray-800 md:w-3/4"> + <div class="p-4 font-normal text-gray-800 md:w-3/4 space-y-5"> <h1 class="mb-4 text-4xl font-bold leading-none tracking-tight text-gray-800"> - Coinos Launch Party! + Launch Party! </h1> + <p class="leading-normal mb-2"> - Come join us at our launch party celebrating 10 years in business! We'll be introducing - our newly designed payments interface and afterwards we'll network and enjoy tasty food - and drinks from <a href="https://loftondenman.com/" class="underline">The Loft</a>! + Come join us at our launch party celebrating our new design and 10 years serving the + Vancouver Bitcoin community! + </p> + + <div class="flex"> + <div class="space-y-5"> + <div class="ml-8"> + <p><b>When</b></p> + <p>6pm October 26</p> + </div> + <div class="ml-8"> + <p><b>Where</b></p> + <p>The Loft Lounge</p> + <p>1184 Denman Street, #203</p> + <p>Vancouver, BC</p> + </div> + </div> + + <img src="/icons/party.svg" alt="Partygoers" class="w-[120px] mx-auto" /> + </div> + + <p> + We'll introduce our new interface and then network and enjoy tasty food and drinks from <a + href="https://loftondenman.com/" + class="underline">The Loft</a + >! + </p> + + <p> + The Loft will be accepting Lightning payments at the event and going forward into the + future as well! We're charging $6 for for an NFT ticket that gets you entry, appies, and the + chance to win some swag and sats. </p> <div class="flex w-full my-8"> - <a href={link}> + <a href={link} class="mx-auto"> <button - class="bg-white text-black border rounded-full px-8 py-4 font-bold hover:opacity-80 mx-auto text-2xl" + class="bg-white text-black border rounded-full px-8 py-4 font-bold hover:opacity-80 text-2xl" > - Purchase Ticket + {text} </button> </a> </div> diff --git a/src/routes/launch/purchase/+page.server.js b/src/routes/launch/purchase/+page.server.js index f6314f7f..2ecce695 100644 --- a/src/routes/launch/purchase/+page.server.js +++ b/src/routes/launch/purchase/+page.server.js @@ -1,8 +1,45 @@ -export const load = ({ parent }) => parent(); +import { auth, get, post } from '$lib/utils'; +import tickets from '$lib/tickets'; +import { redirect } from '@sveltejs/kit'; +import { env } from '$env/dynamic/private'; +import { invalidateAll } from '$app/navigation'; +import { browser } from '$app/environment'; +import { createTicket } from '$lib/ticket'; + +export const load = async ({ parent }) => { + let tickets = await get('/tickets'); + let { user } = await parent(); + let hasTicket = !!user?.accounts.find((a) => tickets.includes(a.asset)); + if (hasTicket) throw redirect(307, '/launch/ticket'); + return { tickets }; +}; export const actions = { - default: async ({ cookies, request }) => { - let form = Object.fromEntries(await request.formData()); - console.log(form); + internal: async ({ cookies, request }) => { + let form = await request.formData(); + let asset = await createTicket(cookies, form.get('username')); + await post('/send', { amount: 22000, username: 'launch' }, auth(cookies)); + + throw redirect(307, `/launch/thanks/${asset}`); + }, + + lightning: async ({ cookies, request }) => { + let form = await request.formData(); + + let rates = await get('/rates'); + + let invoice = { + amount: 22000, + memo: 'launch', + network: 'lightning', + prompt: false, + rate: rates[form.get('currency')] + }; + + let user = { username: form.get('username') }; + + let { uuid } = await post('/invoice', { invoice, user }, auth(cookies)); + + throw redirect(307, `/invoice/${uuid}`); } }; diff --git a/src/routes/launch/purchase/+page.svelte b/src/routes/launch/purchase/+page.svelte index df3048f3..3273752a 100644 --- a/src/routes/launch/purchase/+page.svelte +++ b/src/routes/launch/purchase/+page.svelte @@ -1,4 +1,5 @@ <script> + import { onMount } from 'svelte'; import { enhance } from '$app/forms'; import { selectedRate } from '$lib/store'; import { post } from '$lib/utils'; @@ -6,77 +7,61 @@ export let data; - let amount = 35000; + let amount = 22000; let { + currency, account: { balance }, username } = data.user; - let invoice; - let get = async (network) => { - let { uuid } = await post('/invoice', { - amount, - rate: $selectedRate, - network, - username - }); - - goto(`/invoice/${uuid}`); - }; - - let lightning = () => get('lightning'); - let bitcoin = () => get('bitcoin'); - - // if (balance < amount) throw redirect(307, `/${username}/fund/${amount - balance}`); + let { tickets } = data; + let ticket = tickets.length; </script> -<div class="mx-auto h-screen flex items-center justify-center px-8"> - <div class="p-4 font-normal text-gray-800 mx-auto mb-8"> - {#if balance > amount} - <h1 class="mb-4 text-4xl font-bold leading-none tracking-tight text-gray-800 text-center"> - Buy Your Launch Party Ticket? - </h1> +<div class="mx-auto h-screen flex items-center justify-center px-4"> + <div class="font-normal text-gray-800 mx-auto mb-8 space-y-8"> + <h1 class="mb-4 text-4xl font-bold leading-none tracking-tight text-gray-800 text-center"> + Purchase Ticket + </h1> - <div class="text-center text-4xl mb-12">{amount} sats</div> + <img + src={`/tickets/${(ticket + 1).toString().padStart(2, '0')}.png`} + class="w-full max-w-[800px]" + alt="Ticket" + /> - <div class="w-full flex"> - <form method="POST" use:enhance> + {#if balance >= amount} + <form action="?/internal" method="POST" use:enhance> + <input type="hidden" name="username" value={username} /> + + <div class="w-full flex"> <button class="bg-black text-white border rounded-full px-8 py-4 font-bold hover:opacity-80 mx-auto text-2xl" > Count me in </button> - </form> - </div> + </div> + </form> {:else} - <h1 class="mb-4 text-4xl font-bold leading-none tracking-tight text-gray-800 text-center"> - Ticket Price - </h1> - <div class="text-center text-4xl mb-12">{amount} sats</div> - - <h1 class="mb-4 text-4xl font-bold leading-none tracking-tight text-gray-800 text-center"> - Your Balance - </h1> - - <div class="text-center text-4xl mb-12">{balance} sats</div> - - <h1 class="mb-4 text-4xl font-bold leading-none tracking-tight text-gray-800 text-center"> - Funding Options + <h1 class="mb-4 text-xl font-bold leading-none tracking-tight text-gray-800 text-center"> + Payment Options </h1> - <button - class="bg-black text-white border rounded-full px-8 py-4 font-bold hover:opacity-80 mx-auto text-2xl" - on:click={lightning} - > - Lightning - </button> + <div class="flex justify-center gap-4"> + <form action="?/lightning" method="POST"> + <input type="hidden" name="currency" value={currency} /> + <input type="hidden" name="username" value={username} /> + <button class="border rounded-full px-8 py-4 font-bold hover:opacity-80 mx-auto text-2xl"> + Lightning + </button> + </form> - <button - class="bg-black text-white border rounded-full px-8 py-4 font-bold hover:opacity-80 mx-auto text-2xl" - on:click={bitcoin} - > - Bitcoin - </button> + <a href={`purchase/card`}> + <button class="border rounded-full px-8 py-4 font-bold hover:opacity-80 mx-auto text-2xl"> + Credit Card + </button> + </a> + </div> {/if} </div> </div> diff --git a/src/routes/launch/purchase/card/+page.server.js b/src/routes/launch/purchase/card/+page.server.js new file mode 100644 index 00000000..1f564f78 --- /dev/null +++ b/src/routes/launch/purchase/card/+page.server.js @@ -0,0 +1,44 @@ +import { env } from '$env/dynamic/private'; +import { error, redirect } from '@sveltejs/kit'; +import { post, auth } from '$lib/utils'; +import { createTicket } from '$lib/ticket'; + +let stripe = 'https://api.stripe.com/v1'; + +export const actions = { + default: async ({ cookies, request }) => { + let form = await request.formData(); + + let headers = new Headers(); + headers.set('Authorization', 'Basic ' + new Buffer(env.STRIPE + ':').toString('base64')); + + let body = new URLSearchParams({ + 'card[number]': form.get('number').replace(/\s+/g, ''), + 'card[exp_month]': form.get('expiry').slice(0, 2), + 'card[exp_year]': form.get('expiry').slice(-2), + 'card[cvc]': form.get('cvc') + }); + + let method = 'POST'; + + let { id: source } = await fetch(`${stripe}/tokens`, { body, headers, method }).then((r) => + r.json() + ); + + body = new URLSearchParams({ + amount: 600, + currency: 'cad', + source, + description: 'launch ticket' + }); + + let { status } = await fetch(`${stripe}/charges`, { body, headers, method }).then((r) => + r.json() + ); + + if (status !== 'succeeded') throw error(500, { message: 'Card payment failed' }); + let asset = await createTicket(cookies, form.get('username')); + + throw redirect(307, `/launch/thanks/${asset}`); + } +}; diff --git a/src/routes/launch/purchase/card/+page.svelte b/src/routes/launch/purchase/card/+page.svelte new file mode 100644 index 00000000..05d09025 --- /dev/null +++ b/src/routes/launch/purchase/card/+page.svelte @@ -0,0 +1,77 @@ +<script> + import { enhance } from '$app/forms'; + import { Lock, Card, Calendar, Spinner } from '$comp'; + + export let data; + + let { username } = data.user; + let loading; +</script> + +<div class="container max-w-lg px-4 mx-auto space-y-5"> + <form + method="POST" + class="flex flex-wrap gap-5 w-full p-5 mt-20" + use:enhance={() => { + loading = true; + return ({ update }) => update() && (loading = false); + }} + > + <input type="hidden" name="username" value={username} /> + <label class="relative w-full flex flex-col"> + <span class="font-bold mb-3">Card number</span> + <input + class="rounded-md peer pl-12 pr-2 py-2 border-2 border-gray-200 placeholder-gray-300" + type="text" + name="number" + placeholder="0000 0000 0000 0000" + /> + <Card /> + </label> + + <label class="relative flex-1 flex flex-col"> + <span class="font-bold mb-3">Expire date</span> + <input + class="rounded-md peer pl-12 pr-2 py-2 border-2 border-gray-200 placeholder-gray-300" + type="text" + name="expiry" + placeholder="MM/YY" + /> + <Calendar /> + </label> + + <label class="relative flex-1 flex flex-col"> + <span class="font-bold flex items-center gap-3 mb-3"> + CVC/CVV + <span class="relative group"> + <span + class="hidden group-hover:flex justify-center items-center px-2 py-1 text-xs absolute -right-2 transform translate-x-full -translate-y-1/2 w-max top-1/2 bg-black text-white" + > + 3-digit number on the back of your card</span + > + </span> + </span> + <input + class="rounded-md peer pl-12 pr-2 py-2 border-2 border-gray-200 placeholder-gray-300" + type="text" + name="cvc" + placeholder="•••" + /> + <Lock /> + </label> + + <div class="w-full flex mt-8"> + <button + class="bg-black text-white border rounded-full px-8 py-4 font-bold hover:opacity-80 mx-auto text-xl" + type="submit" + disabled={loading} + > + {#if loading} + <Spinner /> + {:else} + Submit + {/if} + </button> + </div> + </form> +</div> diff --git a/src/routes/launch/thanks/[asset]/+page.server.js b/src/routes/launch/thanks/[asset]/+page.server.js new file mode 100644 index 00000000..e9e01376 --- /dev/null +++ b/src/routes/launch/thanks/[asset]/+page.server.js @@ -0,0 +1 @@ +// export const load = ({ parent }) => parent(); diff --git a/src/routes/launch/thanks/[asset]/+page.svelte b/src/routes/launch/thanks/[asset]/+page.svelte new file mode 100644 index 00000000..43f10057 --- /dev/null +++ b/src/routes/launch/thanks/[asset]/+page.svelte @@ -0,0 +1,29 @@ +<script> + import { page } from '$app/stores'; + + export let data; + + let { user } = data; + + let { asset } = $page.params; +</script> + +<div class="container mx-auto max-w-lg px-4 mt-20"> + <div class="font-normal text-gray-800 mx-auto mb-8 space-y-8"> + <h1 class="mb-4 text-4xl font-bold leading-none tracking-tight text-gray-800 text-center"> + Thanks! + </h1> + + <p>We look forward to seeing you!</p> + </div> + + <div class="w-full flex"> + <a href="/launch/ticket" class="mx-auto"> + <button + class="bg-black text-white border rounded-full px-8 py-4 font-bold hover:opacity-80 text-2xl" + > + Done + </button> + </a> + </div> +</div> diff --git a/src/routes/launch/ticket/+page.server.js b/src/routes/launch/ticket/+page.server.js new file mode 100644 index 00000000..0362eb7d --- /dev/null +++ b/src/routes/launch/ticket/+page.server.js @@ -0,0 +1,9 @@ +import { get } from '$lib/utils'; + +export const load = async ({ cookies, parent }) => { + let { user } = await parent(); + let tickets = await get('/tickets'); + let ticket = tickets.findIndex((t) => user.accounts.find((a) => a.asset === t)); + let asset = tickets[ticket]; + return { asset, ticket }; +}; diff --git a/src/routes/launch/ticket/+page.svelte b/src/routes/launch/ticket/+page.svelte new file mode 100644 index 00000000..3879abcd --- /dev/null +++ b/src/routes/launch/ticket/+page.svelte @@ -0,0 +1,35 @@ +<script> + export let data; + let { asset, ticket } = data; +</script> + +<div class="mx-auto h-screen flex items-center justify-center px-4"> + <div class="font-normal text-gray-800 mx-auto mb-8 space-y-8"> + <h1 class="mb-4 text-4xl font-bold leading-none tracking-tight text-gray-800 text-center"> + Your Ticket + </h1> + + <p> + We've minted your ticket as an <a + href={`https://blockstream.info/liquid/asset/${asset}`} + class="underline">NFT on the Liquid Blockchain</a + > as a proof of purchase and commemorative token. + </p> + + <img + src={`/tickets/${(ticket + 1).toString().padStart(2, '0')}.png`} + class="w-full max-w-[800px]" + alt="Ticket" + /> + + <div class="w-full flex"> + <a href="/" class="mx-auto"> + <button + class="bg-black text-white border rounded-full px-8 py-4 font-bold hover:opacity-80 text-2xl" + > + Done + </button> + </a> + </div> + </div> +</div> |
