All projects
Personal project · web app (PWA)

UniCalendar: timetable, deadlines and grades in one place

2024Web appReactViteZustandPWAGoogle Drive APIWeb CryptoiCalendar

A calendar and study planner for university students that works offline. It imports the official timetable from an .ics feed and adds what students track themselves: attendance, coursework deadlines, grades and the mark needed on the next assignment, with optional encrypted sync to the user's own Google Drive.

The problem

At university my timetable, deadlines, attendance and marks lived in four different systems, and none of them could answer "what do I need to get on this essay?". UniCalendar pulls the timetable in and builds everything else around it, grouped by module.

UniCalendar week view with colour-coded lectures and labs for four modules and an upcoming deadlines sidebar
Week view with a sample timetable: each module has its own colour, and the sidebar lists today's classes and upcoming deadlines.

Features

  • Six calendar views. Stream (a 14-day timeline by module), Radar (upcoming deadlines plotted by how soon they're due), Month, Week, Day and Year, with clash detection and academic terms.
  • Timetable import from an .ics URL or file, with recurring events expanded, and export back to .ics.
  • Attendance per module, keeping what the university recorded separate from what actually happened.
  • Coursework with weights and grades, a Gantt chart where due dates can be dragged, and a grade projection for UK undergraduate and postgraduate classes, US letter grades and GPA, or a generic scale.
  • Notes in a rich-text editor per lecture and module, exportable to PDF, plus CSV export of grades and attendance and full JSON backups.
  • Keyboard first: a command palette on Ctrl/Cmd+K and shortcuts to switch views, plus a mobile layout with swipe navigation and a study timer.
UniCalendar radar view plotting upcoming deadlines as dots on rings by days remaining
Radar view: items sit closer to the centre the sooner they're due, coloured by module, with deadlines drawn larger.
UniCalendar modules page with grade rings, attendance, next class and weekly contact hours per module
Modules: a ring showing the grade so far, attendance, the next class and weekly contact hours for each module.

Architecture

Everything runs in the browser: state lives in a Zustand store saved to local storage, with rich text and attachments in IndexedDB, and a service worker makes it work offline. There is no app database; the only server code is three small Vercel functions for the Google sign-in token exchange and fetching calendar feeds.

From timetable feed to dashboard

  1. 01
    Import
    Fetch the .ics feed directly, falling back to a small serverless proxy
  2. 02
    Parse
    ical.js expands recurring events and exceptions into the app's schema
  3. 03
    Organise
    Events, modules, coursework, attendance and notes in one store
  4. 04
    Persist
    Local storage and IndexedDB, so it works offline
  5. 05
    Encrypt and sync
    AES-256-GCM, uploaded to the user's own Google Drive 1.5 s after the last change
  6. 06
    Plan
    Six views, Gantt chart, grade projection, reminders and exports

Sync and privacy

Sync is optional. Signing in with Google uses the OAuth authorization-code flow with PKCE, with the client secret kept server-side, and the drive.file scope, so the app can only see files it created. Data is encrypted with AES-256-GCM (key derived with PBKDF2-SHA256, 600,000 iterations) before it's uploaded to a folder in the user's own Drive, with a version file to detect conflicts.

Looking back

Sync is push and pull with conflict detection rather than a full merge, and reminders only fire while the app is open. A user-chosen encryption passphrase, and proxying calendar feeds only through my own function, are the next things I'd change.

6
Calendar views
33
React components
~13,800
Lines of JavaScript/JSX (plus ~5,200 of CSS)
3
Serverless functions; no app database

Source: src/ and api/ in the repository

← Back to all projects