Skip to content

Commit cc395d7

Browse files
authored
Merge pull request #72 from DEVxNetwork/aj/add-event-terms
Add event terms
2 parents 820237b + 62a245a commit cc395d7

5 files changed

Lines changed: 525 additions & 17 deletions

File tree

app/components/CheckboxInput.tsx

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
"use client"
2+
import styled from "styled-components"
3+
import { forwardRef } from "react"
4+
5+
// Types //
6+
7+
type BaseCheckboxProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "type">
8+
9+
interface CheckboxInputProps extends BaseCheckboxProps {
10+
variant?: "primary" | "secondary"
11+
size?: "small" | "default"
12+
}
13+
14+
// Components //
15+
16+
export const CheckboxInput = forwardRef<HTMLInputElement, CheckboxInputProps>(
17+
({ variant = "secondary", size = "default", ...props }, ref) => {
18+
return <StyledCheckbox ref={ref} $variant={variant} $size={size} {...props} />
19+
}
20+
)
21+
22+
CheckboxInput.displayName = "CheckboxInput"
23+
24+
// Styled Components //
25+
26+
const StyledCheckbox = styled.input.attrs({ type: "checkbox" })<{
27+
$variant: "primary" | "secondary"
28+
$size: "small" | "default"
29+
}>`
30+
appearance: none;
31+
-webkit-appearance: none;
32+
-moz-appearance: none;
33+
width: ${(props) => (props.$size === "small" ? "1rem" : "1.25rem")};
34+
height: ${(props) => (props.$size === "small" ? "1rem" : "1.25rem")};
35+
border: 2px solid
36+
${(props) =>
37+
props.$variant === "secondary" ? "rgba(255, 255, 255, 0.3)" : "rgba(0, 0, 0, 0.3)"};
38+
border-radius: 0.25rem;
39+
background-color: transparent;
40+
cursor: pointer;
41+
position: relative;
42+
transition: all 0.2s ease;
43+
margin: 0;
44+
flex-shrink: 0;
45+
46+
&:hover {
47+
border-color: ${(props) =>
48+
props.$variant === "secondary" ? "rgba(255, 255, 255, 0.5)" : "rgba(0, 0, 0, 0.5)"};
49+
}
50+
51+
&:checked {
52+
border-color: ${(props) =>
53+
props.$variant === "secondary" ? "rgba(156, 163, 255, 0.9)" : "rgba(0, 0, 0, 0.7)"};
54+
background-color: ${(props) =>
55+
props.$variant === "secondary" ? "rgba(156, 163, 255, 0.9)" : "rgba(0, 0, 0, 0.7)"};
56+
}
57+
58+
&:checked::after {
59+
content: "";
60+
position: absolute;
61+
top: 50%;
62+
left: 50%;
63+
transform: translate(-50%, -50%) rotate(45deg);
64+
width: ${(props) => (props.$size === "small" ? "0.25rem" : "0.375rem")};
65+
height: ${(props) => (props.$size === "small" ? "0.5rem" : "0.625rem")};
66+
border: solid white;
67+
border-width: 0 2px 2px 0;
68+
}
69+
70+
&:focus {
71+
outline: 2px solid
72+
${(props) =>
73+
props.$variant === "secondary" ? "rgba(156, 163, 255, 0.5)" : "rgba(0, 0, 0, 0.3)"};
74+
outline-offset: 2px;
75+
}
76+
77+
&:disabled {
78+
opacity: 0.5;
79+
cursor: not-allowed;
80+
}
81+
`

app/components/Modal.tsx

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
"use client"
2+
import { useEffect } from "react"
3+
import { createPortal } from "react-dom"
4+
import styled from "styled-components"
5+
6+
// Types //
7+
8+
interface ModalProps {
9+
isOpen: boolean
10+
onClose: () => void
11+
children: React.ReactNode
12+
}
13+
14+
// Components //
15+
16+
export const Modal = ({ isOpen, onClose, children }: ModalProps) => {
17+
useEffect(() => {
18+
const handleEscape = (e: KeyboardEvent) => {
19+
if (e.key === "Escape") {
20+
onClose()
21+
}
22+
}
23+
24+
if (isOpen) {
25+
document.addEventListener("keydown", handleEscape)
26+
document.body.style.overflow = "hidden"
27+
}
28+
29+
return () => {
30+
document.removeEventListener("keydown", handleEscape)
31+
document.body.style.overflow = "unset"
32+
}
33+
}, [isOpen, onClose])
34+
35+
if (!isOpen) return null
36+
37+
if (typeof document === "undefined") return null
38+
39+
return createPortal(
40+
<Backdrop onClick={onClose}>
41+
<ModalContent onClick={(e) => e.stopPropagation()}>
42+
<CloseButton onClick={onClose} aria-label="Close modal">
43+
44+
</CloseButton>
45+
{children}
46+
</ModalContent>
47+
</Backdrop>,
48+
document.body
49+
)
50+
}
51+
52+
// Styled Components //
53+
54+
const Backdrop = styled.div`
55+
position: fixed;
56+
top: 0;
57+
left: 0;
58+
width: 100vw;
59+
height: 100vh;
60+
background-color: rgba(0, 0, 0, 0.8);
61+
display: flex;
62+
align-items: center;
63+
justify-content: center;
64+
z-index: 1000;
65+
padding: 1rem;
66+
`
67+
68+
const ModalContent = styled.div`
69+
background-color: rgba(20, 20, 20, 0.95);
70+
border: 1px solid rgba(255, 255, 255, 0.2);
71+
border-radius: 0.5rem;
72+
padding: 2rem;
73+
max-width: 500px;
74+
width: 100%;
75+
position: relative;
76+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
77+
`
78+
79+
const CloseButton = styled.button`
80+
position: absolute;
81+
top: 1rem;
82+
right: 1rem;
83+
background: transparent;
84+
border: none;
85+
color: white;
86+
font-size: 1.5rem;
87+
cursor: pointer;
88+
padding: 0.25rem;
89+
line-height: 1;
90+
transition: opacity 0.2s ease;
91+
92+
&:hover {
93+
opacity: 0.7;
94+
}
95+
`

app/doorbell/page.tsx

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useState, useEffect, useRef, useCallback, useMemo } from "react"
33
import type { RealtimeChannel } from "@supabase/supabase-js"
44
import styled from "styled-components"
55
import { motion } from "framer-motion"
6+
import Link from "next/link"
67
import { PotionBackground } from "../components/PotionBackground"
78
import { ErrorBoundary } from "../components/ErrorBoundary"
89
import { Button } from "../components/Button"
@@ -66,6 +67,12 @@ export default function Doorbell() {
6667
setRingCount((prev) => prev + 1)
6768
}
6869

70+
const handleCheckin = () => {
71+
if (nearestEvent?.url) {
72+
window.open(nearestEvent.url, "_blank")
73+
}
74+
}
75+
6976
useEffect(() => {
7077
const client = supabaseClient
7178
if (!client) {
@@ -117,19 +124,19 @@ export default function Doorbell() {
117124
<Heading>Welcome to</Heading>
118125
<Logo src="/images/sd-devx-brand.png" alt="DEVxSD" />
119126
</HeadingSection>
120-
<ParagraphSection>
121-
<Paragraph>Ring the doorbell to enter the event.</Paragraph>
122-
</ParagraphSection>
127+
<TermsSection>
128+
<TermsMessage>
129+
By attending the event, you agree to the event’s{" "}
130+
<TermsLink href="/event-terms" target="_blank" rel="noopener noreferrer">
131+
Terms of Service
132+
</TermsLink>
133+
.
134+
</TermsMessage>
135+
</TermsSection>
123136
{nearestEvent && (
124137
<ButtonSection>
125-
<Button
126-
href={nearestEvent.url}
127-
variant="primary"
128-
size="default"
129-
target="_blank"
130-
rel="noopener noreferrer"
131-
>
132-
Get Your Ticket
138+
<Button variant="primary" size="default" onClick={handleCheckin}>
139+
Check In
133140
</Button>
134141
</ButtonSection>
135142
)}
@@ -203,7 +210,7 @@ const Hero = styled.section`
203210
flex-direction: column;
204211
align-items: center;
205212
justify-content: center;
206-
gap: 3rem;
213+
gap: 2rem;
207214
`
208215

209216
const HeadingSection = styled.section`
@@ -228,15 +235,21 @@ const Logo = styled.img`
228235
margin: 0 auto;
229236
`
230237

231-
const ParagraphSection = styled.section`
238+
const TermsSection = styled.section`
239+
display: flex;
240+
flex-direction: column;
241+
align-items: center;
242+
justify-content: center;
243+
gap: 1rem;
232244
padding: 0 3rem;
233245
`
234246

235-
const Paragraph = styled.p`
236-
font-size: 1.25rem;
247+
const TermsMessage = styled.p`
248+
font-size: 1rem;
237249
text-align: center;
238-
max-width: 1024px;
250+
max-width: 420px;
239251
margin: 0;
252+
color: rgba(255, 255, 255, 0.7);
240253
`
241254

242255
const ButtonSection = styled.section`
@@ -278,7 +291,6 @@ const CallSection = styled.section`
278291
justify-content: center;
279292
gap: 1rem;
280293
padding: 0 3rem;
281-
margin-top: 2rem;
282294
`
283295

284296
const CallMessage = styled.p`
@@ -288,6 +300,16 @@ const CallMessage = styled.p`
288300
color: white;
289301
`
290302

303+
const TermsLink = styled(Link)`
304+
color: white;
305+
text-decoration: underline;
306+
transition: opacity 0.2s ease;
307+
308+
&:hover {
309+
opacity: 0.7;
310+
}
311+
`
312+
291313
// Constants //
292314

293315
type RingPayload = {

0 commit comments

Comments
 (0)