Skip to content

Commit 2471c06

Browse files
authored
fix: simplify how it works and privacy pages (#77)
Signed-off-by: JaeBrian <[email protected]>
1 parent 529c233 commit 2471c06

File tree

2 files changed

+413
-282
lines changed

2 files changed

+413
-282
lines changed

src/pages/HowItWorks.tsx

Lines changed: 208 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,227 @@
11
import { Link } from 'react-router'
2+
import { useState, useEffect, useRef } from 'react'
23

34
const HowItWorks = () => {
4-
return (
5-
<div className="flex flex-col bg-[linear-gradient(180deg,#1C246E_0%,#040617_12.5%)] relative pt-16 min-h-screen">
6-
<div className="max-w-4xl mx-auto px-4 py-12">
7-
<div className="text-center mb-12">
8-
<h1 className="text-4xl font-bold text-white mb-4">Lorem Ipsum</h1>
9-
<p className="text-gray-300 text-lg">Dolor sit amet consectetur adipiscing elit</p>
10-
</div>
11-
12-
<div className="grid md:grid-cols-3 gap-8 mb-12">
13-
<div className="bg-[#00000033] rounded-lg p-6 backdrop-blur-sm border border-[#ffffff1a] text-center">
14-
<div className="w-16 h-16 bg-white rounded-full flex items-center justify-center mx-auto mb-4">
15-
<span className="text-[#1C246E] text-2xl font-bold">1</span>
16-
</div>
17-
<h3 className="text-xl font-semibold text-white mb-3">Lorem Ipsum</h3>
18-
<p className="text-gray-300 text-sm">
19-
Dolor sit amet consectetur adipiscing elit sed do eiusmod tempor
20-
</p>
21-
</div>
5+
const [activeSection, setActiveSection] = useState('overview')
6+
const [isMobile, setIsMobile] = useState(false)
7+
const isScrollingRef = useRef(false)
228

23-
<div className="bg-[#00000033] rounded-lg p-6 backdrop-blur-sm border border-[#ffffff1a] text-center">
24-
<div className="w-16 h-16 bg-white rounded-full flex items-center justify-center mx-auto mb-4">
25-
<span className="text-[#1C246E] text-2xl font-bold">2</span>
26-
</div>
27-
<h3 className="text-xl font-semibold text-white mb-3">Dolor Sit</h3>
28-
<p className="text-gray-300 text-sm">
29-
Amet consectetur adipiscing elit sed do eiusmod tempor incididunt
30-
</p>
31-
</div>
9+
const sections = [
10+
{ id: 'overview', title: 'Overview', number: null },
11+
{ id: 'signup', title: 'Website Signup Process', number: 1 },
12+
{ id: 'validation', title: 'Smart Contract Validation', number: 2 },
13+
{ id: 'indexer', title: 'Indexer Processing', number: 3 },
14+
{ id: 'authentication', title: 'Profile Download Authentication', number: 4 },
15+
{ id: 'setup', title: 'VPN Client Setup', number: 5 }
16+
]
3217

33-
<div className="bg-[#00000033] rounded-lg p-6 backdrop-blur-sm border border-[#ffffff1a] text-center">
34-
<div className="w-16 h-16 bg-white rounded-full flex items-center justify-center mx-auto mb-4">
35-
<span className="text-[#1C246E] text-2xl font-bold">3</span>
36-
</div>
37-
<h3 className="text-xl font-semibold text-white mb-3">Amet Consectetur</h3>
38-
<p className="text-gray-300 text-sm">
39-
Adipiscing elit sed do eiusmod tempor incididunt ut labore dolore
40-
</p>
41-
</div>
42-
</div>
18+
useEffect(() => {
19+
const checkMobile = () => {
20+
setIsMobile(window.innerWidth < 1024)
21+
}
22+
23+
checkMobile()
24+
window.addEventListener('resize', checkMobile)
25+
return () => window.removeEventListener('resize', checkMobile)
26+
}, [])
4327

44-
<div className="bg-[#00000033] rounded-lg p-8 backdrop-blur-sm border border-[#ffffff1a] mb-8">
45-
<h2 className="text-2xl font-semibold text-white mb-6 text-center">Lorem Ipsum Dolor</h2>
46-
<div className="grid md:grid-cols-2 gap-6 text-gray-300">
47-
<div>
48-
<h3 className="text-lg font-semibold text-white mb-2">🔒 Lorem Ipsum</h3>
49-
<p className="text-sm">Dolor sit amet consectetur adipiscing elit sed do eiusmod tempor</p>
50-
</div>
51-
<div>
52-
<h3 className="text-lg font-semibold text-white mb-2">⚡ Dolor Sit</h3>
53-
<p className="text-sm">Amet consectetur adipiscing elit sed do eiusmod tempor incididunt</p>
54-
</div>
55-
<div>
56-
<h3 className="text-lg font-semibold text-white mb-2">🌐 Amet Consectetur</h3>
57-
<p className="text-sm">Adipiscing elit sed do eiusmod tempor incididunt ut labore dolore</p>
58-
</div>
59-
<div>
60-
<h3 className="text-lg font-semibold text-white mb-2">💎 Tempor Incididunt</h3>
61-
<p className="text-sm">Ut labore et dolore magna aliqua ut enim ad minim veniam</p>
62-
</div>
63-
</div>
64-
</div>
28+
const scrollToSection = (sectionId: string) => {
29+
isScrollingRef.current = true
30+
setActiveSection(sectionId)
31+
32+
const element = document.getElementById(sectionId)
33+
if (element) {
34+
element.scrollIntoView({ behavior: 'smooth', block: 'start' })
35+
36+
setTimeout(() => {
37+
isScrollingRef.current = false
38+
}, 1000)
39+
}
40+
}
6541

66-
<div className="bg-[#00000033] rounded-lg p-8 backdrop-blur-sm border border-[#ffffff1a] mb-8">
67-
<h2 className="text-2xl font-semibold text-white mb-6 text-center">How It Works</h2>
68-
<div className="text-gray-300 text-center">
42+
useEffect(() => {
43+
const handleScroll = () => {
44+
if (isScrollingRef.current) return
45+
46+
const scrollPosition = window.scrollY + 200
47+
48+
for (const section of sections) {
49+
const element = document.getElementById(section.id)
50+
if (element) {
51+
const { offsetTop, offsetHeight } = element
52+
if (scrollPosition >= offsetTop && scrollPosition < offsetTop + offsetHeight) {
53+
setActiveSection(section.id)
54+
break
55+
}
56+
}
57+
}
58+
}
6959

70-
<p className="mb-6">
71-
Our VPN system consists of multiple components, including smart contracts, a custom chain
72-
indexer and API, a web frontend, and OpenVPN. These pieces work together to facilitate signup
73-
and management of your VPN subscription and access to the VPN tunnel in a manner that focuses
74-
on privacy.
75-
</p>
60+
window.addEventListener('scroll', handleScroll, { passive: true })
61+
return () => window.removeEventListener('scroll', handleScroll)
62+
}, [])
7663

77-
<p className="mb-6">
78-
The signup process typically starts on our website. While it's not strictly necessary to use
79-
our website to subscribe to our services, it does make things easier. Once you connect your
80-
wallet, we will query our API for any existing subscriptions, as well as for current region and
81-
plan information. Once you choose a plan and selection the option to purchase, the site will
82-
call our API with your wallet address and chosen plan information. This will build a transaction
83-
based on your wallet, which is then returned to the user to be signed by their wallet and
84-
submitted.
85-
</p>
64+
return (
65+
<div className="flex relative pt-16 min-h-screen overflow-hidden">
66+
{!isMobile && (
67+
<div className="w-80 fixed left-0 top-32 h-[calc(100vh-4rem)] overflow-y-auto z-20">
68+
<div className="p-6">
69+
<nav className="space-y-2">
70+
{sections.map((section) => (
71+
<button
72+
key={section.id}
73+
onClick={() => scrollToSection(section.id)}
74+
className={`w-full text-left px-4 py-3 rounded-lg transition-colors ${
75+
activeSection === section.id
76+
? 'bg-white/10 text-white border border-white/20'
77+
: 'text-gray-300 hover:text-white hover:bg-white/5'
78+
}`}
79+
>
80+
<div className="flex items-center">
81+
{section.number && (
82+
<div className="w-8 h-8 bg-transparent border border-white/30 rounded-full flex items-center justify-center text-sm font-bold mr-3 flex-shrink-0">
83+
{section.number}
84+
</div>
85+
)}
86+
<span className="text-sm font-medium">{section.title}</span>
87+
</div>
88+
</button>
89+
))}
90+
</nav>
91+
</div>
92+
</div>
93+
)}
8694

87-
<p className="mb-6">
88-
The signup transaction will be validated by a smart contract, checking that it conforms to
89-
available regions and plans, the datum matches the expected shape, all funds are the correct amounts
90-
and going to the correct places, and other various sanity checks.
91-
</p>
95+
<div className={`flex-1 ${isMobile ? 'ml-0' : 'ml-70'}`}>
96+
<div className="max-w-4xl mx-auto px-8 py-16">
97+
<section id="overview" className="mb-16">
98+
<div className="bg-[#00000020] rounded-lg p-8 border border-[#ffffff10]">
99+
<h1 className="text-3xl font-semibold text-white mb-6">How It Works</h1>
100+
<p className="text-gray-300 text-lg leading-relaxed">
101+
Our VPN system consists of multiple components, including smart contracts, a custom chain
102+
indexer and API, a web frontend, and OpenVPN. These pieces work together to facilitate signup
103+
and management of your VPN subscription and access to the VPN tunnel in a manner that focuses
104+
on privacy.
105+
</p>
106+
</div>
107+
</section>
92108

93-
<p className="mb-6">
94-
Once the signup TX makes it into a block and on-chain, it will get picked up by our <a href="https://github.com/blinklabs-io/vpn-indexer">custom indexer</a>.
95-
The client datum will be extracted and its information written to a SQLite database. A new client TLS
96-
certificate is generated and signed by our CA certificate, and a new VPN client config built and
97-
uploaded to a private S3 bucket.
98-
</p>
109+
<section id="signup" className="mb-16">
110+
<div className="bg-[#00000020] rounded-lg p-8 border border-[#ffffff10]">
111+
<div className="flex items-center mb-6">
112+
<div className="w-12 h-12 bg-transparent border-2 border-white rounded-full flex items-center justify-center text-white font-bold text-lg mr-4">
113+
1
114+
</div>
115+
<h2 className="text-2xl font-semibold text-white">Website Signup Process</h2>
116+
</div>
117+
<p className="text-gray-300 leading-relaxed">
118+
The signup process typically starts on our website. While it's not strictly necessary to use
119+
our website to subscribe to our services, it does make things easier. Once you connect your
120+
wallet, we will query our API for any existing subscriptions, as well as for current region and
121+
plan information. Once you choose a plan and selection the option to purchase, the site will
122+
call our API with your wallet address and chosen plan information. This will build a transaction
123+
based on your wallet, which is then returned to the user to be signed by their wallet and
124+
submitted.
125+
</p>
126+
</div>
127+
</section>
99128

100-
<p className="mb-6">
101-
Once a profile has been uploaded to S3, our API will allow fetching it by validating ownership of the
102-
wallet used to do the signup. This is done by generating a challenge string (the hex-encoded client
103-
ID and the current UNIX epoch time), signing this message with your wallet, and passing it to our API.
104-
We validate the signature of the challenge message against the wallet PKH provided at signup, and
105-
respond with a pre-signed S3 URL to fetch the client config.
106-
</p>
129+
<section id="validation" className="mb-16">
130+
<div className="bg-[#00000020] rounded-lg p-8 border border-[#ffffff10]">
131+
<div className="flex items-center mb-6">
132+
<div className="w-12 h-12 bg-transparent border-2 border-white rounded-full flex items-center justify-center text-white font-bold text-lg mr-4">
133+
2
134+
</div>
135+
<h2 className="text-2xl font-semibold text-white">Smart Contract Validation</h2>
136+
</div>
137+
<p className="text-gray-300 leading-relaxed">
138+
The signup transaction will be validated by a smart contract, checking that it conforms to
139+
available regions and plans, the datum matches the expected shape, all funds are the correct amounts
140+
and going to the correct places, and other various sanity checks.
141+
</p>
142+
</div>
143+
</section>
107144

108-
<p className="mb-6">
109-
The downloaded VPN client config can be loaded into the OpenVPN client of your choice. The user's client
110-
TLS certificate will be validated against our CA certificate when authenticating to the VPN
111-
server.
112-
</p>
145+
<section id="indexer" className="mb-16">
146+
<div className="bg-[#00000020] rounded-lg p-8 border border-[#ffffff10]">
147+
<div className="flex items-center mb-6">
148+
<div className="w-12 h-12 bg-transparent border-2 border-white rounded-full flex items-center justify-center text-white font-bold text-lg mr-4">
149+
3
150+
</div>
151+
<h2 className="text-2xl font-semibold text-white">Indexer Processing</h2>
152+
</div>
153+
<p className="text-gray-300 leading-relaxed">
154+
Once the signup TX makes it into a block and on-chain, it will get picked up by our{' '}
155+
<a
156+
href="https://github.com/blinklabs-io/vpn-indexer"
157+
className="text-blue-400 hover:text-blue-300 underline"
158+
target="_blank"
159+
rel="noopener noreferrer"
160+
>
161+
custom indexer
162+
</a>.
163+
The client datum will be extracted and its information written to a SQLite database. A new client TLS
164+
certificate is generated and signed by our CA certificate, and a new VPN client config built and
165+
uploaded to a private S3 bucket.
166+
</p>
167+
</div>
168+
</section>
113169

114-
</div>
170+
<section id="authentication" className="mb-16">
171+
<div className="bg-[#00000020] rounded-lg p-8 border border-[#ffffff10]">
172+
<div className="flex items-center mb-6">
173+
<div className="w-12 h-12 bg-transparent border-2 border-white rounded-full flex items-center justify-center text-white font-bold text-lg mr-4">
174+
4
175+
</div>
176+
<h2 className="text-2xl font-semibold text-white">Profile Download Authentication</h2>
177+
</div>
178+
<p className="text-gray-300 leading-relaxed">
179+
Once a profile has been uploaded to S3, our API will allow fetching it by validating ownership of the
180+
wallet used to do the signup. This is done by generating a challenge string (the hex-encoded client
181+
ID and the current UNIX epoch time), signing this message with your wallet, and passing it to our API.
182+
We validate the signature of the challenge message against the wallet PKH provided at signup, and
183+
respond with a pre-signed S3 URL to fetch the client config.
184+
</p>
185+
</div>
186+
</section>
115187

116-
</div>
188+
<section id="setup" className="mb-16">
189+
<div className="bg-[#00000020] rounded-lg p-8 border border-[#ffffff10]">
190+
<div className="flex items-center mb-6">
191+
<div className="w-12 h-12 bg-transparent border-2 border-white rounded-full flex items-center justify-center text-white font-bold text-lg mr-4">
192+
5
193+
</div>
194+
<h2 className="text-2xl font-semibold text-white">VPN Client Setup</h2>
195+
</div>
196+
<p className="text-gray-300 leading-relaxed">
197+
The downloaded VPN client config can be loaded into the OpenVPN client of your choice. The user's client
198+
TLS certificate will be validated against our CA certificate when authenticating to the VPN
199+
server.
200+
</p>
201+
</div>
202+
</section>
117203

118-
<div className="text-center">
119-
<Link
120-
to="/"
121-
className="inline-flex items-center px-6 py-3 bg-white text-[#1C246E] font-semibold rounded-lg hover:bg-gray-100 transition-colors duration-200"
122-
>
123-
Lorem Ipsum
124-
</Link>
204+
<div className="text-center mt-16">
205+
<Link
206+
to="/"
207+
className="inline-flex items-center px-8 py-4 text-white border border-white/20 backdrop-blur-sm font-semibold rounded-xl shadow-lg hover:bg-gray-800 transition-colors"
208+
>
209+
<span className="mr-2">Back Home</span>
210+
<svg
211+
className="w-5 h-5"
212+
fill="none"
213+
stroke="currentColor"
214+
viewBox="0 0 24 24"
215+
>
216+
<path
217+
strokeLinecap="round"
218+
strokeLinejoin="round"
219+
strokeWidth={2}
220+
d="M13 7l5 5m0 0l-5 5m5-5H6"
221+
/>
222+
</svg>
223+
</Link>
224+
</div>
125225
</div>
126226
</div>
127227
</div>

0 commit comments

Comments
 (0)