mirror of
https://github.com/velocitatem/PHANTOM.git
synced 2026-05-31 08:33:36 +00:00
chore: moving route elsewhere and align
This commit is contained in:
@@ -9,98 +9,98 @@ import { transformProduct, type Flight, type AirlineProduct } from '@/lib/airlin
|
|||||||
import type { EventName } from '@/lib/events';
|
import type { EventName } from '@/lib/events';
|
||||||
|
|
||||||
const dispatchInteraction = (eventName: EventName, productId?: string, metadata?: Record<string, unknown>) => {
|
const dispatchInteraction = (eventName: EventName, productId?: string, metadata?: Record<string, unknown>) => {
|
||||||
const e = new CustomEvent('definedInteraction', {
|
const e = new CustomEvent('definedInteraction', {
|
||||||
detail: { eventName, productId, metadata },
|
detail: { eventName, productId, metadata },
|
||||||
});
|
});
|
||||||
document.dispatchEvent(e);
|
document.dispatchEvent(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function AirlineProductPage() {
|
export default function AirlineProductPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { addItem } = useCart();
|
const { addItem } = useCart();
|
||||||
const [product, setProduct] = useState<Flight | null>(null);
|
const [product, setProduct] = useState<Flight | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [added, setAdded] = useState(false);
|
const [added, setAdded] = useState(false);
|
||||||
|
|
||||||
const productId = params.id as string;
|
const productId = params.id as string;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchProduct = async () => {
|
const fetchProduct = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/products/${productId}`);
|
const res = await fetch(`/api/products/${productId}`);
|
||||||
if (!res.ok) throw new Error(`Failed to fetch: ${res.status}`);
|
if (!res.ok) throw new Error(`Failed to fetch: ${res.status}`);
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
const transformed = transformProduct(json.data as AirlineProduct);
|
const transformed = transformProduct(json.data as AirlineProduct);
|
||||||
setProduct(transformed);
|
setProduct(transformed);
|
||||||
|
|
||||||
// fire learn_more_about_item event when product loads
|
// fire learn_more_about_item event when product loads
|
||||||
dispatchInteraction('learn_more_about_item', productId, {
|
dispatchInteraction('learn_more_about_item', productId, {
|
||||||
type: 'airline',
|
type: 'airline',
|
||||||
dateIndex: transformed.dateIndex,
|
dateIndex: transformed.dateIndex,
|
||||||
flightType: transformed.flightType,
|
flightType: transformed.flightType,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
setError(e instanceof Error ? e.message : 'Failed to load product');
|
||||||
|
console.error('[FETCH_FLIGHT_ERROR]', e);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchProduct();
|
||||||
|
}, [productId]);
|
||||||
|
|
||||||
|
const handleAddToCart = () => {
|
||||||
|
if (!product) return;
|
||||||
|
|
||||||
|
addItem({
|
||||||
|
id: productId,
|
||||||
|
type: 'airline',
|
||||||
|
name: product.flightType,
|
||||||
|
price: product.basePrice,
|
||||||
|
metadata: {
|
||||||
|
departure: product.departure,
|
||||||
|
arrival: product.arrival,
|
||||||
|
duration: product.duration,
|
||||||
|
cabinClass: product.cabinClass,
|
||||||
|
},
|
||||||
|
dateIndex: product.dateIndex,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
|
||||||
setError(e instanceof Error ? e.message : 'Failed to load product');
|
dispatchInteraction('add_item_to_cart', productId, {
|
||||||
console.error('[FETCH_FLIGHT_ERROR]', e);
|
type: 'airline',
|
||||||
} finally {
|
price: product.basePrice,
|
||||||
setLoading(false);
|
});
|
||||||
}
|
|
||||||
|
setAdded(true);
|
||||||
|
setTimeout(() => setAdded(false), 2000);
|
||||||
};
|
};
|
||||||
fetchProduct();
|
|
||||||
}, [productId]);
|
|
||||||
|
|
||||||
const handleAddToCart = () => {
|
return (
|
||||||
if (!product) return;
|
<>
|
||||||
|
<Navigation />
|
||||||
|
<main className="max-w-4xl mx-auto px-4 py-8">
|
||||||
|
{loading && <div className="text-center py-8">Loading flight details...</div>}
|
||||||
|
{error && <div className="text-red-500 text-center py-8">{error}</div>}
|
||||||
|
|
||||||
addItem({
|
{!loading && !error && product && (
|
||||||
id: productId,
|
<>
|
||||||
type: 'airline',
|
<button
|
||||||
name: product.flightType,
|
onClick={() => router.back()}
|
||||||
price: product.basePrice,
|
className="mt-6 text-blue-600 hover:underline"
|
||||||
metadata: {
|
>
|
||||||
departure: product.departure,
|
← Back to flights
|
||||||
arrival: product.arrival,
|
</button>
|
||||||
duration: product.duration,
|
<AirlineDetails
|
||||||
cabinClass: product.cabinClass,
|
product={product}
|
||||||
},
|
onAddToCart={handleAddToCart}
|
||||||
dateIndex: product.dateIndex,
|
addedToCart={added}
|
||||||
});
|
/>
|
||||||
|
|
||||||
dispatchInteraction('add_item_to_cart', productId, {
|
</>
|
||||||
type: 'airline',
|
)}
|
||||||
price: product.basePrice,
|
</main>
|
||||||
});
|
</>
|
||||||
|
);
|
||||||
setAdded(true);
|
|
||||||
setTimeout(() => setAdded(false), 2000);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Navigation />
|
|
||||||
<main className="max-w-4xl mx-auto px-4 py-8">
|
|
||||||
{loading && <div className="text-center py-8">Loading flight details...</div>}
|
|
||||||
{error && <div className="text-red-500 text-center py-8">{error}</div>}
|
|
||||||
|
|
||||||
{!loading && !error && product && (
|
|
||||||
<>
|
|
||||||
<AirlineDetails
|
|
||||||
product={product}
|
|
||||||
onAddToCart={handleAddToCart}
|
|
||||||
addedToCart={added}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={() => router.back()}
|
|
||||||
className="mt-6 text-blue-600 hover:underline"
|
|
||||||
>
|
|
||||||
← Back to flights
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</main>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,98 +9,98 @@ import { transformProduct, type Hotel, type HotelProduct } from '@/lib/hotel-uti
|
|||||||
import type { EventName } from '@/lib/events';
|
import type { EventName } from '@/lib/events';
|
||||||
|
|
||||||
const dispatchInteraction = (eventName: EventName, productId?: string, metadata?: Record<string, unknown>) => {
|
const dispatchInteraction = (eventName: EventName, productId?: string, metadata?: Record<string, unknown>) => {
|
||||||
const e = new CustomEvent('definedInteraction', {
|
const e = new CustomEvent('definedInteraction', {
|
||||||
detail: { eventName, productId, metadata },
|
detail: { eventName, productId, metadata },
|
||||||
});
|
});
|
||||||
document.dispatchEvent(e);
|
document.dispatchEvent(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function HotelProductPage() {
|
export default function HotelProductPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { addItem } = useCart();
|
const { addItem } = useCart();
|
||||||
const [product, setProduct] = useState<Hotel | null>(null);
|
const [product, setProduct] = useState<Hotel | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [added, setAdded] = useState(false);
|
const [added, setAdded] = useState(false);
|
||||||
|
|
||||||
const productId = params.id as string;
|
const productId = params.id as string;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchProduct = async () => {
|
const fetchProduct = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/products/${productId}`);
|
const res = await fetch(`/api/products/${productId}`);
|
||||||
if (!res.ok) throw new Error(`Failed to fetch: ${res.status}`);
|
if (!res.ok) throw new Error(`Failed to fetch: ${res.status}`);
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
const transformed = transformProduct(json.data as HotelProduct);
|
const transformed = transformProduct(json.data as HotelProduct);
|
||||||
setProduct(transformed);
|
setProduct(transformed);
|
||||||
|
|
||||||
// fire learn_more_about_item event when product loads
|
// fire learn_more_about_item event when product loads
|
||||||
dispatchInteraction('learn_more_about_item', productId, {
|
dispatchInteraction('learn_more_about_item', productId, {
|
||||||
type: 'hotel',
|
type: 'hotel',
|
||||||
dateIndex: transformed.dateIndex,
|
dateIndex: transformed.dateIndex,
|
||||||
roomType: transformed.roomType,
|
roomType: transformed.roomType,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
setError(e instanceof Error ? e.message : 'Failed to load product');
|
||||||
|
console.error('[FETCH_HOTEL_ERROR]', e);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchProduct();
|
||||||
|
}, [productId]);
|
||||||
|
|
||||||
|
const handleAddToCart = () => {
|
||||||
|
if (!product) return;
|
||||||
|
|
||||||
|
addItem({
|
||||||
|
id: productId,
|
||||||
|
type: 'hotel',
|
||||||
|
name: product.name,
|
||||||
|
price: product.pricePerNight,
|
||||||
|
metadata: {
|
||||||
|
roomType: product.roomType,
|
||||||
|
nights: product.nights,
|
||||||
|
checkIn: product.checkIn,
|
||||||
|
checkOut: product.checkOut,
|
||||||
|
},
|
||||||
|
dateIndex: product.dateIndex,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
|
||||||
setError(e instanceof Error ? e.message : 'Failed to load product');
|
dispatchInteraction('add_item_to_cart', productId, {
|
||||||
console.error('[FETCH_HOTEL_ERROR]', e);
|
type: 'hotel',
|
||||||
} finally {
|
price: product.pricePerNight,
|
||||||
setLoading(false);
|
});
|
||||||
}
|
|
||||||
|
setAdded(true);
|
||||||
|
setTimeout(() => setAdded(false), 2000);
|
||||||
};
|
};
|
||||||
fetchProduct();
|
|
||||||
}, [productId]);
|
|
||||||
|
|
||||||
const handleAddToCart = () => {
|
return (
|
||||||
if (!product) return;
|
<>
|
||||||
|
<Navigation />
|
||||||
|
<main className="max-w-4xl mx-auto px-4 py-8">
|
||||||
|
{loading && <div className="text-center py-8">Loading hotel details...</div>}
|
||||||
|
{error && <div className="text-red-500 text-center py-8">{error}</div>}
|
||||||
|
|
||||||
addItem({
|
{!loading && !error && product && (
|
||||||
id: productId,
|
<>
|
||||||
type: 'hotel',
|
<button
|
||||||
name: product.name,
|
onClick={() => router.back()}
|
||||||
price: product.pricePerNight,
|
className="mt-6 text-blue-600 hover:underline"
|
||||||
metadata: {
|
>
|
||||||
roomType: product.roomType,
|
← Back to rooms
|
||||||
nights: product.nights,
|
</button>
|
||||||
checkIn: product.checkIn,
|
<HotelDetails
|
||||||
checkOut: product.checkOut,
|
product={product}
|
||||||
},
|
onAddToCart={handleAddToCart}
|
||||||
dateIndex: product.dateIndex,
|
addedToCart={added}
|
||||||
});
|
/>
|
||||||
|
|
||||||
dispatchInteraction('add_item_to_cart', productId, {
|
</>
|
||||||
type: 'hotel',
|
)}
|
||||||
price: product.pricePerNight,
|
</main>
|
||||||
});
|
</>
|
||||||
|
);
|
||||||
setAdded(true);
|
|
||||||
setTimeout(() => setAdded(false), 2000);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Navigation />
|
|
||||||
<main className="max-w-4xl mx-auto px-4 py-8">
|
|
||||||
{loading && <div className="text-center py-8">Loading hotel details...</div>}
|
|
||||||
{error && <div className="text-red-500 text-center py-8">{error}</div>}
|
|
||||||
|
|
||||||
{!loading && !error && product && (
|
|
||||||
<>
|
|
||||||
<HotelDetails
|
|
||||||
product={product}
|
|
||||||
onAddToCart={handleAddToCart}
|
|
||||||
addedToCart={added}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={() => router.back()}
|
|
||||||
className="mt-6 text-blue-600 hover:underline"
|
|
||||||
>
|
|
||||||
← Back to rooms
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</main>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user