A landing page application that collects company information and allows users to add additional details through email links.
- Simple landing page with LauraMepson branding
- Form to collect company name and email
- SQLite database storage for submissions
- Email functionality to send users a unique link
- Continuation page for adding more information
- Image upload and storage using Uploadcare
This project includes solutions for handling Uploadcare image uploads, specifically addressing the issue where multi-file uploads create groups instead of individual files.
When using Uploadcare's multi-file uploader, files are grouped together with a UUID like:
cb08730c-9c8b-46bb-a79e-9ab0f228939e~1
To access individual files, you need to use the /nth/0/ syntax, which can be cumbersome and doesn't give you direct access to individual file UUIDs.
Two solutions are provided:
- Use Single File Uploaders: Configure Uploadcare widgets to upload one file at a time
- Extract Individual Files from Groups: Use the multi-file uploader but extract individual file UUIDs
/public/uploadcare-demo.ts- A comprehensive demo showing both problems and solutions/public/uploadcare-fix.ts- A focused solution with implementation guide/public/single-file-demo.ts- A demo of the single file uploader solution
The single file uploader solution has been implemented in the main application:
- Changed
UPLOADCARE_MULTIPLEtofalsein the global configuration - Implemented a clean UI with a single uploader and "Add Another Image" button
- Updated the JavaScript to handle individual file uploads
- Added a helper script (
/public/js/uploadcare-helper.js) with utility functions
βββ api/ # API route handlers
β βββ images.ts # Image-related API endpoints
β βββ submissions.ts # Submission-related API endpoints
β βββ index.ts # API routes configuration
βββ controllers/ # Request handling logic
β βββ imageController.ts # Image upload/retrieval logic
β βββ submissionController.ts # Submission handling logic
βββ models/ # Data models and types
β βββ image.ts # Image-related types
β βββ submission.ts # Submission-related types
βββ services/ # Business logic
β βββ imageService.ts # Image metadata operations
β βββ uploadcareService.ts # Uploadcare integration
β βββ databaseService.ts # Database operations
β βββ emailService.ts # Email sending functionality
β βββ templateService.ts # HTML template rendering
βββ utils/ # Utility functions
β βββ helpers.ts # Helper functions
β βββ responseUtils.ts # Standardized API responses
βββ views/ # HTML templates
β βββ landing.html # Main landing page
β βββ continue.html # Continuation page
βββ public/ # Static assets and client-side JS
β βββ css/ # Stylesheets
β β βββ styles.css # Common styles
β βββ js/ # Client-side JavaScript
β βββ landing.js # Landing page script
β βββ continue.js # Continuation page script
βββ index.ts # Main entry point
The application uses a SQLite database with the following schemas:
CREATE TABLE IF NOT EXISTS laura_mepson_submissions_v1 (
id TEXT PRIMARY KEY,
company_name TEXT NOT NULL,
email TEXT NOT NULL,
created_at TEXT NOT NULL,
additional_fields TEXT
)
CREATE TABLE IF NOT EXISTS laura_mepson_images_v1 (
id TEXT PRIMARY KEY,
original_name TEXT NOT NULL,
content_type TEXT NOT NULL,
size INTEGER NOT NULL,
uploaded_at TEXT NOT NULL,
submission_id TEXT NOT NULL,
cdn_url TEXT NOT NULL
)
- User visits the landing page
- User submits company name and email
- Data is saved to SQLite database
- User receives an email with a unique link
- User can click the link to add more information
- Additional information is saved to the database
- User can upload and manage images related to their submission
- Main landing page:
https://[username].web.val.run - Continuation page:
https://[username].web.val.run?action=continue&id=[unique_id]
Images are stored using Uploadcare:
- Uploadcare handles file uploads, storage, and CDN delivery
- Uploadcare's built-in image preview and cropping tools are used
- Image metadata is stored in our SQLite database
- Users can upload, view, and delete images
- Images are associated with a specific submission
UPLOADCARE_SECRET_KEY: Secret key for Uploadcare API authentication
- When modifying the database schema, create a new table with a new version number
- Email templates are defined in
emailService.ts - The unique ID generation is handled in
utils/helpers.ts - Val Town HTTP vals use query parameters instead of path parameters for routing
The application uses a SQLite database with the following schema:
CREATE TABLE IF NOT EXISTS laura_mepson_submissions_v1 (
id TEXT PRIMARY KEY,
company_name TEXT NOT NULL,
email TEXT NOT NULL,
created_at TEXT NOT NULL,
additional_fields TEXT
)
- User visits the landing page
- User submits company name and email
- Data is saved to SQLite database
- User receives an email with a unique link
- User can click the link to add more information
- Additional information is saved to the database
- User can upload and manage images related to their submission
- Main landing page:
https://[username].web.val.run - Continuation page:
https://[username].web.val.run?action=continue&id=[unique_id]
Images are stored using Val Town's blob storage:
- Images are stored with a unique ID
- Metadata is stored alongside each image
- Users can upload, view, and delete images
- Images are associated with a specific submission
- When modifying the database schema, create a new table with a new version number
- Email templates are defined in
email.ts - The unique ID generation is handled in
utils.ts - Val Town HTTP vals use query parameters instead of path parameters for routing