Skip to content

Implement Pejla poll creation, voting, and explore features#152

Open
daniellauding wants to merge 66 commits intoTechnigo:mainfrom
daniellauding:main
Open

Implement Pejla poll creation, voting, and explore features#152
daniellauding wants to merge 66 commits intoTechnigo:mainfrom
daniellauding:main

Conversation

@daniellauding
Copy link
Copy Markdown

@daniellauding daniellauding commented Mar 8, 2026

Summary

  • Full poll CRUD with anonymous voting, password protection, and visibility controls (public/unlisted/private)
  • File uploads via Cloudinary with progress tracking, embed support (YouTube, Vimeo, Spotify, etc.), and text file rendering
  • Remix system with parent-child linking, explore page, markdown comments, and notification system
  • Frontend: React + Tailwind v4 + shadcn/ui with PWA support, custom cursors, and Storybook components

Highlights

  • 14 REST endpoints for poll management
  • Cloudinary middleware auto-routes by file type, skips resize for SVG/GIF
  • Anonymous voting via localStorage fingerprint
  • Paste-anywhere UX with smart target detection
  • Hero with animated Figma-style cursors

Test plan

  • Create, edit, delete polls
  • Upload images/videos and verify Cloudinary delivery
  • Vote anonymously and with auth
  • Test embed URLs (YouTube, Vimeo, CodePen)
  • Verify public/unlisted/private visibility
  • Test remix flow and parent-child linking
  • Check mobile responsiveness and accessibility

Front end: https://pejla.io/
Back End: https://project-final-msof.onrender.com/

daniellauding and others added 30 commits February 24, 2026 09:35
- VotePoll: fullscreen embed with edge controls, no overlays blocking content
- VotePoll: slide-up panels for results, comments, remixes, report
- VotePoll: change vote, password protection, deep link login
- Dashboard: thumbnails, visibility icons, better cards
- EditPoll: add/remove unlimited options, visibility, password, remix toggle
- CreatePoll: unlimited options, remix pre-fill support
- Profile page: stats, contributions list, avatar, delete account
- Home: public poll feed with thumbnails
- Header: profile link instead of plain logout
- Backend: unvote, change vote, avatar upload, password protection
- Backend: Team model with roles (admin/editor/viewer) + invite codes
- Backend: Project model linked to teams and polls
- Backend: team CRUD, join, invite, remove member endpoints
- Remixes hidden from main feed, shown as tree on original poll

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Figma blocks direct iframe embedding via CSP. Added toEmbedUrl() utility
that converts Figma, YouTube, Loom, CodePen URLs to their embed format.
Also removed max 4 option limit — now unlimited.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Poll model: added "closed" status, showWinner toggle
- Backend: blocks votes when poll closed or deadline passed
- Backend: PATCH accepts showWinner, deadline fields
- EditPoll: settings panel with open/close toggle, deadline picker,
  show winner toggle, allow remix toggle
- VotePoll: shows "Stängd" label, grayed out vote button when closed
- VotePoll: hides winner crown when showWinner is false

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Support video, audio, and camera capture in upload (Create + Edit)
- Render video/audio players in VotePoll
- Add allowAnonymousVotes setting (toggle on Create + Edit)
- Anonymous vote endpoint with fingerprint-based dedup
- Comments and remix still require login

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Zustand pollStore for global poll state (Home + Dashboard)
- Add useDebounce and useMediaQuery custom hooks
- Embed URL: return null for non-embeddable domains, show "open in
  new tab" fallback instead of broken iframe
- Write comprehensive README with API docs, tech stack, hooks list

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- embedUrl: 15 tests (Figma, YouTube, Vimeo, CodePen, fallback)
- useDebounce: 4 tests (initial value, delay, timer reset)
- useMediaQuery: 4 tests (initial, match, change, cleanup)
- pollStore: 5 tests (fetch, error, delete, reset)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- lang="sv", meta description, proper title
- Skip-to-content link, <main> landmark
- aria-label on all icon-only buttons
- focus-visible rings on custom buttons
- Touch targets increased to 44px+
- role="tablist" + aria-selected on carousel dots
- Label on comment input
- Alt text on Profile thumbnails
- Add 10-slide HTML presentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove all shadows from UI components (input, textarea, dropdown, tabs, card, button, dialog)
- Remove all console.error statements from frontend pages and components
- Remove JSDoc comment from useDebounce hook
- Use Zustand store in Home and Dashboard pages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix production build (inline @font-face, remove broken CSS @imports)
- Add accessibility: aria-labels, role=dialog, Escape handlers, prefers-reduced-motion
- Replace all empty catch blocks with user-facing toast errors
- Remove dead code (ThemeToggle, Comments component)
- Unified header with single hamburger menu across all pages
- Profile editing (username, avatar upload) with overlay modal
- Home intro animation plays once per session
- Custom fonts (Apercu, Exposure Trial) bundled in public/
- Clean up boilerplate assets and old dist/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix skipped heading level (h4 → h3 in poll cards)
- Remove redundant alt text on poll thumbnails (title shown as text)
- Add ::selection color using primary brand color
- Add prefers-reduced-motion already in place

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Apply Exposure Trial font to primary & secondary buttons
- Increase all button sizes to meet 48px touch target minimum
- Add robots.txt for SEO crawling
- Selection color already in place from previous commit

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Step 1: two cards alternating with tilt animation
- Step 2: animated voting bars that fill on scroll
- Step 3: animated checkmark circle that draws on scroll
- Move recent polls above How it works section
- CTA: "Create a poll" with subtle "How it works" link below
- Primary color → soft lavender (oklch 0.72 0.11 270)
- ::selection matches the new primary
- Button font sizes bumped (sm→14px, default→15px, lg→16px)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- All buttons → rounded-full (pill shape)
- Primary: white text, inner highlight, soft shadow, hover glow
- Outline/secondary: subtle shadow + lift on hover
- Active press: scale(0.97) for tactile feel
- Hero CTA bumped to h-14 text-lg
- Removed black primary-foreground, now pure white

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add cursor-pointer to all button variants
- Bump horizontal padding (default px-6, sm px-5, lg px-8)
- Hero CTA → px-10 for extra breathing room

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- "Start for free" → "Get feedback for free"
- "Create a poll" → "Share your work"
- "Create your first poll" → "Share your first design"
- Supporting text now speaks to feedback, not polls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Results bars now use bg-primary (not bg-foreground/20)
- First place: full opacity, second: 60%, rest: 30%
- Bars slightly thicker (h-0.5 → h-1) for readability
- Matches landing page VotingBars illustration style

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend POST /polls now saves visibility, password, showWinner,
deadline, and allowRemix. Frontend hides winner highlight when
showWinner is off. Visibility filtering for private/unlisted
was already fixed in a prior edit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add XHR-based uploadWithProgress with cancel support to polls API
- Show progress bar + cancel button during file uploads (CreatePoll + EditPoll)
- Better file previews: extension badges, audio icon, richer layout
- Reorder create steps: Options first, Question second (auto-fills title)
- Make stepper sticky on mobile so it stays visible
- Favicon now matches logo.svg, added apple-touch-icon + web manifest for PWA
- Show visibility/password badges on poll view for owner

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add TextFilePreview component: fetches raw content from Cloudinary URL
- .md files rendered with react-markdown (prose styling)
- .txt/.csv files rendered as preformatted text
- Applied in VotePoll (full-screen preview), CreatePoll, and EditPoll

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SVGs don't need raster resizing; GIFs lose animation with crop transform.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Six cursors in pastel colors (pink, blue, green, lavender, yellow, red)
float gently and pulse with a staggered click effect — visual metaphor
for voting/clicking. Positioned behind hero content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ions

- Add pt-20 to logged-in dashboard so content isn't behind sticky header
- Filter unlisted/private polls from landing page "Recent polls"
- Add visibility + password badges on dashboard poll cards
- Replace 6 static cursors with 3 Figma-live-style cursors that move
  across the hero with name labels, click ripples, and smooth paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…hots

- Hero CTA buttons now stack vertically on mobile (flex-col sm:flex-row)
- Step 1 (Share) and Step 2 (Vote) use real app screenshots with srcSet
  for 1x/2x retina support
- Portrait 3:4 images (960x1280 / 1920x2560)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CardStack now shows 01.png and 02.png as the two switching cards
with tilt + fade animation. VotingBars stays as animated bars.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
daniellauding and others added 29 commits March 6, 2026 12:07
Previously errors were silently swallowed when data.success was false.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Share button now copies link with ?option= for current slide.
Opening /poll/abc?option=2 jumps directly to Option 2.
Also redesigns Recent Polls section as horizontal scroll cards.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Hero poll card slides off-screen right as user scrolls (parallax)
- Recent polls section: focus carousel with center card enlarged,
  side cards smaller/dimmed, ← → navigation
- Click ripple effect (pink/blue/green) on entire landing page
- Slide animation on hero poll card ← → navigation
- CTA "Your turn" card after cycling through polls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- textContent field: create/edit/save inline .md/.txt/.csv without upload
- coverUrl field: upload cover images for audio, video, text, PDF options
- Cover upload with XHR progress bar and cancel support
- "Write text" button in create + edit flows
- /poll/:shareId/option/:n URL routing with replaceState sync
- Audio/video pause on slide change
- Paper-style markdown rendering with @tailwindcss/typography
- Edit panel: narrower (max-w-md) with transparent backdrop
- Dashboard + Home: text preview thumbnails, cover priority, option labels
- Fix: textContent/coverUrl included in API response and remix endpoint
- Fix: "View all" link → /dashboard
- Add docs/ Obsidian vault and demo-content/ .md briefs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Notification model: vote/comment/remix/mention types
- 4 API endpoints: GET list, GET unread-count, PATCH read-all, PATCH :id/read
- Auto-create notifications on vote, comment, and remix (skip if self)
- NotificationBell component in header: unread badge, dropdown, auto-poll every 30s
- Landing copy: broader tagline including briefs and tracks
- Added "Project briefs" to rotating words sequence

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New: Slack Integration (webhook MVP, full app Phase 2, OAuth2, unfurling)
- New: AI Integration (vote summary MVP, brief generator, smart tagging)
- Updated: Figma Plugin, Browser Extension, Beta Launch, Notifications

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix NotificationBell parsing (data.notifications instead of raw data)
- Fix backend to populate poll shareId/title in notification responses
- Fix CreatePoll hooks ordering crash (moved refs before early returns)
- Custom cursor now applies everywhere (text selection, clicking)
- Apple-style subtle scrollbar across platform
- Add Roadmap.md and update Features.md with shipped status
- Update remix API type signature

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move hooks before early return in Profile.tsx (fixes "fewer hooks" crash)
- Guard NotificationBell fetches with token check (prevents 401 after logout)
- Logout now navigates to landing page instead of goBack()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Backend: "Something went wrong — please try again" instead of "Could not vote"
- Frontend: network errors show "Could not connect" instead of raw error
- Specific errors (poll closed, deadline passed) still shown as-is

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove "poll" wording from dashboard (decisions, contributions)
- Empty state: "Nothing here yet" + broader format messaging
- Vote errors include contact email (hello@pejla.io)
- Network errors show helpful reconnect message
- Add missing fields to PollOption store type (coverUrl, textContent, etc.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Default cursor on all elements (no !important)
- Pointer cursor on a, button, input, select, [role=button], etc.
- Separate light/dark rules for both default and pointer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add pt-20 to dashboard for fixed header clearance
- NotificationBell silently ignores 401 responses (stale token)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add text/audio/embed/title fallback thumbnails on welcome feed (was "3 opt.")
- Fix anonymous voting: change votes schema from ObjectId to String
  (ObjectIds serialize to strings anyway, but anon fingerprints need String)
- Update welcome copy: remove "poll" wording

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Sequence words: added "Code reviews," replaced "Project briefs,"
- Hero: "Share anything — designs, code, music, docs — and let your team vote on what ships."
- CTA: "Share something" instead of "Share your designs"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Anonymous votes now create "Someone voted on your poll" notification
- Poll creator gets notified regardless of auth vs anon vote

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Comment input: textarea with multi-line, code block support (Cmd+Enter to send)
- Comments render as markdown with monochrome code styling
- Notifications: unread dot, bold text, left border accent
- Landing copy: "people" instead of "team"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Comments: textarea input, markdown + code block rendering (monochrome)
- Remix: banner on create page explaining the flow
- Remix: "Remix of [title] by [creator]" pill on vote page (links to original)
- Info panel: shows remix origin + list of remixes with links
- Backend: returns remixedFromData (shareId, title, creatorName)
- Home cards: show Remix badge for remixed polls
- Notifications: unread dot + bold + left accent border
- Copy: "people" instead of "team"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New /explore route: public gallery of all polls with smart thumbnails
- Recent designs cards show Remix badge
- "View all" links to /explore instead of /dashboard
- Header menu: added Explore link with compass icon
- Dashboard = your stuff, Explore = everyone's stuff

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- "Recent designs" → "Recent"
- "Share your designs" → "Share something"
- "Get your first design feedback" → "Get your first feedback"
- "Share your first design" → "Get started"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Close poll creation and uploads after March 31 2026 (beta deadline)
- Registration and login remain open to collect emails
- Add beta status banner on landing page and empty states
- Add PostHog tracking for pageviews, auth, voting, sharing, comments
- Add poll-level thumbnail/cover image (EditPoll upload, card priority)
- Fix OG meta tags with absolute URL and proper PNG image
- Update meta description and page title

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add thumbnailUrl to Poll interface in store
- Pass thumbnailUrl to LoopingThumbnail component
- LoopingThumbnail renders poll thumbnail as full-cover image when set

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix totalVotes not showing on cards (enrich GET /polls response)
- Use localStorage for intro animation (only plays on first ever visit)
- Add cookie consent banner with PostHog opt-in/out
- Add visible remix indicator pill on poll page
- PostHog respects consent before tracking

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@HIPPIEKICK HIPPIEKICK left a comment

Choose a reason for hiding this comment

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

Really nice job with the final project! Had a look at your demo too ⭐

You have more design knowledge than me so take this from a random user's perspective: I think it would be nice with a back-button if you're inside a poll and want to go back.

For the backend, you could break out the authentication middlewear, as well as break out the endpoints into different files as well to make it more overviewable. Apart from that, your project is structured and your code looks all good.

Keep up the good work Daniel!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants