https://github.com/skye-flyhigh/flymorocco
just a migration of my old website, from hardcoded HTML CSS JS to modern frameworks Next.js
https://github.com/skye-flyhigh/flymorocco
daisyui-react interactive-map leaflet-map nextjs openair openair-parser pdf-generation useactionstate zod-validation
Last synced: 28 days ago
JSON representation
just a migration of my old website, from hardcoded HTML CSS JS to modern frameworks Next.js
- Host: GitHub
- URL: https://github.com/skye-flyhigh/flymorocco
- Owner: Skye-flyhigh
- Created: 2025-04-02T08:36:41.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2026-03-03T20:13:01.000Z (3 months ago)
- Last Synced: 2026-03-03T21:36:59.572Z (3 months ago)
- Topics: daisyui-react, interactive-map, leaflet-map, nextjs, openair, openair-parser, pdf-generation, useactionstate, zod-validation
- Language: TypeScript
- Homepage: https://flymorocco.info
- Size: 60.9 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- Security: SECURITY.md
- Roadmap: roadmap.md
Awesome Lists containing this project
README
# πͺ FlyMorocco
**Multilingual paragliding hub for pilots exploring the skies of Morocco.**
Built with Next.js, Tailwind CSS, and the occasional chaos-fueled tea session.
---
## π Project Overview
Flymorocco is a fully static, SEO-friendly, and i18n-ready web app tailored for paragliding pilots looking to fly in Morocco.
It serves guide pages for multiple flying sites, dynamically rendered and maintained by a single JSON data source, localized in both **English** and **French**.
---
## β¨ Features
### Core Platform
- π **Multilingual** with `next-intl` (EN/FR)
- πͺ **Dynamic site guides** powered by slug-based routing
- πΌοΈ **Visual-first layout** to highlight the beauty of flying sites
- π **SEO-ready** with custom meta tags per page
- πΊοΈ **Interactive airspace maps** with Morocco's official ENR 5.5 data
### E-Commerce Booking System
- π³ **Multi-currency booking** (GBP, USD, EUR, CAD) through Wise
- π₯ **Multi-participant support** with pilot detection and verification
- π **Solo room options** with dynamic pricing calculations
- π§ **Professional email pipeline** (confirmations, notifications, verifications)
- π― **Marketing-optimized emails** with clickable tour banners
- π **PDF document generation** for CAA authorization forms
- π§βπ» **Google Spreadsheet integration** for booking management
### Technical Excellence
- βοΈ **Type-safe data** validation with Zod schemas
- π **Security features** with reCAPTCHA and input sanitization
- π± **Responsive design** with accessibility built-in
- π **Static generation** for optimal performance
---
## π§ Dev Stack
- [Next.js 15](https://nextjs.org/) the goat π
- [Tailwind CSS](https://tailwindcss.com/) the 1000 pieces jigsaw puzzle of styling π§©
- [DaisyUI](https://daisyui.com/) the picture of the box of the puzzle π§©
- [Lucide React](https://lucide.dev/) for clean, consistent icons
- [Zod](https://zod.dev/?id=objects) to break my app again
- [React Leaflet](https://react-leaflet.js.org/), who does like a good map?
- [OpenAir parser](https://www.npmjs.com/package/@openaip/openair-parser?activeTab=readme), need content for map
- [pdf-lib](https://www.npmjs.com/package/pdf-lib), advanced pdf generation π
- [sendGrid](https://www.npmjs.com/package/@sendgrid/mail), to send the advanced pdfs
- [react-scroll-parallax](https://www.npmjs.com/package/react-scroll-parallax), smooth scrolling effects
---
## π§ Setup
bash
git clone https://github.com/skye-flyhigh/flymorocco.git
cd flymorocco
npm install
npm run dev
---
## π Folder Structure Highlights
app/
βββ [locale]/
β βββ layout.tsx # Locale-aware layout << Case of the missing E
β βββ page.tsx # Localized homepage
β βββ components/ # πͺ Magic π«
β βββ site-guides/ # Dynamic ποΈ (per location)
βββ layout.tsx # Language overlay
βββ lib/
β βββ site.ts
βββ types/
β βββ siteMeta.ts # Zod's schema validation for site guide meta
βββ i18n/ # next-intl language package
βββ middleware.ts # i18n routing redirect
The messages folder for the translations are living outside of the src/app folder according to next-intl docs.
π
βββ messages/
β βββ en.json
β βββ fr.json
βββ public/images/
βββ src/app/
---
## π₯ Developer Lore
> **βThe Case of the Missing Eβ**
During the i18n setup, a rogue param named `local` (missing the "e") hijacked the entire layout and crashed the app via a top-level `await`.
After hours of meticulous logs, terminal therapy, and a _French-accented scream_, the bug was identified.
π§ͺ Resolved by explicitly setting:
const { local: locale } = resolvedParams;
// Official docs said it returns { locale }... THEY LIED. IT'S 'local'.
// Yes, I logged it. Yes, I screamed.
Also the correct solution is in `middleware.ts`, to force the correct `param` key
createMiddleware({
...routing,
localeParam: 'locale' // << WITH a 'e'
})
This project will proudly wear the battle scars of this journey.
> **"πΊοΈ The Cartographic Conquest (April 2025)"**
βIt started with a fileβ¦ and ended in 20,000 lines of polygon geometry.β
- Parsed Moroccoβs official ENR 5.5 airspaces from OpenAir format using a hacked parser and caffeine-fueled determination
- Resolved cryptic parser errors like "Unknown altitude definition '3500'" and "Token 'DB' does not allow subsequent token 'AY'" by reverse-engineering format expectations
- Used fixGeometry: true to handle self-intersecting madness (and hoped nothing got lost in convex purgatory)
- Successfully converted nested sectors, parachute zones, and TMA fragments into GeoJSON, rendered live with Leaflet
- Deployed hoverable, paintable polygons with visual filtering (GSEC toggle) and type-based coloring
π Status: All airspaces rendered. CTR drama avoided. Moroccan CAA blocked my IP β success confirmed.
π¬ βTurns out drawing maps is harder than flying through them.β β Skye
### π§Ύ The CAA Form Saga (April 2025)
The CAA submission form was fully implemented using:
- `useActionState` from React 19 for async validation + response control
- Schema-driven layout using Zod and dynamic JSX generation
- Modular error handling with inline accessibility-friendly feedback
- `SiteSelector` custom component for dynamic zone selection
- Locale-aware translation of all labels and placeholders (`next-intl`)
- Future-proofed design for PDF generation and multilingual submission
This form is now the template for any future high-logic form on FlyMorocco or other apps.
π¬ βThe amount of logic this form contains is unhealthy. But it's clean.β β Skye
---
## πͺ Author
Skye β Paraglider pilot and instructor, Chaos Wielder, Front-End Dev, AI Architect, Mint Tea Enthusiast
---
## π§ββοΈ Want to Contribute?
This is a personal dev playground, not open source (yet).
Youβre welcome to star, fork, or fly by.
---
Β© 2025 Skye.cmd / FlyMorocco. All rights reserved.
This project is **not open source**. No reuse, redistribution, or derivative works permitted without express permission.