Berkay Orhan
WorkResearchExperienceAboutAskContact
Contact
← All projects

PROJECT / 2025

Kliv Idrottsförening

Website for a youth judo club in Norsborg that had basically no online presence. Covers everything from event listings and trainer profiles to an admin dashboard where the board manages Google Calendar-synced events and email notifications.

stack
TypeScript · Next.js 16 · React 19 · Tailwind CSS v4 · shadcn/ui · Framer Motion · Google Calendar API · Google Maps API · Nodemailer · Redis · Clerk Auth · Cloudinary · React Hook Form · Zod

Live site ↗Source ↗

How it works

  1. Google Calendar
    the board adds events

  2. webhook
    flags new events

  3. Redis
    pending queue

  4. approve
    emails every subscriber

Kliv Idrottsförening website homepage with judo theme
Kliv Idrottsförening website homepage with judo theme

01 / Overview

Kliv Idrottsförening is a small youth judo club in Norsborg, Botkyrka — south of Stockholm. They run judo training for kids aged 7–12 and organize free holiday sports activities during school breaks. Their whole thing is "run by young people, for young people" — low-barrier, pressure-free sports as an alternative to the demanding structure of traditional Swedish clubs. Before this site, they had almost no online presence. The website is their public face: a homepage with an animated bento grid explaining their vision, a dedicated judo page with an image slider and their instructor's profile (Raja Fernando, 6th dan), a holiday activities page pulling events from Google Calendar, a contact page with an embedded map, and a newsletter signup. Behind the scenes there's an admin dashboard where the board can approve incoming calendar events, create new ones, and trigger email notifications to subscribers — all backed by Redis and Clerk auth.

02 / Key features

  • –Animated bento grid on the homepage — six cards with micro-animations (cycling leadership icons, sport-discovery flip cards, radar pulse, particle bursts) that trigger on scroll via Framer Motion
  • –Judo page with a full-bleed image slider that swaps between landscape and portrait sources at the md breakpoint, plus a trainer profile section for their 6th dan instructor
  • –Holiday activities page fetching events from Google Calendar, displayed as expandable cards with hero images, details, and newsletter signup
  • –Google Calendar webhook sync — when something changes on the calendar, the webhook re-fetches and queues new events in Redis instead of polling. The Watch channel has a 1-hour TTL
  • –Admin dashboard behind Clerk auth where the board can approve, edit, or reject pending events, create new calendar events directly, and manage subscribers
  • –Subscriber notifications via Nodemailer — approving an event sends formatted HTML emails in Swedish to everyone in a Redis set
  • –Floating navbar that shrinks with backdrop blur after scrolling, with per-link glow effects and a layoutId-driven hover indicator
  • –Contact form with React Hook Form + Zod validation, embedded Google Maps, and a swipeable team carousel on mobile

03 / Challenges

  • –Google's Watch API just pings you with 'hey, something changed' — no diff, no details. The handler has to re-fetch events and figure out what's new by comparing creation timestamps against a 10-minute window. And the channel expires after an hour, so it goes silent if nobody renews it.
  • –Event images, CTA buttons, and formatted content all had to live inside a plain-text Calendar description field. That meant building a custom key-value parser and handling both well-formatted and messy input, since the field doesn't enforce any structure.
  • –The site needed to feel polished for a club that had no visual brand to work with. The bento grid, floating nav, and image slider all had to establish a visual identity from scratch — dark zinc with red accents, Oswald headings, animated section transitions — while still being easy for the board to maintain content-wise.

04 / Solution

The public site is built with server components by default, with client components for the interactive pieces — the bento grid animations, the image slider, expandable event cards, and the floating navbar. Content lives in a centralized config file so the board doesn't need to touch code to update text. On the backend, Google Calendar is the single source of truth for events. A Watch webhook notifies a Next.js API route when events change, the handler fetches recently-updated events and classifies anything created in the last 10 minutes as new. New events get stored in a Redis hash as pending. Admins authenticate through Clerk (one hardcoded email checked against an env var) and manage the queue from a tabbed dashboard — approve, edit, reject, or create events directly. Approving triggers Nodemailer to email every subscriber in a Redis set. The admin can also create events directly through the Google Calendar API with write scope, formatting descriptions with the same structured metadata.

05 / Outcome

The site is Kliv's entire digital presence — they had virtually nothing online before. The board can publish and manage events from the admin dashboard instead of coordinating through group chats, and subscribers get an email when something new goes up. For a small youth club with no budget for a CMS, the Google Calendar-as-database approach means they can keep using tools they already know while the website stays in sync automatically.

Berkay Orhan© 2026

WorkResearchExperienceCVBack to top ↑