Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions app/components/CheckboxInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"use client"
import styled from "styled-components"
import { forwardRef } from "react"

// Types //

type BaseCheckboxProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "type">

interface CheckboxInputProps extends BaseCheckboxProps {
variant?: "primary" | "secondary"
size?: "small" | "default"
}

// Components //

export const CheckboxInput = forwardRef<HTMLInputElement, CheckboxInputProps>(
({ variant = "secondary", size = "default", ...props }, ref) => {
return <StyledCheckbox ref={ref} $variant={variant} $size={size} {...props} />
}
)

CheckboxInput.displayName = "CheckboxInput"

// Styled Components //

const StyledCheckbox = styled.input.attrs({ type: "checkbox" })<{
$variant: "primary" | "secondary"
$size: "small" | "default"
}>`
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
width: ${(props) => (props.$size === "small" ? "1rem" : "1.25rem")};
height: ${(props) => (props.$size === "small" ? "1rem" : "1.25rem")};
border: 2px solid
${(props) =>
props.$variant === "secondary" ? "rgba(255, 255, 255, 0.3)" : "rgba(0, 0, 0, 0.3)"};
border-radius: 0.25rem;
background-color: transparent;
cursor: pointer;
position: relative;
transition: all 0.2s ease;
margin: 0;
flex-shrink: 0;

&:hover {
border-color: ${(props) =>
props.$variant === "secondary" ? "rgba(255, 255, 255, 0.5)" : "rgba(0, 0, 0, 0.5)"};
}

&:checked {
border-color: ${(props) =>
props.$variant === "secondary" ? "rgba(156, 163, 255, 0.9)" : "rgba(0, 0, 0, 0.7)"};
background-color: ${(props) =>
props.$variant === "secondary" ? "rgba(156, 163, 255, 0.9)" : "rgba(0, 0, 0, 0.7)"};
}

&:checked::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(45deg);
width: ${(props) => (props.$size === "small" ? "0.25rem" : "0.375rem")};
height: ${(props) => (props.$size === "small" ? "0.5rem" : "0.625rem")};
border: solid white;
border-width: 0 2px 2px 0;
}

&:focus {
outline: 2px solid
${(props) =>
props.$variant === "secondary" ? "rgba(156, 163, 255, 0.5)" : "rgba(0, 0, 0, 0.3)"};
outline-offset: 2px;
}

&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
`
95 changes: 95 additions & 0 deletions app/components/Modal.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should not have the modal (remove it). My main concern is about the check-in friction. I want to remove the friction and instead go with a clean disclaimer on the page.

Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"use client"
import { useEffect } from "react"
import { createPortal } from "react-dom"
import styled from "styled-components"

// Types //

interface ModalProps {
isOpen: boolean
onClose: () => void
children: React.ReactNode
}

// Components //

export const Modal = ({ isOpen, onClose, children }: ModalProps) => {
useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === "Escape") {
onClose()
}
}

if (isOpen) {
document.addEventListener("keydown", handleEscape)
document.body.style.overflow = "hidden"
}

return () => {
document.removeEventListener("keydown", handleEscape)
document.body.style.overflow = "unset"
}
}, [isOpen, onClose])

if (!isOpen) return null

if (typeof document === "undefined") return null

return createPortal(
<Backdrop onClick={onClose}>
<ModalContent onClick={(e) => e.stopPropagation()}>
<CloseButton onClick={onClose} aria-label="Close modal">
</CloseButton>
{children}
</ModalContent>
</Backdrop>,
document.body
)
}

// Styled Components //

const Backdrop = styled.div`
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 1rem;
`

const ModalContent = styled.div`
background-color: rgba(20, 20, 20, 0.95);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 0.5rem;
padding: 2rem;
max-width: 500px;
width: 100%;
position: relative;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
`

const CloseButton = styled.button`
position: absolute;
top: 1rem;
right: 1rem;
background: transparent;
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
padding: 0.25rem;
line-height: 1;
transition: opacity 0.2s ease;

&:hover {
opacity: 0.7;
}
`
48 changes: 30 additions & 18 deletions app/doorbell/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useState, useEffect, useRef, useCallback, useMemo } from "react"
import type { RealtimeChannel } from "@supabase/supabase-js"
import styled from "styled-components"
import { motion } from "framer-motion"
import Link from "next/link"
import { PotionBackground } from "../components/PotionBackground"
import { ErrorBoundary } from "../components/ErrorBoundary"
import { Button } from "../components/Button"
Expand Down Expand Up @@ -66,6 +67,12 @@ export default function Doorbell() {
setRingCount((prev) => prev + 1)
}

const handleCheckin = () => {
if (nearestEvent?.url) {
window.open(nearestEvent.url, "_blank")
}
}

useEffect(() => {
const client = supabaseClient
if (!client) {
Expand Down Expand Up @@ -117,20 +124,18 @@ export default function Doorbell() {
<Heading>Welcome to</Heading>
<Logo src="/images/sd-devx-brand.png" alt="DEVxSD" />
</HeadingSection>
<ParagraphSection>
<Paragraph>Ring the doorbell to enter the event.</Paragraph>
</ParagraphSection>
{nearestEvent && (
<ButtonSection>
<Button
href={nearestEvent.url}
variant="primary"
size="default"
target="_blank"
rel="noopener noreferrer"
>
Get Your Ticket
<Button variant="primary" size="default" onClick={handleCheckin}>
Check In
</Button>
<TermsMessage>
By checking in I agree to the{" "}
<TermsLink href="/event-terms" target="_blank" rel="noopener noreferrer">
event terms and conditions
</TermsLink>
.
</TermsMessage>
</ButtonSection>
)}
<DoorbellSection>
Expand Down Expand Up @@ -228,15 +233,12 @@ const Logo = styled.img`
margin: 0 auto;
`

const ParagraphSection = styled.section`
padding: 0 3rem;
`

const Paragraph = styled.p`
font-size: 1.25rem;
const TermsMessage = styled.p`
font-size: 1rem;
text-align: center;
max-width: 1024px;
max-width: 420px;
margin: 0;
color: rgba(255, 255, 255, 0.7);
`

const ButtonSection = styled.section`
Expand Down Expand Up @@ -288,6 +290,16 @@ const CallMessage = styled.p`
color: white;
`

const TermsLink = styled(Link)`
color: white;
text-decoration: underline;
transition: opacity 0.2s ease;

&:hover {
opacity: 0.7;
}
`

// Constants //

type RingPayload = {
Expand Down
Loading