Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# CI for immigration-tools
# Runs tests, typecheck, and build on every PR and push to main.
# Deploys to Cloudflare Pages only after a successful build on main.

name: CI

on:
pull_request:
push:
branches:
- main

jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: npm

- name: Install dependencies
run: npm ci

- name: Typecheck
run: npm run typecheck

- name: Test
run: npm test

- name: Build
run: npm run build

- name: Deploy to Cloudflare Pages
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy dist --project-name=immicalc
21 changes: 21 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Dependencies
node_modules

# Build output
dist
dist-ssr

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# Editor / OS
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.local
32 changes: 32 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# AGENTS.md

Guidance for AI agents working in this repo. It is a React 19 + TypeScript + Tailwind v4 + react-router SPA built with Vite, tested with vitest + Testing Library.

## Commands

- `npm run dev` - local dev server
- `npm run test` - run all vitest tests
- `npm run typecheck` - `tsc --noEmit`
- `npm run build` - typecheck + production build

## Hard rules

- No em-dashes in user-facing copy or code comments. Use hyphens, commas, or restructure. En-dashes only in numeric ranges like "13-24 months".
- When computing what-if or recommendation point gains, simulate by re-running the score function on modified copies of the input. Never hardcode point deltas.
- Run `npm run typecheck` and `npm test` before finishing any change.

## Conventions

- Each calculator is a pure scoring module in `src/lib/<province>/score.ts` (a `score(input)` function) plus a tool page in `src/routes/<province>/`. Use the OINP tool (`src/routes/oinp/OinpTool.tsx`) as the reference pattern.
- Each module also exports `eligibility(input)` returning `{ eligible, reasons }`, surfaced via the shared `EligibilityBanner`. Every scoring field gets a `help` prop linking to the official government doc.
- Tool pages render their score via `ToolSidebar` (pot gauge with total/max, plus a breakdown as `<ScoreCard variant="breakdown" />`). The federal CRS sidebar passes a `draws` prop for a "Breakdown / Historical draws" tab switcher; other tools show a static "Points breakdown" tab.
- The tool switcher at the top of tool pages is `ToolTiles` (`<ToolTiles current="<tool-id>" />`).
- The draws feed (`DrawFeed`) is client-side IRCC JSON (parse `drawNumberURL`, `drawText2`, `drawCRS`, `drawSize`; do not assume the feed filename is stable). Provincial tools do not render it yet.
- The landing page map is `src/components/CanadaMap.tsx`, rendering paths from `@svg-maps/canada` (lazy-loaded via `React.lazy`). Which provinces are clickable is driven by the `PROVINCE_ROUTES` map inside the component.
- Theme: accent is Ford blue `#003478` (`--color-accent` in `src/index.css`). Keep accent-colored UI on this token.

## Testing

- Wrap tool components in `MemoryRouter` when rendering (they use `react-router` `Link`s).
- Mock `DrawFeed` in tool tests: `vi.mock('../../components/DrawFeed', () => ({ DrawFeed: () => null }))`.
- Stub `global.fetch` in any test that touches the draws feed.
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# ImmiCalc

Canadian immigration points calculator web-app. Runs client-side.

## Features

- Runs entirely in the browser. No account, no server, nothing stored or tracked.
- Live Express Entry draws feed, pulled from IRCC's published data.
- Score-improvement tips on the CRS page, computed from your actual inputs.

## Getting started

```sh
npm install
npm run dev
npm test
npm run typecheck
npm run build
```

`npm run build` runs typecheck plus the production build.

## Project structure

Each calculator is a pure scoring module in `src/lib/<province>/score.ts` with a `score()` function and an `eligibility()` function, plus a tool page in `src/routes/<province>/`. Shared UI such as the score sidebar, eligibility banner, and map lives in `src/components/`.

## Disclaimers

Not affiliated with any government agency. Immigration rules change often. These are estimates for planning, not legal advice. Confirm anything important against the official IRCC or provincial pages.

## License

MIT. See [LICENSE](LICENSE).
26 changes: 26 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="robots" content="index, follow" />
<meta
name="description"
content="Free, open-source Canadian immigration point calculators. Work out your Express Entry CRS score and provincial nominee points (OINP, BC PNP, SINP, AAIP, MPNP), all in your browser."
/>
<meta property="og:type" content="website" />
<meta property="og:site_name" content="ImmiCalc" />
<meta property="og:title" content="ImmiCalc | Free Canadian immigration calculators" />
<meta
property="og:description"
content="Free, open-source Canadian immigration point calculators. Work out your Express Entry CRS score and provincial nominee points (OINP, BC PNP, SINP, AAIP, MPNP), all in your browser."
/>
<meta property="og:url" content="https://immicalc.org/" />
<title>ImmiCalc | Free Canadian immigration calculators</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading
Loading