aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsecondl1ght <[email protected]>2022-10-25 18:01:56 -0600
committersecondl1ght <[email protected]>2022-10-25 18:01:56 -0600
commita67b375473f1f40e1c0febfac16d7e36e0d72561 (patch)
tree10a5fa750f2ccb53cff3510ab8fbbce108a35eb6
parentaa6debcd83c0b4067e0f8ce9a11d9c9ac02476ad (diff)
parent5a5ea3ccc327ff52fb1c313998d90e4bfefea90a (diff)
downloadcoinos-ui-a67b375473f1f40e1c0febfac16d7e36e0d72561.tar.gz
coinos-ui-a67b375473f1f40e1c0febfac16d7e36e0d72561.zip
Merge branch 'master' of github.com:coinos/coinos-ui-v2
-rw-r--r--.env.sample (renamed from .env)0
-rw-r--r--.gitignore1
-rw-r--r--Dockerfile4
-rw-r--r--package.json15
-rw-r--r--pnpm-lock.yaml487
-rw-r--r--src/app.html3
-rw-r--r--src/components/AppHeader.svelte3
-rw-r--r--src/components/Avatar.svelte3
-rw-r--r--src/components/Calendar.svelte14
-rw-r--r--src/components/Card.svelte14
-rw-r--r--src/components/Lock.svelte14
-rw-r--r--src/components/Pin.svelte35
-rw-r--r--src/components/Qr.svelte4
-rw-r--r--src/components/RegisterOrLogin.svelte197
-rw-r--r--src/components/Tip.svelte4
-rw-r--r--src/components/index.js4
-rw-r--r--src/hooks.server.js4
-rw-r--r--src/lib/socket.js9
-rw-r--r--src/lib/store.js14
-rw-r--r--src/lib/ticket.js31
-rw-r--r--src/lib/tickets.js52
-rw-r--r--src/lib/utils.js25
-rw-r--r--src/locales/en.json4
-rw-r--r--src/locales/es.json2
-rw-r--r--src/routes/+layout.server.js10
-rw-r--r--src/routes/+layout.svelte15
-rw-r--r--src/routes/[username]/+page.server.js1
-rw-r--r--src/routes/[username]/dashboard/+page.server.js1
-rw-r--r--src/routes/[username]/settings/+page.server.js4
-rw-r--r--src/routes/[username]/settings/+page.svelte41
-rw-r--r--src/routes/[username]/settings/_account.svelte35
-rw-r--r--src/routes/[username]/settings/_security.svelte109
-rw-r--r--src/routes/invoice/[id]/+page.svelte4
-rw-r--r--src/routes/invoice/[id]/paid/+page.svelte2
-rw-r--r--src/routes/launch/+page.server.js6
-rw-r--r--src/routes/launch/+page.svelte91
-rw-r--r--src/routes/launch/purchase/+page.server.js45
-rw-r--r--src/routes/launch/purchase/+page.svelte91
-rw-r--r--src/routes/launch/purchase/card/+page.server.js44
-rw-r--r--src/routes/launch/purchase/card/+page.svelte77
-rw-r--r--src/routes/launch/thanks/[asset]/+page.server.js1
-rw-r--r--src/routes/launch/thanks/[asset]/+page.svelte29
-rw-r--r--src/routes/launch/ticket/+page.server.js9
-rw-r--r--src/routes/launch/ticket/+page.svelte35
-rw-r--r--src/routes/login/+page.server.js10
-rw-r--r--src/routes/login/+page.svelte1
-rw-r--r--src/routes/register/+page.server.js4
-rw-r--r--src/routes/register/+page.svelte2
-rw-r--r--src/routes/scan/+page.svelte2
-rw-r--r--src/routes/send/+layout.svelte18
-rw-r--r--src/routes/send/[...text]/+page.server.js2
-rw-r--r--src/routes/send/[...text]/+page.svelte4
-rw-r--r--src/routes/send/[uuid=uuid]/+page.server.js15
-rw-r--r--src/routes/send/[uuid=uuid]/+page.svelte15
-rw-r--r--src/routes/send/bitcoin/[address]/+page.server.js13
-rw-r--r--src/routes/send/bitcoin/[address]/+page.svelte16
-rw-r--r--src/routes/send/lightning/[payreq]/+page.server.js16
-rw-r--r--src/routes/send/lightning/[payreq]/+page.svelte14
-rw-r--r--src/routes/send/user/[username]/[...amount]/+page.server.js15
-rw-r--r--src/routes/send/user/[username]/[...amount]/+page.svelte16
-rw-r--r--src/routes/user/+server.js1
-rw-r--r--static/icons/party.svg64
-rw-r--r--static/images/loft.jpgbin0 -> 286853 bytes
-rw-r--r--static/images/logo.pngbin0 -> 5637 bytes
-rw-r--r--static/tickets/01.pngbin0 -> 328175 bytes
-rw-r--r--static/tickets/02.pngbin0 -> 328809 bytes
-rw-r--r--static/tickets/03.pngbin0 -> 328778 bytes
-rw-r--r--static/tickets/04.pngbin0 -> 328539 bytes
-rw-r--r--static/tickets/05.pngbin0 -> 328735 bytes
-rw-r--r--static/tickets/06.pngbin0 -> 328887 bytes
-rw-r--r--static/tickets/07.pngbin0 -> 328562 bytes
-rw-r--r--static/tickets/08.pngbin0 -> 329032 bytes
-rw-r--r--static/tickets/09.pngbin0 -> 328984 bytes
-rw-r--r--static/tickets/10.pngbin0 -> 328193 bytes
-rw-r--r--static/tickets/11.pngbin0 -> 327215 bytes
-rw-r--r--static/tickets/12.pngbin0 -> 327960 bytes
-rw-r--r--static/tickets/13.pngbin0 -> 328043 bytes
-rw-r--r--static/tickets/14.pngbin0 -> 327772 bytes
-rw-r--r--static/tickets/15.pngbin0 -> 327942 bytes
-rw-r--r--static/tickets/16.pngbin0 -> 328184 bytes
-rw-r--r--static/tickets/17.pngbin0 -> 327705 bytes
-rw-r--r--static/tickets/18.pngbin0 -> 328330 bytes
-rw-r--r--static/tickets/19.pngbin0 -> 328094 bytes
-rw-r--r--static/tickets/20.pngbin0 -> 328762 bytes
-rw-r--r--static/tickets/21.pngbin0 -> 327907 bytes
-rw-r--r--static/tickets/22.pngbin0 -> 327742 bytes
-rw-r--r--static/tickets/23.pngbin0 -> 328659 bytes
-rw-r--r--static/tickets/24.pngbin0 -> 328342 bytes
-rw-r--r--static/tickets/25.pngbin0 -> 328559 bytes
-rw-r--r--static/tickets/26.pngbin0 -> 328749 bytes
-rw-r--r--static/tickets/27.pngbin0 -> 328339 bytes
-rw-r--r--static/tickets/28.pngbin0 -> 328867 bytes
-rw-r--r--static/tickets/29.pngbin0 -> 328698 bytes
-rw-r--r--static/tickets/30.pngbin0 -> 328710 bytes
-rw-r--r--static/tickets/31.pngbin0 -> 327985 bytes
-rw-r--r--static/tickets/32.pngbin0 -> 328621 bytes
-rw-r--r--static/tickets/33.pngbin0 -> 327720 bytes
-rw-r--r--static/tickets/34.pngbin0 -> 328366 bytes
-rw-r--r--static/tickets/35.pngbin0 -> 328507 bytes
-rw-r--r--static/tickets/36.pngbin0 -> 328767 bytes
-rw-r--r--static/tickets/37.pngbin0 -> 328358 bytes
-rw-r--r--static/tickets/38.pngbin0 -> 328839 bytes
-rw-r--r--static/tickets/39.pngbin0 -> 328764 bytes
-rw-r--r--static/tickets/40.pngbin0 -> 328562 bytes
-rw-r--r--static/tickets/41.pngbin0 -> 327591 bytes
-rw-r--r--static/tickets/42.pngbin0 -> 328279 bytes
-rw-r--r--static/tickets/43.pngbin0 -> 328364 bytes
-rw-r--r--static/tickets/44.pngbin0 -> 327599 bytes
-rw-r--r--static/tickets/45.pngbin0 -> 328331 bytes
-rw-r--r--static/tickets/46.pngbin0 -> 328518 bytes
-rw-r--r--static/tickets/47.pngbin0 -> 328120 bytes
-rw-r--r--static/tickets/48.pngbin0 -> 328703 bytes
-rw-r--r--static/tickets/49.pngbin0 -> 328488 bytes
-rw-r--r--static/tickets/50.pngbin0 -> 328729 bytes
114 files changed, 1281 insertions, 540 deletions
diff --git a/.env b/.env.sample
index 468bbf9c..468bbf9c 100644
--- a/.env
+++ b/.env.sample
diff --git a/.gitignore b/.gitignore
index dad6f805..75631d29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ node_modules
/build
/.svelte-kit
/package
+.env
diff --git a/Dockerfile b/Dockerfile
index f61d1034..ed7c9613 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,8 +6,8 @@ ENV NODE_ENV $NODE_ENV
RUN npm i -g pnpm
WORKDIR /app
-COPY package.json .
-RUN NODE_ENV=development pnpm i
+ADD package.json .
+RUN --mount=type=cache,target=/root/.local/share/pnpm/store NODE_ENV=development pnpm i
COPY . .
RUN pnpm build
diff --git a/package.json b/package.json
index 808e5761..b00befb7 100644
--- a/package.json
+++ b/package.json
@@ -11,29 +11,28 @@
},
"devDependencies": {
"@sveltejs/adapter-node": "next",
- "@sveltejs/kit": "1.0.0-next.505",
+ "@sveltejs/kit": "1.0.0-next.516",
"@zerodevx/svelte-toast": "^0.7.2",
"autoprefixer": "^10.4.12",
"bip21": "^2.0.3",
"bitcoin-address-validation": "^2.2.1",
"bolt11": "^1.4.0",
- "cookie": "^0.5.0",
"date-fns": "^2.29.3",
- "leaflet": "^1.9.1",
+ "leaflet": "^1.9.2",
"leaflet.markercluster": "^1.5.3",
- "postcss": "^8.4.17",
+ "postcss": "^8.4.18",
"prettier": "^2.7.1",
- "prettier-plugin-svelte": "^2.7.1",
+ "prettier-plugin-svelte": "^2.8.0",
"qr-code-styling": "1.6.0-rc.1",
"qr-scanner": "^1.4.1",
"screenfull": "^6.0.2",
- "svelte": "^3.50.1",
- "svelte-outclick": "^3.1.0",
+ "svelte": "^3.52.0",
+ "svelte-outclick": "^3.2.0",
"svelte-pincode": "^2.1.2",
"svelte-preprocess": "^4.10.7",
"sveltekit-i18n": "^2.2.2",
"tailwindcss": "^3.1.8",
- "vite": "^3.1.4"
+ "vite": "^3.1.8"
},
"type": "module"
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 644cca0e..04bec42b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -2,60 +2,58 @@ lockfileVersion: 5.4
specifiers:
'@sveltejs/adapter-node': next
- '@sveltejs/kit': 1.0.0-next.505
+ '@sveltejs/kit': 1.0.0-next.516
'@zerodevx/svelte-toast': ^0.7.2
autoprefixer: ^10.4.12
bip21: ^2.0.3
bitcoin-address-validation: ^2.2.1
bolt11: ^1.4.0
- cookie: ^0.5.0
date-fns: ^2.29.3
- leaflet: ^1.9.1
+ leaflet: ^1.9.2
leaflet.markercluster: ^1.5.3
- postcss: ^8.4.17
+ postcss: ^8.4.18
prettier: ^2.7.1
- prettier-plugin-svelte: ^2.7.1
+ prettier-plugin-svelte: ^2.8.0
qr-code-styling: 1.6.0-rc.1
qr-scanner: ^1.4.1
screenfull: ^6.0.2
- svelte: ^3.50.1
- svelte-outclick: ^3.1.0
+ svelte: ^3.52.0
+ svelte-outclick: ^3.2.0
svelte-pincode: ^2.1.2
svelte-preprocess: ^4.10.7
sveltekit-i18n: ^2.2.2
tailwindcss: ^3.1.8
- vite: ^3.1.4
+ vite: ^3.1.8
devDependencies:
- '@sveltejs/adapter-node': 1.0.0-next.96
+ '@sveltejs/adapter-node': 1.0.0-next.98
'@zerodevx/svelte-toast': 0.7.2
- autoprefixer: [email protected]
+ autoprefixer: [email protected]
bip21: 2.0.3
bitcoin-address-validation: 2.2.1
bolt11: 1.4.0
- cookie: 0.5.0
date-fns: 2.29.3
- leaflet: 1.9.1
- leaflet.markercluster: [email protected]
- postcss: 8.4.17
+ leaflet: 1.9.2
+ leaflet.markercluster: [email protected]
+ postcss: 8.4.18
prettier: 2.7.1
- prettier-plugin-svelte: 2.7.1_nk6d2fkgcllkkdynqbuearcure
+ prettier-plugin-svelte: 2.8.0_lrllcp5xtrkmmdzifit4hd52ze
qr-code-styling: 1.6.0-rc.1
qr-scanner: 1.4.1
screenfull: 6.0.2
- svelte: 3.50.1
- svelte-outclick: 3.1.0
+ svelte: 3.52.0
+ svelte-outclick: 3.2.0
svelte-pincode: 2.1.2
- svelte-preprocess: 4.10.7_r763xggw3my2ousygwguxmp6ru
- sveltekit-i18n: [email protected]
- tailwindcss: [email protected]
- vite: 3.1.4
+ svelte-preprocess: 4.10.7_vidagnlh55bt6yxji7dk5y5wla
+ sveltekit-i18n: [email protected]
+ tailwindcss: [email protected]
+ vite: 3.1.8
packages:
- /@esbuild/android-arm/0.15.10:
- resolution: {integrity: sha512-FNONeQPy/ox+5NBkcSbYJxoXj9GWu8gVGJTVmUyoOCKQFDTrHVKgNSzChdNt0I8Aj/iKcsDf2r9BFwv+FSNUXg==}
+ /@esbuild/android-arm/0.15.11:
+ resolution: {integrity: sha512-PzMcQLazLBkwDEkrNPi9AbjFt6+3I7HKbiYF2XtWQ7wItrHvEOeO3T8Am434zAozWtVP7lrTue1bEfc2nYWeCA==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
@@ -63,8 +61,8 @@ packages:
dev: true
optional: true
- /@esbuild/linux-loong64/0.15.10:
- resolution: {integrity: sha512-w0Ou3Z83LOYEkwaui2M8VwIp+nLi/NA60lBLMvaJ+vXVMcsARYdEzLNE7RSm4+lSg4zq4d7fAVuzk7PNQ5JFgg==}
+ /@esbuild/linux-loong64/0.15.11:
+ resolution: {integrity: sha512-geWp637tUhNmhL3Xgy4Bj703yXB9dqiLJe05lCUfjSFDrQf9C/8pArusyPUbUbPwlC/EAUjBw32sxuIl/11dZw==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
@@ -97,39 +95,48 @@ packages:
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
dev: true
- /@rollup/plugin-commonjs/[email protected]:
- resolution: {integrity: sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==}
- engines: {node: '>= 12.0.0'}
+ /@rollup/plugin-commonjs/[email protected]:
+ resolution: {integrity: sha512-JbrTRyDNtLQj/rhl7RFUuYXwQ2fac+33oLDAu2k++WD95zweyo28UAomLVA0JMGx4vmCa7Nw4T6k/1F6lelExg==}
+ engines: {node: '>=14.0.0'}
peerDependencies:
- rollup: ^2.68.0
+ rollup: ^2.68.0||^3.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
dependencies:
- '@rollup/pluginutils': [email protected]
+ '@rollup/pluginutils': 4.2.1
commondir: 1.0.1
estree-walker: 2.0.2
- glob: 7.2.3
+ glob: 8.0.3
is-reference: 1.2.1
- magic-string: 0.25.9
- resolve: 1.22.1
+ magic-string: 0.26.7
rollup: 2.79.1
dev: true
- /@rollup/plugin-json/[email protected]:
- resolution: {integrity: sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==}
+ /@rollup/plugin-json/[email protected]:
+ resolution: {integrity: sha512-LsWDA5wJs/ggzakVuKQhZo7HPRcQZgBa3jWIVxQSFxaRToUGNi8ZBh3+k/gQ+1eInVYJgn4WBRCUkmoDrmmGzw==}
+ engines: {node: '>=14.0.0'}
peerDependencies:
- rollup: ^1.20.0 || ^2.0.0
+ rollup: ^1.20.0||^2.0.0||^3.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
dependencies:
- '@rollup/pluginutils': [email protected]
+ '@rollup/pluginutils': 4.2.1
rollup: 2.79.1
dev: true
- /@rollup/plugin-node-resolve/[email protected]:
- resolution: {integrity: sha512-5G2niJroNCz/1zqwXtk0t9+twOSDlG00k1Wfd7bkbbXmwg8H8dvgHdIWAun53Ps/rckfvOC7scDBjuGFg5OaWw==}
- engines: {node: '>= 10.0.0'}
+ /@rollup/plugin-node-resolve/[email protected]:
+ resolution: {integrity: sha512-iwJbzfTzlzDDQcGmkS7EkCKwe2kSkdBrjX87Fy/KrNjr6UNnLpod0t6X66e502LRe5JJCA4FFqrEscWPnZAkig==}
+ engines: {node: '>=14.0.0'}
peerDependencies:
- rollup: ^2.78.0
+ rollup: ^2.78.0||^3.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
dependencies:
- '@rollup/pluginutils': [email protected]
- '@types/resolve': 1.17.1
+ '@rollup/pluginutils': 4.2.1
+ '@types/resolve': 1.20.2
deepmerge: 4.2.2
is-builtin-module: 3.2.0
is-module: 1.0.0
@@ -137,18 +144,6 @@ packages:
rollup: 2.79.1
dev: true
- /@rollup/pluginutils/[email protected]:
- resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
- engines: {node: '>= 8.0.0'}
- peerDependencies:
- rollup: ^1.20.0||^2.0.0
- dependencies:
- '@types/estree': 0.0.39
- estree-walker: 1.0.1
- picomatch: 2.3.1
- rollup: 2.79.1
- dev: true
-
/@rollup/pluginutils/4.2.1:
resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
engines: {node: '>= 8.0.0'}
@@ -157,17 +152,17 @@ packages:
picomatch: 2.3.1
dev: true
- /@sveltejs/adapter-node/1.0.0-next.96:
- resolution: {integrity: sha512-tIHaRolUYy2PiHl4RUWaOsYxEjK5lN9501qzCzFbYr/uoLnZcnPGSXNJICwX0AX9AUkV6cvkZey6bLbUQcwH0Q==}
+ /@sveltejs/adapter-node/1.0.0-next.98:
+ resolution: {integrity: sha512-eo89sswzm3ntZJgaQzz2MneqMqBfQWQj6b8VtImlHeq2AB+RSodippmKY0RyPcIJ0hJqdDc4DubU7XMDKkoTew==}
dependencies:
- '@rollup/plugin-commonjs': [email protected]
- '@rollup/plugin-json': [email protected]
- '@rollup/plugin-node-resolve': [email protected]
+ '@rollup/plugin-commonjs': [email protected]
+ '@rollup/plugin-json': [email protected]
+ '@rollup/plugin-node-resolve': [email protected]
rollup: 2.79.1
dev: true
- resolution: {integrity: sha512-vg2WvWiUB7useJZOKbdM8WOXv10WD7SVDER74IXd1t/TWb/uXHzwMQ/ZAsXZFdxQsz1cDGFub3iC76PW+j58Pg==}
+ resolution: {integrity: sha512-n0oGcv7xpgJ81ld1oER5HVREP4TdeDUJ8S64XNDcl3Y2xfQLKk8C4SLYQw2D6V+DxUm8V3aRrj7N7/tm4CQm6A==}
engines: {node: '>=16.14'}
hasBin: true
requiresBuild: true
@@ -175,28 +170,27 @@ packages:
svelte: ^3.44.0
vite: ^3.1.0
dependencies:
- '@sveltejs/vite-plugin-svelte': [email protected][email protected]
+ '@sveltejs/vite-plugin-svelte': [email protected][email protected]
'@types/cookie': 0.5.1
cookie: 0.5.0
- devalue: 3.1.3
+ devalue: 4.0.1
kleur: 4.1.5
- magic-string: 0.26.5
+ magic-string: 0.26.7
mime: 3.0.0
- node-fetch: 3.2.10
sade: 1.8.1
set-cookie-parser: 2.5.1
sirv: 2.0.2
- svelte: 3.50.1
+ svelte: 3.52.0
tiny-glob: 0.2.9
undici: 5.11.0
- vite: 3.1.4
+ vite: 3.1.8
transitivePeerDependencies:
- diff-match-patch
- supports-color
dev: true
- /@sveltejs/vite-plugin-svelte/[email protected][email protected]:
- resolution: {integrity: sha512-1xkVTB4pm6zuign858FzVYE9Fdw9MQBOlxrdd85STV0NvTDmcofcRpcrK+zcIyT8SZ2dseHLu8hvDwzssF6RfA==}
+ /@sveltejs/vite-plugin-svelte/[email protected][email protected]:
+ resolution: {integrity: sha512-+SDrAnT7TDi8sdj4OfD2SC4s9DNrpNVBrue8fT2PmKks9Ddu0JIfSeX91wXZb/1xHz4EkGb+rli8GTRI0yGOjg==}
engines: {node: ^14.18.0 || >= 16}
peerDependencies:
diff-match-patch: ^1.0.5
@@ -210,20 +204,20 @@ packages:
debug: 4.3.4
deepmerge: 4.2.2
kleur: 4.1.5
- magic-string: 0.26.5
- svelte: 3.50.1
- svelte-hmr: [email protected]
- vite: 3.1.4
+ magic-string: 0.26.7
+ svelte: 3.52.0
+ svelte-hmr: [email protected]
+ vite: 3.1.8
transitivePeerDependencies:
- supports-color
dev: true
- /@sveltekit-i18n/base/[email protected]:
+ /@sveltekit-i18n/base/[email protected]:
resolution: {integrity: sha512-F8gqG2+KAOeT0o2wYlUrW3TRCX7zaD7rBy/1CEVNw0irfw9TgFf/ODmhubkHHT3+6Zk+SMz8RNgeuffBfAMbJw==}
peerDependencies:
svelte: ^3.x
dependencies:
- svelte: 3.50.1
+ svelte: 3.52.0
optionalDependencies:
'@sveltekit-i18n/parser-default': 1.0.3
dev: true
@@ -235,23 +229,19 @@ packages:
/@types/bn.js/4.11.6:
resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==}
dependencies:
- '@types/node': 18.8.0
+ '@types/node': 18.11.0
dev: true
/@types/cookie/0.5.1:
resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==}
dev: true
- /@types/estree/0.0.39:
- resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
- dev: true
-
/@types/estree/1.0.0:
resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==}
dev: true
- /@types/node/18.8.0:
- resolution: {integrity: sha512-u+h43R6U8xXDt2vzUaVP3VwjjLyOJk6uEciZS8OSyziUQGOwmk+l+4drxcsDboHXwyTaqS1INebghmWMRxq3LA==}
+ /@types/node/18.11.0:
+ resolution: {integrity: sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==}
dev: true
/@types/offscreencanvas/2019.7.0:
@@ -262,16 +252,14 @@ packages:
resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==}
dev: true
- /@types/resolve/1.17.1:
- resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
- dependencies:
- '@types/node': 18.8.0
+ /@types/resolve/1.20.2:
+ resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
dev: true
/@types/sass/1.43.1:
resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==}
dependencies:
- '@types/node': 18.8.0
+ '@types/node': 18.11.0
dev: true
/@zerodevx/svelte-toast/0.7.2:
@@ -309,7 +297,7 @@ packages:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
dev: true
- /autoprefixer/[email protected]:
+ /autoprefixer/[email protected]:
resolution: {integrity: sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
@@ -317,11 +305,11 @@ packages:
postcss: ^8.1.0
dependencies:
browserslist: 4.21.4
- caniuse-lite: 1.0.30001414
+ caniuse-lite: 1.0.30001420
fraction.js: 4.2.0
normalize-range: 0.1.2
picocolors: 1.0.0
- postcss: 8.4.17
+ postcss: 8.4.18
postcss-value-parser: 4.2.0
dev: true
@@ -410,6 +398,12 @@ packages:
concat-map: 0.0.1
dev: true
+ /brace-expansion/2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ dependencies:
+ balanced-match: 1.0.2
+ dev: true
+
/braces/3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
@@ -426,10 +420,10 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
- caniuse-lite: 1.0.30001414
- electron-to-chromium: 1.4.271
+ caniuse-lite: 1.0.30001420
+ electron-to-chromium: 1.4.283
node-releases: 2.0.6
- update-browserslist-db: [email protected]
+ update-browserslist-db: [email protected]
dev: true
/bs58/4.0.1:
@@ -474,8 +468,8 @@ packages:
engines: {node: '>= 6'}
dev: true
- /caniuse-lite/1.0.30001414:
- resolution: {integrity: sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==}
+ /caniuse-lite/1.0.30001420:
+ resolution: {integrity: sha512-OnyeJ9ascFA9roEj72ok2Ikp7PHJTKubtEJIQ/VK3fdsS50q4KWy+Z5X0A1/GswEItKX0ctAp8n4SYDE7wTu6A==}
dev: true
/chokidar/3.5.3:
@@ -533,11 +527,6 @@ packages:
hasBin: true
dev: true
- /data-uri-to-buffer/4.0.0:
- resolution: {integrity: sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==}
- engines: {node: '>= 12'}
- dev: true
-
/date-fns/2.29.3:
resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==}
engines: {node: '>=0.11'}
@@ -560,8 +549,8 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
- /defined/1.0.0:
- resolution: {integrity: sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==}
+ /defined/1.0.1:
+ resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==}
dev: true
/detect-indent/6.1.0:
@@ -575,12 +564,12 @@ packages:
hasBin: true
dependencies:
acorn-node: 1.8.2
- defined: 1.0.0
- minimist: 1.2.6
+ defined: 1.0.1
+ minimist: 1.2.7
dev: true
- /devalue/3.1.3:
- resolution: {integrity: sha512-9KO89Cb+qjzf2CqdrH+NuLaqdk9GhDP5EhR4zlkR51dvuIaiqtlkDkGzLMShDemwUy21raSMdu+kpX8Enw3yGQ==}
+ /devalue/4.0.1:
+ resolution: {integrity: sha512-Oksbel8g2rv5ivcCyImF1RXEU2FcS1OtCwVs4tJCCeVws/Dp9EE15fUbEsNr/xLD3ZxsQURBCDf56Lk1CgwCpg==}
dev: true
/didyoumean/1.2.2:
@@ -591,8 +580,8 @@ packages:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
dev: true
- /electron-to-chromium/1.4.271:
- resolution: {integrity: sha512-BCPBtK07xR1/uY2HFDtl3wK2De66AW4MSiPlLrnPNxKC/Qhccxd59W73654S3y6Rb/k3hmuGJOBnhjfoutetXA==}
+ /electron-to-chromium/1.4.283:
+ resolution: {integrity: sha512-g6RQ9zCOV+U5QVHW9OpFR7rdk/V7xfopNXnyAamdpFgCHgZ1sjI8VuR1+zG2YG/TZk+tQ8mpNkug4P8FU0fuOA==}
dev: true
/elliptic/6.5.4:
@@ -611,8 +600,8 @@ packages:
resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
dev: true
- /esbuild-android-64/0.15.10:
- resolution: {integrity: sha512-UI7krF8OYO1N7JYTgLT9ML5j4+45ra3amLZKx7LO3lmLt1Ibn8t3aZbX5Pu4BjWiqDuJ3m/hsvhPhK/5Y/YpnA==}
+ /esbuild-android-64/0.15.11:
+ resolution: {integrity: sha512-rrwoXEiuI1kaw4k475NJpexs8GfJqQUKcD08VR8sKHmuW9RUuTR2VxcupVvHdiGh9ihxL9m3lpqB1kju92Ialw==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
@@ -620,8 +609,8 @@ packages:
dev: true
optional: true
- /esbuild-android-arm64/0.15.10:
- resolution: {integrity: sha512-EOt55D6xBk5O05AK8brXUbZmoFj4chM8u3riGflLa6ziEoVvNjRdD7Cnp82NHQGfSHgYR06XsPI8/sMuA/cUwg==}
+ /esbuild-android-arm64/0.15.11:
+ resolution: {integrity: sha512-/hDubOg7BHOhUUsT8KUIU7GfZm5bihqssvqK5PfO4apag7YuObZRZSzViyEKcFn2tPeHx7RKbSBXvAopSHDZJQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
@@ -629,8 +618,8 @@ packages:
dev: true
optional: true
- /esbuild-darwin-64/0.15.10:
- resolution: {integrity: sha512-hbDJugTicqIm+WKZgp208d7FcXcaK8j2c0l+fqSJ3d2AzQAfjEYDRM3Z2oMeqSJ9uFxyj/muSACLdix7oTstRA==}
+ /esbuild-darwin-64/0.15.11:
+ resolution: {integrity: sha512-1DqHD0ms3AhiwkKnjRUzmiW7JnaJJr5FKrPiR7xuyMwnjDqvNWDdMq4rKSD9OC0piFNK6n0LghsglNMe2MwJtA==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
@@ -638,8 +627,8 @@ packages:
dev: true
optional: true
- /esbuild-darwin-arm64/0.15.10:
- resolution: {integrity: sha512-M1t5+Kj4IgSbYmunf2BB6EKLkWUq+XlqaFRiGOk8bmBapu9bCDrxjf4kUnWn59Dka3I27EiuHBKd1rSO4osLFQ==}
+ /esbuild-darwin-arm64/0.15.11:
+ resolution: {integrity: sha512-OMzhxSbS0lwwrW40HHjRCeVIJTURdXFA8c3GU30MlHKuPCcvWNUIKVucVBtNpJySXmbkQMDJdJNrXzNDyvoqvQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
@@ -647,8 +636,8 @@ packages:
dev: true
optional: true
- /esbuild-freebsd-64/0.15.10:
- resolution: {integrity: sha512-KMBFMa7C8oc97nqDdoZwtDBX7gfpolkk6Bcmj6YFMrtCMVgoU/x2DI1p74DmYl7CSS6Ppa3xgemrLrr5IjIn0w==}
+ /esbuild-freebsd-64/0.15.11:
+ resolution: {integrity: sha512-8dKP26r0/Qyez8nTCwpq60QbuYKOeBygdgOAWGCRalunyeqWRoSZj9TQjPDnTTI9joxd3QYw3UhVZTKxO9QdRg==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
@@ -656,8 +645,8 @@ packages:
dev: true
optional: true
- /esbuild-freebsd-arm64/0.15.10:
- resolution: {integrity: sha512-m2KNbuCX13yQqLlbSojFMHpewbn8wW5uDS6DxRpmaZKzyq8Dbsku6hHvh2U+BcLwWY4mpgXzFUoENEf7IcioGg==}
+ /esbuild-freebsd-arm64/0.15.11:
+ resolution: {integrity: sha512-aSGiODiukLGGnSg/O9+cGO2QxEacrdCtCawehkWYTt5VX1ni2b9KoxpHCT9h9Y6wGqNHmXFnB47RRJ8BIqZgmQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
@@ -665,8 +654,8 @@ packages:
dev: true
optional: true
- /esbuild-linux-32/0.15.10:
- resolution: {integrity: sha512-guXrwSYFAvNkuQ39FNeV4sNkNms1bLlA5vF1H0cazZBOLdLFIny6BhT+TUbK/hdByMQhtWQ5jI9VAmPKbVPu1w==}
+ /esbuild-linux-32/0.15.11:
+ resolution: {integrity: sha512-lsrAfdyJBGx+6aHIQmgqUonEzKYeBnyfJPkT6N2dOf1RoXYYV1BkWB6G02tjsrz1d5wZzaTc3cF+TKmuTo/ZwA==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
@@ -674,8 +663,8 @@ packages:
dev: true
optional: true
- /esbuild-linux-64/0.15.10:
- resolution: {integrity: sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==}
+ /esbuild-linux-64/0.15.11:
+ resolution: {integrity: sha512-Y2Rh+PcyVhQqXKBTacPCltINN3uIw2xC+dsvLANJ1SpK5NJUtxv8+rqWpjmBgaNWKQT1/uGpMmA9olALy9PLVA==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
@@ -683,8 +672,8 @@ packages:
dev: true
optional: true
- /esbuild-linux-arm/0.15.10:
- resolution: {integrity: sha512-6N8vThLL/Lysy9y4Ex8XoLQAlbZKUyExCWyayGi2KgTBelKpPgj6RZnUaKri0dHNPGgReJriKVU6+KDGQwn10A==}
+ /esbuild-linux-arm/0.15.11:
+ resolution: {integrity: sha512-TJllTVk5aSyqPFvvcHTvf6Wu1ZKhWpJ/qNmZO8LL/XeB+LXCclm7HQHNEIz6MT7IX8PmlC1BZYrOiw2sXSB95A==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
@@ -692,8 +681,8 @@ packages:
dev: true
optional: true
- /esbuild-linux-arm64/0.15.10:
- resolution: {integrity: sha512-GByBi4fgkvZFTHFDYNftu1DQ1GzR23jws0oWyCfhnI7eMOe+wgwWrc78dbNk709Ivdr/evefm2PJiUBMiusS1A==}
+ /esbuild-linux-arm64/0.15.11:
+ resolution: {integrity: sha512-uhcXiTwTmD4OpxJu3xC5TzAAw6Wzf9O1XGWL448EE9bqGjgV1j+oK3lIHAfsHnuIn8K4nDW8yjX0Sv5S++oRuw==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
@@ -701,8 +690,8 @@ packages:
dev: true
optional: true
- /esbuild-linux-mips64le/0.15.10:
- resolution: {integrity: sha512-BxP+LbaGVGIdQNJUNF7qpYjEGWb0YyHVSKqYKrn+pTwH/SiHUxFyJYSP3pqkku61olQiSBnSmWZ+YUpj78Tw7Q==}
+ /esbuild-linux-mips64le/0.15.11:
+ resolution: {integrity: sha512-WD61y/R1M4BLe4gxXRypoQ0Ci+Vjf714QYzcPNkiYv5I8K8WDz2ZR8Bm6cqKxd6rD+e/rZgPDbhQ9PCf7TMHmA==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
@@ -710,8 +699,8 @@ packages:
dev: true
optional: true
- /esbuild-linux-ppc64le/0.15.10:
- resolution: {integrity: sha512-LoSQCd6498PmninNgqd/BR7z3Bsk/mabImBWuQ4wQgmQEeanzWd5BQU2aNi9mBURCLgyheuZS6Xhrw5luw3OkQ==}
+ /esbuild-linux-ppc64le/0.15.11:
+ resolution: {integrity: sha512-JVleZS9oPVLTlBhPTWgOwxFWU/wMUdlBwTbGA4GF8c38sLbS13cupj+C8bLq929jU7EMWry4SaL+tKGIaTlqKg==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
@@ -719,8 +708,8 @@ packages:
dev: true
optional: true
- /esbuild-linux-riscv64/0.15.10:
- resolution: {integrity: sha512-Lrl9Cr2YROvPV4wmZ1/g48httE8z/5SCiXIyebiB5N8VT7pX3t6meI7TQVHw/wQpqP/AF4SksDuFImPTM7Z32Q==}
+ /esbuild-linux-riscv64/0.15.11:
+ resolution: {integrity: sha512-9aLIalZ2HFHIOZpmVU11sEAS9F8TnHw49daEjcgMpBXHFF57VuT9f9/9LKJhw781Gda0P9jDkuCWJ0tFbErvJw==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
@@ -728,8 +717,8 @@ packages:
dev: true
optional: true
- /esbuild-linux-s390x/0.15.10:
- resolution: {integrity: sha512-ReP+6q3eLVVP2lpRrvl5EodKX7EZ1bS1/z5j6hsluAlZP5aHhk6ghT6Cq3IANvvDdscMMCB4QEbI+AjtvoOFpA==}
+ /esbuild-linux-s390x/0.15.11:
+ resolution: {integrity: sha512-sZHtiXXOKsLI3XGBGoYO4qKBzJlb8xNsWmvFiwFMHFzA4AXgDP1KDp7Dawe9C2pavTRBDvl+Ok4n/DHQ59oaTg==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
@@ -737,8 +726,8 @@ packages:
dev: true
optional: true
- /esbuild-netbsd-64/0.15.10:
- resolution: {integrity: sha512-iGDYtJCMCqldMskQ4eIV+QSS/CuT7xyy9i2/FjpKvxAuCzrESZXiA1L64YNj6/afuzfBe9i8m/uDkFHy257hTw==}
+ /esbuild-netbsd-64/0.15.11:
+ resolution: {integrity: sha512-hUC9yN06K9sg7ju4Vgu9ChAPdsEgtcrcLfyNT5IKwKyfpLvKUwCMZSdF+gRD3WpyZelgTQfJ+pDx5XFbXTlB0A==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
@@ -746,8 +735,8 @@ packages:
dev: true
optional: true
- /esbuild-openbsd-64/0.15.10:
- resolution: {integrity: sha512-ftMMIwHWrnrYnvuJQRJs/Smlcb28F9ICGde/P3FUTCgDDM0N7WA0o9uOR38f5Xe2/OhNCgkjNeb7QeaE3cyWkQ==}
+ /esbuild-openbsd-64/0.15.11:
+ resolution: {integrity: sha512-0bBo9SQR4t66Wd91LGMAqmWorzO0TTzVjYiifwoFtel8luFeXuPThQnEm5ztN4g0fnvcp7AnUPPzS/Depf17wQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
@@ -755,8 +744,8 @@ packages:
dev: true
optional: true
- /esbuild-sunos-64/0.15.10:
- resolution: {integrity: sha512-mf7hBL9Uo2gcy2r3rUFMjVpTaGpFJJE5QTDDqUFf1632FxteYANffDZmKbqX0PfeQ2XjUDE604IcE7OJeoHiyg==}
+ /esbuild-sunos-64/0.15.11:
+ resolution: {integrity: sha512-EuBdTGlsMTjEl1sQnBX2jfygy7iR6CKfvOzi+gEOfhDqbHXsmY1dcpbVtcwHAg9/2yUZSfMJHMAgf1z8M4yyyw==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
@@ -764,8 +753,8 @@ packages:
dev: true
optional: true
- /esbuild-windows-32/0.15.10:
- resolution: {integrity: sha512-ttFVo+Cg8b5+qHmZHbEc8Vl17kCleHhLzgT8X04y8zudEApo0PxPg9Mz8Z2cKH1bCYlve1XL8LkyXGFjtUYeGg==}
+ /esbuild-windows-32/0.15.11:
+ resolution: {integrity: sha512-O0/Wo1Wk6dc0rZSxkvGpmTNIycEznHmkObTFz2VHBhjPsO4ZpCgfGxNkCpz4AdAIeMczpTXt/8d5vdJNKEGC+Q==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
@@ -773,8 +762,8 @@ packages:
dev: true
optional: true
- /esbuild-windows-64/0.15.10:
- resolution: {integrity: sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA==}
+ /esbuild-windows-64/0.15.11:
+ resolution: {integrity: sha512-x977Q4HhNjnHx00b4XLAnTtj5vfbdEvkxaQwC1Zh5AN8g5EX+izgZ6e5QgqJgpzyRNJqh4hkgIJF1pyy1be0mQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
@@ -782,8 +771,8 @@ packages:
dev: true
optional: true
- /esbuild-windows-arm64/0.15.10:
- resolution: {integrity: sha512-S+th4F+F8VLsHLR0zrUcG+Et4hx0RKgK1eyHc08kztmLOES8BWwMiaGdoW9hiXuzznXQ0I/Fg904MNbr11Nktw==}
+ /esbuild-windows-arm64/0.15.11:
+ resolution: {integrity: sha512-VwUHFACuBahrvntdcMKZteUZ9HaYrBRODoKe4tIWxguQRvvYoYb7iu5LrcRS/FQx8KPZNaa72zuqwVtHeXsITw==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
@@ -791,34 +780,34 @@ packages:
dev: true
optional: true
- /esbuild/0.15.10:
- resolution: {integrity: sha512-N7wBhfJ/E5fzn/SpNgX+oW2RLRjwaL8Y0ezqNqhjD6w0H2p0rDuEz2FKZqpqLnO8DCaWumKe8dsC/ljvVSSxng==}
+ /esbuild/0.15.11:
+ resolution: {integrity: sha512-OgHGuhlfZ//mToxjte1D5iiiQgWfJ2GByVMwEC/IuoXsBGkuyK1+KrjYu0laSpnN/L1UmLUCv0s25vObdc1bVg==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
- '@esbuild/android-arm': 0.15.10
- '@esbuild/linux-loong64': 0.15.10
- esbuild-android-64: 0.15.10
- esbuild-android-arm64: 0.15.10
- esbuild-darwin-64: 0.15.10
- esbuild-darwin-arm64: 0.15.10
- esbuild-freebsd-64: 0.15.10
- esbuild-freebsd-arm64: 0.15.10
- esbuild-linux-32: 0.15.10
- esbuild-linux-64: 0.15.10
- esbuild-linux-arm: 0.15.10
- esbuild-linux-arm64: 0.15.10
- esbuild-linux-mips64le: 0.15.10
- esbuild-linux-ppc64le: 0.15.10
- esbuild-linux-riscv64: 0.15.10
- esbuild-linux-s390x: 0.15.10
- esbuild-netbsd-64: 0.15.10
- esbuild-openbsd-64: 0.15.10
- esbuild-sunos-64: 0.15.10
- esbuild-windows-32: 0.15.10
- esbuild-windows-64: 0.15.10
- esbuild-windows-arm64: 0.15.10
+ '@esbuild/android-arm': 0.15.11
+ '@esbuild/linux-loong64': 0.15.11
+ esbuild-android-64: 0.15.11
+ esbuild-android-arm64: 0.15.11
+ esbuild-darwin-64: 0.15.11
+ esbuild-darwin-arm64: 0.15.11
+ esbuild-freebsd-64: 0.15.11
+ esbuild-freebsd-arm64: 0.15.11
+ esbuild-linux-32: 0.15.11
+ esbuild-linux-64: 0.15.11
+ esbuild-linux-arm: 0.15.11
+ esbuild-linux-arm64: 0.15.11
+ esbuild-linux-mips64le: 0.15.11
+ esbuild-linux-ppc64le: 0.15.11
+ esbuild-linux-riscv64: 0.15.11
+ esbuild-linux-s390x: 0.15.11
+ esbuild-netbsd-64: 0.15.11
+ esbuild-openbsd-64: 0.15.11
+ esbuild-sunos-64: 0.15.11
+ esbuild-windows-32: 0.15.11
+ esbuild-windows-64: 0.15.11
+ esbuild-windows-arm64: 0.15.11
dev: true
/escalade/3.1.1:
@@ -826,10 +815,6 @@ packages:
engines: {node: '>=6'}
dev: true
- /estree-walker/1.0.1:
- resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==}
- dev: true
-
/estree-walker/2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
dev: true
@@ -851,14 +836,6 @@ packages:
reusify: 1.0.4
dev: true
- /fetch-blob/3.2.0:
- resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
- engines: {node: ^12.20 || >= 14.13}
- dependencies:
- node-domexception: 1.0.0
- web-streams-polyfill: 3.2.1
- dev: true
-
/fill-range/7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
@@ -866,13 +843,6 @@ packages:
to-regex-range: 5.0.1
dev: true
- /formdata-polyfill/4.0.10:
- resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
- engines: {node: '>=12.20.0'}
- dependencies:
- fetch-blob: 3.2.0
- dev: true
-
/fraction.js/4.2.0:
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
dev: true
@@ -926,6 +896,17 @@ packages:
path-is-absolute: 1.0.1
dev: true
+ /glob/8.0.3:
+ resolution: {integrity: sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 5.1.0
+ once: 1.4.0
+ dev: true
+
/globalyzer/0.1.0:
resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==}
dev: true
@@ -1037,16 +1018,16 @@ packages:
engines: {node: '>=6'}
dev: true
- /leaflet.markercluster/[email protected]:
+ /leaflet.markercluster/[email protected]:
resolution: {integrity: sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==}
peerDependencies:
leaflet: ^1.3.1
dependencies:
- leaflet: 1.9.1
+ leaflet: 1.9.2
dev: true
- /leaflet/1.9.1:
- resolution: {integrity: sha512-5FcDAMTLAuOq0RisQQbTFatl8Sl4bM0gMrBfuHbl7CYbYJv45BfCS8oU3T644MLjleBq1Ncq541QEA1pqUGTFA==}
+ /leaflet/1.9.2:
+ resolution: {integrity: sha512-Kc77HQvWO+y9y2oIs3dn5h5sy2kr3j41ewdqCMEUA4N89lgfUUfOBy7wnnHEstDpefiGFObq12FdopGRMx4J7g==}
dev: true
/lilconfig/2.0.6:
@@ -1064,8 +1045,8 @@ packages:
sourcemap-codec: 1.4.8
dev: true
- /magic-string/0.26.5:
- resolution: {integrity: sha512-yXUIYOOQnEHKHOftp5shMWpB9ImfgfDJpapa38j/qMtTj5QHWucvxP4lUtuRmHT9vAzvtpHkWKXW9xBwimXeNg==}
+ /magic-string/0.26.7:
+ resolution: {integrity: sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==}
engines: {node: '>=12'}
dependencies:
sourcemap-codec: 1.4.8
@@ -1117,15 +1098,22 @@ packages:
brace-expansion: 1.1.11
dev: true
- /minimist/1.2.6:
- resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==}
+ /minimatch/5.1.0:
+ resolution: {integrity: sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==}
+ engines: {node: '>=10'}
+ dependencies:
+ brace-expansion: 2.0.1
+ dev: true
+
+ /minimist/1.2.7:
+ resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==}
dev: true
/mkdirp/0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
hasBin: true
dependencies:
- minimist: 1.2.6
+ minimist: 1.2.7
dev: true
/mri/1.2.0:
@@ -1152,20 +1140,6 @@ packages:
resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==}
dev: true
- /node-domexception/1.0.0:
- resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
- engines: {node: '>=10.5.0'}
- dev: true
-
- /node-fetch/3.2.10:
- resolution: {integrity: sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- dependencies:
- data-uri-to-buffer: 4.0.0
- fetch-blob: 3.2.0
- formdata-polyfill: 4.0.10
- dev: true
-
/node-gyp-build/4.5.0:
resolution: {integrity: sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==}
hasBin: true
@@ -1223,29 +1197,29 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
- /postcss-import/[email protected]:
+ /postcss-import/[email protected]:
resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==}
engines: {node: '>=10.0.0'}
peerDependencies:
postcss: ^8.0.0
dependencies:
- postcss: 8.4.17
+ postcss: 8.4.18
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.1
dev: true
- /postcss-js/[email protected]:
+ /postcss-js/[email protected]:
resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==}
engines: {node: ^12 || ^14 || >= 16}
peerDependencies:
postcss: ^8.3.3
dependencies:
camelcase-css: 2.0.1
- postcss: 8.4.17
+ postcss: 8.4.18
dev: true
- /postcss-load-config/[email protected]:
+ /postcss-load-config/[email protected]:
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
engines: {node: '>= 10'}
peerDependencies:
@@ -1258,17 +1232,17 @@ packages:
optional: true
dependencies:
lilconfig: 2.0.6
- postcss: 8.4.17
+ postcss: 8.4.18
yaml: 1.10.2
dev: true
- /postcss-nested/[email protected]:
+ /postcss-nested/[email protected]:
resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==}
engines: {node: '>=12.0'}
peerDependencies:
postcss: ^8.2.14
dependencies:
- postcss: 8.4.17
+ postcss: 8.4.18
postcss-selector-parser: 6.0.10
dev: true
@@ -1284,8 +1258,8 @@ packages:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
dev: true
- /postcss/8.4.17:
- resolution: {integrity: sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==}
+ /postcss/8.4.18:
+ resolution: {integrity: sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: 3.3.4
@@ -1293,14 +1267,14 @@ packages:
source-map-js: 1.0.2
dev: true
- /prettier-plugin-svelte/2.7.1_nk6d2fkgcllkkdynqbuearcure:
- resolution: {integrity: sha512-H33qjhCBZyd9Zr1A5hUAYDh7j0Mf97uvy7XcA7CP4nNSYrNcPvBUf7wI8K9NptWTIs0S41QtgTWmJIUiGlEBtw==}
+ /prettier-plugin-svelte/2.8.0_lrllcp5xtrkmmdzifit4hd52ze:
+ resolution: {integrity: sha512-QlXv/U3bUszks3XYDPsk1fsaQC+fo2lshwKbcbO+lrSVdJ+40mB1BfL8OCAk1W9y4pJxpqO/4gqm6NtF3zNGCw==}
peerDependencies:
prettier: ^1.16.4 || ^2.0.0
svelte: ^3.2.0
dependencies:
prettier: 2.7.1
- svelte: 3.50.1
+ svelte: 3.52.0
dev: true
/prettier/2.7.1:
@@ -1486,7 +1460,7 @@ packages:
hasBin: true
dependencies:
buffer-crc32: 0.2.13
- minimist: 1.2.6
+ minimist: 1.2.7
sander: 0.5.1
sourcemap-codec: 1.4.8
dev: true
@@ -1523,24 +1497,24 @@ packages:
engines: {node: '>= 0.4'}
dev: true
- /svelte-hmr/[email protected]:
+ /svelte-hmr/[email protected]:
resolution: {integrity: sha512-Aw21SsyoohyVn4yiKXWPNCSW2DQNH/76kvUnE9kpt4h9hcg9tfyQc6xshx9hzgMfGF0kVx0EGD8oBMWSnATeOg==}
engines: {node: ^12.20 || ^14.13.1 || >= 16}
peerDependencies:
svelte: '>=3.19.0'
dependencies:
- svelte: 3.50.1
+ svelte: 3.52.0
dev: true
- /svelte-outclick/3.1.0:
- resolution: {integrity: sha512-1p/4UAuBfgfltMByTXjE3wbNAYaPihsB9HkhYrKgkiUgZSUtQ+Tpr/gxLu0LIsgft1EKt1izWg/VfzO+f5lQUA==}
+ /svelte-outclick/3.2.0:
+ resolution: {integrity: sha512-mQ8myBEnB4GoVlwSkQ6tmTtLKHz2ZmZJ9WKgolEGjKf6DzbO3eqkFZIZgzLFU1PR/GQngdPativJzrL3/oeQ+Q==}
dev: true
/svelte-pincode/2.1.2:
resolution: {integrity: sha512-TlW0PScUjPR3Abaptcgw0gP+52F+1nlDlXy8zvnO9DVgkESm9kvwFY4RRj0po5aDy/Tp0docNiQmoaLKVTLMiw==}
dev: true
- /svelte-preprocess/4.10.7_r763xggw3my2ousygwguxmp6ru:
+ /svelte-preprocess/4.10.7_vidagnlh55bt6yxji7dk5y5wla:
resolution: {integrity: sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==}
engines: {node: '>= 9.11.2'}
requiresBuild: true
@@ -1585,28 +1559,28 @@ packages:
'@types/sass': 1.43.1
detect-indent: 6.1.0
magic-string: 0.25.9
- postcss: 8.4.17
+ postcss: 8.4.18
sorcery: 0.10.0
strip-indent: 3.0.0
- svelte: 3.50.1
+ svelte: 3.52.0
dev: true
- /svelte/3.50.1:
- resolution: {integrity: sha512-bS4odcsdj5D5jEg6riZuMg5NKelzPtmsCbD9RG+8umU03TeNkdWnP6pqbCm0s8UQNBkqk29w/Bdubn3C+HWSwA==}
+ /svelte/3.52.0:
+ resolution: {integrity: sha512-FxcnEUOAVfr10vDU5dVgJN19IvqeHQCS1zfe8vayTfis9A2t5Fhx+JDe5uv/C3j//bB1umpLJ6quhgs9xyUbCQ==}
engines: {node: '>= 8'}
dev: true
- /sveltekit-i18n/[email protected]:
+ /sveltekit-i18n/[email protected]:
resolution: {integrity: sha512-6eygICleGCSL7elY7A3trF8XUhV+mlW56ZSoD0UUKXlw+Y6u0MTTHDq48u1LyY73SfnlbPHXgTarhTjZ0BvUKA==}
peerDependencies:
svelte: ^3.x
dependencies:
- '@sveltekit-i18n/base': [email protected]
+ '@sveltekit-i18n/base': [email protected]
'@sveltekit-i18n/parser-default': 1.0.3
- svelte: 3.50.1
+ svelte: 3.52.0
dev: true
- /tailwindcss/[email protected]:
+ /tailwindcss/[email protected]:
resolution: {integrity: sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==}
engines: {node: '>=12.13.0'}
hasBin: true
@@ -1626,11 +1600,11 @@ packages:
normalize-path: 3.0.0
object-hash: 3.0.0
picocolors: 1.0.0
- postcss: 8.4.17
- postcss-import: [email protected]
- postcss-js: [email protected]
- postcss-load-config: [email protected]
- postcss-nested: [email protected]
+ postcss: 8.4.18
+ postcss-import: [email protected]
+ postcss-js: [email protected]
+ postcss-load-config: [email protected]
+ postcss-nested: [email protected]
postcss-selector-parser: 6.0.10
postcss-value-parser: 4.2.0
quick-lru: 5.1.1
@@ -1669,8 +1643,8 @@ packages:
busboy: 1.6.0
dev: true
- /update-browserslist-db/[email protected]:
- resolution: {integrity: sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==}
+ /update-browserslist-db/[email protected]:
+ resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
@@ -1690,8 +1664,8 @@ packages:
safe-buffer: 5.2.1
dev: true
- /vite/3.1.4:
- resolution: {integrity: sha512-JoQI08aBjY9lycL7jcEq4p9o1xUjq5aRvdH4KWaXtkSx7e7RpAh9D3IjzDWRD4Fg44LS3oDAIOG/Kq1L+82psA==}
+ /vite/3.1.8:
+ resolution: {integrity: sha512-m7jJe3nufUbuOfotkntGFupinL/fmuTNuQmiVE7cH2IZMuf4UbfbGYMUT3jVWgGYuRVLY9j8NnrRqgw5rr5QTg==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
@@ -1709,19 +1683,14 @@ packages:
terser:
optional: true
dependencies:
- esbuild: 0.15.10
- postcss: 8.4.17
+ esbuild: 0.15.11
+ postcss: 8.4.18
resolve: 1.22.1
rollup: 2.78.1
optionalDependencies:
fsevents: 2.3.2
dev: true
- /web-streams-polyfill/3.2.1:
- resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==}
- engines: {node: '>= 8'}
- dev: true
-
/wif/2.0.6:
resolution: {integrity: sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==}
dependencies:
diff --git a/src/app.html b/src/app.html
index d8545747..57ffbcce 100644
--- a/src/app.html
+++ b/src/app.html
@@ -4,7 +4,8 @@
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta name="description" content="Easy to use bitcoin point of sale app and web wallet." />
+ <meta name="description" content="An easy bitcoin web wallet" />
+ <meta name="keywords" content="open source bitcoin lightning web wallet" />
<meta property="og:image" content="/icons/logo.svg" />
<title>coinos</title>
%sveltekit.head%
diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte
index f9413efb..302a9c7a 100644
--- a/src/components/AppHeader.svelte
+++ b/src/components/AppHeader.svelte
@@ -7,7 +7,6 @@
import { page } from '$app/stores';
export let data;
- export let avatarPosition = 'left-[calc(50vw-64px)] md:left-[calc(15vw-48px)] bottom-[-64px]';
let { subject, user } = data;
$: update(data);
@@ -35,7 +34,7 @@
$tempProfileFiles && $tempProfileFiles.banner
? `url(${$tempProfileFiles.banner})`
: subject?.banner
- ? `url(/api/public/${subject.username}-banner.png)`
+ ? `url(/api/public/${subject.username}-banner.webp)`
: undefined;
</script>
diff --git a/src/components/Avatar.svelte b/src/components/Avatar.svelte
index ed1a499a..c7339bf5 100644
--- a/src/components/Avatar.svelte
+++ b/src/components/Avatar.svelte
@@ -2,7 +2,6 @@
import { colorTheme, tempProfileFiles } from '$lib/store';
import { Icon } from '$comp';
- export let avatarPosition;
export let user;
</script>
@@ -14,7 +13,7 @@
<img
src={$tempProfileFiles && $tempProfileFiles.profile
? $tempProfileFiles.profile
- : `/api/public/${user.username}-profile.png`}
+ : `/api/public/${user.username}-profile.webp`}
class="w-full h-full object-cover object-center overflow-hidden"
alt={user.username}
/>
diff --git a/src/components/Calendar.svelte b/src/components/Calendar.svelte
new file mode 100644
index 00000000..7504f48e
--- /dev/null
+++ b/src/components/Calendar.svelte
@@ -0,0 +1,14 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ class="absolute bottom-0 left-0 -mb-0.5 transform translate-x-1/2 -translate-y-1/2 text-black peer-placeholder-shown:text-gray-300 h-6 w-6"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke="currentColor"
+>
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
+ />
+</svg>
diff --git a/src/components/Card.svelte b/src/components/Card.svelte
new file mode 100644
index 00000000..44ab635f
--- /dev/null
+++ b/src/components/Card.svelte
@@ -0,0 +1,14 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ class="absolute bottom-0 left-0 -mb-0.5 transform translate-x-1/2 -translate-y-1/2 text-black peer-placeholder-shown:text-gray-300 h-6 w-6"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke="currentColor"
+>
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"
+ />
+</svg>
diff --git a/src/components/Lock.svelte b/src/components/Lock.svelte
new file mode 100644
index 00000000..11475acf
--- /dev/null
+++ b/src/components/Lock.svelte
@@ -0,0 +1,14 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ class="absolute bottom-0 left-0 -mb-0.5 transform translate-x-1/2 -translate-y-1/2 text-black peer-placeholder-shown:text-gray-300 h-6 w-6"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke="currentColor"
+>
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
+ />
+</svg>
diff --git a/src/components/Pin.svelte b/src/components/Pin.svelte
new file mode 100644
index 00000000..8f33a7f3
--- /dev/null
+++ b/src/components/Pin.svelte
@@ -0,0 +1,35 @@
+<script>
+ import { tick } from 'svelte';
+ import { pin } from '$lib/store';
+ import { Pincode, PincodeInput } from 'svelte-pincode';
+ let pinCode = [];
+ let pinInput;
+
+ $: pinInput && tick().then(pinInput && pinInput.focusFirstInput);
+ $: pinCode.length > 5 && ($pin = pinCode.join(''));
+</script>
+
+<div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-20">
+ <div class="relative top-1/3 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white space-y-5">
+ <h1 class="text-center text-2xl font-semibold">Please enter your PIN</h1>
+ <div class="text-center">
+ <Pincode bind:code={pinCode} bind:this={pinInput}>
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ </Pincode>
+ </div>
+
+ <div class="w-full flex">
+ <button
+ type="submit"
+ class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto"
+ >
+ <div class="my-auto">Cancel</div>
+ </button>
+ </div>
+ </div>
+</div>
diff --git a/src/components/Qr.svelte b/src/components/Qr.svelte
index 0ae028b9..3870abe0 100644
--- a/src/components/Qr.svelte
+++ b/src/components/Qr.svelte
@@ -57,8 +57,8 @@
{#if mask}
<div class="absolute bg-white w-[300px] h-[300px] t-0 l-0 z-10" out:fade />
{/if}
-<div bind:this={qr} on:click={toggle} class:hidden={full} class="relative overflow-visible" />
-<div bind:this={fullQr} on:click={toggle} class:hidden={!full} />
+<div bind:this={qr} on:click={toggle} on:keydown={toggle} class:hidden={full} class="relative overflow-visible" />
+<div bind:this={fullQr} on:click={toggle} on:keydown={toggle} class:hidden={!full} />
<style>
div {
diff --git a/src/components/RegisterOrLogin.svelte b/src/components/RegisterOrLogin.svelte
index 0b954387..bf2d2084 100644
--- a/src/components/RegisterOrLogin.svelte
+++ b/src/components/RegisterOrLogin.svelte
@@ -1,18 +1,28 @@
<script>
+ import { tick } from 'svelte';
+ import { Pincode, PincodeInput } from 'svelte-pincode';
import { fly } from 'svelte/transition';
import { enhance } from '$app/forms';
import { Icon } from '$comp';
import { focus } from '$lib/utils';
- import { redirect } from '$lib/store';
+ import { loginRedirect } from '$lib/store';
import { t } from '$lib/translations';
+ let token, tokenInput;
+ let code = [];
+
+ $: need2fa = form?.message === '2fa';
+ $: if (need2fa) tokenInput && tick().then(tokenInput.focusFirstInput);
+
export let form;
export let pageID;
- let username,
- password,
- email,
- twofa = '';
+ let username, password, email, submit;
+
+ $: update(form);
+ let update = (form) => form && ({ username, password } = form);
+
+ $: token && token?.length === 6 && tick().then(() => submit.click());
let revealPassword = false;
@@ -31,101 +41,122 @@
<div class="flex justify-center items-center">
<div class="shadow-xl rounded-3xl p-10 pb-12 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]">
- <h1 class="text-2xl font-bold text-center">{$t('login.' + pageID)}</h1>
+ {#if need2fa}
+ <h1 class="text-2xl font-bold text-center">Enter 2FA Code</h1>
- {#if form?.error}
- <div class="text-red-600 text-center" in:fly>
- {form.error}
- </div>
- {/if}
+ {#if form?.token}
+ <div class="text-red-600 text-center" in:fly>Invalid token, try again</div>
+ {/if}
+
+ <form class="space-y-5" {action} method="POST" use:enhance>
+ <input type="hidden" name="username" value={username} />
+ <input type="hidden" name="password" value={password} />
+ <input type="hidden" name="token" value={token} />
+
+ <div>
+ <Pincode bind:code bind:value={token} bind:this={tokenInput}>
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ </Pincode>
+ </div>
+ <button
+ bind:this={submit}
+ type="submit"
+ class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80"
+ >{$t('login.' + pageID)}
+ </button>
+ </form>
+ {:else}
+ <h1 class="text-2xl font-bold text-center">{$t('login.' + pageID)}</h1>
- <form class="space-y-5" {action} method="POST" use:enhance>
- {#if $redirect}
- <input type="hidden" name="redirect" value={$redirect} />
+ {#if form?.error}
+ <div class="text-red-600 text-center" in:fly>
+ {form.error}
+ </div>
{/if}
- <div>
- <label for="username" class="font-semibold">{$t('login.username')}</label>
- <input
- name="username"
- type="text"
- required
- class="bg-primary"
- bind:value={username}
- use:focus
- autocapitalize="none"
- />
- </div>
+ <form class="space-y-5" {action} method="POST" use:enhance>
+ {#if $loginRedirect}
+ <input type="hidden" name="loginRedirect" value={$loginRedirect} />
+ {/if}
- <div class="relative">
- <label for="password" class="block font-semibold">{$t('login.password')}</label>
- {#if revealPassword}
+ <div>
+ <label for="username" class="font-semibold">{$t('login.username')}</label>
<input
- name="password"
+ name="username"
type="text"
required
class="bg-primary"
- bind:value={password}
+ bind:value={username}
+ use:focus
autocapitalize="none"
/>
- {:else}
- <input
- name="password"
- type="password"
- required
- class="bg-primary"
- bind:value={password}
- autocapitalize="none"
- />
- {/if}
- <button
- type="button"
- on:click={() => (revealPassword = !revealPassword)}
- class="absolute right-5 top-10"
- >
- <Icon icon={revealPassword ? 'eye' : 'eye-off'} />
- </button>
- </div>
+ </div>
- {#if pageID === 'signIn'}
- <div>
- <label for="token" class="font-semibold"
- >{$t('login.token')}
- <span class="text-secondary">({$t('login.optional')})</span></label
+ <div class="relative">
+ <label for="password" class="block font-semibold">{$t('login.password')}</label>
+ {#if revealPassword}
+ <input
+ name="password"
+ type="text"
+ required
+ class="bg-primary"
+ bind:value={password}
+ autocapitalize="none"
+ />
+ {:else}
+ <input
+ name="password"
+ type="password"
+ required
+ class="bg-primary"
+ bind:value={password}
+ autocapitalize="none"
+ />
+ {/if}
+ <button
+ type="button"
+ on:click={() => (revealPassword = !revealPassword)}
+ class="absolute right-5 top-10"
>
- <input name="token" type="text" class="bg-primary" bind:value={twofa} />
+ <Icon icon={revealPassword ? 'eye' : 'eye-off'} />
+ </button>
</div>
- {/if}
- {#if pageID === 'register'}
- <p class="text-secondary text-sm">
- {$t('login.passwordRecommendation')}
- </p>
- {:else}
- <!-- TODO -->
- <!-- <div class="flex justify-end items-center"> -->
- <!-- <a href="/forgot" class="underline underline-offset-4 text-black text-sm" -->
- <!-- >{$t('login.forgotUserOrPassword')}</a -->
- <!-- > -->
- <!-- </div> -->
- {/if}
+ {#if pageID === 'register'}
+ <p class="text-secondary text-sm">
+ {$t('login.passwordRecommendation')}
+ </p>
+ {:else}
+ <!-- TODO -->
+ <!-- <div class="flex justify-end items-center"> -->
+ <!-- <a href="/forgot" class="underline underline-offset-4 text-black text-sm" -->
+ <!-- >{$t('login.forgotUserOrPassword')}</a -->
+ <!-- > -->
+ <!-- </div> -->
+ {/if}
- <button
- type="submit"
- class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80"
- >{$t('login.' + pageID)}
- </button>
- </form>
+ <button
+ type="submit"
+ class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80"
+ >{$t('login.' + pageID)}
+ </button>
+ </form>
- <p class="text-secondary text-center font-medium">
- {pageID === 'register' ? $t('login.haveAccount') : $t('login.noAccount')}
- <a
- href={pageID === 'register' ? '/login' : '/register'}
- class="block md:inline text-black underline underline-offset-4 hover:opacity-80"
- >
- {pageID === 'register' ? $t('login.signIn') : $t('login.register')}
- </a>
- </p>
+ <p class="text-secondary text-center font-medium">
+ {pageID === 'register' ? $t('login.haveAccount') : $t('login.noAccount')}
+ <a
+ href={pageID === 'register' ? '/login' : '/register'}
+ class="block md:inline text-black underline underline-offset-4 hover:opacity-80"
+ >
+ {pageID === 'register' ? $t('login.signIn') : $t('login.register')}
+ </a>
+ </p>
+ {/if}
</div>
</div>
</div>
diff --git a/src/components/Tip.svelte b/src/components/Tip.svelte
index 25dbe3b9..6af1e00a 100644
--- a/src/components/Tip.svelte
+++ b/src/components/Tip.svelte
@@ -188,8 +188,4 @@
background: black;
cursor: pointer;
}
-
- #slider.slider-track::-moz-range-progress {
- background: black;
- }
</style>
diff --git a/src/components/index.js b/src/components/index.js
index 08ec217a..c3a5000c 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -1,3 +1,7 @@
+export { default as Pin } from './Pin.svelte';
+export { default as Card } from './Card.svelte';
+export { default as Lock } from './Lock.svelte';
+export { default as Calendar } from './Calendar.svelte';
export { default as Avatar } from './Avatar.svelte';
export { default as Left } from './Left.svelte';
export { default as Numpad } from './Numpad.svelte';
diff --git a/src/hooks.server.js b/src/hooks.server.js
index 58882771..a5b1eef3 100644
--- a/src/hooks.server.js
+++ b/src/hooks.server.js
@@ -2,9 +2,8 @@ import { auth, get } from '$lib/utils';
export async function handle({ event, resolve }) {
let token = event.cookies.get('token');
- if (token) {
- event.request.headers.set('authorization', `Bearer ${token}`);
+ if (token) {
try {
event.locals.user = await get('/me', auth(event.cookies));
} catch (e) {
@@ -13,7 +12,6 @@ export async function handle({ event, resolve }) {
}
const response = await resolve(event);
- response.headers.set('x-custom-header', 'potato');
return response;
}
diff --git a/src/lib/socket.js b/src/lib/socket.js
index 02d73a48..b385db9d 100644
--- a/src/lib/socket.js
+++ b/src/lib/socket.js
@@ -1,9 +1,10 @@
import { get } from 'svelte/store';
-import { invoices, newPayment, rate } from '$lib/store';
+import { invoices, newPayment, rate, user } from '$lib/store';
import { success } from '$lib/utils';
import { env } from '$env/dynamic/public';
const socketUrl = env.PUBLIC_SOCKET;
+const btc = env.PUBLIC_BTC;
let interval, socket, token;
@@ -18,12 +19,14 @@ export const messages = (data) => ({
rate.set(data);
},
- payment() {
+ async payment() {
let { amount, invoice } = data;
- console.log('INVOICE', invoice);
+ if (get(user).account_id !== data.account_id) return;
+
if (invoice) {
invoices.set({ ...get(invoices), [invoice.uuid]: invoice });
}
+
newPayment.set(true);
if (amount > 0) {
success(`Received ${amount} sats!`);
diff --git a/src/lib/store.js b/src/lib/store.js
index c64ad39f..3174a86c 100644
--- a/src/lib/store.js
+++ b/src/lib/store.js
@@ -1,20 +1,24 @@
import { get, writable } from 'svelte/store';
import { browser } from '$app/environment';
-// creates a Svelte store synced to sessionStorage with the given key and default value
-const persistSession = (key, defaultValue) => {
+const persistSession = (key, defaultValue, expiry) => {
+ if (expiry && browser && new Date() - expiry > sessionStorage.getItem(key + 'time')) {
+ sessionStorage.removeItem(key);
+ }
+
let s = writable(
browser && sessionStorage.getItem(key) && sessionStorage.getItem(key) !== 'undefined'
? JSON.parse(sessionStorage.getItem(key))
: defaultValue
);
+ expiry && browser && sessionStorage.setItem(key + 'time', Date.now());
+
s.subscribe((v) => browser && sessionStorage.setItem(key, JSON.stringify(v)));
return s;
};
-// creates a Svelte store synced to localStorage with the given key and default value
const persistLocal = (key, defaultValue) => {
let s = writable(
browser && localStorage.getItem(key) && localStorage.getItem(key) !== 'undefined'
@@ -27,8 +31,9 @@ const persistLocal = (key, defaultValue) => {
return s;
};
-export const redirect = writable();
+export const loginRedirect = writable();
export const rate = writable();
+export const user = writable();
export const selectedRate = writable();
export const token = persistSession('token');
export const invoices = writable({});
@@ -37,3 +42,4 @@ export const colorTheme = writable('from-primary to-gradient');
export const tempProfileFiles = writable();
export const avatarUpload = writable();
export const bannerUpload = writable();
+export const pin = persistSession('pin', undefined, 5 * 60 * 1000);
diff --git a/src/lib/ticket.js b/src/lib/ticket.js
new file mode 100644
index 00000000..708c10f4
--- /dev/null
+++ b/src/lib/ticket.js
@@ -0,0 +1,31 @@
+import { auth, get, post } from '$lib/utils';
+import { env } from '$env/dynamic/private';
+import tickets from '$lib/tickets';
+
+export const createTicket = async (cookies, username) => {
+ let { ticket } = await get('/ticket');
+
+ let { address } = await post(
+ '/invoice',
+ { invoice: { network: 'liquid' }, user: { username } },
+ auth(cookies)
+ );
+
+ let { asset } = await post(
+ '/assets',
+ {
+ address,
+ name: `Launch Party Ticket ${ticket}`,
+ ticker: 'LPT',
+ precision: 0,
+ asset_amount: '1',
+ token_amount: 0,
+ domain: 'coinos.io',
+ filename: tickets[ticket]
+ },
+ { authorization: `Bearer ${env.LAUNCH}` }
+ );
+
+ await post('/ticket', { asset }, { authorization: `Bearer ${env.LAUNCH}` });
+ return asset;
+};
diff --git a/src/lib/tickets.js b/src/lib/tickets.js
new file mode 100644
index 00000000..b0ca0ac0
--- /dev/null
+++ b/src/lib/tickets.js
@@ -0,0 +1,52 @@
+export default [
+ 'QmPbFkiXNuaQyfwD4W9GcXP7qWaNd6wFd9KCnJir5mes1J',
+ 'QmPVjvbaMxSJRpDxMLYTdUWQbknej1vYLckBQ2pAgxZgJN',
+ 'QmVasycSFzCYhyXrcvTE7mN3d6W78RFnrhzg5cRF6Dp6Zq',
+ 'QmTmnhjpTBjZdeHwXgT9Dftc3uWMW73qsZpZ5ECrTyiKKZ',
+ 'QmWDBiyVPyFkzUrEdvy7DSJe1rBQpene1m6quKAtyjBP6a',
+ 'QmcxxzQZwgG7SE9QbHNvoTiCi6Dhs9rrz9roqvxm2JQA88',
+ 'Qmd9ThEpXLLHimEzRUWEFrAGLSw5PAHzn2SmwfCnjNLwWt',
+ 'Qmc7pWw1yxc2ARBWitDMYiyPkWK61NsXXU8oYAQwNAvcx1',
+ 'QmX9Hgw1rMFUgBBuq8QfZZDzLjN5xCED19fwFdDeDDqwmr',
+ 'QmconCAyNyaagqKvvfKCbG7Eu8c6vCtkv2ivvxMoFN9YwA',
+ 'QmWbFmvViy5gx4JdD5sw5YJETet4ZQcXtYgijYnrsnSZ3a',
+ 'QmP6QiiJwoqkduZMqdd5e5htHZ4aYHCsvEu7WEEUknKYa5',
+ 'QmefHk8hvBUHsuKugntok5u75Q8i886cnPwsj4LZZB6uWg',
+ 'QmdrSDK5ByYHxc88hfDu8hQgK5XYFpXSfPorUXdyTbE437',
+ 'QmZ6ZycjRzYpsjnLm1Lfgk1fXXDdhcYRkyfmqYJZVGwADy',
+ 'QmSkBxS5yLPjB2VPs89oQRZANsoyodK6s8s52E8GKXr2zt',
+ 'QmSn8TCPwq3UZ1Z4eyko76CvQo2H2Hyef1NGboDQN22m5i',
+ 'QmP6CTH5zrKMzZwtjy7VaK9NXiq4Gw53kmuRjUbJjeovoe',
+ 'QmdwT4yvz9Xf8g3t6irKRoh3Wa7MwRQrcUJckQxyQe1Bc5',
+ 'QmcwuHH3bD5JExqjDvKqRQ3V5xEVGqs94qPNVDzaCqJa5a',
+ 'QmRfVduHwn8sXwSoyfgZpxSi8L7EjP4LMp6fmijo9VApDp',
+ 'Qmc4TGj1Ahbg9HJ9WDXDm2bXsNkT4zRDp8Wdw9wqqdEwuH',
+ 'QmY8uQiHMWA8ztf2wAurNFW7eiTHQEUiLTQ2vGceMwVqz3',
+ 'QmXiXbaD12F4mkbUSQcKhWshkPU4oi29cUawZGnPk86VVU',
+ 'QmZaiAGjvBZBw4suz33s9JQNzY2Kshean2mQQPCa6gKMQe',
+ 'Qme8bDSdzX7tanPYf672xXW8vPdkLkeSLqLzHJqidRXsYJ',
+ 'QmRJirjuUKgh2AMyBF4jNquaXHFPBtDJf3gKFC614hX7qu',
+ 'QmdRoSKSgabcrpekNBPB6T47RBtJnCETYE8ry2a3P37MUe',
+ 'QmXoqArruHSghrUGW35vVQHPknBG5Cj939iWWHHXU3B616',
+ 'QmYCxtDuoHLMAFhNpifUsLU9ptAeFKwyxSiSEJhDQLMZtN',
+ 'QmQZQBw8wgzUsrmVDEejdePK23AEJbk9aUracvxLPyHz2x',
+ 'QmSsbu7U3i62AQKuYqfisRo5E6nqdMZfHRKWYJgouaXDxD',
+ 'QmaP4adVQuWyqtN4QCXeYXj4nr19Je4EqsaTG1zM9ywqFS',
+ 'QmPPsvgfXsiN3wNqdAwHAhQVpw6SZWNpry9Na6R2Xb7zXY',
+ 'QmR7z6wQmcfZUvRsVK83GRRboyvwZEDQujLwumMY33nAit',
+ 'QmQXgkgorDLPUyQpFbW8aLUW6jioQjUKamtXw5UuNCttDg',
+ 'QmcwYBeXt1BPfdSrtSrXFpWctRZ7RDHvmKTttC5hPPTSzG',
+ 'QmTUexZnw3xPy3YVdUsqJALwTvy2qFax5b3QpJVMvTCJQb',
+ 'QmNLkYXFUvctpfeeDTZxruZE2f834EUnYMM6JJUeTcUB4J',
+ 'QmT7544UaTPgKFYMCpPE4unXphNGX71BLZBPKLkxAijSmj',
+ 'QmTpVR4dqX1QV4fae5pZ1ACtRcANHwEWCLwpMXFmwE95Sm',
+ 'Qmdfyps5fW8d8wstXMfpvpei2DTmaADBWgmxLT7e7uan4P',
+ 'QmUSK8byipYoG3H97QpmPrHw9vYrvHygyhkiM81XmaKyxS',
+ 'QmQUGRvp96LTw5i8Ly9f5LoMvUpeQHCLGNqC88KV74wEHK',
+ 'Qma693TFLh9Z1MeBFzhPHi6Yk4tmTcZY2jogwJ8cPkU2B4',
+ 'QmNu8FyMpmkFdbCXGRVG8mKJtMvvCoLP8LNzFsxBQwxQeS',
+ 'QmWZHE87PKujL1MGLuFgP3D12o5GQxYbvbeTRgr12f1XMu',
+ 'QmcZJn8gPGd3poS9yuiNJh6iP4cn9uy5fnypky71r4sSSw',
+ 'QmTwrAF4E9ucpdnrUZFj6EfrQamGv7Qyn7ceSx1DUQYceC',
+ 'QmexssxU5iTXypgNqrmrQwMDJnTNxyZUxor5wDLnwb5TZp'
+];
diff --git a/src/lib/utils.js b/src/lib/utils.js
index 54e965d9..7eeab648 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -9,6 +9,17 @@ export function scroll(section) {
const base = browser ? '' : env.PUBLIC_COINOS_URL;
+export const g = (url, fetch, headers) =>
+ fetch(base + url, { headers })
+ .then((r) => r.text())
+ .then((body) => {
+ try {
+ return JSON.parse(body);
+ } catch (e) {
+ throw new Error(body);
+ }
+ });
+
export const get = (url, headers = {}) =>
fetch(base + url, { headers })
.then((r) => r.text())
@@ -31,6 +42,8 @@ export const post = (url, body, headers) => {
throw new Error(body);
}
+
+ if (body.error) throw body.error;
if (body instanceof Error) throw body;
if (body.name === 'Error') throw new Error(body.message);
@@ -97,7 +110,17 @@ export const info = (m) => {
export const login = async (user, cookies) => {
let maxAge = 30 * 24 * 60 * 60;
- let { token } = await post('/login', user);
+ let res = await fetch(base + '/login', {
+ method: 'POST',
+ body: JSON.stringify(user),
+ headers: { 'content-type': 'application/json', accept: 'application/json' }
+ });
+ if (res.status === 401) {
+ let text = await res.text();
+ if (text.startsWith('2fa')) throw new Error('2fa');
+ }
+
+ let { token } = await res.json();
if (!token) throw new Error('Login failed');
let expires = new Date();
diff --git a/src/locales/en.json b/src/locales/en.json
index a6c94b58..b5aef47a 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -32,7 +32,7 @@
"bio": "Strategic & Project Management. Jack of all Trades. Can always find time to meet for coffee."
},
"cole": {
- "name": "Cole Goodwin",
+ "name": "Cole",
"position": "Bitcoin Professional",
"bio": "As a Certified Bitcoin Professional, Cole is a driven individual with a passion for freedom. He came across bitcoin in 2016 and studied it in depth. Now he wants to introduce the lightning network to as many users as possible."
},
@@ -152,7 +152,7 @@
"settings": "Settings",
"support": "Support"
},
- "newSiteHeader": "Welcome to the <a href=\"/news\" class=\"underline underline-offset-4 text-black hover:opacity-80\" >new and improved coinos</a>, focused on merchant adoption! Looking for the old coinos? Visit <a href=\"https://classic.coinos.io\" class=\"underline underline-offset-4 text-black hover:opacity-80\">classic.coinos.io</a>.",
+ "newSiteHeader": "Join us at our <a href=\"/launch\" class=\"underline underline-offset-4 text-black hover:opacity-80\">launch party</a> in Vancouver on October 26! Looking for the old coinos? Visit <a href=\"https://classic.coinos.io\" class=\"underline underline-offset-4 text-black hover:opacity-80\">classic.coinos.io</a>",
"news": {
"header": "News",
"subheader": "Latest Updates",
diff --git a/src/locales/es.json b/src/locales/es.json
index 5fad6dd8..068d93a5 100644
--- a/src/locales/es.json
+++ b/src/locales/es.json
@@ -32,7 +32,7 @@
"bio": "Gestión Estratégica y de Proyectos. Ella es una todóloga. Siempre encuentra tiempo para reunirse a tomar un café."
},
"cole": {
- "name": "Cole Goodwin",
+ "name": "Cole",
"position": "Profesional en Bitcoin",
"bio": "Como profesional certificado de Bitcoin, Cole es una persona motivada y apasionada por la libertad. Encontró bitcoin en el año 2016 bitcoin y se dedicó a estudiarlo en profundidad. Ahora quiere presentar Lightning Network a tantos usuarios como sea posible."
},
diff --git a/src/routes/+layout.server.js b/src/routes/+layout.server.js
index e110b467..be81e19f 100644
--- a/src/routes/+layout.server.js
+++ b/src/routes/+layout.server.js
@@ -1,12 +1,12 @@
import { error, redirect } from '@sveltejs/kit';
-import cookie from 'cookie';
import { protectedRoutes } from '$lib/utils';
import { get, post, auth } from '$lib/utils';
import { env } from '$env/dynamic/public';
export const { PUBLIC_BTC: btc } = env;
-export async function load({ cookies, request, url, params }) {
+export async function load({ cookies, locals, request, url, params }) {
+ url.pathname;
let token = cookies.get('token');
let user;
let rates;
@@ -17,11 +17,7 @@ export async function load({ cookies, request, url, params }) {
}
if (token && token !== 'undefined') {
- try {
- user = await get('/me', auth(cookies));
- } catch (e) {
- throw redirect(307, '/logout');
- }
+ user = locals.user;
if (protectedRoutes.find((p) => url.pathname.match(p))) {
if (user.username !== params.username) throw error(404, 'user not found');
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 42d249f4..5cc75b30 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -3,7 +3,7 @@
import '../app.css';
import { onMount } from 'svelte';
import { connect } from '$lib/socket';
- import { selectedRate, rate } from '$lib/store';
+ import { selectedRate, rate, user } from '$lib/store';
import { page } from '$app/stores';
import { browser } from '$app/environment';
import { goto } from '$app/navigation';
@@ -14,12 +14,17 @@
const localeLocalStorageKey = 'sveltekit-i18n-locale';
export let data;
- let { user, rate: r, token, rates } = data;
+
+ let r, u, token, rates;
+
$: update(data);
- let update = () => ({ user, rate: r, token, rates } = data);
- $rate = r;
+ let update = () => {
+ ({ user: u, rate: r, token, rates } = data);
+ $rate = r;
+ $user = u;
+ };
- $: $selectedRate = user && $rate * (rates[user.currency] / rates.USD);
+ $: $selectedRate = u && r * (rates[u.currency] / rates.USD);
onMount(() => {
let localStorageLocale = localStorage.getItem(localeLocalStorageKey);
diff --git a/src/routes/[username]/+page.server.js b/src/routes/[username]/+page.server.js
index d6f2978c..0840161a 100644
--- a/src/routes/[username]/+page.server.js
+++ b/src/routes/[username]/+page.server.js
@@ -1,4 +1,3 @@
-import cookie from 'cookie';
import { get, post } from '$lib/utils';
export async function load({ params }) {
diff --git a/src/routes/[username]/dashboard/+page.server.js b/src/routes/[username]/dashboard/+page.server.js
new file mode 100644
index 00000000..b6206324
--- /dev/null
+++ b/src/routes/[username]/dashboard/+page.server.js
@@ -0,0 +1 @@
+export const load = ({ parent }) => parent();
diff --git a/src/routes/[username]/settings/+page.server.js b/src/routes/[username]/settings/+page.server.js
index 7053a939..ae7e0a78 100644
--- a/src/routes/[username]/settings/+page.server.js
+++ b/src/routes/[username]/settings/+page.server.js
@@ -3,9 +3,11 @@ import { auth, get, post } from '$lib/utils';
export const actions = {
default: async ({ cookies, request }) => {
+ let form = Object.fromEntries(await request.formData());
+
let user = {
...(await get('/me', auth(cookies))),
- ...Object.fromEntries(await request.formData())
+ ...form
};
try {
diff --git a/src/routes/[username]/settings/+page.svelte b/src/routes/[username]/settings/+page.svelte
index c1ac20d0..7bd4ddcc 100644
--- a/src/routes/[username]/settings/+page.svelte
+++ b/src/routes/[username]/settings/+page.svelte
@@ -1,21 +1,28 @@
<script>
+ import { fly } from 'svelte/transition';
import { enhance } from '$app/forms';
import Account from './_account.svelte';
import Pos from './_pos.svelte';
import Security from './_security.svelte';
- import { Icon } from '$comp';
+ import { Icon, Spinner, Pin } from '$comp';
import { t } from '$lib/translations';
import { failure, success } from '$lib/utils';
- import { avatarUpload, bannerUpload } from '$lib/store';
+ import { avatarUpload, bannerUpload, pin } from '$lib/store';
import { upload } from '$lib/upload';
export let data;
+ export let form;
let { user, rates, token } = data;
$: update(data);
let update = () => ({ user, rates, token } = data);
+ $: if (form?.message?.startsWith('Pin')) {
+ failure('Wrong pin, try again');
+ $pin = '';
+ }
+
let tab = 'account';
let tabs = [
@@ -26,23 +33,37 @@
$: ({ comp } = tabs.find((t) => t.name === tab));
- let save = async () => {
+ let loading, submit;
+ let save = async (msg) => {
+ loading = true;
+ if (typeof msg !== 'string') msg = 'Settings saved';
+
try {
if ($avatarUpload) {
await upload($avatarUpload.file, $avatarUpload.type, $avatarUpload.progress, token);
}
+
if ($bannerUpload) {
await upload($bannerUpload.file, $bannerUpload.type, $bannerUpload.progress, token);
}
- success('Settings saved');
+
+ success(msg);
} catch (e) {
console.log(e);
failure('Something went wrong');
}
+
+ loading = false;
};
</script>
+{#if user.haspin && $pin?.length !== 6}
+ <Pin />
+{/if}
+
<form method="POST" class="mb-[154px]" use:enhance on:submit={save}>
+ <input type="hidden" name="pin" value={$pin} />
+
<div class="mt-24 mb-20 px-3 md:px-0 w-full md:w-[400px] mx-auto space-y-8">
<h1 class="text-center text-3xl md:text-4xl font-semibold mb-10">
{$t('user.settings.header')}
@@ -58,16 +79,22 @@
{/each}
</div>
- <svelte:component this={comp} {user} {rates} />
+ <svelte:component this={comp} {user} {rates} {submit} />
</div>
<div
class="z-10 fixed bottom-0 bg-white shadow border-t w-full flex justify-center items-center py-3"
>
<button
+ bind:this={submit}
type="submit"
- class="bg-black text-white rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80"
+ class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80"
+ class:bg-black={loading}
>
- <div class="my-auto">Save Settings</div>
+ {#if loading}
+ <Spinner />
+ {:else}
+ <div class="my-auto">Save Settings</div>
+ {/if}
</button>
</div>
</form>
diff --git a/src/routes/[username]/settings/_account.svelte b/src/routes/[username]/settings/_account.svelte
index bb229b93..f139b3f4 100644
--- a/src/routes/[username]/settings/_account.svelte
+++ b/src/routes/[username]/settings/_account.svelte
@@ -17,6 +17,7 @@
$: banner = files.banner.src;
$: $tempProfileFiles = { profile: files.profile.src, banner: files.banner.src };
+ let togglePassword = () => (revealPassword = !revealPassword);
let colorThemes = [
{ theme: 1, color1: 'from-[#F5F7FA]', color2: 'to-[#C3CFE2]' },
{ theme: 2, color1: 'from-[#FDFCFB]', color2: 'to-[#E2D1C3]' },
@@ -36,9 +37,14 @@
percent = Math.round((event.loaded / event.total) * 100);
};
+ let tooLarge = {};
+
let files = { profile: {}, banner: {} };
let handleFile = async ({ target }, type) => {
+ tooLarge[type] = false;
let file = target.files[0];
+ console.log('TYPE', file.size);
+ if (file.size > 5000000) return (tooLarge[type] = true);
var reader = new FileReader();
reader.onload = async (e) => {
files[type].src = e.target.result;
@@ -83,7 +89,8 @@
{/if}
<button
type="button"
- on:click={() => (revealPassword = !revealPassword)}
+ on:click={togglePassword}
+ on:keydown={togglePassword}
class="absolute right-5 top-11"
>
<Icon icon={revealPassword ? 'eye' : 'eye-off'} />
@@ -118,11 +125,13 @@
<div>
<span class="font-bold">{$t('user.settings.profileImage')}</span>
+
<div class="flex">
{#if profile}
<div
class="relative rounded-full overflow-hidden text-center w-20 h-20 my-auto hover:opacity-80 cursor-pointer"
on:click={() => select('profile')}
+ on:keydown={() => select('profile')}
>
<img
src={profile}
@@ -134,9 +143,10 @@
<div
class="relative rounded-full overflow-hidden text-center w-20 h-20 my-auto hover:opacity-80 cursor-pointer"
on:click={() => select('profile')}
+ on:keydown={() => select('profile')}
>
<img
- src={`/api/public/${user.username}-profile.png`}
+ src={`/api/public/${user.username}-profile.webp`}
class="absolute w-full h-full object-cover object-center visible overflow-hidden"
alt={user.username}
/>
@@ -145,6 +155,7 @@
<div
class="rounded-full border-4 border-white p-4 bg-gradient-to-r {$colorTheme} w-24 my-auto hover:opacity-80 cursor-pointer"
on:click={() => select('profile')}
+ on:keydown={() => select('profile')}
>
<Icon icon="logo-symbol-white" style="mx-auto" />
</div>
@@ -154,7 +165,8 @@
<button
type="button"
class="border rounded-2xl font-bold w-24 text-center px-0 py-2 hover:opacity-80"
- on:click={() => select('profile')}>Select</button
+ on:click={() => select('profile')}
+ on:keydown={() => select('profile')}>Select</button
>
<input
type="file"
@@ -167,6 +179,10 @@
{/if}
</div>
</div>
+
+ {#if tooLarge['profile']}
+ <div class="text-red-600">Max file size 5MB</div>
+ {/if}
</div>
<div>
@@ -180,19 +196,22 @@
src={banner}
class="w-full object-cover object-center visible overflow-hidden h-48 mb-4 hover:opacity-80"
on:click={() => select('banner')}
+ on:keydown={() => select('banner')}
alt="Banner"
/>
{:else if user.banner}
<img
- src={`/api/public/${user.username}-banner.png`}
+ src={`/api/public/${user.username}-banner.webp`}
class="w-full object-cover object-center visible overflow-hidden h-48 mb-4 hover:opacity-80"
on:click={() => select('banner')}
+ on:keydown={() => select('banner')}
alt="Banner"
/>
{:else}
<div
class="bg-gradient-to-r {$colorTheme} w-full h-48 mb-4 cursor-pointer hover:opacity-80"
on:click={() => select('banner')}
+ on:keydown={() => select('banner')}
alt="Banner"
/>
{/if}
@@ -201,7 +220,8 @@
<button
type="button"
class="border rounded-2xl font-bold w-24 text-center px-0 py-2 hover:opacity-80"
- on:click={() => select('banner')}>Select</button
+ on:click={() => select('banner')}
+ on:keydown={() => select('banner')}>Select</button
>
<input
type="file"
@@ -212,6 +232,10 @@
{#if files.banner.filename}
<div class="mt-2 text-sm">{files.banner.filename}</div>
{/if}
+
+ {#if tooLarge['banner']}
+ <div class="text-red-600">Max file size 5MB</div>
+ {/if}
</div>
<!-- TODO
@@ -226,6 +250,7 @@
? 'border-black'
: ''}"
on:click={() => handleThemeClick(colors)}
+ on:keydown={() => handleThemeClick(colors)}
/>
{/each}
</div> -->
diff --git a/src/routes/[username]/settings/_security.svelte b/src/routes/[username]/settings/_security.svelte
index 2a490aa4..98b9b503 100644
--- a/src/routes/[username]/settings/_security.svelte
+++ b/src/routes/[username]/settings/_security.svelte
@@ -4,26 +4,80 @@
import { Icon, Qr } from '$comp';
import { Pincode, PincodeInput } from 'svelte-pincode';
import { post, success, failure } from '$lib/utils';
+ import { pin as current } from '$lib/store';
- export let user;
+ export let user, submit;
let settingPin, setting2fa, disabling2fa;
- let code = [];
- let pin = '';
let token = '';
- let tokenInput, pinInput;
+ let pinCode = [];
+ let verifyCode = [];
+ let tokenInput, pinInput, verifyInput;
+ let verifying = false;
+ let old;
+ let startVerifying = () => {
+ verifying = true;
+ };
+
+ $: pin = pinCode.join('');
+
+ let locked;
+ $: verifyCode.join('').length > 5 && checkPin();
+ let checkPin = async () => {
+ old = $current;
+ if (locked) return;
+ locked = true;
+
+ let verify = verifyCode.join('');
+
+ pinCode = ['', '', '', '', '', ''];
+ verifyCode = ['', '', '', '', '', ''];
+ settingPin = false;
+
+ try {
+ if (pin.length > 5 && pin === verify) {
+ user.haspin = true;
+ $current = pin;
+ submit.click();
+ } else {
+ failure('Pin mismatch, try again');
+ settingPin = true;
+ pinInput.focusFirstInput();
+ }
+ } catch (e) {
+ failure('Problem setting PIN');
+ }
+
+ verifying = false;
+
+ await new Promise((r) => setTimeout(r, 500));
+ locked = false;
+ };
+
+ $: if (verifying) verifyInput && tick().then(verifyInput.focusFirstInput);
$: if (settingPin) pinInput && tick().then(pinInput.focusFirstInput);
- $: if (setting2fa || disabling2fa) tokenInput && tick().then(tokenInput.focusFirstInput);
+ $: if (setting2fa || disabling2fa) tokenInput && tick().then(tokenInput?.focusFirstInput);
let reset = () => {
token = '';
- code = [];
return true;
};
- let togglePin = () => (settingPin = !settingPin);
+ let togglePin = async () => {
+ if (user.haspin) {
+ try {
+ pin = null;
+ submit.click();
+ } catch (e) {
+ failure('Failed to disable pin');
+ }
+ } else {
+ settingPin = true;
+ }
+ };
+
let toggleEnabling = () => reset() && (setting2fa = !setting2fa);
let toggleDisabling = () => reset() && (disabling2fa = !disabling2fa);
@@ -58,31 +112,44 @@
$: otpUri = `otpauth://totp/coinos:${user.username}?secret=${user.otpsecret}&period=30&digits=6&algorithm=SHA1&issuer=coinos`;
</script>
-<!-- TODO
<div>
- <span class="font-bold mb-1">{$t('user.settings.securityPIN')}</span>
+ <input type="hidden" name="newpin" value={pin} />
+
+ <span class="font-bold mb-1">{verifying ? 'Verify' : 'Security'} PIN</span>
<p class="text-secondary mb-1">
{$t('user.settings.securityPINDescription')}
</p>
{#if settingPin}
<div class="flex my-4">
<div class="mx-auto">
- <Pincode bind:code bind:value={user.pin} bind:this={pinInput}>
- <PincodeInput />
- <PincodeInput />
- <PincodeInput />
- <PincodeInput />
- <PincodeInput />
- <PincodeInput />
- </Pincode>
+ <div class:hidden={verifying}>
+ <Pincode on:complete={startVerifying} bind:code={pinCode} bind:this={pinInput}>
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ </Pincode>
+ </div>
+ <div class:hidden={!verifying}>
+ <Pincode bind:code={verifyCode} bind:this={verifyInput}>
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ <PincodeInput />
+ </Pincode>
+ </div>
</div>
</div>
{:else}
<button type="button" class="primary" on:click={togglePin}
- ><Icon icon="lock" style="mr-1" /> {$t('user.settings.setPIN')}</button
+ ><Icon icon="lock" style="mr-1" /> {user.haspin ? 'Disable Pin' : 'Enable Pin'}</button
>
{/if}
-</div> -->
+</div>
<!-- TODO
<div>
@@ -116,7 +183,7 @@
<div class="text-center my-4">
{$t('user.settings.oneTimeCode')}<br />
- <Pincode bind:code bind:value={token} bind:this={tokenInput}>
+ <Pincode bind:value={token} bind:this={tokenInput}>
<PincodeInput />
<PincodeInput />
<PincodeInput />
@@ -128,7 +195,7 @@
{:else if disabling2fa}
<div class="text-center my-4">
{$t('user.settings.oneTimeCode')}<br />
- <Pincode bind:code bind:value={token} bind:this={tokenInput}>
+ <Pincode bind:value={token} bind:this={tokenInput}>
<PincodeInput />
<PincodeInput />
<PincodeInput />
diff --git a/src/routes/invoice/[id]/+page.svelte b/src/routes/invoice/[id]/+page.svelte
index 04a31813..84b03593 100644
--- a/src/routes/invoice/[id]/+page.svelte
+++ b/src/routes/invoice/[id]/+page.svelte
@@ -44,7 +44,9 @@
$: tip = Math.round((amount / 100) * tipPercent);
$invoices[id] = { amount, id, rate, received, text, tip, username };
- $: browser && $invoices[id]?.received >= $invoices[id]?.amount && goto(`/invoice/${id}/paid`);
+ $: browser &&
+ $invoices[id]?.received >= $invoices[id]?.amount &&
+ goto(($invoices[id].memo === 'launch' && '/launch/purchase') || `/invoice/${id}/paid`);
$: amountFiat = parseFloat(((amount * rate) / sats).toFixed(2));
diff --git a/src/routes/invoice/[id]/paid/+page.svelte b/src/routes/invoice/[id]/paid/+page.svelte
index 95c721d0..d619b7ff 100644
--- a/src/routes/invoice/[id]/paid/+page.svelte
+++ b/src/routes/invoice/[id]/paid/+page.svelte
@@ -22,7 +22,7 @@
};
</script>
-<div class="container px-4 text-center">
+<div class="container px-4 text-center mx-auto">
<div class="flex w-full py-20 max-w-[200px] mx-auto" in:scale={{ start: 0.5 }}>
<Icon icon="check" style="mx-auto" />
</div>
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="&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>
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>
diff --git a/src/routes/login/+page.server.js b/src/routes/login/+page.server.js
index 94981ff7..b46af49e 100644
--- a/src/routes/login/+page.server.js
+++ b/src/routes/login/+page.server.js
@@ -4,15 +4,15 @@ import { login } from '$lib/utils';
export const actions = {
default: async ({ cookies, request }) => {
let form = Object.fromEntries(await request.formData());
- let { username, password, redirect: r } = form;
- let user = { username, password };
+ let { username, password, token, loginRedirect } = form;
+ let user = { username, password, token };
try {
- await login(user, cookies);
+ let r = await login(user, cookies);
} catch (e) {
- return invalid(400, { error: 'Login failed' });
+ return invalid(400, { error: 'Login failed', message: e.message, ...form });
}
- throw redirect(303, r || `/${user.username}/dashboard`);
+ throw redirect(303, loginRedirect || `/${user.username}/dashboard`);
}
};
diff --git a/src/routes/login/+page.svelte b/src/routes/login/+page.svelte
index cf7cb517..75998cd0 100644
--- a/src/routes/login/+page.svelte
+++ b/src/routes/login/+page.svelte
@@ -1,5 +1,6 @@
<script>
import { RegisterOrLogin } from '$comp';
+
export let form;
</script>
diff --git a/src/routes/register/+page.server.js b/src/routes/register/+page.server.js
index bfe1a9b7..c5751d4c 100644
--- a/src/routes/register/+page.server.js
+++ b/src/routes/register/+page.server.js
@@ -4,7 +4,7 @@ import { post, login } from '$lib/utils';
export const actions = {
default: async ({ cookies, request }) => {
let form = Object.fromEntries(await request.formData());
- let { username, password, redirect: r } = form;
+ let { username, password, loginRedirect } = form;
let user = { username, password };
let error;
@@ -23,6 +23,6 @@ export const actions = {
}
if (error) return invalid(400, { error });
- throw redirect(307, r || `/${user.username}/dashboard`);
+ throw redirect(307, loginRedirect || `/${user.username}/dashboard`);
}
};
diff --git a/src/routes/register/+page.svelte b/src/routes/register/+page.svelte
index aa0e66e0..fd9e4417 100644
--- a/src/routes/register/+page.svelte
+++ b/src/routes/register/+page.svelte
@@ -5,9 +5,7 @@
afterNavigate(async () => {
try {
- console.log('whoa');
await invalidateAll();
- console.log('no');
} catch (e) {
console.log(e);
}
diff --git a/src/routes/scan/+page.svelte b/src/routes/scan/+page.svelte
index 1c14cb6d..dc6e291d 100644
--- a/src/routes/scan/+page.svelte
+++ b/src/routes/scan/+page.svelte
@@ -7,7 +7,7 @@
let scanner, vid;
onMount(() => {
- scanner = new QrScanner(vid, (text) => goto(`/send/${text}`));
+ scanner = new QrScanner(vid, (text) => goto(`/send/${text}`), { highlightScanRegion: true, highlightCodeOutline: true });
scanner.start();
});
diff --git a/src/routes/send/+layout.svelte b/src/routes/send/+layout.svelte
new file mode 100644
index 00000000..c9122466
--- /dev/null
+++ b/src/routes/send/+layout.svelte
@@ -0,0 +1,18 @@
+<script>
+ import { Pin } from '$comp';
+ import { pin } from '$lib/store';
+ import { onMount } from 'svelte';
+
+ export let data;
+
+ let loaded;
+ let { user } = data;
+
+ onMount(() => setTimeout(() => (loaded = true), 50));
+</script>
+
+{#if loaded && user.haspin && $pin?.length !== 6}
+ <Pin />
+{/if}
+
+<slot />
diff --git a/src/routes/send/[...text]/+page.server.js b/src/routes/send/[...text]/+page.server.js
index 45bb597d..b909ab4d 100644
--- a/src/routes/send/[...text]/+page.server.js
+++ b/src/routes/send/[...text]/+page.server.js
@@ -55,6 +55,6 @@ export const actions = {
const form = await request.formData();
await parse(form.get('text'));
- return invalid(403, { error: 'Failed to recognize input' });
+ return invalid(403, { error: 'Does not compute, try again' });
}
};
diff --git a/src/routes/send/[...text]/+page.svelte b/src/routes/send/[...text]/+page.svelte
index 5d6d123e..fe949617 100644
--- a/src/routes/send/[...text]/+page.svelte
+++ b/src/routes/send/[...text]/+page.svelte
@@ -92,8 +92,4 @@
line-height: 20px;
@apply block border rounded-2xl p-3 py-4 w-full;
}
-
- .expandable-expandable::-webkit-resizer {
- background: transparent;
- }
</style>
diff --git a/src/routes/send/[uuid=uuid]/+page.server.js b/src/routes/send/[uuid=uuid]/+page.server.js
index 661e9e7b..c9c77f70 100644
--- a/src/routes/send/[uuid=uuid]/+page.server.js
+++ b/src/routes/send/[uuid=uuid]/+page.server.js
@@ -10,14 +10,19 @@ export async function load({ params, parent }) {
export const actions = {
default: async ({ cookies, params, request }) => {
- let body = Object.fromEntries(await request.formData());
- let { confirmed } = body;
+ try {
+ let body = Object.fromEntries(await request.formData());
+ let { confirmed } = body;
- if (!confirmed) {
- return invalid(403, { amount, confirm: true });
+ if (!confirmed) {
+ return invalid(403, { amount, confirm: true });
+ }
+
+ await post('/send', body, auth(cookies));
+ } catch (e) {
+ return invalid(400, { message: e.message });
}
- await post('/send', body, auth(cookies));
throw redirect(307, '/sent');
}
};
diff --git a/src/routes/send/[uuid=uuid]/+page.svelte b/src/routes/send/[uuid=uuid]/+page.svelte
index aa798bc1..73712f71 100644
--- a/src/routes/send/[uuid=uuid]/+page.svelte
+++ b/src/routes/send/[uuid=uuid]/+page.svelte
@@ -1,6 +1,6 @@
<script>
import { goto } from '$app/navigation';
- import { selectedRate } from '$lib/store';
+ import { pin, selectedRate } from '$lib/store';
import { enhance } from '$app/forms';
import { Icon, Numpad, Spinner } from '$comp';
import { page } from '$app/stores';
@@ -31,12 +31,24 @@
let loading;
let submit = () => (loading = true);
+
+ $: update(form);
+ let update = () => {
+ if (form?.message.includes('pin')) $pin = undefined;
+ loading = false;
+ };
</script>
<button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" on:click={handleBack}>
<Icon icon="arrow-left" style="w-10" />
</button>
+{#if form?.message}
+ <div class="text-red-600 text-center">
+ {form.message}
+ </div>
+{/if}
+
<div class="container px-4 mt-20 max-w-xl mx-auto">
{#if amount}
<div class="text-center mb-8">
@@ -61,6 +73,7 @@
<input name="payreq" value={payreq} type="hidden" />
<input name="username" value={recipient.username} type="hidden" />
<input name="confirmed" value={form?.confirm} type="hidden" />
+ <input name="pin" value={$pin} type="hidden" />
<div class="flex w-full">
{#if amount}
diff --git a/src/routes/send/bitcoin/[address]/+page.server.js b/src/routes/send/bitcoin/[address]/+page.server.js
index 9b29a6da..642593ab 100644
--- a/src/routes/send/bitcoin/[address]/+page.server.js
+++ b/src/routes/send/bitcoin/[address]/+page.server.js
@@ -1,11 +1,16 @@
-import { redirect } from '@sveltejs/kit';
+import { invalid, redirect } from '@sveltejs/kit';
import { auth, post } from '$lib/utils';
export const actions = {
default: async ({ cookies, request }) => {
- let { address, amount } = Object.fromEntries(await request.formData());
- let { tx } = await post('/bitcoin/fee', { address, amount }, auth(cookies));
- await post('/bitcoin/send', { address, tx }, auth(cookies));
+ try {
+ let { address, amount, pin } = Object.fromEntries(await request.formData());
+ let { tx } = await post('/bitcoin/fee', { address, amount }, auth(cookies));
+ await post('/bitcoin/send', { address, pin, tx }, auth(cookies));
+ } catch (e) {
+ return invalid(400, { message: e.message });
+ }
+
throw redirect(307, '/sent');
}
};
diff --git a/src/routes/send/bitcoin/[address]/+page.svelte b/src/routes/send/bitcoin/[address]/+page.svelte
index 8c9e72ff..c9023180 100644
--- a/src/routes/send/bitcoin/[address]/+page.svelte
+++ b/src/routes/send/bitcoin/[address]/+page.svelte
@@ -3,19 +3,33 @@
import { Icon, Numpad, Spinner } from '$comp';
import { page } from '$app/stores';
import { back } from '$lib/utils';
+ import { pin } from '$lib/store';
+
export let data;
+ export let form;
let { address } = $page.params;
let { currency } = data.user;
let amount, loading;
let submit = () => (loading = true);
+ $: update(form);
+ let update = () => {
+ if (form?.message.includes('pin')) $pin = undefined;
+ loading = false;
+ };
</script>
<button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" on:click={back}>
<Icon icon="arrow-left" style="w-10" />
</button>
+{#if form?.message}
+ <div class="text-red-600 text-center">
+ {form.message}
+ </div>
+{/if}
+
<div class="container px-4 mt-20 max-w-xl mx-auto">
<div class="text-center mb-8">
<h1 class="text-3xl md:text-4xl font-semibold mb-2">Send to</h1>
@@ -26,6 +40,8 @@
<form method="POST" use:enhance on:submit={submit}>
<input name="address" value={address} type="hidden" />
<input name="amount" value={amount} type="hidden" />
+ <input name="pin" value={$pin} type="hidden" />
+
<div class="flex w-full">
<button
type="submit"
diff --git a/src/routes/send/lightning/[payreq]/+page.server.js b/src/routes/send/lightning/[payreq]/+page.server.js
index f17d6a60..49ebac1c 100644
--- a/src/routes/send/lightning/[payreq]/+page.server.js
+++ b/src/routes/send/lightning/[payreq]/+page.server.js
@@ -7,14 +7,20 @@ export async function load({ params }) {
export const actions = {
default: async ({ cookies, request }) => {
- let body = Object.fromEntries(await request.formData());
- let { amount, confirmed } = body;
+ try {
+ let body = Object.fromEntries(await request.formData());
+ let { amount, confirmed } = body;
- if (!confirmed) {
- return invalid(403, { amount, confirm: true });
+ if (!confirmed) {
+ return invalid(403, { amount, confirm: true });
+ }
+
+ await post('/lightning/send', body, auth(cookies));
+ } catch (e) {
+ if (e.message.includes("unusable")) e.message = "Failed to route payment, try sending a lower amount"
+ return invalid(400, { message: e.message });
}
- await post('/lightning/send', body, auth(cookies));
throw redirect(307, '/sent');
}
};
diff --git a/src/routes/send/lightning/[payreq]/+page.svelte b/src/routes/send/lightning/[payreq]/+page.svelte
index 973550f6..bda10038 100644
--- a/src/routes/send/lightning/[payreq]/+page.svelte
+++ b/src/routes/send/lightning/[payreq]/+page.svelte
@@ -3,6 +3,8 @@
import { Icon, Numpad, Spinner } from '$comp';
import { page } from '$app/stores';
import { back, s } from '$lib/utils';
+ import { pin } from '$lib/store';
+
export let data;
export let form;
@@ -14,12 +16,23 @@
let loading;
let submit = () => (loading = true);
+ $: update(form);
+ let update = () => {
+ if (form?.message.includes('pin')) $pin = undefined;
+ loading = false;
+ };
</script>
<button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" on:click={back}>
<Icon icon="arrow-left" style="w-10" />
</button>
+{#if form?.message}
+ <div class="text-red-600 text-center">
+ {form.message}
+ </div>
+{/if}
+
<div class="container px-4 mt-20 max-w-xl mx-auto">
{#if amount}
<div class="text-center mb-8">
@@ -38,6 +51,7 @@
<input name="payreq" value={payreq} type="hidden" />
<input name="amount" value={amount} type="hidden" />
<input name="confirmed" value={form?.confirm} type="hidden" />
+ <input name="pin" value={$pin} type="hidden" />
<div class="flex w-full">
<button
diff --git a/src/routes/send/user/[username]/[...amount]/+page.server.js b/src/routes/send/user/[username]/[...amount]/+page.server.js
index 12bae186..a659eef3 100644
--- a/src/routes/send/user/[username]/[...amount]/+page.server.js
+++ b/src/routes/send/user/[username]/[...amount]/+page.server.js
@@ -11,14 +11,19 @@ export async function load({ params, parent }) {
export const actions = {
default: async ({ cookies, request }) => {
- let body = Object.fromEntries(await request.formData());
- let { amount, confirmed } = body;
+ try {
+ let body = Object.fromEntries(await request.formData());
+ let { amount, confirmed } = body;
- if (!confirmed) {
- return invalid(403, { amount, confirm: true });
+ if (!confirmed) {
+ return invalid(403, { amount, confirm: true });
+ }
+
+ await post('/send', body, auth(cookies));
+ } catch (e) {
+ return invalid(400, { message: e.message });
}
- await post('/send', body, auth(cookies));
throw redirect(307, '/sent');
}
};
diff --git a/src/routes/send/user/[username]/[...amount]/+page.svelte b/src/routes/send/user/[username]/[...amount]/+page.svelte
index e50acd5b..6f4cb313 100644
--- a/src/routes/send/user/[username]/[...amount]/+page.svelte
+++ b/src/routes/send/user/[username]/[...amount]/+page.svelte
@@ -1,10 +1,11 @@
<script>
import { goto } from '$app/navigation';
- import { selectedRate } from '$lib/store';
+ import { pin, selectedRate } from '$lib/store';
import { enhance } from '$app/forms';
import { Avatar, Icon, Numpad, Spinner } from '$comp';
import { page } from '$app/stores';
import { back, f, s, sats } from '$lib/utils';
+
export let data;
export let form;
@@ -31,12 +32,24 @@
let loading;
let submit = () => (loading = true);
+
+ $: update(form);
+ let update = () => {
+ if (form?.message.includes('pin')) $pin = undefined;
+ loading = false;
+ };
</script>
<button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" on:click={handleBack}>
<Icon icon="arrow-left" style="w-10" />
</button>
+{#if form?.message}
+ <div class="text-red-600 text-center">
+ {form.message}
+ </div>
+{/if}
+
<div class="container px-4 mt-20 max-w-xl mx-auto">
{#if amount}
<div class="text-center mb-8">
@@ -63,6 +76,7 @@
<input name="amount" value={amount} type="hidden" />
<input name="username" value={recipient.username} type="hidden" />
<input name="confirmed" value={form?.confirm} type="hidden" />
+ <input name="pin" value={$pin} type="hidden" />
<div class="flex w-full">
{#if amount}
diff --git a/src/routes/user/+server.js b/src/routes/user/+server.js
index c9490984..b9c37e6e 100644
--- a/src/routes/user/+server.js
+++ b/src/routes/user/+server.js
@@ -1,5 +1,4 @@
import { auth, post } from '$lib/utils';
-import cookie from 'cookie';
export async function PUT({ cookies, request }) {
let user = await request.json();
diff --git a/static/icons/party.svg b/static/icons/party.svg
new file mode 100644
index 00000000..f33b9fc1
--- /dev/null
+++ b/static/icons/party.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 300.948 300.948" style="enable-background:new 0 0 300.948 300.948;" xml:space="preserve">
+<g id="XMLID_1505_">
+ <g>
+ <g>
+ <path d="M132.166,219.612L120.7,189.007l-18.92,25.645l4.57,12.2l1.089,52.22c0.152,7.28,6.101,13.079,13.349,13.079
+ c0.094,0,0.189-0.001,0.284-0.003c7.375-0.154,13.229-6.257,13.076-13.632l-1.137-54.496
+ C132.98,222.513,132.694,221.023,132.166,219.612z"/>
+ <circle cx="92.165" cy="50.896" r="23.069"/>
+ <path d="M170.846,40.209c-4.878-3.74-11.866-2.818-15.606,2.061l-29.253,38.153l-12.6,2.504c-2.239-1.26-4.819-1.987-7.57-1.997
+ l-27.79-0.113c-8.606-0.035-15.612,6.914-15.647,15.521l-0.041,10.148c5.894-4.85,10.2-8.395,16.342-13.449l-27.839,36.752
+ c-2.212,3.006-2.77,6.913-1.494,10.412l15.522,42.623c2.131,5.848,8.593,8.715,14.271,6.644c5.774-2.105,8.75-8.493,6.644-14.271
+ l-13.189-36.173l25.099-34.09l-1.65,4.137c-2.548,6.388-9.458,23.716-12.013,30.124c9.171,25.153,8.43,23.12,11.792,32.342
+ c4.13,11.328-1.694,23.839-13.023,27.969c-5.156,1.88-10.876,1.768-16.015-0.416l-6.946,9.415L7.481,234.98
+ c-6.635,3.253-9.357,11.259-6.115,17.872c3.249,6.627,11.25,9.361,17.872,6.115l55.291-27.913
+ c1.927-0.944,3.596-2.338,4.87-4.064l39.4-53.405c2.39-3.245,2.291-6.351,2.272-10.854l0.238-58.684l13.132-2.61
+ c2.651-0.527,5.019-2,6.663-4.145l31.803-41.48C176.646,50.936,175.724,43.949,170.846,40.209z"/>
+ <path d="M250.435,216.627c-2.072,3.485-1.699,6.841-1.363,9.642l6.507,54.118c0.881,7.325,7.533,12.547,14.856,11.667
+ c7.324-0.88,12.547-7.532,11.667-14.856l-6.236-51.857l7.302-32.973L250.435,216.627z"/>
+ <circle cx="255.17" cy="49.131" r="23.069"/>
+ <path d="M300.801,157.11c-0.001-0.005-0.001-0.009-0.002-0.013l-9.775-67.144c-1.24-8.517-9.15-14.416-17.666-13.176
+ l-27.433,3.994l-25.751-17.246l-12.368-46.457c-1.582-5.94-7.68-9.474-13.62-7.892c-5.94,1.581-9.474,7.679-7.892,13.62
+ l13.447,50.51c0.696,2.612,2.317,4.881,4.563,6.385l25.379,16.996c29.946-8.374,25.085-7.015,34.511-9.651l-36.571,21.323
+ l-34.561-16.97c-5.132-2.52-11.407-0.729-14.403,4.194c-3.469,5.696-1.193,12.949,4.591,15.789
+ c44.139,21.651,40.969,20.131,41.842,20.447c3.002,1.088,6.429,0.864,9.395-0.846l39.51-23.763l-35.156,33.548l3.577,24.567
+ l18.423-2.959l-43.669,32.365c-1.723,1.278-3.113,2.95-4.053,4.879l-27.793,55.352c-3.232,6.631-0.477,14.626,6.154,17.859
+ c6.617,3.225,14.619,0.49,17.859-6.154l26.362-52.417c44.648-33.09,34.888-25.947,59.437-43.736
+ C299.365,167.448,301.554,162.275,300.801,157.11z"/>
+ </g>
+ </g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/static/images/loft.jpg b/static/images/loft.jpg
new file mode 100644
index 00000000..39ca49ab
--- /dev/null
+++ b/static/images/loft.jpg
Binary files differ
diff --git a/static/images/logo.png b/static/images/logo.png
new file mode 100644
index 00000000..6503a7d2
--- /dev/null
+++ b/static/images/logo.png
Binary files differ
diff --git a/static/tickets/01.png b/static/tickets/01.png
new file mode 100644
index 00000000..555904c0
--- /dev/null
+++ b/static/tickets/01.png
Binary files differ
diff --git a/static/tickets/02.png b/static/tickets/02.png
new file mode 100644
index 00000000..65d35ba2
--- /dev/null
+++ b/static/tickets/02.png
Binary files differ
diff --git a/static/tickets/03.png b/static/tickets/03.png
new file mode 100644
index 00000000..b073cef5
--- /dev/null
+++ b/static/tickets/03.png
Binary files differ
diff --git a/static/tickets/04.png b/static/tickets/04.png
new file mode 100644
index 00000000..14d6b567
--- /dev/null
+++ b/static/tickets/04.png
Binary files differ
diff --git a/static/tickets/05.png b/static/tickets/05.png
new file mode 100644
index 00000000..99351b3d
--- /dev/null
+++ b/static/tickets/05.png
Binary files differ
diff --git a/static/tickets/06.png b/static/tickets/06.png
new file mode 100644
index 00000000..366747ac
--- /dev/null
+++ b/static/tickets/06.png
Binary files differ
diff --git a/static/tickets/07.png b/static/tickets/07.png
new file mode 100644
index 00000000..f774c683
--- /dev/null
+++ b/static/tickets/07.png
Binary files differ
diff --git a/static/tickets/08.png b/static/tickets/08.png
new file mode 100644
index 00000000..4f8ad5c3
--- /dev/null
+++ b/static/tickets/08.png
Binary files differ
diff --git a/static/tickets/09.png b/static/tickets/09.png
new file mode 100644
index 00000000..f8fd9cf6
--- /dev/null
+++ b/static/tickets/09.png
Binary files differ
diff --git a/static/tickets/10.png b/static/tickets/10.png
new file mode 100644
index 00000000..d557099c
--- /dev/null
+++ b/static/tickets/10.png
Binary files differ
diff --git a/static/tickets/11.png b/static/tickets/11.png
new file mode 100644
index 00000000..484150a6
--- /dev/null
+++ b/static/tickets/11.png
Binary files differ
diff --git a/static/tickets/12.png b/static/tickets/12.png
new file mode 100644
index 00000000..05b4a337
--- /dev/null
+++ b/static/tickets/12.png
Binary files differ
diff --git a/static/tickets/13.png b/static/tickets/13.png
new file mode 100644
index 00000000..a853d777
--- /dev/null
+++ b/static/tickets/13.png
Binary files differ
diff --git a/static/tickets/14.png b/static/tickets/14.png
new file mode 100644
index 00000000..3ad8105a
--- /dev/null
+++ b/static/tickets/14.png
Binary files differ
diff --git a/static/tickets/15.png b/static/tickets/15.png
new file mode 100644
index 00000000..d34eed52
--- /dev/null
+++ b/static/tickets/15.png
Binary files differ
diff --git a/static/tickets/16.png b/static/tickets/16.png
new file mode 100644
index 00000000..8a1b15b6
--- /dev/null
+++ b/static/tickets/16.png
Binary files differ
diff --git a/static/tickets/17.png b/static/tickets/17.png
new file mode 100644
index 00000000..a763b6c9
--- /dev/null
+++ b/static/tickets/17.png
Binary files differ
diff --git a/static/tickets/18.png b/static/tickets/18.png
new file mode 100644
index 00000000..14811954
--- /dev/null
+++ b/static/tickets/18.png
Binary files differ
diff --git a/static/tickets/19.png b/static/tickets/19.png
new file mode 100644
index 00000000..04c3915b
--- /dev/null
+++ b/static/tickets/19.png
Binary files differ
diff --git a/static/tickets/20.png b/static/tickets/20.png
new file mode 100644
index 00000000..c42c311d
--- /dev/null
+++ b/static/tickets/20.png
Binary files differ
diff --git a/static/tickets/21.png b/static/tickets/21.png
new file mode 100644
index 00000000..3863d45e
--- /dev/null
+++ b/static/tickets/21.png
Binary files differ
diff --git a/static/tickets/22.png b/static/tickets/22.png
new file mode 100644
index 00000000..0e8cb413
--- /dev/null
+++ b/static/tickets/22.png
Binary files differ
diff --git a/static/tickets/23.png b/static/tickets/23.png
new file mode 100644
index 00000000..bac50642
--- /dev/null
+++ b/static/tickets/23.png
Binary files differ
diff --git a/static/tickets/24.png b/static/tickets/24.png
new file mode 100644
index 00000000..140abd01
--- /dev/null
+++ b/static/tickets/24.png
Binary files differ
diff --git a/static/tickets/25.png b/static/tickets/25.png
new file mode 100644
index 00000000..fb5d5b32
--- /dev/null
+++ b/static/tickets/25.png
Binary files differ
diff --git a/static/tickets/26.png b/static/tickets/26.png
new file mode 100644
index 00000000..980f824f
--- /dev/null
+++ b/static/tickets/26.png
Binary files differ
diff --git a/static/tickets/27.png b/static/tickets/27.png
new file mode 100644
index 00000000..6892cd7d
--- /dev/null
+++ b/static/tickets/27.png
Binary files differ
diff --git a/static/tickets/28.png b/static/tickets/28.png
new file mode 100644
index 00000000..03f1b0fa
--- /dev/null
+++ b/static/tickets/28.png
Binary files differ
diff --git a/static/tickets/29.png b/static/tickets/29.png
new file mode 100644
index 00000000..39a1eaff
--- /dev/null
+++ b/static/tickets/29.png
Binary files differ
diff --git a/static/tickets/30.png b/static/tickets/30.png
new file mode 100644
index 00000000..35f7463a
--- /dev/null
+++ b/static/tickets/30.png
Binary files differ
diff --git a/static/tickets/31.png b/static/tickets/31.png
new file mode 100644
index 00000000..2f7a6b2c
--- /dev/null
+++ b/static/tickets/31.png
Binary files differ
diff --git a/static/tickets/32.png b/static/tickets/32.png
new file mode 100644
index 00000000..cae96a35
--- /dev/null
+++ b/static/tickets/32.png
Binary files differ
diff --git a/static/tickets/33.png b/static/tickets/33.png
new file mode 100644
index 00000000..1754a731
--- /dev/null
+++ b/static/tickets/33.png
Binary files differ
diff --git a/static/tickets/34.png b/static/tickets/34.png
new file mode 100644
index 00000000..4d3eb544
--- /dev/null
+++ b/static/tickets/34.png
Binary files differ
diff --git a/static/tickets/35.png b/static/tickets/35.png
new file mode 100644
index 00000000..be8775dc
--- /dev/null
+++ b/static/tickets/35.png
Binary files differ
diff --git a/static/tickets/36.png b/static/tickets/36.png
new file mode 100644
index 00000000..a80c1b39
--- /dev/null
+++ b/static/tickets/36.png
Binary files differ
diff --git a/static/tickets/37.png b/static/tickets/37.png
new file mode 100644
index 00000000..a6536293
--- /dev/null
+++ b/static/tickets/37.png
Binary files differ
diff --git a/static/tickets/38.png b/static/tickets/38.png
new file mode 100644
index 00000000..06a22e8f
--- /dev/null
+++ b/static/tickets/38.png
Binary files differ
diff --git a/static/tickets/39.png b/static/tickets/39.png
new file mode 100644
index 00000000..a45ce455
--- /dev/null
+++ b/static/tickets/39.png
Binary files differ
diff --git a/static/tickets/40.png b/static/tickets/40.png
new file mode 100644
index 00000000..acfd2a9a
--- /dev/null
+++ b/static/tickets/40.png
Binary files differ
diff --git a/static/tickets/41.png b/static/tickets/41.png
new file mode 100644
index 00000000..5e98fa33
--- /dev/null
+++ b/static/tickets/41.png
Binary files differ
diff --git a/static/tickets/42.png b/static/tickets/42.png
new file mode 100644
index 00000000..eeefd71b
--- /dev/null
+++ b/static/tickets/42.png
Binary files differ
diff --git a/static/tickets/43.png b/static/tickets/43.png
new file mode 100644
index 00000000..c1ce6eac
--- /dev/null
+++ b/static/tickets/43.png
Binary files differ
diff --git a/static/tickets/44.png b/static/tickets/44.png
new file mode 100644
index 00000000..36b79835
--- /dev/null
+++ b/static/tickets/44.png
Binary files differ
diff --git a/static/tickets/45.png b/static/tickets/45.png
new file mode 100644
index 00000000..f1889622
--- /dev/null
+++ b/static/tickets/45.png
Binary files differ
diff --git a/static/tickets/46.png b/static/tickets/46.png
new file mode 100644
index 00000000..1a74008f
--- /dev/null
+++ b/static/tickets/46.png
Binary files differ
diff --git a/static/tickets/47.png b/static/tickets/47.png
new file mode 100644
index 00000000..0d9bb11c
--- /dev/null
+++ b/static/tickets/47.png
Binary files differ
diff --git a/static/tickets/48.png b/static/tickets/48.png
new file mode 100644
index 00000000..3f4c9b1f
--- /dev/null
+++ b/static/tickets/48.png
Binary files differ
diff --git a/static/tickets/49.png b/static/tickets/49.png
new file mode 100644
index 00000000..0b88dc78
--- /dev/null
+++ b/static/tickets/49.png
Binary files differ
diff --git a/static/tickets/50.png b/static/tickets/50.png
new file mode 100644
index 00000000..bd2aa215
--- /dev/null
+++ b/static/tickets/50.png
Binary files differ