Skip to content

SriramDivi1/ItsMyScreen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

39 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

⚑ ItsMyScreen

Real-time polling. Zero friction.

Create a poll in seconds β†’ Share the link β†’ Watch votes roll in live

No sign-up. No forms. Just instant feedback.

Live Demo GitHub

Next.js React Supabase Tailwind TypeScript


πŸ“– Overview

ItsMyScreen is a full-stack real-time polling application. Users create polls with questions and options, share a link, and anyone with the link can vote. Results update live for all viewersβ€”no refresh needed.

Built as a modern, production-ready demo of Next.js 16, Supabase, and Tailwind CSS.

Create Share Vote Results
Question + 2–10 options in under 10 seconds One-click copy link or QR code Anyone with the link can vote (single-choice) Live updates for everyone via Realtime + polling

✨ Features (Detailed)

πŸ“ Poll Creation

Feature Details
Question & options Question (max 200 chars), optional description (300 chars), 2–10 options (100 chars each)
6 templates Yes/No, 1–5 Scale, Simple Choice, Feedback, Meeting Time, Topic Vote
Live preview See your poll as you type, with sticky sidebar on desktop
Validation Duplicate option detection, character counters, required fields
URL templates /create?template=yes-no pre-fills the form

πŸ—³οΈ Voting & Results

Feature Details
Single-choice One vote per person per poll
Change vote Switch your choice before the poll ends
Real-time sync Supabase Realtime subscriptions + payload-based updates (no full refetch)
Polling fallback 5-second polling when Realtime doesn’t deliver
Optimistic UI Instant feedback when you vote; state updates before server response
Animated bars Progress bars and percentages animate when votes change

πŸ”— Sharing & Export

Feature Details
Copy link One-click copy with clipboard API + execCommand fallback
QR code Generate scannable QR for in-person voting
CSV export Download results (Option, Votes, Percentage)
Print Print-friendly layout; hides nav, footer, non-essential UI

πŸ” Discovery

Feature Details
Browse Search by question, sort by most recent or most votes
Quick-create Template buttons on Browse page β†’ jump to Create with form pre-filled
Recent polls Home page shows 6 most recent community polls

🎨 UX & Design

Feature Details
Theme Light, warm off-white with orange accent (#c2410c)
Typography DM Sans
Confetti CSS confetti on first vote
Toasts Non-intrusive feedback for actions (vote, copy, errors)
Live badge Pulsing green dot for real-time connection
Loading Skeleton loaders (home, browse, poll), spinners
Animations Staggered fade-in, scale-in, smooth transitions
Responsive Mobile-first; safe-area support for notched devices
Error states Poll not found, 404, error boundary with retry

πŸ› οΈ Tech Stack (Detailed)

Layer Technology Notes
Framework Next.js 16.1.6 App Router, Turbopack, React 19
Language TypeScript 5 Strict mode
Styling Tailwind CSS 4 Custom theme, animations
Backend Supabase PostgreSQL, Realtime, RLS
Icons Lucide React
QR qrcode.react
Deployment Vercel Edge, serverless

πŸ—„οΈ Database

Tables

Table Purpose
polls id (UUID), question, description, created_at, created_by
options id, poll_id (FK), text, vote_count
votes id, poll_id, option_id, voter_token, created_at; unique on (poll_id, voter_token)

RPC Functions

  • vote(p_poll_id, p_option_id, p_voter_token) β€” Inserts vote, increments option vote_count. Validates option belongs to poll.
  • change_vote(p_poll_id, p_old_option_id, p_new_option_id, p_voter_token) β€” Deletes old vote, inserts new one; updates both option counts.

Realtime

Tables polls, options, votes are in supabase_realtime publication.

Row Level Security (RLS)

All tables have RLS enabled. Policies allow anonymous select/insert; delete on polls restricted to created_by.


πŸ“ Project Structure

ItsMyScreen/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”œβ”€β”€ Confetti.tsx       # CSS confetti on vote
β”‚   β”‚   β”œβ”€β”€ Footer.tsx         # Branded footer
β”‚   β”‚   └── Navbar.tsx         # Minimal navbar (logo)
β”‚   β”œβ”€β”€ create/
β”‚   β”‚   └── page.tsx           # Poll creation + templates + live preview
β”‚   β”œβ”€β”€ poll/
β”‚   β”‚   └── [id]/
β”‚   β”‚       β”œβ”€β”€ layout.tsx     # Metadata
β”‚   β”‚       β”œβ”€β”€ loading.tsx    # Skeleton loading
β”‚   β”‚       β”œβ”€β”€ opengraph-image.tsx  # Dynamic OG image for sharing
β”‚   β”‚       └── page.tsx       # Vote, results, share, QR, CSV, print
β”‚   β”œβ”€β”€ polls/
β”‚   β”‚   └── page.tsx           # Browse, search, sort, quick-create
β”‚   β”œβ”€β”€ globals.css            # Theme, components, keyframes
β”‚   β”œβ”€β”€ layout.tsx             # Root layout, viewport, metadata
β”‚   β”œβ”€β”€ page.tsx               # Home: hero, features, how it works, recent polls
β”‚   β”œβ”€β”€ not-found.tsx          # 404 page
β”‚   β”œβ”€β”€ error.tsx              # Error boundary
β”‚   └── global-error.tsx       # Root error boundary
β”œβ”€β”€ utils/
β”‚   β”œβ”€β”€ pollTemplates.ts       # 6 templates + getTemplateById
β”‚   β”œβ”€β”€ sanitize.ts            # sanitizeText (trim + length limit)
β”‚   β”œβ”€β”€ supabase.ts            # Supabase client
β”‚   └── timeAgo.ts             # Relative time ("5m ago")
β”œβ”€β”€ supabase/
β”‚   β”œβ”€β”€ schema.sql             # Base schema
β”‚   └── migrations/            # Incremental migrations
β”œβ”€β”€ scripts/
β”‚   └── apply-schema.js        # Apply schema to Supabase (optional)
└── .env.local                 # NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY

πŸ”„ User Flow

  1. Create β€” User goes to /create, picks a template or writes from scratch, adds options, clicks Create.
  2. Redirect β€” App creates poll + options in DB, redirects to /poll/[id].
  3. Share β€” User copies link or shows QR code.
  4. Vote β€” Visitors open link, vote (single choice), can change vote.
  5. Results β€” All viewers see live updates via Realtime; 5s polling as fallback.

πŸš€ Getting Started

Prerequisites

  • Node.js 18+
  • Supabase account (free tier)

1. Clone & install

git clone https://github.com/SriramDivi1/ItsMyScreen.git
cd ItsMyScreen
npm install

2. Supabase setup

  1. Create a project at supabase.com.
  2. Apply schema:
    • Option A: Run npm run db:sql, copy output, paste into Supabase β†’ SQL Editor, run.
    • Option B: SUPABASE_PROJECT_REF=xxx SUPABASE_DB_PASSWORD=xxx npm run db:apply
  3. Copy Project URL and Anon Key from Settings β†’ API.

3. Environment variables

Create .env.local:

NEXT_PUBLIC_SUPABASE_URL=your_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key

4. Run

npm run dev

Open http://localhost:3000.


πŸ“„ Routes

Route Description
/ Home β€” hero, features, how it works, 6 recent polls
/create Create poll; ?template=id pre-fills form
/polls Browse β€” search, sort, quick-create templates
/poll/[id] Poll view β€” vote, results, share, QR, CSV, print

🌐 Deployment (Vercel)

  1. Push to GitHub.
  2. Import repo at vercel.com.
  3. Add env vars: NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY.
  4. Deploy.
npm run build   # Test locally

πŸ“‹ Scripts

Script Description
npm run dev Start dev server
npm run build Production build
npm run start Start production server
npm run db:sql Print schema + migrations for SQL Editor
npm run db:apply Apply schema via pg (needs DB credentials)

Two fairness / anti-abuse mechanisms

1. Voter token (one vote per device)

  • What it does: Each browser gets a unique token (crypto.randomUUID) in localStorage. DB enforces unique(poll_id, voter_token).
  • What it prevents: Same user voting multiple times from the same browser on the same poll.
  • Limitations: Clearing storage, incognito, or another device/browser = new token = another vote. Acceptable for no-sign-up.

2. Vote cooldown (2 seconds)

  • What it does: 2s cooldown between vote attempts (including vote changes). Blocked attempts show a toast.
  • What it prevents: Double-clicks, rapid automated clicking, simple bot abuse.
  • Limitations: Determined attackers can space out votes; cooldown improves UX and slows basic abuse.

Additional: RPCs vote and change_vote validate that the option belongs to the poll before counting.


Edge cases handled

  • Invalid poll ID β†’ "Poll not found" + link home
  • Duplicate options β†’ Client validation + highlight
  • Option validation β†’ RPC rejects invalid options
  • Clipboard fallback β†’ execCommand('copy') if navigator.clipboard unavailable
  • Voter token fallback β†’ Session token if localStorage fails
  • Realtime fallback β†’ 5s polling
  • Input limits β†’ 200 / 300 / 100 chars; sanitized before DB
  • Invalid dates β†’ timeAgo returns empty string
  • Empty options β†’ Fallback message
  • Orphan voted option β†’ "You voted for" only when option exists

Known limitations / improvements

  • No poll expiry or closure
  • Device-based token (multiple devices = multiple votes)
  • No auth β†’ no poll ownership
  • No API rate limiting
  • Future: Poll expiry, CAPTCHA, optional sign-in, email verification

β–Ά Live Demo Β· πŸ“¦ GitHub

Built with ❀️ By Sriram using Next.js & Supabase

About

A real-time, futuristic polling application built with Next.js 16, Supabase, and Tailwind CSS. Create instant polls, vote anonymously, and watch live results.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors