main #6
@@ -1,19 +0,0 @@
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
export const fakeApi = createApi({
|
||||
reducerPath: 'fakeApi',
|
||||
baseQuery: fetchBaseQuery({
|
||||
baseUrl: " https://fakestoreapi.com",
|
||||
|
||||
}),
|
||||
endpoints: (builder) => ({
|
||||
getProducts: builder.query<any, void>({
|
||||
query: () => ({
|
||||
url: 'products',
|
||||
method: 'GET',
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export const { useGetProductsQuery} = fakeApi
|
||||
@@ -31,7 +31,14 @@ export function CitySelectionDialog({
|
||||
const { data: cities, isLoading } = useGetCityListWithBannerQuery({ search })
|
||||
|
||||
if (isLoading) {
|
||||
return <div>Loading...</div>
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#F95F62] mx-auto"></div>
|
||||
<p className="mt-4 text-gray-600">Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -113,8 +113,15 @@ export function LandingUpcomingCities() {
|
||||
|
||||
const { data, isLoading } = useGetUpcomingCitiesQuery(listType)
|
||||
|
||||
if(isLoading){
|
||||
return <div>Loading...</div>
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#F95F62] mx-auto"></div>
|
||||
<p className="mt-4 text-gray-600">Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const handleMouseDown = (e: React.MouseEvent) => {
|
||||
|
||||
@@ -31,7 +31,14 @@ export function AttractionDetailsPage({
|
||||
const { data: attraction, isLoading } = useGetAttractionDetailsByIdQuery(Number(attractionId));
|
||||
|
||||
if (isLoading) {
|
||||
return <div>loading...</div>
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#F95F62] mx-auto"></div>
|
||||
<p className="mt-4 text-gray-600">Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -40,7 +47,7 @@ export function AttractionDetailsPage({
|
||||
onSignInClick={onSignInClick}
|
||||
onSignOutClick={onSignOutClick}
|
||||
user={user}
|
||||
// showCitySubmenu={false}
|
||||
// showCitySubmenu={false}
|
||||
>
|
||||
<div className="container mx-auto px-4 pt-40 pb-16 max-w-6xl">
|
||||
{/* Back Button */}
|
||||
@@ -82,7 +89,7 @@ export function AttractionDetailsPage({
|
||||
{attraction.title}
|
||||
</span>{' '}
|
||||
<span className="text-[#2d3134]">
|
||||
Day Trip by {attraction.partner.businessName}
|
||||
Day Trip by {attraction.partner.businessName}
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
@@ -99,10 +106,10 @@ export function AttractionDetailsPage({
|
||||
</div>
|
||||
|
||||
{/* Gallery images */}
|
||||
{attraction.attractionGalleries.slice().map((image:any) => (
|
||||
{attraction.attractionGalleries.slice().map((image: any) => (
|
||||
<div key={image.id} className="col-span-1 row-span-1">
|
||||
<ImageWithFallback
|
||||
src={image.filePathUrl}
|
||||
src={image.filePathUrl}
|
||||
alt={`Gallery image ${image.id}`}
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
/>
|
||||
|
||||
@@ -230,7 +230,7 @@ export function AttractionsPage({
|
||||
const [selectedPassType, setSelectedPassType] = useState<string | null>(null);
|
||||
|
||||
const cityId = 1
|
||||
|
||||
|
||||
const { data: filterData, isLoading } = useGetAttractionFiltersQuery(cityId)
|
||||
const { data: attractions } = useGetCustomerAttractionsQuery({
|
||||
cityId, // required
|
||||
@@ -239,9 +239,16 @@ export function AttractionsPage({
|
||||
cardType: selectedPassType, // optional
|
||||
search, // optional
|
||||
});
|
||||
|
||||
|
||||
if (isLoading) {
|
||||
return <div>Loading...</div>
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#F95F62] mx-auto"></div>
|
||||
<p className="mt-4 text-gray-600">Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const handleAttractionClick = (attractionId: string) => {
|
||||
@@ -254,7 +261,7 @@ export function AttractionsPage({
|
||||
const showingFrom = 1;
|
||||
const showingTo = Math.min(12, attractions?.length);
|
||||
const totalItems = attractions?.length;
|
||||
|
||||
|
||||
function handlePassTypeSelection(key: string, checked: boolean) {
|
||||
if (checked) {
|
||||
setSelectedPassType(key); // only keep the newly selected one
|
||||
@@ -403,7 +410,7 @@ export function AttractionsPage({
|
||||
htmlFor={key}
|
||||
className="font-poppins text-sm text-[#414141] cursor-pointer flex-1 font-normal"
|
||||
>
|
||||
{key==="selective_pass" ?"Selective":"Unlimited"} ({count as number})
|
||||
{key === "selective_pass" ? "Selective" : "Unlimited"} ({count as number})
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
@@ -493,7 +500,7 @@ export function AttractionsPage({
|
||||
</div>
|
||||
<Button
|
||||
className="bg-primary hover:bg-primary/90 text-white font-poppins font-semibold text-xs px-4 min-h-[44px] min-w-[44px] h-[44px] whitespace-nowrap"
|
||||
onClick={(e:React.MouseEvent<HTMLButtonElement>) => {
|
||||
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
handleCheckoutClick();
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user