aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/launch/purchase/card
diff options
context:
space:
mode:
Diffstat (limited to 'src/routes/launch/purchase/card')
-rw-r--r--src/routes/launch/purchase/card/+page.server.js44
-rw-r--r--src/routes/launch/purchase/card/+page.svelte77
2 files changed, 121 insertions, 0 deletions
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="&bull;&bull;&bull;"
+ />
+ <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>