whenwasthelasttime
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
A single-user Progressive Web App (PWA) for tracking when events and activities last occurred.
Keep track of when things last happened - from personal activities like "Went to the gym" to general events like "It rained" or home maintenance tasks like "Changed air filter". The app displays time elapsed since the last occurrence and maintains a complete historical record with statistics.
- Track Items: Record when specific events or activities occur
- Time Elapsed Display: See how long it's been since each item last occurred (e.g., "2 years, 3 months, 5 days")
- Historical Record: View complete history of all occurrences with dates and optional notes
- Statistics:
- Average interval between occurrences
- Longest/shortest intervals
- Frequency (occurrences per month/year)
- Total occurrence count
- Categories: Organize items into customizable categories
- Search & Filter: Find items by name/description or filter by category
- Archive: Soft delete items (can be restored) to keep your active list clean
- Offline Capable: Works without internet connection
- Installable: Add to home screen on mobile/desktop
- Fast Loading: Optimized caching for quick startup
- Backend: Hono web framework, SQLite database (Turso/libSQL)
- Frontend: React 18, Tailwind CSS
- Platform: Val Town (Deno-based serverless)
- PWA: Service worker with offline support
├── backend/
│ ├── index.ts # Hono server & API endpoints
│ └── db.ts # Database schema & queries
├── frontend/
│ ├── index.html # HTML shell
│ ├── index.tsx # React root
│ ├── App.tsx # Main app component with routing
│ ├── components/
│ │ ├── ItemList.tsx
│ │ ├── ItemDetail.tsx
│ │ ├── AddItem.tsx
│ │ ├── CategoryManager.tsx
│ │ └── ArchiveView.tsx
│ └── utils/
│ ├── api.ts # API client
│ └── timeCalc.ts # Time calculation utilities
├── public/
│ ├── manifest.json # PWA manifest
│ ├── sw.js # Service worker
│ ├── icon-192.svg # App icon (192x192)
│ └── icon-512.svg # App icon (512x512)
└── README.md
id(text/UUID): Primary keyname(text): Unique category namecreated_at(text): ISO 8601 timestamp
id(text/UUID): Primary keycategory_id(text): Foreign key to categoriesname(text): Item namedescription(text): Optional descriptioncreated_at(text): ISO 8601 timestamparchived(integer): 0 = active, 1 = archived
id(text/UUID): Primary keyitem_id(text): Foreign key to items (cascade delete)occurrence_date(text): Date in YYYY-MM-DD formatnote(text): Optional notecreated_at(text): ISO 8601 timestamp
GET /api/categories- List all categoriesGET /api/categories/:id- Get category by IDPOST /api/categories- Create new categoryPUT /api/categories/:id- Update categoryDELETE /api/categories/:id- Delete category (fails if has items)
GET /api/items- List items (query params:include_archived,category_id,search)GET /api/items/:id- Get item by IDPOST /api/items- Create new itemPUT /api/items/:id- Update itemDELETE /api/items/:id- Permanently delete itemPOST /api/items/:id/archive- Archive itemPOST /api/items/:id/restore- Restore archived item
GET /api/items/:id/occurrences- List occurrences for an itemGET /api/items/:id/statistics- Get statistics for an itemPOST /api/occurrences- Create new occurrencePUT /api/occurrences/:id- Update occurrenceDELETE /api/occurrences/:id- Delete occurrence
- Visit the app URL
- Create your first category (e.g., "Health", "Home", "Activities")
- Add items you want to track
- Record occurrences when events happen
- Click on an item to view details
- Click "Record New Occurrence"
- Select the date (defaults to today)
- Optionally add a note
- Click "Add"
- Click any item to see detailed statistics
- View time elapsed, frequency, and patterns
- See complete historical timeline
- Click "Categories" from the main screen
- Add, edit, or delete categories
- Note: Categories with items cannot be deleted
- Edit an item and click "Archive"
- View archived items from the "Archive" screen
- Restore or permanently delete archived items
- Single-User Design: No authentication required (keep your URL private)
- SQL Injection Protection: All queries use parameterized statements
- Input Validation: All user input is validated on the server
- Uses lowercase SQL keywords (Val Town convention)
- UUIDs generated via
crypto.randomUUID() - Dates stored as ISO 8601 strings
- No build step required - ESM imports from CDN
- Service worker provides offline capability
The app is built for Val Town and uses:
- Import maps from esm.sh for npm packages
- React 18.2.0 with pinned dependencies
- Tailwind CSS via CDN (twind)
- SQLite via Val Town's sqlite utility
MIT
For issues or questions, please refer to the Val Town documentation or create an issue in the project repository.