From 314c5b43b5a66a1bc6821e7411823a0bd137a43a Mon Sep 17 00:00:00 2001 From: "m@" <35651510+BlockSavvy@users.noreply.github.com> Date: Thu, 10 Apr 2025 16:10:48 -0500 Subject: [PATCH 1/6] chore: organize codebase and fix JetSeatVisualizer API - Archive SQL migrations, fix scripts, organize docs, fix API issues, consolidate utils --- app/api/jets/[id]/route.ts | 18 +++- .../fix-scripts/fix-crew-db.js | 0 .../fix-scripts/fix-status-constraint.js | 0 .../fix-scripts/run-add-missing-columns.js | 0 cookies.txt => archive/logs/cookies.txt | 0 .../logs/supabase_logs.csv | 0 .../Screen Shot 2025-03-31 at 6.06.36 PM.png | Bin .../Screen Shot 2025-03-31 at 6.10.15 PM.png | Bin .../sql/add_missing_columns_to_jets.sql | 0 .../sql/concierge_voice_tables.sql | 0 .../sql/data-exports/aircraft_models_rows.sql | 0 .../sql/data-exports/jet_interiors_rows.sql | 0 .../sql/data-exports/jets_rows.sql | 0 .../sql/fix-offers-status.sql | 0 .../sql/jetshare_seed.sql | 0 .../sql/migration_embedding_logs.sql | 0 .../sql/migration_fix_database_admin.sql | 0 .../sql/migration_fix_embedding_logs.sql | 0 .../sql/migration_fix_run_sql.sql | 0 seed-jets.sql => archive/sql/seed-jets.sql | 0 .../sql/seed_marketplace_offers.sql | 0 cleanup-report.md | 79 ++++++++++++++++++ .../feature-docs/AI-INFERENCE-SETUP-NOTES.md | 0 .../feature-docs/FIX-JETSHARE-STATUS.md | 0 .../feature-docs/FIX-STATUS-ISSUE.md | 0 .../JETSHARE-AI-CONCIERGE-DOCS.md | 0 .../feature-docs/PILOTS-CREW-FEATURE.md | 0 .../feature-docs/README-OPENAI.md | 0 .../feature-docs/README-jet-images.md | 0 .../project-docs/MIGRATION-NEXT15.md | 0 .../project-docs/PR-TEMPLATE-CONCIERGE.md | 0 lib/utils.ts | 45 +--------- 32 files changed, 98 insertions(+), 44 deletions(-) rename fix-crew-db.js => archive/fix-scripts/fix-crew-db.js (100%) rename fix-status-constraint.js => archive/fix-scripts/fix-status-constraint.js (100%) rename run-add-missing-columns.js => archive/fix-scripts/run-add-missing-columns.js (100%) rename cookies.txt => archive/logs/cookies.txt (100%) rename supabase_logs.csv => archive/logs/supabase_logs.csv (100%) rename Screen Shot 2025-03-31 at 6.06.36 PM.png => archive/screenshots/Screen Shot 2025-03-31 at 6.06.36 PM.png (100%) rename Screen Shot 2025-03-31 at 6.10.15 PM.png => archive/screenshots/Screen Shot 2025-03-31 at 6.10.15 PM.png (100%) rename add_missing_columns_to_jets.sql => archive/sql/add_missing_columns_to_jets.sql (100%) rename concierge_voice_tables.sql => archive/sql/concierge_voice_tables.sql (100%) rename aircraft_models_rows (2).sql => archive/sql/data-exports/aircraft_models_rows.sql (100%) rename jet_interiors_rows (1).sql => archive/sql/data-exports/jet_interiors_rows.sql (100%) rename jets_rows (3).sql => archive/sql/data-exports/jets_rows.sql (100%) rename fix-offers-status.sql => archive/sql/fix-offers-status.sql (100%) rename jetshare_seed.sql => archive/sql/jetshare_seed.sql (100%) rename migration_embedding_logs.sql => archive/sql/migration_embedding_logs.sql (100%) rename migration_fix_database_admin.sql => archive/sql/migration_fix_database_admin.sql (100%) rename migration_fix_embedding_logs.sql => archive/sql/migration_fix_embedding_logs.sql (100%) rename migration_fix_run_sql.sql => archive/sql/migration_fix_run_sql.sql (100%) rename seed-jets.sql => archive/sql/seed-jets.sql (100%) rename seed_marketplace_offers.sql => archive/sql/seed_marketplace_offers.sql (100%) create mode 100644 cleanup-report.md rename AI-INFERENCE-SETUP-NOTES.md => docs/feature-docs/AI-INFERENCE-SETUP-NOTES.md (100%) rename FIX-JETSHARE-STATUS.md => docs/feature-docs/FIX-JETSHARE-STATUS.md (100%) rename FIX-STATUS-ISSUE.md => docs/feature-docs/FIX-STATUS-ISSUE.md (100%) rename JETSHARE-AI-CONCIERGE-DOCS.md => docs/feature-docs/JETSHARE-AI-CONCIERGE-DOCS.md (100%) rename PILOTS-CREW-FEATURE.md => docs/feature-docs/PILOTS-CREW-FEATURE.md (100%) rename README-OPENAI.md => docs/feature-docs/README-OPENAI.md (100%) rename README-jet-images.md => docs/feature-docs/README-jet-images.md (100%) rename MIGRATION-NEXT15.md => docs/project-docs/MIGRATION-NEXT15.md (100%) rename PR-TEMPLATE-CONCIERGE.md => docs/project-docs/PR-TEMPLATE-CONCIERGE.md (100%) diff --git a/app/api/jets/[id]/route.ts b/app/api/jets/[id]/route.ts index 38920f16..5a1c1459 100644 --- a/app/api/jets/[id]/route.ts +++ b/app/api/jets/[id]/route.ts @@ -1,6 +1,6 @@ import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'; import { cookies } from 'next/headers'; -import { NextResponse } from 'next/server'; +import { NextRequest, NextResponse } from 'next/server'; import { GetRouteHandler, PostRouteHandler, PatchRouteHandler, DeleteRouteHandler, PutRouteHandler, IdParam } from '@/lib/types/route-types'; // Define interface for aircraft layout template @@ -54,7 +54,21 @@ export const GET: GetRouteHandler<{ id: string }> = async ( ) => { try { const { id } = await context.params; -const jet_id = id; + const jet_id = id; + + // Special case: If "default" is requested, return the default layout + if (jet_id === 'default') { + return NextResponse.json({ + jet: { + id: 'default', + model: 'Default Jet', + manufacturer: 'Generic', + capacity: 12 + }, + interior: null, + seatLayout: AIRCRAFT_LAYOUTS['default'] + }); + } // Initialize Supabase client const supabase = createServerComponentClient({ cookies }); diff --git a/fix-crew-db.js b/archive/fix-scripts/fix-crew-db.js similarity index 100% rename from fix-crew-db.js rename to archive/fix-scripts/fix-crew-db.js diff --git a/fix-status-constraint.js b/archive/fix-scripts/fix-status-constraint.js similarity index 100% rename from fix-status-constraint.js rename to archive/fix-scripts/fix-status-constraint.js diff --git a/run-add-missing-columns.js b/archive/fix-scripts/run-add-missing-columns.js similarity index 100% rename from run-add-missing-columns.js rename to archive/fix-scripts/run-add-missing-columns.js diff --git a/cookies.txt b/archive/logs/cookies.txt similarity index 100% rename from cookies.txt rename to archive/logs/cookies.txt diff --git a/supabase_logs.csv b/archive/logs/supabase_logs.csv similarity index 100% rename from supabase_logs.csv rename to archive/logs/supabase_logs.csv diff --git a/Screen Shot 2025-03-31 at 6.06.36 PM.png b/archive/screenshots/Screen Shot 2025-03-31 at 6.06.36 PM.png similarity index 100% rename from Screen Shot 2025-03-31 at 6.06.36 PM.png rename to archive/screenshots/Screen Shot 2025-03-31 at 6.06.36 PM.png diff --git a/Screen Shot 2025-03-31 at 6.10.15 PM.png b/archive/screenshots/Screen Shot 2025-03-31 at 6.10.15 PM.png similarity index 100% rename from Screen Shot 2025-03-31 at 6.10.15 PM.png rename to archive/screenshots/Screen Shot 2025-03-31 at 6.10.15 PM.png diff --git a/add_missing_columns_to_jets.sql b/archive/sql/add_missing_columns_to_jets.sql similarity index 100% rename from add_missing_columns_to_jets.sql rename to archive/sql/add_missing_columns_to_jets.sql diff --git a/concierge_voice_tables.sql b/archive/sql/concierge_voice_tables.sql similarity index 100% rename from concierge_voice_tables.sql rename to archive/sql/concierge_voice_tables.sql diff --git a/aircraft_models_rows (2).sql b/archive/sql/data-exports/aircraft_models_rows.sql similarity index 100% rename from aircraft_models_rows (2).sql rename to archive/sql/data-exports/aircraft_models_rows.sql diff --git a/jet_interiors_rows (1).sql b/archive/sql/data-exports/jet_interiors_rows.sql similarity index 100% rename from jet_interiors_rows (1).sql rename to archive/sql/data-exports/jet_interiors_rows.sql diff --git a/jets_rows (3).sql b/archive/sql/data-exports/jets_rows.sql similarity index 100% rename from jets_rows (3).sql rename to archive/sql/data-exports/jets_rows.sql diff --git a/fix-offers-status.sql b/archive/sql/fix-offers-status.sql similarity index 100% rename from fix-offers-status.sql rename to archive/sql/fix-offers-status.sql diff --git a/jetshare_seed.sql b/archive/sql/jetshare_seed.sql similarity index 100% rename from jetshare_seed.sql rename to archive/sql/jetshare_seed.sql diff --git a/migration_embedding_logs.sql b/archive/sql/migration_embedding_logs.sql similarity index 100% rename from migration_embedding_logs.sql rename to archive/sql/migration_embedding_logs.sql diff --git a/migration_fix_database_admin.sql b/archive/sql/migration_fix_database_admin.sql similarity index 100% rename from migration_fix_database_admin.sql rename to archive/sql/migration_fix_database_admin.sql diff --git a/migration_fix_embedding_logs.sql b/archive/sql/migration_fix_embedding_logs.sql similarity index 100% rename from migration_fix_embedding_logs.sql rename to archive/sql/migration_fix_embedding_logs.sql diff --git a/migration_fix_run_sql.sql b/archive/sql/migration_fix_run_sql.sql similarity index 100% rename from migration_fix_run_sql.sql rename to archive/sql/migration_fix_run_sql.sql diff --git a/seed-jets.sql b/archive/sql/seed-jets.sql similarity index 100% rename from seed-jets.sql rename to archive/sql/seed-jets.sql diff --git a/seed_marketplace_offers.sql b/archive/sql/seed_marketplace_offers.sql similarity index 100% rename from seed_marketplace_offers.sql rename to archive/sql/seed_marketplace_offers.sql diff --git a/cleanup-report.md b/cleanup-report.md new file mode 100644 index 00000000..b16b7321 --- /dev/null +++ b/cleanup-report.md @@ -0,0 +1,79 @@ +# JetStream Codebase Cleanup Report + +## Overview +This document outlines the changes made during the systematic cleanup and refactoring of the JetStream codebase, performed under the feature branch `feature/cleanup-archive-refactor`. + +## 1. SQL and Database Files +Moved the following SQL files to an organized archive structure: + +### Migrated to /archive/sql +- migration_fix_run_sql.sql +- migration_fix_database_admin.sql +- migration_fix_embedding_logs.sql +- migration_embedding_logs.sql +- concierge_voice_tables.sql +- fix-offers-status.sql +- seed_marketplace_offers.sql +- seed-jets.sql +- jetshare_seed.sql +- add_missing_columns_to_jets.sql + +### Migrated to /archive/sql/data-exports +- jets_rows.sql (renamed from "jets_rows (3).sql") +- jet_interiors_rows.sql (renamed from "jet_interiors_rows (1).sql") +- aircraft_models_rows.sql (renamed from "aircraft_models_rows (2).sql") + +## 2. Fix Scripts +Moved one-time data fix scripts to the archive: + +### Migrated to /archive/fix-scripts +- fix-crew-db.js +- fix-status-constraint.js +- run-add-missing-columns.js + +## 3. Documentation Organization +Organized documentation files into a more structured hierarchy: + +### Migrated to /docs/feature-docs +- AI-INFERENCE-SETUP-NOTES.md +- FIX-JETSHARE-STATUS.md +- FIX-STATUS-ISSUE.md +- JETSHARE-AI-CONCIERGE-DOCS.md +- PILOTS-CREW-FEATURE.md +- README-OPENAI.md +- README-jet-images.md + +### Migrated to /docs/project-docs +- MIGRATION-NEXT15.md +- PR-TEMPLATE-CONCIERGE.md + +## 4. Miscellaneous Files +Organized miscellaneous files into appropriate archive locations: + +### Migrated to /archive/logs +- supabase_logs.csv +- cookies.txt + +### Migrated to /archive/screenshots +- Screen Shot 2025-03-31 at 6.10.15 PM.png +- Screen Shot 2025-03-31 at 6.06.36 PM.png + +## 5. Bug Fixes + +### Fixed JetSeatVisualizer API Issue +- Modified `/app/api/jets/[id]/route.ts` to handle 'default' ID case specifically +- Added proper handling for the 'default' case to avoid database querying with invalid UUID +- Fixed NextRequest import to resolve TypeScript error + +## 6. Code Consolidation + +### Consolidated Utility Functions +- Removed duplicate formatting functions from `lib/utils.ts` +- Centralized formatting functions in `lib/utils/format.ts` +- Updated `lib/utils.ts` to re-export formatting functions to maintain backward compatibility + +## Next Steps +- Continue identifying and consolidating any other duplicated code +- Review and clean up unused dependencies in package.json +- Standardize naming conventions across the codebase +- Run linting and fix any style issues \ No newline at end of file diff --git a/AI-INFERENCE-SETUP-NOTES.md b/docs/feature-docs/AI-INFERENCE-SETUP-NOTES.md similarity index 100% rename from AI-INFERENCE-SETUP-NOTES.md rename to docs/feature-docs/AI-INFERENCE-SETUP-NOTES.md diff --git a/FIX-JETSHARE-STATUS.md b/docs/feature-docs/FIX-JETSHARE-STATUS.md similarity index 100% rename from FIX-JETSHARE-STATUS.md rename to docs/feature-docs/FIX-JETSHARE-STATUS.md diff --git a/FIX-STATUS-ISSUE.md b/docs/feature-docs/FIX-STATUS-ISSUE.md similarity index 100% rename from FIX-STATUS-ISSUE.md rename to docs/feature-docs/FIX-STATUS-ISSUE.md diff --git a/JETSHARE-AI-CONCIERGE-DOCS.md b/docs/feature-docs/JETSHARE-AI-CONCIERGE-DOCS.md similarity index 100% rename from JETSHARE-AI-CONCIERGE-DOCS.md rename to docs/feature-docs/JETSHARE-AI-CONCIERGE-DOCS.md diff --git a/PILOTS-CREW-FEATURE.md b/docs/feature-docs/PILOTS-CREW-FEATURE.md similarity index 100% rename from PILOTS-CREW-FEATURE.md rename to docs/feature-docs/PILOTS-CREW-FEATURE.md diff --git a/README-OPENAI.md b/docs/feature-docs/README-OPENAI.md similarity index 100% rename from README-OPENAI.md rename to docs/feature-docs/README-OPENAI.md diff --git a/README-jet-images.md b/docs/feature-docs/README-jet-images.md similarity index 100% rename from README-jet-images.md rename to docs/feature-docs/README-jet-images.md diff --git a/MIGRATION-NEXT15.md b/docs/project-docs/MIGRATION-NEXT15.md similarity index 100% rename from MIGRATION-NEXT15.md rename to docs/project-docs/MIGRATION-NEXT15.md diff --git a/PR-TEMPLATE-CONCIERGE.md b/docs/project-docs/PR-TEMPLATE-CONCIERGE.md similarity index 100% rename from PR-TEMPLATE-CONCIERGE.md rename to docs/project-docs/PR-TEMPLATE-CONCIERGE.md diff --git a/lib/utils.ts b/lib/utils.ts index 8dff2f5b..3ba93745 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,49 +1,10 @@ import { type ClassValue, clsx } from "clsx" import { twMerge } from "tailwind-merge" +import { formatDate, formatTime, formatCurrency } from "./utils/format" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } -/** - * Formats a date string to a human-readable format - * @param dateString - ISO date string - * @returns Formatted date (e.g., "Jan 5, 2023") - */ -export function formatDate(dateString: string): string { - const date = new Date(dateString); - return date.toLocaleDateString('en-US', { - month: 'short', - day: 'numeric', - year: 'numeric' - }); -} - -/** - * Formats a date string to display time only - * @param dateString - ISO date string - * @returns Formatted time (e.g., "2:30 PM") - */ -export function formatTime(dateString: string): string { - const date = new Date(dateString); - return date.toLocaleTimeString('en-US', { - hour: 'numeric', - minute: '2-digit', - hour12: true - }); -} - -/** - * Formats a number as currency - * @param amount - Number to format - * @param currency - Currency code (default: USD) - * @returns Formatted currency string - */ -export function formatCurrency(amount: number, currency: string = 'USD'): string { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency, - minimumFractionDigits: 0, - maximumFractionDigits: 0 - }).format(amount); -} +// Re-export formatting utilities from utils/format.ts +export { formatDate, formatTime, formatCurrency } From c3e0005ff958224704dfee316acd5171db8be64a Mon Sep 17 00:00:00 2001 From: "m@" <35651510+BlockSavvy@users.noreply.github.com> Date: Thu, 10 Apr 2025 16:12:53 -0500 Subject: [PATCH 2/6] chore: archive database fix and restore scripts, update cleanup report --- .../db/fix-scripts}/airport-flights-fixer.js | 0 .../db/fix-scripts}/final-flight-fixer.js | 0 .../db/fix-scripts}/fix-flights-direct.js | 0 .../fix-scripts}/fix-flights-sql-editor.sql | 0 .../db/fix-scripts}/fix-flights-v2.js | 0 .../fix-flights-with-airports.sql | 0 {db => archive/db/fix-scripts}/fix-flights.js | 0 .../db/fix-scripts}/fix-flights.sql | 0 .../db/fix-scripts}/flight-airports-fixer.js | 0 .../db/fix-scripts}/flight-fixer-backup.js | 0 .../db/fix-scripts}/flight-fixer.js | 0 .../db/restore-scripts}/restore-database.js | 0 .../restore-db-for-dashboard.sql | 0 .../db/restore-scripts}/restore-direct.js | 0 .../restore-jetstream-1-schema.sql | 0 .../restore-jetstream-2-crew-tables.sql | 0 .../restore-jetstream-3-jetshare-tables.sql | 0 .../restore-jetstream-4-rls-policies.sql | 0 .../restore-jetstream-5-triggers.sql | 0 .../restore-jetstream-6-seed-data.sql | 0 .../restore-jetstream-README.md | 0 .../restore-jetstream-complete.sql | 0 cleanup-report.md | 37 +++++++++++++++++++ 23 files changed, 37 insertions(+) rename {db => archive/db/fix-scripts}/airport-flights-fixer.js (100%) rename {db => archive/db/fix-scripts}/final-flight-fixer.js (100%) rename {db => archive/db/fix-scripts}/fix-flights-direct.js (100%) rename {db => archive/db/fix-scripts}/fix-flights-sql-editor.sql (100%) rename {db => archive/db/fix-scripts}/fix-flights-v2.js (100%) rename {db => archive/db/fix-scripts}/fix-flights-with-airports.sql (100%) rename {db => archive/db/fix-scripts}/fix-flights.js (100%) rename {db => archive/db/fix-scripts}/fix-flights.sql (100%) rename {db => archive/db/fix-scripts}/flight-airports-fixer.js (100%) rename {db => archive/db/fix-scripts}/flight-fixer-backup.js (100%) rename {db => archive/db/fix-scripts}/flight-fixer.js (100%) rename {db => archive/db/restore-scripts}/restore-database.js (100%) rename {db => archive/db/restore-scripts}/restore-db-for-dashboard.sql (100%) rename {db => archive/db/restore-scripts}/restore-direct.js (100%) rename {db => archive/db/restore-scripts}/restore-jetstream-1-schema.sql (100%) rename {db => archive/db/restore-scripts}/restore-jetstream-2-crew-tables.sql (100%) rename {db => archive/db/restore-scripts}/restore-jetstream-3-jetshare-tables.sql (100%) rename {db => archive/db/restore-scripts}/restore-jetstream-4-rls-policies.sql (100%) rename {db => archive/db/restore-scripts}/restore-jetstream-5-triggers.sql (100%) rename {db => archive/db/restore-scripts}/restore-jetstream-6-seed-data.sql (100%) rename {db => archive/db/restore-scripts}/restore-jetstream-README.md (100%) rename {db => archive/db/restore-scripts}/restore-jetstream-complete.sql (100%) diff --git a/db/airport-flights-fixer.js b/archive/db/fix-scripts/airport-flights-fixer.js similarity index 100% rename from db/airport-flights-fixer.js rename to archive/db/fix-scripts/airport-flights-fixer.js diff --git a/db/final-flight-fixer.js b/archive/db/fix-scripts/final-flight-fixer.js similarity index 100% rename from db/final-flight-fixer.js rename to archive/db/fix-scripts/final-flight-fixer.js diff --git a/db/fix-flights-direct.js b/archive/db/fix-scripts/fix-flights-direct.js similarity index 100% rename from db/fix-flights-direct.js rename to archive/db/fix-scripts/fix-flights-direct.js diff --git a/db/fix-flights-sql-editor.sql b/archive/db/fix-scripts/fix-flights-sql-editor.sql similarity index 100% rename from db/fix-flights-sql-editor.sql rename to archive/db/fix-scripts/fix-flights-sql-editor.sql diff --git a/db/fix-flights-v2.js b/archive/db/fix-scripts/fix-flights-v2.js similarity index 100% rename from db/fix-flights-v2.js rename to archive/db/fix-scripts/fix-flights-v2.js diff --git a/db/fix-flights-with-airports.sql b/archive/db/fix-scripts/fix-flights-with-airports.sql similarity index 100% rename from db/fix-flights-with-airports.sql rename to archive/db/fix-scripts/fix-flights-with-airports.sql diff --git a/db/fix-flights.js b/archive/db/fix-scripts/fix-flights.js similarity index 100% rename from db/fix-flights.js rename to archive/db/fix-scripts/fix-flights.js diff --git a/db/fix-flights.sql b/archive/db/fix-scripts/fix-flights.sql similarity index 100% rename from db/fix-flights.sql rename to archive/db/fix-scripts/fix-flights.sql diff --git a/db/flight-airports-fixer.js b/archive/db/fix-scripts/flight-airports-fixer.js similarity index 100% rename from db/flight-airports-fixer.js rename to archive/db/fix-scripts/flight-airports-fixer.js diff --git a/db/flight-fixer-backup.js b/archive/db/fix-scripts/flight-fixer-backup.js similarity index 100% rename from db/flight-fixer-backup.js rename to archive/db/fix-scripts/flight-fixer-backup.js diff --git a/db/flight-fixer.js b/archive/db/fix-scripts/flight-fixer.js similarity index 100% rename from db/flight-fixer.js rename to archive/db/fix-scripts/flight-fixer.js diff --git a/db/restore-database.js b/archive/db/restore-scripts/restore-database.js similarity index 100% rename from db/restore-database.js rename to archive/db/restore-scripts/restore-database.js diff --git a/db/restore-db-for-dashboard.sql b/archive/db/restore-scripts/restore-db-for-dashboard.sql similarity index 100% rename from db/restore-db-for-dashboard.sql rename to archive/db/restore-scripts/restore-db-for-dashboard.sql diff --git a/db/restore-direct.js b/archive/db/restore-scripts/restore-direct.js similarity index 100% rename from db/restore-direct.js rename to archive/db/restore-scripts/restore-direct.js diff --git a/db/restore-jetstream-1-schema.sql b/archive/db/restore-scripts/restore-jetstream-1-schema.sql similarity index 100% rename from db/restore-jetstream-1-schema.sql rename to archive/db/restore-scripts/restore-jetstream-1-schema.sql diff --git a/db/restore-jetstream-2-crew-tables.sql b/archive/db/restore-scripts/restore-jetstream-2-crew-tables.sql similarity index 100% rename from db/restore-jetstream-2-crew-tables.sql rename to archive/db/restore-scripts/restore-jetstream-2-crew-tables.sql diff --git a/db/restore-jetstream-3-jetshare-tables.sql b/archive/db/restore-scripts/restore-jetstream-3-jetshare-tables.sql similarity index 100% rename from db/restore-jetstream-3-jetshare-tables.sql rename to archive/db/restore-scripts/restore-jetstream-3-jetshare-tables.sql diff --git a/db/restore-jetstream-4-rls-policies.sql b/archive/db/restore-scripts/restore-jetstream-4-rls-policies.sql similarity index 100% rename from db/restore-jetstream-4-rls-policies.sql rename to archive/db/restore-scripts/restore-jetstream-4-rls-policies.sql diff --git a/db/restore-jetstream-5-triggers.sql b/archive/db/restore-scripts/restore-jetstream-5-triggers.sql similarity index 100% rename from db/restore-jetstream-5-triggers.sql rename to archive/db/restore-scripts/restore-jetstream-5-triggers.sql diff --git a/db/restore-jetstream-6-seed-data.sql b/archive/db/restore-scripts/restore-jetstream-6-seed-data.sql similarity index 100% rename from db/restore-jetstream-6-seed-data.sql rename to archive/db/restore-scripts/restore-jetstream-6-seed-data.sql diff --git a/db/restore-jetstream-README.md b/archive/db/restore-scripts/restore-jetstream-README.md similarity index 100% rename from db/restore-jetstream-README.md rename to archive/db/restore-scripts/restore-jetstream-README.md diff --git a/db/restore-jetstream-complete.sql b/archive/db/restore-scripts/restore-jetstream-complete.sql similarity index 100% rename from db/restore-jetstream-complete.sql rename to archive/db/restore-scripts/restore-jetstream-complete.sql diff --git a/cleanup-report.md b/cleanup-report.md index b16b7321..6ec91051 100644 --- a/cleanup-report.md +++ b/cleanup-report.md @@ -23,6 +23,32 @@ Moved the following SQL files to an organized archive structure: - jet_interiors_rows.sql (renamed from "jet_interiors_rows (1).sql") - aircraft_models_rows.sql (renamed from "aircraft_models_rows (2).sql") +### Migrated to /archive/db/fix-scripts +- flight-airports-fixer.js +- flight-fixer-backup.js +- flight-fixer.js +- fix-flights-direct.js +- fix-flights-sql-editor.sql +- fix-flights-v2.js +- fix-flights-with-airports.sql +- fix-flights.js +- fix-flights.sql +- final-flight-fixer.js +- airport-flights-fixer.js + +### Migrated to /archive/db/restore-scripts +- restore-jetstream-1-schema.sql +- restore-jetstream-2-crew-tables.sql +- restore-jetstream-3-jetshare-tables.sql +- restore-jetstream-4-rls-policies.sql +- restore-jetstream-5-triggers.sql +- restore-jetstream-6-seed-data.sql +- restore-jetstream-complete.sql +- restore-jetstream-README.md +- restore-direct.js +- restore-db-for-dashboard.sql +- restore-database.js + ## 2. Fix Scripts Moved one-time data fix scripts to the archive: @@ -72,6 +98,17 @@ Organized miscellaneous files into appropriate archive locations: - Centralized formatting functions in `lib/utils/format.ts` - Updated `lib/utils.ts` to re-export formatting functions to maintain backward compatibility +## 7. Next.js Configuration +- Analyzed both next.config.js and next.config.mjs +- Found significant differences in functionality: + - next.config.mjs supports user config merging and ES modules + - next.config.js has different webpack configs and module resolution +- Kept both files as they appear to serve different purposes + +## 8. TODO Items +- Identified several TODO comments and temporary settings in config files +- Left TypeScript error handling settings in place as they appear to be intentional + ## Next Steps - Continue identifying and consolidating any other duplicated code - Review and clean up unused dependencies in package.json From 255d6831c376f62cadf55719eeacf933d7cb2bd6 Mon Sep 17 00:00:00 2001 From: "m@" <35651510+BlockSavvy@users.noreply.github.com> Date: Thu, 10 Apr 2025 16:37:08 -0500 Subject: [PATCH 3/6] fix: improve seat visualizer accuracy and fix cookies handling --- app/api/jets/[id]/route.ts | 87 ++++++++++++++++++++++++++++----- cleanup-report.md | 19 +++++-- migrations/jet_seat_layouts.sql | 62 +++++++++++++++++++++++ 3 files changed, 151 insertions(+), 17 deletions(-) create mode 100644 migrations/jet_seat_layouts.sql diff --git a/app/api/jets/[id]/route.ts b/app/api/jets/[id]/route.ts index 5a1c1459..653e7747 100644 --- a/app/api/jets/[id]/route.ts +++ b/app/api/jets/[id]/route.ts @@ -70,8 +70,9 @@ export const GET: GetRouteHandler<{ id: string }> = async ( }); } - // Initialize Supabase client - const supabase = createServerComponentClient({ cookies }); + // Initialize Supabase client with the correct cookie handling + const cookieStore = cookies(); + const supabase = createServerComponentClient({ cookies: () => cookieStore }); // Get jet data const { data: jet, error: jetError } = await supabase @@ -104,16 +105,29 @@ export const GET: GetRouteHandler<{ id: string }> = async ( // Continue without interior data } - // Get jet seat layout data - const { data: seatLayoutData, error: layoutError } = await supabase - .from('jet_seat_layouts') - .select('layout') - .eq('jet_id', jet_id) - .maybeSingle(); + // Try to get jet seat layout data - but handle the case where table doesn't exist yet + let seatLayoutData = null; + let layoutError = null; - if (layoutError) { - console.error('Error fetching seat layout:', layoutError); - // Continue without seat layout data + try { + const result = await supabase + .from('jet_seat_layouts') + .select('layout') + .eq('jet_id', jet_id) + .maybeSingle(); + + seatLayoutData = result.data; + layoutError = result.error; + + if (layoutError && layoutError.code === '42P01') { + console.log('Seat layout table does not exist yet, using default layout'); + layoutError = null; // Clear the error since we'll handle it gracefully + } else if (layoutError) { + console.error('Error fetching seat layout:', layoutError); + } + } catch (err) { + console.error('Error in seat layout query:', err); + // Continue without layout data } // Create a default seat layout based on capacity if no custom layout exists @@ -124,9 +138,10 @@ export const GET: GetRouteHandler<{ id: string }> = async ( seatLayout = seatLayoutData.layout; } else { // Create a default layout based on capacity - const capacity = jet.capacity || (interior?.seats || 4); + const capacity = jet.capacity || (interior?.seats ? parseInt(interior.seats) : 4); let rows = 0; let seatsPerRow = 0; + let skipPositions: number[][] = []; // Calculate a reasonable layout if (capacity <= 4) { @@ -135,24 +150,70 @@ export const GET: GetRouteHandler<{ id: string }> = async ( } else if (capacity <= 8) { rows = 2; seatsPerRow = 4; + + // Handle non-standard counts (5, 6, 7) + const extraSeats = (rows * seatsPerRow) - capacity; + if (extraSeats > 0) { + // Skip seats from the last row, right to left + for (let i = 0; i < extraSeats; i++) { + skipPositions.push([rows - 1, seatsPerRow - 1 - i]); + } + } } else if (capacity <= 12) { rows = 3; seatsPerRow = 4; + + // Handle non-standard counts (9, 10, 11) + const extraSeats = (rows * seatsPerRow) - capacity; + if (extraSeats > 0) { + // Skip seats from the last row, right to left + for (let i = 0; i < extraSeats; i++) { + skipPositions.push([rows - 1, seatsPerRow - 1 - i]); + } + } } else if (capacity <= 16) { rows = 4; seatsPerRow = 4; + + // Handle non-standard counts (13, 14, 15) + const extraSeats = (rows * seatsPerRow) - capacity; + if (extraSeats > 0) { + // Skip seats from the last row, right to left + for (let i = 0; i < extraSeats; i++) { + skipPositions.push([rows - 1, seatsPerRow - 1 - i]); + } + } } else { rows = 5; seatsPerRow = 4; + + // Handle non-standard counts (17, 18, 19) + const extraSeats = (rows * seatsPerRow) - capacity; + if (extraSeats > 0) { + // Skip seats from the last row, right to left + for (let i = 0; i < extraSeats; i++) { + skipPositions.push([rows - 1, seatsPerRow - 1 - i]); + } + } } + // Create the layout object seatLayout = { rows, seatsPerRow, layoutType: 'standard', totalSeats: capacity, - skipPositions: [] + seatMap: { + skipPositions: skipPositions + } }; + + console.log(`Generated layout for ${capacity} seats:`, { + rows, + seatsPerRow, + skipPositions, + actualSeats: (rows * seatsPerRow) - skipPositions.length + }); } // Return combined data diff --git a/cleanup-report.md b/cleanup-report.md index 6ec91051..ac7c5b71 100644 --- a/cleanup-report.md +++ b/cleanup-report.md @@ -49,6 +49,9 @@ Moved the following SQL files to an organized archive structure: - restore-db-for-dashboard.sql - restore-database.js +### Added New Migrations +- Added jet_seat_layouts.sql migration to create the missing table for custom jet seat layouts + ## 2. Fix Scripts Moved one-time data fix scripts to the archive: @@ -86,10 +89,17 @@ Organized miscellaneous files into appropriate archive locations: ## 5. Bug Fixes -### Fixed JetSeatVisualizer API Issue +### Fixed JetSeatVisualizer API Issues - Modified `/app/api/jets/[id]/route.ts` to handle 'default' ID case specifically -- Added proper handling for the 'default' case to avoid database querying with invalid UUID -- Fixed NextRequest import to resolve TypeScript error +- Fixed cookie handling to properly handle cookies as per Next.js requirements +- Improved error handling for missing jet_seat_layouts table +- Added jet_seat_layouts.sql migration to create the required table + +### Fixed Seat Visualizer Display Issues +- Enhanced the layout calculation to properly handle non-standard seat counts +- Added proper skipPositions calculation to ensure correct number of seats display +- Now displays exactly the number of seats specified in the jet's capacity or interior.seats +- Improved logging to help troubleshoot seat layout issues ## 6. Code Consolidation @@ -113,4 +123,5 @@ Organized miscellaneous files into appropriate archive locations: - Continue identifying and consolidating any other duplicated code - Review and clean up unused dependencies in package.json - Standardize naming conventions across the codebase -- Run linting and fix any style issues \ No newline at end of file +- Run linting and fix any style issues +- Create comprehensive documentation for both the main application and JetShare feature \ No newline at end of file diff --git a/migrations/jet_seat_layouts.sql b/migrations/jet_seat_layouts.sql new file mode 100644 index 00000000..20573d8a --- /dev/null +++ b/migrations/jet_seat_layouts.sql @@ -0,0 +1,62 @@ +-- Create jet_seat_layouts table if it doesn't exist +CREATE TABLE IF NOT EXISTS public.jet_seat_layouts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + jet_id UUID NOT NULL REFERENCES public.jets(id) ON DELETE CASCADE, + layout JSONB NOT NULL, -- Store the entire seat layout JSON object + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() +); + +-- Add comment to table +COMMENT ON TABLE public.jet_seat_layouts IS 'Custom seat layouts for specific jets'; + +-- Add row-level security policies +ALTER TABLE public.jet_seat_layouts ENABLE ROW LEVEL SECURITY; + +-- Policy to allow reading by any authenticated user +CREATE POLICY "Allow reading layouts" + ON public.jet_seat_layouts + FOR SELECT + USING (true); + +-- Policy to allow jet owners to update layouts +CREATE POLICY "Allow owners to update layouts" + ON public.jet_seat_layouts + FOR UPDATE + USING ( + auth.uid() IN ( + SELECT j.owner_id + FROM public.jets j + WHERE j.id = jet_seat_layouts.jet_id + ) + ); + +-- Policy to allow jet owners to insert layouts +CREATE POLICY "Allow owners to insert layouts" + ON public.jet_seat_layouts + FOR INSERT + WITH CHECK ( + auth.uid() IN ( + SELECT j.owner_id + FROM public.jets j + WHERE j.id = jet_seat_layouts.jet_id + ) + ); + +-- Create index for faster lookup +CREATE INDEX IF NOT EXISTS jet_seat_layouts_jet_id_idx ON public.jet_seat_layouts(jet_id); + +-- Add function to update updated_at timestamp +CREATE OR REPLACE FUNCTION update_jet_seat_layouts_updated_at() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = NOW(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Create trigger to update timestamp +CREATE TRIGGER update_jet_seat_layouts_updated_at +BEFORE UPDATE ON public.jet_seat_layouts +FOR EACH ROW +EXECUTE FUNCTION update_jet_seat_layouts_updated_at(); \ No newline at end of file From 5aa774341ef3ea4538ba32042536888e08bfba5d Mon Sep 17 00:00:00 2001 From: "m@" <35651510+BlockSavvy@users.noreply.github.com> Date: Thu, 10 Apr 2025 17:08:34 -0500 Subject: [PATCH 4/6] fix: improve admin navigation and fix cookie handling in APIs --- app/admin/components/sidebar.tsx | 115 +++++++-- app/admin/jets/layout-editor.tsx | 331 ++++++++++++++++++++++++++ app/admin/jets/layouts/page.tsx | 27 +++ app/api/admin/jets/route.ts | 38 +++ app/api/admin/jets/setLayout/route.ts | 162 +++++++++++++ app/api/jets/[id]/route.ts | 64 ++--- 6 files changed, 675 insertions(+), 62 deletions(-) create mode 100644 app/admin/jets/layout-editor.tsx create mode 100644 app/admin/jets/layouts/page.tsx create mode 100644 app/api/admin/jets/route.ts create mode 100644 app/api/admin/jets/setLayout/route.ts diff --git a/app/admin/components/sidebar.tsx b/app/admin/components/sidebar.tsx index 740ab26e..788764d8 100644 --- a/app/admin/components/sidebar.tsx +++ b/app/admin/components/sidebar.tsx @@ -12,11 +12,25 @@ import { UserCog, BrainCircuit, Database, - Braces + Braces, + Grid } from 'lucide-react'; +// Define the type for navigation items +type NavItem = { + name: string; + href: string | undefined; + icon: any; + isCategory?: boolean; + submenu?: { + name: string; + href: string; + icon?: any; + }[]; +}; + // Define navigation items -const navigationItems = [ +const navigationItems: NavItem[] = [ { name: 'Overview', href: '/admin/overview', @@ -29,8 +43,20 @@ const navigationItems = [ }, { name: 'Jets', - href: '/admin/jets', - icon: Plane + href: undefined, + icon: Plane, + isCategory: true, + submenu: [ + { + name: 'Jets List', + href: '/admin/jets' + }, + { + name: 'Seat Layouts', + href: '/admin/jets/layouts', + icon: Grid + } + ] }, { name: 'JetStream Flights', @@ -77,28 +103,71 @@ export default function Sidebar() { diff --git a/app/admin/jets/layout-editor.tsx b/app/admin/jets/layout-editor.tsx new file mode 100644 index 00000000..35ff965b --- /dev/null +++ b/app/admin/jets/layout-editor.tsx @@ -0,0 +1,331 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from '@/components/ui/card'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { toast } from 'sonner'; +import { Loader2, Check, RefreshCw, Save } from 'lucide-react'; + +type PresetLayout = { + value: string; + label: string; +}; + +type PresetCategory = { + label: string; + options: PresetLayout[]; +}; + +type PresetLayouts = { + [key: string]: PresetCategory; +}; + +type Jet = { + id: string; + model: string; + manufacturer: string; + capacity: number; +}; + +type SeatLayout = { + rows: number; + seatsPerRow: number; + layoutType: string; + totalSeats: number; + seatMap?: { + skipPositions?: number[][]; + customPositions?: { row: number; col: number; id: string }[]; + }; +}; + +export default function JetLayoutEditor() { + const [jets, setJets] = useState([]); + const [selectedJetId, setSelectedJetId] = useState(''); + const [selectedJet, setSelectedJet] = useState(null); + const [currentLayout, setCurrentLayout] = useState(null); + const [presetLayouts, setPresetLayouts] = useState(null); + const [selectedPresetCategory, setSelectedPresetCategory] = useState(''); + const [selectedPresetLayout, setSelectedPresetLayout] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const [isSaving, setIsSaving] = useState(false); + const [isSuccess, setIsSuccess] = useState(false); + + // Load all jets + useEffect(() => { + async function loadJets() { + try { + const response = await fetch('/api/admin/jets'); + if (!response.ok) { + throw new Error('Failed to load jets'); + } + const data = await response.json(); + setJets(data.jets || []); + } catch (error) { + console.error('Error loading jets:', error); + toast.error('Failed to load jets'); + } + } + + loadJets(); + }, []); + + // Load preset layouts + useEffect(() => { + async function loadPresetLayouts() { + try { + const response = await fetch('/api/admin/jets/setLayout'); + if (!response.ok) { + throw new Error('Failed to load preset layouts'); + } + const data = await response.json(); + setPresetLayouts(data.presetLayouts || {}); + } catch (error) { + console.error('Error loading preset layouts:', error); + toast.error('Failed to load preset layouts'); + } + } + + loadPresetLayouts(); + }, []); + + // Load current layout when a jet is selected + useEffect(() => { + if (!selectedJetId) { + setCurrentLayout(null); + setSelectedJet(null); + return; + } + + async function loadJetLayout() { + setIsLoading(true); + try { + const response = await fetch(`/api/jets/${selectedJetId}`); + if (!response.ok) { + throw new Error('Failed to load jet layout'); + } + const data = await response.json(); + setCurrentLayout(data.seatLayout || null); + setSelectedJet(data.jet || null); + } catch (error) { + console.error('Error loading jet layout:', error); + toast.error('Failed to load jet layout'); + } finally { + setIsLoading(false); + } + } + + loadJetLayout(); + }, [selectedJetId]); + + // Generate layout from preset selection + function generateLayoutFromPreset() { + if (!selectedPresetLayout || !selectedJet) return; + + const [rows, cols] = selectedPresetLayout.split('x').map(Number); + + // Calculate total seats based on the preset + const totalSeats = rows * cols; + + // If the total seats don't match the jet capacity, we'll adapt + // The seat layout will display exactly the selected preset configuration + + const newLayout: SeatLayout = { + rows, + seatsPerRow: cols, + layoutType: 'custom', + totalSeats: Math.min(totalSeats, selectedJet.capacity || totalSeats), + seatMap: { + skipPositions: [] + } + }; + + // If the jet capacity is less than the total preset seats, + // add skipPositions for the extra seats + if (selectedJet.capacity < totalSeats) { + const extraSeats = totalSeats - selectedJet.capacity; + for (let i = 0; i < extraSeats; i++) { + const row = Math.floor((totalSeats - 1 - i) / cols); + const col = (totalSeats - 1 - i) % cols; + newLayout.seatMap!.skipPositions!.push([row, col]); + } + } + + setCurrentLayout(newLayout); + } + + // Save the current layout to the database + async function saveLayout() { + if (!selectedJetId || !currentLayout) return; + + setIsSaving(true); + try { + const response = await fetch('/api/admin/jets/setLayout', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + jetId: selectedJetId, + layout: currentLayout + }), + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.error || 'Failed to save layout'); + } + + toast.success('Seat layout saved successfully'); + setIsSuccess(true); + + // Reset success state after 2 seconds + setTimeout(() => { + setIsSuccess(false); + }, 2000); + } catch (error) { + console.error('Error saving layout:', error); + toast.error(error instanceof Error ? error.message : 'Failed to save layout'); + } finally { + setIsSaving(false); + } + } + + return ( + + + Jet Seat Layout Editor + Configure custom seating layouts for jets + + + {/* Jet Selection */} +
+ + +
+ + {isLoading ? ( +
+ + Loading jet configuration... +
+ ) : selectedJet && ( + <> + {/* Current Layout Display */} +
+

Current Layout

+ {currentLayout ? ( +
+

Rows: {currentLayout.rows}

+

Seats per row: {currentLayout.seatsPerRow}

+

Total seats: {currentLayout.totalSeats}

+

Layout type: {currentLayout.layoutType}

+

Skipped positions: {currentLayout.seatMap?.skipPositions?.length || 0}

+
+ ) : ( +

No custom layout configured. Using auto-generated layout.

+ )} +
+ + {/* Layout Presets */} + {presetLayouts && ( +
+

Configure New Layout

+ +
+ + +
+ + {selectedPresetCategory && ( +
+ + +
+ )} + + {selectedPresetLayout && ( + + )} +
+ )} + + )} +
+ + + + +
+ ); +} \ No newline at end of file diff --git a/app/admin/jets/layouts/page.tsx b/app/admin/jets/layouts/page.tsx new file mode 100644 index 00000000..10ef28ee --- /dev/null +++ b/app/admin/jets/layouts/page.tsx @@ -0,0 +1,27 @@ +import { Metadata } from 'next'; +import JetLayoutEditor from '../layout-editor'; + +export const metadata: Metadata = { + title: 'Jet Seat Layout Editor', + description: 'Configure custom seating layouts for jets', +}; + +export default function JetLayoutsPage() { + return ( +
+
+
+

+ Jet Seat Layouts +

+

+ Configure how seats are arranged in each jet for the JetShare mobile app. +

+
+
+
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/api/admin/jets/route.ts b/app/api/admin/jets/route.ts new file mode 100644 index 00000000..fa2b234c --- /dev/null +++ b/app/api/admin/jets/route.ts @@ -0,0 +1,38 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { cookies } from 'next/headers'; +import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'; + +export async function GET(request: NextRequest) { + try { + // Initialize Supabase client with proper cookie handling + const cookieStore = cookies(); + const supabase = createServerComponentClient({ cookies: () => cookieStore }); + + // Check if the user is authenticated + const { data: { user } } = await supabase.auth.getUser(); + + if (!user) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }); + } + + // Get all jets + const { data: jets, error } = await supabase + .from('jets') + .select('id, model, manufacturer, capacity, image_url') + .order('manufacturer', { ascending: true }) + .order('model', { ascending: true }); + + if (error) { + console.error('Error fetching jets:', error); + return NextResponse.json({ error: 'Failed to fetch jets' }, { status: 500 }); + } + + return NextResponse.json({ jets }); + } catch (error) { + console.error('Error processing request:', error); + return NextResponse.json({ + error: 'Internal server error', + details: error instanceof Error ? error.message : 'Unknown error' + }, { status: 500 }); + } +} \ No newline at end of file diff --git a/app/api/admin/jets/setLayout/route.ts b/app/api/admin/jets/setLayout/route.ts new file mode 100644 index 00000000..530cd49f --- /dev/null +++ b/app/api/admin/jets/setLayout/route.ts @@ -0,0 +1,162 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { cookies } from 'next/headers'; +import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'; + +// Admin-only endpoint to set a custom seat layout for a jet +export async function POST(request: NextRequest) { + try { + // Initialize Supabase client with proper cookie handling + const cookieStore = cookies(); + const supabase = createServerComponentClient({ cookies: () => cookieStore }); + + // Check if the user is authenticated and has admin privileges + const { data: { user } } = await supabase.auth.getUser(); + + if (!user) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }); + } + + // Check if user is an admin (modify this according to your auth system) + const { data: isAdmin } = await supabase + .from('profiles') + .select('is_admin') + .eq('id', user.id) + .single(); + + if (!isAdmin?.is_admin) { + return NextResponse.json({ error: 'Admin privileges required' }, { status: 403 }); + } + + // Parse the request body + const { jetId, layout } = await request.json(); + + if (!jetId || !layout) { + return NextResponse.json({ error: 'Missing required fields: jetId, layout' }, { status: 400 }); + } + + // Ensure layout has required properties + if (!layout.rows || !layout.seatsPerRow || !layout.totalSeats) { + return NextResponse.json({ + error: 'Layout must include rows, seatsPerRow, and totalSeats' + }, { status: 400 }); + } + + // Check if the jet exists + const { data: jet, error: jetError } = await supabase + .from('jets') + .select('id') + .eq('id', jetId) + .single(); + + if (jetError || !jet) { + return NextResponse.json({ error: 'Jet not found' }, { status: 404 }); + } + + // Check if a layout already exists for this jet + const { data: existingLayout } = await supabase + .from('jet_seat_layouts') + .select('id') + .eq('jet_id', jetId) + .maybeSingle(); + + let result; + + if (existingLayout) { + // Update existing layout + result = await supabase + .from('jet_seat_layouts') + .update({ layout }) + .eq('jet_id', jetId) + .select(); + } else { + // Insert new layout + result = await supabase + .from('jet_seat_layouts') + .insert({ jet_id: jetId, layout }) + .select(); + } + + if (result.error) { + console.error('Database error:', result.error); + return NextResponse.json({ + error: 'Failed to save layout', + details: result.error.message + }, { status: 500 }); + } + + return NextResponse.json({ + success: true, + message: 'Seat layout saved successfully', + data: result.data[0] + }); + + } catch (error) { + console.error('Error processing request:', error); + return NextResponse.json({ + error: 'Internal server error', + details: error instanceof Error ? error.message : 'Unknown error' + }, { status: 500 }); + } +} + +// Admin-only endpoint to get all available preset layouts +export async function GET(request: NextRequest) { + try { + // Initialize Supabase client with proper cookie handling + const cookieStore = cookies(); + const supabase = createServerComponentClient({ cookies: () => cookieStore }); + + // Check if the user is authenticated + const { data: { user } } = await supabase.auth.getUser(); + + if (!user) { + return NextResponse.json({ error: 'Authentication required' }, { status: 401 }); + } + + // Return available preset layouts + const presetLayouts = { + // 2 seats per row layouts + 'private-2-seats': { + label: '2 seats per row (A1-A2, B1-B2, etc.)', + options: [ + { value: '2x2', label: '2 rows x 2 seats (4 total)' }, + { value: '3x2', label: '3 rows x 2 seats (6 total)' }, + { value: '4x2', label: '4 rows x 2 seats (8 total)' }, + { value: '5x2', label: '5 rows x 2 seats (10 total)' }, + { value: '6x2', label: '6 rows x 2 seats (12 total)' }, + { value: '7x2', label: '7 rows x 2 seats (14 total)' }, + { value: '8x2', label: '8 rows x 2 seats (16 total)' }, + ] + }, + // 3 seats per row layouts + 'mid-size-3-seats': { + label: '3 seats per row (A1-A3, B1-B3, etc.)', + options: [ + { value: '3x3', label: '3 rows x 3 seats (9 total)' }, + { value: '4x3', label: '4 rows x 3 seats (12 total)' }, + { value: '5x3', label: '5 rows x 3 seats (15 total)' }, + { value: '6x3', label: '6 rows x 3 seats (18 total)' }, + { value: '7x3', label: '7 rows x 3 seats (21 total)' }, + ] + }, + // 4 seats per row layouts + 'commercial-4-seats': { + label: '4 seats per row (A1-A4, B1-B4, etc.)', + options: [ + { value: '3x4', label: '3 rows x 4 seats (12 total)' }, + { value: '4x4', label: '4 rows x 4 seats (16 total)' }, + { value: '5x4', label: '5 rows x 4 seats (20 total)' }, + { value: '6x4', label: '6 rows x 4 seats (24 total)' }, + ] + } + }; + + return NextResponse.json({ presetLayouts }); + + } catch (error) { + console.error('Error processing request:', error); + return NextResponse.json({ + error: 'Internal server error' + }, { status: 500 }); + } +} \ No newline at end of file diff --git a/app/api/jets/[id]/route.ts b/app/api/jets/[id]/route.ts index 653e7747..b94ee308 100644 --- a/app/api/jets/[id]/route.ts +++ b/app/api/jets/[id]/route.ts @@ -143,56 +143,42 @@ export const GET: GetRouteHandler<{ id: string }> = async ( let seatsPerRow = 0; let skipPositions: number[][] = []; - // Calculate a reasonable layout + // Configure typical aircraft layout - prioritize 2 seats per row for most jets if (capacity <= 4) { + // For very small jets, 2 rows of 2 seats rows = 2; seatsPerRow = 2; - } else if (capacity <= 8) { - rows = 2; - seatsPerRow = 4; - - // Handle non-standard counts (5, 6, 7) - const extraSeats = (rows * seatsPerRow) - capacity; - if (extraSeats > 0) { - // Skip seats from the last row, right to left - for (let i = 0; i < extraSeats; i++) { - skipPositions.push([rows - 1, seatsPerRow - 1 - i]); - } - } - } else if (capacity <= 12) { - rows = 3; - seatsPerRow = 4; + } else if (capacity <= 16) { + // For most private jets, use 2 seats per row + seatsPerRow = 2; + rows = Math.ceil(capacity / seatsPerRow); - // Handle non-standard counts (9, 10, 11) - const extraSeats = (rows * seatsPerRow) - capacity; - if (extraSeats > 0) { - // Skip seats from the last row, right to left - for (let i = 0; i < extraSeats; i++) { - skipPositions.push([rows - 1, seatsPerRow - 1 - i]); - } + // Handle odd number of seats by skipping the last position + if (capacity % 2 !== 0) { + skipPositions.push([rows - 1, 1]); // Skip last seat in last row } - } else if (capacity <= 16) { - rows = 4; - seatsPerRow = 4; + } else if (capacity <= 30) { + // For larger jets, use 3 seats per row + seatsPerRow = 3; + rows = Math.ceil(capacity / seatsPerRow); - // Handle non-standard counts (13, 14, 15) - const extraSeats = (rows * seatsPerRow) - capacity; - if (extraSeats > 0) { - // Skip seats from the last row, right to left - for (let i = 0; i < extraSeats; i++) { - skipPositions.push([rows - 1, seatsPerRow - 1 - i]); + // Handle seats that don't fill the last row + const lastRowPositions = capacity % seatsPerRow; + if (lastRowPositions > 0) { + for (let i = lastRowPositions; i < seatsPerRow; i++) { + skipPositions.push([rows - 1, i]); } } } else { - rows = 5; + // For commercial aircraft, use 4 seats per row seatsPerRow = 4; + rows = Math.ceil(capacity / seatsPerRow); - // Handle non-standard counts (17, 18, 19) - const extraSeats = (rows * seatsPerRow) - capacity; - if (extraSeats > 0) { - // Skip seats from the last row, right to left - for (let i = 0; i < extraSeats; i++) { - skipPositions.push([rows - 1, seatsPerRow - 1 - i]); + // Handle seats that don't fill the last row + const lastRowPositions = capacity % seatsPerRow; + if (lastRowPositions > 0) { + for (let i = lastRowPositions; i < seatsPerRow; i++) { + skipPositions.push([rows - 1, i]); } } } From 05511e1843ec49e3f20fc8ee3bafc617daaea588 Mon Sep 17 00:00:00 2001 From: "m@" <35651510+BlockSavvy@users.noreply.github.com> Date: Thu, 10 Apr 2025 17:31:11 -0500 Subject: [PATCH 5/6] fix: use createClient() from supabase-server.ts to resolve auth issues --- app/admin/jets/layout-editor.tsx | 40 +++++++++++++++++++++++++-- app/api/admin/jets/route.ts | 15 ++-------- app/api/admin/jets/setLayout/route.ts | 40 ++++----------------------- 3 files changed, 46 insertions(+), 49 deletions(-) diff --git a/app/admin/jets/layout-editor.tsx b/app/admin/jets/layout-editor.tsx index 35ff965b..ff6ccaec 100644 --- a/app/admin/jets/layout-editor.tsx +++ b/app/admin/jets/layout-editor.tsx @@ -55,15 +55,25 @@ export default function JetLayoutEditor() { useEffect(() => { async function loadJets() { try { + setIsLoading(true); const response = await fetch('/api/admin/jets'); + if (!response.ok) { + if (response.status === 401) { + // Let the app's built-in auth system handle redirects for authentication + toast.error('Authentication required'); + return; + } throw new Error('Failed to load jets'); } + const data = await response.json(); setJets(data.jets || []); } catch (error) { console.error('Error loading jets:', error); toast.error('Failed to load jets'); + } finally { + setIsLoading(false); } } @@ -75,9 +85,15 @@ export default function JetLayoutEditor() { async function loadPresetLayouts() { try { const response = await fetch('/api/admin/jets/setLayout'); + if (!response.ok) { + if (response.status === 401) { + // Let the app's built-in auth system handle redirects + return; + } throw new Error('Failed to load preset layouts'); } + const data = await response.json(); setPresetLayouts(data.presetLayouts || {}); } catch (error) { @@ -172,6 +188,13 @@ export default function JetLayoutEditor() { }); if (!response.ok) { + // Handle 401 authentication errors using the app's built-in auth system + if (response.status === 401) { + toast.error('Authentication required'); + setIsSaving(false); + return; + } + const errorData = await response.json(); throw new Error(errorData.error || 'Failed to save layout'); } @@ -203,7 +226,10 @@ export default function JetLayoutEditor() { { + // Handle state update in event handler, not during render + setSelectedPresetCategory(value); + // Reset the layout selection when category changes + setSelectedPresetLayout(''); + }} > @@ -270,7 +301,10 @@ export default function JetLayoutEditor() {