Skip to content

Repository files navigation

AIS — Academic Improvement Solutions

Marketing and student-registration site for Academic Improvement Solutions, a South African tutoring service offering CAPS & IEB Mathematics and Physical Sciences lessons (online via Microsoft Teams and one-on-one in person).

It is a single-page React site: one scrolling landing page with anchored sections, plus a 404 route. There is no backend — registrations and enquiries are handed off to WhatsApp.

Tech stack

Framework React 18 + TypeScript
Build Vite 5 (@vitejs/plugin-react-swc)
Styling Tailwind CSS 3 with CSS-variable design tokens
Components shadcn/ui (Radix primitives) in src/components/ui/
Forms react-hook-form + zod
Routing react-router-dom (BrowserRouter, no basename)
Unit tests Vitest + Testing Library (jsdom)
E2E Playwright
Hosting GitHub Pages via GitHub Actions

@tanstack/react-query is wired up in App.tsx but not yet used — there is no data fetching today.

Getting started

Requires Node 20+ (CI builds on Node 24). npm and bun lockfiles are both committed; CI uses npm ci.

npm install
npm run dev      # http://localhost:8080

Scripts

Command Description
npm run dev Vite dev server on port 8080 (HMR error overlay disabled)
npm run build Production build to dist/
npm run build:dev Build in development mode
npm run preview Serve the built dist/ locally
npm run lint ESLint over the repo
npm test Vitest, single run
npm run test:watch Vitest in watch mode

Playwright is configured through playwright.config.ts / playwright-fixture.ts; run specs with npx playwright test.

Project structure

src/
├── main.tsx              # React root
├── App.tsx               # Providers (react-query, tooltips, toasters) + routes
├── index.css             # Tailwind layers + light/dark design tokens
├── pages/
│   ├── Index.tsx         # Composes every landing-page section
│   └── NotFound.tsx      # Catch-all route
├── components/
│   ├── Navbar.tsx        # Fixed nav, anchor links, mobile menu
│   ├── Hero.tsx          # Headline + CTAs into #pricing / #contact
│   ├── Services.tsx      # Subject/offering cards
│   ├── Pricing.tsx       # Online packages A/B/C + in-person per-grade rates
│   ├── Registration.tsx  # Validated enrolment form → WhatsApp
│   ├── About.tsx         # Founder bio
│   ├── Contact.tsx       # WhatsApp / email / Facebook / location cards
│   ├── Footer.tsx
│   ├── NavLink.tsx       # react-router NavLink with activeClassName support
│   └── ui/               # shadcn/ui primitives — generated, avoid hand-editing
├── hooks/                # use-toast, use-mobile
├── lib/utils.ts          # cn() class merge helper
├── assets/               # Logo and founder image
└── test/                 # Vitest setup + example spec

Sections are rendered in a fixed order by pages/Index.tsx and linked by the id on each <section> (#home, #services, #pricing, #register, #about, #contact). Adding a section means creating the component, giving it an id, rendering it in Index.tsx, and adding an entry to navLinks in Navbar.tsx.

How registration works

Registration.tsx validates the form with a zod schema (student details, parent/guardian details, and three required agreement checkboxes), then formats the answers into a message and opens a https://wa.me/... link in a new tab. Nothing is stored or sent server-side, and the submitted state only reflects that the WhatsApp hand-off was opened — not that a message was actually delivered.

The WhatsApp number lives in two places today: Registration.tsx (in the wa.me URL) and Contact.tsx (as WHATSAPP_NUMBER). Update both when it changes.

Editing site content

Content is hard-coded as arrays at the top of each component — no CMS:

  • Prices and packages — onlinePlans and autumnPlans in Pricing.tsx. The popular and recommended flags control the badge and card styling. Package labels are duplicated in the packages array in Registration.tsx; keep them in sync.
  • Subjects / offerings — services in Services.tsx.
  • Contact details and social links — Contact.tsx.
  • Founder bio and credentials — About.tsx.
  • Page title, description and Open Graph tags — index.html.

Theming

Colours are HSL CSS variables defined in index.css and mapped to Tailwind names in tailwind.config.ts. The palette is deep teal (--primary) with a gold accent (--secondary); headings use Playfair Display, body text uses Inter, both loaded from Google Fonts. A .dark token set exists but no theme toggle is currently mounted, so the site always renders light.

Use the semantic Tailwind classes (bg-primary, text-secondary, border-border, …) rather than literal colours, so a palette change stays a one-file edit.

Deployment

Every push to main triggers .github/workflows/deploy.yml, which installs with npm ci, runs npm run build, and publishes dist/ to the github-pages branch with JamesIves/github-pages-deploy-action. Lint and tests are not part of the pipeline — run them locally before pushing.

The build uses the default / base path and BrowserRouter without a basename, so the site expects to be served from a domain root (a custom domain or a user/organisation Pages site) rather than from a /<repo>/ project-page subpath. Note also that GitHub Pages has no SPA rewrite: deep links other than / will 404 at the server before the router sees them. Since every section is an anchor on /, this only matters if real routes are added later.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages