A weekly planner for UOC (Universitat Oberta de Catalunya) students. Visualize your courses, deadlines, and weekly tasks in a modern interface with a full semester roadmap.
Developed by Edgar @edbrsk
- ๐ Weekly planning โ Tasks organized by week and course
- ๐ Visual roadmap โ Swimlane timeline of all semester deliverables
- ๐ฅ Real-time sync โ Firebase-backed, works across devices
- ๐พ Offline mode โ Works without an account using browser localStorage
- ๐ Self-hosted data โ Each user connects their own Firebase project
- โก Upcoming deadline highlights โ Deliverables due within 15 days are flagged
- โฌ๏ธ JSON import โ Paste LLM-generated planning data directly into the app
- โฌ๏ธ JSON export โ Export your modified data to share or back up
- ๐ฒ Installable PWA โ Add to home screen on iOS and Android for a native app experience
- ๐จ๏ธ Print-ready โ Optimized layout for printing
- ๐ฑ Responsive โ Works on desktop and mobile
UOC Planner is a Progressive Web App (PWA) โ you can install it on your phone for a native app look and feel, no app store needed.
- Open the app in Safari
- Tap the Share button (โฌ๏ธ)
- Select "Add to Home Screen"
- Tap "Add"
- Open the app in Chrome
- Tap the three-dot menu (โฎ)
- Select "Add to Home Screen" or "Install App"
- Tap "Install"
The app will appear on your home screen with its own icon and launch in full-screen mode, just like a native app.
Want to try the app without any configuration?
- Open the app and click ๐พ Usar sin cuenta (offline)
- Click your profile avatar (top-right) โ โฌ๏ธ Importar JSON
- Copy the contents of
demo/uoc_planner_2025-2.jsonand paste it - Click Validar JSON โ Importar semestre
- Explore the full app with 18 weeks, 5 courses, and 30+ deadlines!
Just click ๐พ Usar sin cuenta (offline) on the login screen. Your data is stored in the browser's localStorage โ no Firebase, no Google account needed.
- Go to console.firebase.google.com
- Create a new project (free Spark plan)
- Add a Web app and copy the
firebaseConfigobject - Enable Authentication โ Google as a sign-in provider
- Create a Firestore Database in test mode
- On the setup screen, paste your
firebaseConfigJSON
git clone https://github.com/edbrsk/uoc-planner.git
cd uoc-planner
npm install
npm run devThe power of UOC Planner is that an LLM (Claude, ChatGPT, etc.) can automatically generate your entire weekly plan by analyzing your virtual campus.
- Install the Canvas MCP server โ mcp-canvas-lms
- Generate an access token from your campus:
- Navigate to aula.uoc.edu/profile/settings
- Find the "Approved Integrations" section
- Generate a new access token
- Configure the MCP in Claude Desktop with your token and Canvas base URL
- Use the prompt below to generate your planning data
If you don't have the Canvas MCP, you can manually copy the syllabus, calendar, and deliverable schedule from each course in your virtual campus, then paste it into a chat with your preferred LLM alongside the prompt and JSON schema below.
You have access to my Canvas LMS courses for the current semester using the mcp-canvas-lms. Build a comprehensive weekly study plan following ALL the rules below exactly.
STEP 1 โ COURSE DISCOVERY:
โข Use canvas_list_courses to find all active courses for the current semester term. Ignore any courses from previous terms (check enrollment_term_id). โข For each active course, call canvas_list_assignments and capture for every assignment: name, due_at, unlock_at, html_url, submission_types, points_possible.
STEP 2 โ TIMEZONE CONVERSION (CRITICAL):
Canvas stores all timestamps in UTC. My timezone is Spain: โข CET = UTC+1 โ applies before the last Sunday of March โข CEST = UTC+2 โ applies from the last Sunday of March onward For 2026: CET before March 29; CEST from March 29 onward.
Convert EVERY unlock_at and due_at to Spain local time before using them > anywhere. Key rule: an unlock_at of 23:00 UTC on day D becomes 00:00 local time on > day D+1. โ Display as "abre D+1 mmm", never "abre D mmm". Example: unlock_at 2026-03-19T23:00:00Z โ 2026-03-20 00:00 CET โ "abre 20 mar"
STEP 3 โ UNLOCK-DATE RULE:
โข Never schedule a task to start working on an assignment before its unlock_at (converted to Spain local time). โข For weeks before unlock: use study/reading preparation tasks instead, with "(preparacion NombreTarea, abre DD mmm)" in the task text. โข If an assignment unlocks mid-week: it may appear in that week with "(abre DD mmm)".
STEP 4 โ TASK GRANULARITY (CRITICAL):
โข ONE task per deliverable per week. Never merge multiple separate deliverables into a single task. โ WRONG: "Hacer Q1, Q2, Q3 y empezar R1 (vencen 13 mar)" โ RIGHT: Three separate tasks โ Q1 in week 1, Q2 in week 2, Q3 in week 3
โข For courses with weekly cuestionarios (e.g., AL), place exactly ONE cuestionario per week following the course's intended weekly schedule, even if they all share the same final deadline.
โข Reading/study tasks must also be split per chapter or unit, one per week, mirroring the course's own weekly structure.
โข For each Reto in AL: create separate tasks for (1) reading/preparation, (2) Preparar Reto, (3) Entregar Reto, and (4) Subir Video โ each in its own week.
STEP 5 โ VIDEO SUBMISSION TASKS:
โข Video submissions have very short unlock windows (3โ5 days). Place video tasks ONLY in the week they actually unlock โ never earlier. โข Task text format: "Subir Video Reto 1 (abre 20 mar, entrega: 23 mar)" โข Set "urgent": true for video deadlines with โค 3 days window.
STEP 6 โ COMBINED TASK RULE:
When a deadline and the start of the next assignment fall in the same week but the new assignment is still locked: create two separate entries โ one for the delivery, one for study/preparation. Never write "Entregar X. Empezar Y" if Y is not yet unlocked.
STEP 7 โ WEEK-BY-WEEK PLAN:
โข Cover all active courses simultaneously, interleaved by urgency and workload. โข Each week: 3โ8 tasks across multiple courses. โข Within each week, order tasks by priority (most urgent / closest deadline first). โข Use these course abbreviations exactly: AL, Prob, Prog, Redes, Lab (not "LabPyR" or any other variant).
STEP 8 โ CANVAS URLs:
โข For every task that maps to a specific Canvas assignment, include: "url": <html_url from canvas_get_assignment> โข For generic study/preparation tasks with no direct Canvas assignment, omit the "url" field entirely. Do not include null or empty strings.
STEP 9 โ NOTES AND taskId (CRITICAL):
The "tasks" array is 0-indexed. The taskId in each note must be "task_N" where N is the 0-BASED position of that task in the tasks array. โ tasks[0] = "task_0", tasks[1] = "task_1", tasks[38] = "task_38", etc.
NEVER use an empty string "", null, or undefined for taskId. Every note must be linked to a specific task โ for general/calendar notes, choose the most relevant task (e.g., the delivery task it warns about).
Before writing the final JSON: verify each note's taskId by counting the 0-based position of the intended task in the tasks array and confirm the text at that index matches your intent.
STEP 10 โ SELF-VERIFICATION BEFORE OUTPUT:
Before writing the final JSON, run these checks:
- All unlock_at dates have been converted to Spain local time (CET/CEST).
- No task appears in a week before its unlock date.
- No week has merged cuestionarios that should be separate weekly tasks.
- Every note's taskId resolves to tasks[N] where tasks[N].text matches what the note is referring to.
- No taskId uses "", null, or a non-existent index.
OUTPUT SCHEMA (exact โ do not deviate):
{ "semester": { "name": "2025-2", "label": "Semestre 2025-2", "startDate": "2026-02-17", "endDate": "2026-06-22" }, "weeks": { "1": { "dates": "17 feb โ 23 feb", "title": "Arranque del semestre" } }, "tasks": [ { "weekNum": 1, "course": "AL", "text": "Hacer Cuestionario 1 (Q1) โ entrega: 13 mar", "order": 0, "done": false, "url": "https://aula.uoc.edu/courses/..." } ], "deadlines": [ { "date": "2026-03-13", "label": "AL โ Reto 1 + Q1+Q2+Q3", "course": "AL", "urgent": false, "order": 0 } ], "notes": [ { "taskId": "task_3", "text": "Note text โ taskId is the 0-based index of the task in the tasks array." } ] }
Additional output rules: โข All dates in YYYY-MM-DD format. โข "urgent": true only for deliverables with โค 3 days between unlock and due date. โข "done": false for all tasks. โข tasks array ordered chronologically (weekNum ASC, then order ASC within each week). โข Output only the raw JSON โ no markdown code fences, no explanations.
Both features are accessible from the profile menu (click your avatar in the top-right corner).
- Click your profile avatar โ โฌ๏ธ Importar JSON
- Paste the complete JSON (from an LLM, an export, or the demo file)
- Click Validar JSON โ a preview shows courses, task count, and deadline count
- Click Importar semestre
- Click your profile avatar โ โฌ๏ธ Exportar JSON
- A
.jsonfile downloads with the exact same schema used for import - Share it, back it up, or re-import it later
This means you can: generate data with AI โ import โ modify in the app โ export โ share with classmates.
| Field | Type | Description |
|---|---|---|
semester.name |
string |
Unique identifier (e.g., "2025-2") |
semester.label |
string |
Display name (e.g., "Semester 2025-2") |
semester.startDate |
string |
Start date in YYYY-MM-DD format |
semester.endDate |
string |
End date in YYYY-MM-DD format |
weeks.N.dates |
string |
Human-readable date range (e.g., "Feb 17 โ 23") |
weeks.N.title |
string |
Week summary / theme |
tasks[].weekNum |
number |
Week number (1, 2, 3...) |
tasks[].course |
string |
Course abbreviation (e.g., "AL") |
tasks[].text |
string |
Task description |
tasks[].order |
number |
Sort order within the week (0, 1, 2...) |
tasks[].done |
boolean |
Completion status โ default false |
tasks[].url |
string (optional) |
Direct Canvas URL to the assignment/quiz (html_url from Canvas API) |
deadlines[].date |
string |
Due date in YYYY-MM-DD format |
deadlines[].label |
string |
Deliverable description |
deadlines[].course |
string |
Course abbreviation |
deadlines[].urgent |
boolean |
true for extremely short submission windows |
deadlines[].order |
number |
Display order |
notes[].taskId |
string |
ID of the task this note belongs to (optional on import if mapped during generation) |
notes[].text |
string |
The note content |
| Technology | Purpose |
|---|---|
| React 19 | UI components |
| Vite 6 | Build tool + dev server |
| TailwindCSS v4 | Styling |
| Firebase Firestore | Real-time database (optional) |
| Firebase Auth | Google sign-in (optional) |
| localStorage | Offline data storage |
| GitHub Pages | Deployment |
The app deploys automatically to GitHub Pages via GitHub Actions on every push to main. See .github/workflows/deploy.yml.
npm run dev # Dev server (http://localhost:5173)
npm run build # Production build
npm run preview # Preview production buildโโโ demo/
โ โโโ uoc_planner_2025-2.json # Demo data for quick testing
src/
โโโ App.jsx # Main application component
โโโ main.jsx # Entry point
โโโ index.css # Global styles + Tailwind
โโโ lib/
โ โโโ firebase.js # Dynamic Firebase initialization
โ โโโ constants.js # Colors, date helpers
โ โโโ store.js # Offline localStorage data layer
โโโ hooks/
โ โโโ useAuth.js # Authentication (Firebase + offline)
โ โโโ useSemesters.js # Semester CRUD (Firebase + offline)
โ โโโ useTasks.js # Task CRUD (Firebase + offline)
โ โโโ useDeadlines.js # Deadline CRUD (Firebase + offline)
โโโ components/
โโโ AuthScreen.jsx # Login screen (Google + offline)
โโโ SetupScreen.jsx # Firebase / offline mode selection
โโโ Header.jsx # Header + profile dropdown
โโโ CoursePills.jsx # Course filter pills
โโโ WeekCard.jsx # Collapsible week card
โโโ TaskItem.jsx # Individual task item
โโโ DeadlinesSection.jsx # Deadline table
โโโ RoadmapView.jsx # Swimlane roadmap
โโโ ImportModal.jsx # JSON import modal
โโโ Modal.jsx # Reusable modal shell
โโโ TaskModal.jsx # Task form
โโโ DeadlineModal.jsx # Deadline form
โโโ SemesterModal.jsx # Semester + week forms
โโโ Toast.jsx # Toast notifications
MIT
