{"id":28327347,"url":"https://github.com/skye-flyhigh/flymorocco","last_synced_at":"2026-04-27T11:31:12.011Z","repository":{"id":285712318,"uuid":"959082244","full_name":"Skye-flyhigh/flymorocco","owner":"Skye-flyhigh","description":"just a migration of my old website, from hardcoded HTML CSS JS to modern frameworks Next.js","archived":false,"fork":false,"pushed_at":"2026-03-03T20:13:01.000Z","size":63867,"stargazers_count":1,"open_issues_count":6,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-03T21:36:59.572Z","etag":null,"topics":["daisyui-react","interactive-map","leaflet-map","nextjs","openair","openair-parser","pdf-generation","useactionstate","zod-validation"],"latest_commit_sha":null,"homepage":"https://flymorocco.info","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Skye-flyhigh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-02T08:36:41.000Z","updated_at":"2026-03-03T18:02:18.000Z","dependencies_parsed_at":"2025-04-02T09:34:15.463Z","dependency_job_id":"034c4a70-03c4-4dec-9c6e-4304c936d2ef","html_url":"https://github.com/Skye-flyhigh/flymorocco","commit_stats":null,"previous_names":["skye-flyhigh/flymorocco"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Skye-flyhigh/flymorocco","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skye-flyhigh%2Fflymorocco","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skye-flyhigh%2Fflymorocco/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skye-flyhigh%2Fflymorocco/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skye-flyhigh%2Fflymorocco/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Skye-flyhigh","download_url":"https://codeload.github.com/Skye-flyhigh/flymorocco/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skye-flyhigh%2Fflymorocco/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32335295,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["daisyui-react","interactive-map","leaflet-map","nextjs","openair","openair-parser","pdf-generation","useactionstate","zod-validation"],"created_at":"2025-05-26T02:18:27.512Z","updated_at":"2026-04-27T11:31:12.006Z","avatar_url":"https://github.com/Skye-flyhigh.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🪂 FlyMorocco\n\n**Multilingual paragliding hub for pilots exploring the skies of Morocco.**  \nBuilt with Next.js, Tailwind CSS, and the occasional chaos-fueled tea session.\n\n---\n\n## 🚀 Project Overview\n\nFlymorocco is a fully static, SEO-friendly, and i18n-ready web app tailored for paragliding pilots looking to fly in Morocco.  \nIt serves guide pages for multiple flying sites, dynamically rendered and maintained by a single JSON data source, localized in both **English** and **French**.\n\n---\n\n## ✨ Features\n\n### Core Platform\n\n- 🌍 **Multilingual** with `next-intl` (EN/FR)\n- 🪁 **Dynamic site guides** powered by slug-based routing\n- 🖼️ **Visual-first layout** to highlight the beauty of flying sites\n- 🔍 **SEO-ready** with custom meta tags per page\n- 🗺️ **Interactive airspace maps** with Morocco's official ENR 5.5 data\n\n### E-Commerce Booking System\n\n- 💳 **Multi-currency booking** (GBP, USD, EUR, CAD) through Wise\n- 👥 **Multi-participant support** with pilot detection and verification\n- 🏠 **Solo room options** with dynamic pricing calculations\n- 📧 **Professional email pipeline** (confirmations, notifications, verifications)\n- 🎯 **Marketing-optimized emails** with clickable tour banners\n- 📋 **PDF document generation** for CAA authorization forms\n- 🧑‍💻 **Google Spreadsheet integration** for booking management\n\n### Technical Excellence\n\n- ⚙️ **Type-safe data** validation with Zod schemas\n- 🔒 **Security features** with reCAPTCHA and input sanitization\n- 📱 **Responsive design** with accessibility built-in\n- 🚀 **Static generation** for optimal performance\n\n---\n\n## 🧠 Dev Stack\n\n- [Next.js 15](https://nextjs.org/) the goat 🐐\n- [Tailwind CSS](https://tailwindcss.com/) the 1000 pieces jigsaw puzzle of styling 🧩\n- [DaisyUI](https://daisyui.com/) the picture of the box of the puzzle 🧩\n- [Lucide React](https://lucide.dev/) for clean, consistent icons\n- [Zod](https://zod.dev/?id=objects) to break my app again\n- [React Leaflet](https://react-leaflet.js.org/), who does like a good map?\n- [OpenAir parser](https://www.npmjs.com/package/@openaip/openair-parser?activeTab=readme), need content for map\n- [pdf-lib](https://www.npmjs.com/package/pdf-lib), advanced pdf generation 📝\n- [sendGrid](https://www.npmjs.com/package/@sendgrid/mail), to send the advanced pdfs\n- [react-scroll-parallax](https://www.npmjs.com/package/react-scroll-parallax), smooth scrolling effects\n\n---\n\n## 🧠 Setup\n\n    bash\n    git clone https://github.com/skye-flyhigh/flymorocco.git\n    cd flymorocco\n    npm install\n    npm run dev\n\n---\n\n## 📂 Folder Structure Highlights\n\n    app/\n    ├── [locale]/\n    │   ├── layout.tsx         # Locale-aware layout \u003c\u003c Case of the missing E\n    │   ├── page.tsx           # Localized homepage\n    │   ├── components/        # 🪄 Magic 💫\n    │   └── site-guides/       # Dynamic 🏔️ (per location)\n    ├── layout.tsx             # Language overlay\n    ├── lib/\n    │   └── site.ts\n    ├── types/\n    │   └── siteMeta.ts        # Zod's schema validation for site guide meta\n    ├── i18n/                  # next-intl language package\n    └── middleware.ts          # i18n routing redirect\n\nThe messages folder for the translations are living outside of the src/app folder according to next-intl docs.\n\n    📂\n    ├── messages/\n    │   ├── en.json\n    │   └── fr.json\n    ├── public/images/\n    ├── src/app/\n\n---\n\n## 🔥 Developer Lore\n\n\u003e **“The Case of the Missing E”**\n\nDuring the i18n setup, a rogue param named `local` (missing the \"e\") hijacked the entire layout and crashed the app via a top-level `await`.  \nAfter hours of meticulous logs, terminal therapy, and a _French-accented scream_, the bug was identified.\n\n🧪 Resolved by explicitly setting:\n\n    const { local: locale } = resolvedParams;\n    // Official docs said it returns { locale }... THEY LIED. IT'S 'local'.\n    // Yes, I logged it. Yes, I screamed.\n\nAlso the correct solution is in `middleware.ts`, to force the correct `param` key\n\n    createMiddleware({\n        ...routing,\n        localeParam: 'locale' // \u003c\u003c WITH a 'e'\n    })\n\nThis project will proudly wear the battle scars of this journey.\n\n\u003e **\"🗺️ The Cartographic Conquest (April 2025)\"**\n\n“It started with a file… and ended in 20,000 lines of polygon geometry.”\n\n- Parsed Morocco’s official ENR 5.5 airspaces from OpenAir format using a hacked parser and caffeine-fueled determination\n- Resolved cryptic parser errors like \"Unknown altitude definition '3500'\" and \"Token 'DB' does not allow subsequent token 'AY'\" by reverse-engineering format expectations\n- Used fixGeometry: true to handle self-intersecting madness (and hoped nothing got lost in convex purgatory)\n- Successfully converted nested sectors, parachute zones, and TMA fragments into GeoJSON, rendered live with Leaflet\n- Deployed hoverable, paintable polygons with visual filtering (GSEC toggle) and type-based coloring\n\n📌 Status: All airspaces rendered. CTR drama avoided. Moroccan CAA blocked my IP — success confirmed.\n\n    💬 “Turns out drawing maps is harder than flying through them.” — Skye\n\n### 🧾 The CAA Form Saga (April 2025)\n\nThe CAA submission form was fully implemented using:\n\n- `useActionState` from React 19 for async validation + response control\n- Schema-driven layout using Zod and dynamic JSX generation\n- Modular error handling with inline accessibility-friendly feedback\n- `SiteSelector` custom component for dynamic zone selection\n- Locale-aware translation of all labels and placeholders (`next-intl`)\n- Future-proofed design for PDF generation and multilingual submission\n\nThis form is now the template for any future high-logic form on FlyMorocco or other apps.\n\n    💬 “The amount of logic this form contains is unhealthy. But it's clean.” — Skye\n\n---\n\n## 🪂 Author\n\nSkye – Paraglider pilot and instructor, Chaos Wielder, Front-End Dev, AI Architect, Mint Tea Enthusiast\n\n---\n\n## 🧙‍♂️ Want to Contribute?\n\nThis is a personal dev playground, not open source (yet).\nYou’re welcome to star, fork, or fly by.\n\n---\n\n© 2025 Skye.cmd / FlyMorocco. All rights reserved.  \nThis project is **not open source**. No reuse, redistribution, or derivative works permitted without express permission.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskye-flyhigh%2Fflymorocco","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskye-flyhigh%2Fflymorocco","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskye-flyhigh%2Fflymorocco/lists"}