mirror of
https://github.com/web3privacy/w3ps1.git
synced 2024-10-15 16:26:26 +02:00
Add badges discount
This commit is contained in:
parent
90b158861f
commit
bb3194dce7
8 changed files with 7954 additions and 94 deletions
7817
package-lock.json
generated
7817
package-lock.json
generated
File diff suppressed because it is too large
Load diff
10
package.json
10
package.json
|
@ -27,8 +27,16 @@
|
||||||
"remove-markdown": "^0.5.0",
|
"remove-markdown": "^0.5.0",
|
||||||
"svelte": "^3.54.0",
|
"svelte": "^3.54.0",
|
||||||
"svelte-markdown": "^0.2.3",
|
"svelte-markdown": "^0.2.3",
|
||||||
|
"svelte-web3": "^4.0.1",
|
||||||
"tailwindcss": "^3.2.6",
|
"tailwindcss": "^3.2.6",
|
||||||
"vite": "^4.0.0"
|
"vite": "^4.0.0"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"@wagmi/core": "^0.9.7",
|
||||||
|
"@web3modal/ethereum": "^2.1.1",
|
||||||
|
"@web3modal/html": "^2.1.1",
|
||||||
|
"ethers": "^5.7.2",
|
||||||
|
"web3": "^1.8.2"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
20
src/app.css
20
src/app.css
|
@ -33,14 +33,26 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
@apply px-3 py-1.5 text-black bg-white border border-black;
|
@apply px-3 py-1.5 text-black bg-white border border-black cursor-pointer;
|
||||||
}
|
}
|
||||||
.button:hover {
|
.button:hover, .button-inactive {
|
||||||
@apply text-white bg-black border border-white;
|
@apply text-white bg-black border border-white;
|
||||||
}
|
}
|
||||||
|
.button:hover.button-inactive {
|
||||||
|
@apply cursor-default text-gray-600 border-gray-600;
|
||||||
|
}
|
||||||
|
.button-inverse {
|
||||||
|
@apply px-3 py-1.5 text-white bg-black border border-black cursor-pointer;
|
||||||
|
}
|
||||||
|
.button-inverse:hover {
|
||||||
|
@apply text-black bg-white border border-black;
|
||||||
|
}
|
||||||
.section-header {
|
.section-header {
|
||||||
@apply text-3xl md:text-5xl mb-8 md:mb-16 font-bold pt-10;
|
@apply text-3xl md:text-5xl mb-8 md:mb-16 font-bold pt-10;
|
||||||
}
|
}
|
||||||
|
.section-subheader {
|
||||||
|
@apply text-3xl font-bold mb-4 md:mb-8;
|
||||||
|
}
|
||||||
|
|
||||||
.text-mild {
|
.text-mild {
|
||||||
@apply text-white/70;
|
@apply text-white/70;
|
||||||
|
@ -89,4 +101,8 @@
|
||||||
.topic-item:hover .text-supermild {
|
.topic-item:hover .text-supermild {
|
||||||
@apply text-black;
|
@apply text-black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.eligible .text-mild {
|
||||||
|
@apply text-black;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body data-sveltekit-preload-data="hover">
|
<body data-sveltekit-preload-data="hover">
|
||||||
<div style="display: contents">%sveltekit.body%</div>
|
<div style="display: contents">%sveltekit.body%</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
|
||||||
<script
|
<script
|
||||||
defer
|
defer
|
||||||
data-domain="prague.web3privacy.info"
|
data-domain="prague.web3privacy.info"
|
||||||
|
|
176
src/lib/components/Web3Dialog.svelte
Normal file
176
src/lib/components/Web3Dialog.svelte
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
<script>
|
||||||
|
import { browser } from '$app/environment';
|
||||||
|
import { configureChains, createClient, disconnect, signMessage, getAccount } from '@wagmi/core'
|
||||||
|
import { arbitrum, mainnet, polygon, optimism, gnosis } from '@wagmi/core/chains'
|
||||||
|
import { EthereumClient, modalConnectors, walletConnectProvider } from '@web3modal/ethereum'
|
||||||
|
import { Web3Modal } from '@web3modal/html'
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
import SvelteMarkdown from 'svelte-markdown';
|
||||||
|
import { animateText, animateSection } from '$lib/helpers';
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
|
||||||
|
const projectId = '43a2f1e1b1753e7d4e628b5a1827d319'
|
||||||
|
const chains = [mainnet, arbitrum, optimism, polygon, gnosis]
|
||||||
|
const redeemUrl = 'https://tickets.web3privacy.info/w3ps1/redeem?voucher='
|
||||||
|
|
||||||
|
const badges = data.badges
|
||||||
|
let web3Modal
|
||||||
|
let enable = () => init()
|
||||||
|
let disable
|
||||||
|
let userBadges = null
|
||||||
|
let claimed = {}
|
||||||
|
|
||||||
|
const web3store = writable({})
|
||||||
|
|
||||||
|
$: connected = $web3store.isConnected
|
||||||
|
$: selectedAccount = $web3store.address
|
||||||
|
|
||||||
|
async function checkBadges (addr) {
|
||||||
|
const resp = await fetch(`${data.config.badgesApiUrl}/account/${addr}`)
|
||||||
|
return resp.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function init () {
|
||||||
|
|
||||||
|
const { provider } = configureChains(chains, [walletConnectProvider({ projectId })])
|
||||||
|
const wagmiClient = createClient({
|
||||||
|
autoConnect: false,
|
||||||
|
connectors: [...modalConnectors({ appName: 'web3Modal', chains })],
|
||||||
|
provider
|
||||||
|
})
|
||||||
|
|
||||||
|
const ethereumClient = new EthereumClient(wagmiClient, chains)
|
||||||
|
|
||||||
|
disable = async () => {
|
||||||
|
await disconnect()
|
||||||
|
userBadges = {}
|
||||||
|
web3store.set({})
|
||||||
|
}
|
||||||
|
enable = async () => {
|
||||||
|
await web3Modal.openModal()
|
||||||
|
}
|
||||||
|
|
||||||
|
web3Modal = new Web3Modal({ projectId }, ethereumClient)
|
||||||
|
await web3Modal.openModal()
|
||||||
|
|
||||||
|
const unsubscribe = web3Modal.subscribeModal(async (newState) => {
|
||||||
|
const account = getAccount()
|
||||||
|
web3store.set(account)
|
||||||
|
claimed = {}
|
||||||
|
userBadges = await checkBadges(account.address)
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function claimHandler (badgeId) {
|
||||||
|
return async () => {
|
||||||
|
const badge = badges.find(b => b.id === badgeId)
|
||||||
|
const addr = selectedAccount
|
||||||
|
claimed[badgeId] = {}
|
||||||
|
const msg = `I want to get a discount on a ticket to Web3Privacy Prague 2023. My address is "${addr}" and I own "${badge.name}". ${new Date().toISOString()}`
|
||||||
|
let signature;
|
||||||
|
try {
|
||||||
|
signature = await signMessage({ message: msg })
|
||||||
|
} catch (e) {
|
||||||
|
claimed[badgeId] = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!signature) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
claimed[badgeId] = { text: "Wait for the voucher to be generated from our ticketing system .." }
|
||||||
|
const query = {
|
||||||
|
addr,
|
||||||
|
badgeId,
|
||||||
|
msg,
|
||||||
|
signature
|
||||||
|
}
|
||||||
|
console.log(query)
|
||||||
|
const resp = await fetch(`${data.config.badgesApiUrl}/claim`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(query)
|
||||||
|
})
|
||||||
|
const res = await resp.json()
|
||||||
|
claimed[badgeId] = {
|
||||||
|
claimed: true,
|
||||||
|
voucher: res.voucher,
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if !connected}
|
||||||
|
<div class="buttons">
|
||||||
|
<button class="button is-link is-light" on:click={enable} on:mouseenter={(ev) => animateText(ev, 15)}>Connect using Web3 wallet</button>
|
||||||
|
</div>
|
||||||
|
<div class="text-supermild mt-4 text-lg md:w-4/5 mx-auto">Once connected, you will see what discount you are entitled to - based on ownership of the specific ZK Badges or SBT tokens.</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if connected}
|
||||||
|
<div>
|
||||||
|
Connected as: <span class="font-bold">{selectedAccount}</span>
|
||||||
|
<button class="button is-link is-light inline-block cursor-pointer" on:click={disable} on:mouseenter={animateText}>disconnect</button>
|
||||||
|
</div>
|
||||||
|
<!--<p>Connected chain: chainId = {$chainId}</p>
|
||||||
|
<p>Selected account: {$selectedAccount || 'not defined'</p>
|
||||||
|
|
||||||
|
<p>Wallet type: {$walletType || 'not defined'}</p>
|
||||||
|
<p>chainData = {JSON.stringify($chainData)}</p>
|
||||||
|
<p>Selected account balance = <Balance address={checkAccount} /> {$chainData.nativeCurrency?.symbol}</p>
|
||||||
|
-->
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="w-full mt-16">
|
||||||
|
<div class="m-auto">
|
||||||
|
<div class="text-2xl font-bold mb-10" on:mouseenter={animateText}>Eligible ZK Badges / SBTs</div>
|
||||||
|
<div class="pb-8 lg:w-2/3 xl:w-2/3 mx-auto">
|
||||||
|
{#each badges as badge}
|
||||||
|
<div class="lg:flex justify-center mb-10 badge {userBadges?.badges && userBadges?.badges[badge?.id]?.eligible ? 'bg-white text-black eligible' : 'bg-[#0d1117]'} p-4" on:mouseenter={animateSection(30)}>
|
||||||
|
<div class="w-28 lg:w-40 mr-6 inline-block xl:block"><img src={badge.img} class="w-full {connected && userBadges && userBadges.badges[badge.id]?.eligible ? '' : 'grayscale'} badge-image" /></div>
|
||||||
|
<div class="lg:text-left w-full">
|
||||||
|
{#if badge.shortname}<div class="uppercase font-bold">{badge.shortname}</div>{/if}
|
||||||
|
<div class="{badge.shortname ? '' : 'font-bold'} animate-section">
|
||||||
|
<a href={badge.url} target="_blank" class="external">{badge.name}</a>
|
||||||
|
</div>
|
||||||
|
<div class="text-xl">Price: <span class="font-bold">€{data.config.ticketBasePrice - data.config.ticketBasePrice*(badge.discount/100)}</span> ({badge.discount}% discount)</div>
|
||||||
|
{#if connected && userBadges}
|
||||||
|
<div class="pt-2">
|
||||||
|
{#if claimed[badge.id]}
|
||||||
|
{#if claimed[badge.id].voucher}
|
||||||
|
Your personal voucher: <a href="{redeemUrl+claimed[badge.id].voucher}" target="_blank" class="underline hover:no-underline external">{claimed[badge.id].voucher}</a>
|
||||||
|
<div class="pt-2">
|
||||||
|
<a href="{redeemUrl+claimed[badge.id].voucher}" target="_blank"><button class="button-inverse" on:mouseenter={(ev) => animateText(ev, 15)}>Buy ticket using voucher</button></a>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
{claimed[badge.id].text || 'Please sign message in your wallet ..'}
|
||||||
|
{/if}
|
||||||
|
{:else}
|
||||||
|
{#if userBadges.badges[badge.id]?.eligible}
|
||||||
|
<button class="button-inverse" on:click={claimHandler(badge.id)} on:mouseenter={(ev) => animateText(ev, 15)}>Eligible! Get discount!</button>
|
||||||
|
{:else}
|
||||||
|
<button class="button button-inactive text-gray-600 border-gray-600">Not eligible</button>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if badge.text}
|
||||||
|
<div class="text-base pt-2 text-mild">{badge.text}</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold mb-8" on:mouseenter={animateText}>Other discounts (via form)</div>
|
||||||
|
<div class="text-lg md:w-4/5 mx-auto">
|
||||||
|
<SvelteMarkdown source={data.config.ticketsDiscounts} />
|
||||||
|
</div>
|
||||||
|
<div class="mt-8 mb-8">
|
||||||
|
<a href={data.config.ticketsDiscountForm}><button class="button" on:mouseenter={animateText}>Apply for a discount</button></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -54,6 +54,10 @@ ticketsIntro: Be a part of the first Web3Privacy Summit experience…
|
||||||
ticketsNote: Tickets will go on sale in late February 2023.
|
ticketsNote: Tickets will go on sale in late February 2023.
|
||||||
ticketing: false
|
ticketing: false
|
||||||
ticketingUrl: https://tickets.web3privacy.info/w3ps1/
|
ticketingUrl: https://tickets.web3privacy.info/w3ps1/
|
||||||
|
ticketBasePrice: 99
|
||||||
|
ticketsDiscountForm: https://attend.web3privacy.info
|
||||||
|
ticketsDiscounts: |
|
||||||
|
We also offer discounts for other groups such as active open-source contributors to privacy protocols, privacy (lunarpunk) advocates, full-time students, attendees from OECD low income countries, independent developers, etc. Feel free to request your special discount using the form:
|
||||||
tickets:
|
tickets:
|
||||||
- title: All-day Access
|
- title: All-day Access
|
||||||
price: €99
|
price: €99
|
||||||
|
@ -64,7 +68,7 @@ tickets:
|
||||||
- Networking drinks with speakers & attendees
|
- Networking drinks with speakers & attendees
|
||||||
- '#Lunarpunk party'
|
- '#Lunarpunk party'
|
||||||
hint: |
|
hint: |
|
||||||
[Apply for a discount →](https://attend.web3privacy.info)<br />(as independent developer, student, privacy advocate, open-source contributor..)
|
Discounts: We offer various discounts up to 100%, see below
|
||||||
- title: '#Lunarpunk Party'
|
- title: '#Lunarpunk Party'
|
||||||
price: €15
|
price: €15
|
||||||
includes:
|
includes:
|
||||||
|
@ -201,3 +205,4 @@ program:
|
||||||
type: other
|
type: other
|
||||||
- time: 16:10 - 18:30
|
- time: 16:10 - 18:30
|
||||||
title: Workshops IV.
|
title: Workshops IV.
|
||||||
|
badgesApiUrl: https://badges-pretix-voucher-api.web3privacy.info
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import config from '$lib/config.yaml';
|
import config from '$lib/config.yaml';
|
||||||
|
|
||||||
export async function load({ params, url, fetch }) {
|
export async function load({ params, url, fetch }) {
|
||||||
|
|
||||||
|
const resp = await fetch(config.badgesApiUrl + "/badges")
|
||||||
|
const badges = await resp.json()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
config
|
config,
|
||||||
|
badges
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import PeopleList from '$lib/components/PeopleList.svelte';
|
import PeopleList from '$lib/components/PeopleList.svelte';
|
||||||
import { animateText, animateSection } from '$lib/helpers';
|
import { animateText, animateSection } from '$lib/helpers';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import Web3Dialog from '$lib/components/Web3Dialog.svelte';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
</script>
|
</script>
|
||||||
|
@ -134,7 +135,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-black" id="ticket">
|
<div class="bg-black" id="ticket">
|
||||||
<div class="middle-pane-medium pt-16 text-xl text-center mx-auto pb-32">
|
<div class="middle-pane-medium pt-16 text-xl text-center mx-auto">
|
||||||
<div class="section-header" on:mouseenter={animateText}>Ticket</div>
|
<div class="section-header" on:mouseenter={animateText}>Ticket</div>
|
||||||
<div class="mb-8 text-lg text-mild">{data.config.ticketsIntro}</div>
|
<div class="mb-8 text-lg text-mild">{data.config.ticketsIntro}</div>
|
||||||
<div class="grid lg:grid-cols-2 gap-10 md:w-2/3 mx-auto">
|
<div class="grid lg:grid-cols-2 gap-10 md:w-2/3 mx-auto">
|
||||||
|
@ -181,8 +182,15 @@
|
||||||
<div class="mt-8 text-xl">{data.config.ticketsNote}</div>
|
<div class="mt-8 text-xl">{data.config.ticketsNote}</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="middle-pane-medium text-xl text-center mx-auto pt-10 pb-32">
|
||||||
|
<div class="section-subheader" on:mouseenter={animateText}>Get your discount</div>
|
||||||
|
<div>
|
||||||
|
<Web3Dialog {data} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="mb-36" id="faq">
|
<div class="mb-36" id="faq">
|
||||||
<div class="middle-pane-medium pt-20 text-xl text-center mx-auto">
|
<div class="middle-pane-medium pt-20 text-xl text-center mx-auto">
|
||||||
<div class="section-header" on:mouseenter={animateText}>FAQ</div>
|
<div class="section-header" on:mouseenter={animateText}>FAQ</div>
|
||||||
|
|
Loading…
Reference in a new issue