A modern, single-page web application that mimics the official CELPIP Writing test environment for effective practice. Built with React and TypeScript, featuring AI-powered feedback, realistic timers, and comprehensive progress tracking.
Screenshot placeholder: Add images of the app in action
- Two Task Types - Email (Task 1) and Survey Response (Task 2) with accurate timers (27 min and 26 min)
- Question Bank - 30 practice questions (15 per task type) included out of the box
- AI-Powered Feedback - Integrated with Google Gemini API for detailed writing analysis
- Realistic Writing Interface - Countdown timer, word count, and browser spellcheck
- Practice History - Full history with progress tracking and statistics
- Dark Mode - Toggle between light and dark themes
- PWA Installable - Install as a native-like app on desktop and mobile
- Admin Panel - Add, edit, and delete questions without touching code
- Auto-Save Drafts - Never lose your writing; drafts persist in localStorage
- Fully Responsive - Works on desktop, tablet, and mobile devices
| Technology | Purpose |
|---|---|
| React 18 | UI framework |
| Vite | Build tool and dev server |
| TypeScript | Type safety |
| Tailwind CSS | Utility-first styling |
| Zustand | State management |
| Google Generative AI SDK | AI feedback via Gemini API |
| React Router | Client-side routing |
git clone <repo-url>
cd CELPIP_Writing
npm install
npm run devThe app will be available at http://localhost:5173.
npm run build
npm run previewThe production build will be output to the dist/ directory.
CELPIP_Writing/
├── index.html # Entry HTML file
├── package.json # Dependencies and scripts
├── vite.config.ts # Vite configuration
├── tsconfig.json # TypeScript configuration
├── tailwind.config.js # Tailwind CSS theme and plugins
├── postcss.config.js # PostCSS config
├── public/
│ └── favicon.svg # App icon (SVG)
└── src/
├── main.tsx # App entry point
├── App.tsx # Root component with routing
├── index.css # Global styles and Tailwind imports
├── types/index.ts # TypeScript interfaces
├── store/
│ ├── useAppStore.ts # Main application state (Zustand)
│ └── useTimerStore.ts # Timer state management
├── data/
│ └── questions.json # Question bank (15 Task 1 + 15 Task 2)
├── utils/
│ ├── localStorage.ts # LocalStorage helpers
│ ├── wordCount.ts # Word counting utility
│ └── gemini.ts # Gemini API integration
├── components/
│ ├── Layout/ # Header and Layout wrapper
│ ├── Dashboard/ # Dashboard and stats cards
│ ├── Practice/ # Practice session components
│ ├── AI/ # AI feedback and settings
│ ├── History/ # History list and detail views
│ ├── Admin/ # Admin panel for question management
│ └── Instructions/ # Writing instructions panel
└── pages/ # Route page components
├── DashboardPage.tsx
├── PracticePage.tsx
├── HistoryPage.tsx
├── SettingsPage.tsx
└── AdminPage.tsx
This app uses the Google Gemini API for AI-powered writing feedback. To set it up:
- Get a Google Gemini API key from Google AI Studio
- Open the app and navigate to Settings
- Enter your API key in the provided field
- Select a model (default:
gemini-2.0-flash) - Click Save
Your API key is stored locally in your browser's localStorage and is never sent to any server other than the Google Gemini API.
Note: The AI feedback feature is optional. The app works fully without an API key for practice sessions, timers, and history tracking.
- Go to Settings and enable Admin Mode
- Navigate to the Admin page
- Use the form to add new questions for Task 1 (Email) or Task 2 (Survey)
- Edit or delete existing questions as needed
- Use the Export button to back up your question bank
- Use the Import button to restore from a backup
Edit src/data/questions.json directly. The file follows this format:
Task 1 (Email) example:
{
"id": "t1_custom_1",
"taskType": 1,
"prompt": "Write an email to your landlord requesting a repair.",
"context": "The kitchen faucet has been leaking for two weeks. You have already mentioned it verbally but nothing has been done.",
"bulletPoints": [
"Describe the problem",
"Explain what you have already done",
"Request specific action and timeline"
]
}Task 2 (Survey Response) example:
{
"id": "t2_custom_1",
"taskType": 2,
"prompt": "Respond to a survey about remote work policies.",
"context": "Your company is considering making remote work permanent. They want employee input.",
"options": [
"Fully remote",
"Hybrid (3 days office, 2 days home)",
"Return to office full-time"
],
"questionText": "Which work arrangement do you prefer and why?"
}Use the Admin panel's Import and Export buttons to transfer question banks between browsers or share them with others.
Edit tailwind.config.js to change the CELPIP brand colors:
colors: {
celpip: {
blue: '#003366',
lightblue: '#0066CC',
accent: '#0099FF',
dark: '#001a33'
}
}Timer durations are set to match the official CELPIP test:
- Task 1 (Email): 27 minutes
- Task 2 (Survey Response): 26 minutes
These values are defined in the practice session component.
The recommended word count ranges displayed during practice can be adjusted in the WritingArea component.
This app can be installed as a Progressive Web App for an app-like experience:
- Open the app in your browser
- Look for the install icon in the address bar (or the three-dot menu)
- Click "Install" to add it to your desktop
- Open the app in Chrome
- Tap the three-dot menu
- Select "Add to Home screen" or "Install app"
- The app will appear on your home screen
- Open the app in Safari
- Tap the Share button
- Select "Add to Home Screen"
Once installed, the app works offline for practice sessions (AI feedback requires an internet connection).
Contributions are welcome! To contribute:
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Make your changes
- Run the linter:
npm run lint - Commit your changes:
git commit -m "feat: add your feature" - Push to your branch:
git push origin feature/your-feature - Open a Pull Request
MIT License. See LICENSE for details.