diff --git a/src/Redux/Store.tsx b/src/Redux/Store.tsx index 444e72e..ecb7f5d 100644 --- a/src/Redux/Store.tsx +++ b/src/Redux/Store.tsx @@ -2,12 +2,14 @@ import { configureStore } from "@reduxjs/toolkit"; import { attractionsApi } from "./services/attractions.service"; import { citiesApi } from "./services/cities.service"; import { authApi } from "./services/auth.service"; +import { profileApi } from "./services/profile.service"; export const store = configureStore({ reducer: { [attractionsApi.reducerPath]: attractionsApi.reducer, [citiesApi.reducerPath]: citiesApi.reducer, - [authApi.reducerPath]:authApi.reducer + [authApi.reducerPath]: authApi.reducer, + [profileApi.reducerPath]: profileApi.reducer }, @@ -15,7 +17,8 @@ export const store = configureStore({ getDefaultMiddleware().concat( attractionsApi.middleware, citiesApi.middleware, - authApi.middleware + authApi.middleware, + profileApi.middleware ), }); export type RootState = ReturnType; diff --git a/src/Redux/services/profile.service.ts b/src/Redux/services/profile.service.ts new file mode 100644 index 0000000..9dcf61d --- /dev/null +++ b/src/Redux/services/profile.service.ts @@ -0,0 +1,33 @@ + +import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; +import { baseQuery } from "../baseQuery"; + +export const profileApi = createApi({ + reducerPath: "profileApi", + baseQuery, + + tagTypes: ["userDetails"], + + endpoints: (builder) => ({ + + getUserProfileDetails: builder.query({ + query: (id) => `/website/user/${id}`, + providesTags:["userDetails"] + }), + + updateUserProfileDetails: builder.mutation({ + query: ({ userDetails, userId }) => ({ // keep the name of the variables being passed here same as when calling the mutation hook + url: `/website/user/${userId}`, + method: "PUT", + body: userDetails + }), + invalidatesTags:["userDetails"] + }) + + }) +}); + +export const { + useGetUserProfileDetailsQuery, + useUpdateUserProfileDetailsMutation +} = profileApi; \ No newline at end of file diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx index b7df501..91c0d1c 100644 --- a/src/pages/ProfilePage.tsx +++ b/src/pages/ProfilePage.tsx @@ -1,11 +1,11 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { motion } from 'motion/react'; -import { - ArrowLeft, - User, - CreditCard, - Calendar, - MapPin, +import { + ArrowLeft, + User, + CreditCard, + Calendar, + MapPin, Settings, Download, QrCode, @@ -26,6 +26,8 @@ import { Badge } from '../components/ui/badge'; import Navbar from '../components/Navbar'; import { Footer } from '../components/Footer'; import { ImageWithFallback } from '../components/figma/ImageWithFallback'; +import { useGetUserProfileDetailsQuery, useUpdateUserProfileDetailsMutation } from '../Redux/services/profile.service'; +import { toast } from 'sonner'; interface ProfilePageProps { onBackClick: () => void; @@ -86,7 +88,7 @@ const mockPasses = [ usedAttractions: 8 }, { - id: '2', + id: '2', name: 'Melbourne Selective Card', city: 'Melbourne', type: 'Flexi Pass', @@ -160,26 +162,76 @@ export function ProfilePage({ currentPage }: ProfilePageProps) { const [activeTab, setActiveTab] = useState('profile'); - const [formData, setFormData] = useState(mockUserData); + const [formData, setFormData] = useState({ + firstName: '', + lastName: '', + email: '', + phone: '', + country: '', + address1: '', + address2: '', + city: '', + postalCode: '' + }); + + const userId = localStorage.getItem("userId") + const { data: userDetails, isLoading } = useGetUserProfileDetailsQuery(userId) + + useEffect(() => { + if (userDetails) { + setFormData({ + firstName: userDetails?.firstName, + lastName: userDetails?.lastName, + email: userDetails?.emailAddress, + phone: userDetails?.mobileNumber, + country: userDetails?.country, + address1: userDetails?.address1, + address2: userDetails?.address2, + city: userDetails?.cityName, + postalCode: userDetails?.zipCode + }) + } + + }, [userDetails]) + + const [updateUserProfileDetails] = useUpdateUserProfileDetailsMutation(); const handleInputChange = (field: string, value: string) => { setFormData(prev => ({ ...prev, [field]: value })); }; - const handleSaveProfile = () => { - console.log('Saving profile...', formData); - // Handle profile save + const handleSaveProfile = async () => { + try { + console.log("Saving profile...", formData); + const response = await updateUserProfileDetails({ userDetails: formData, userId }); + console.log(response) + toast.success("Profile updated successfully!"); + } catch (error) { + console.error("Error saving profile:", error); + toast.error("Failed to update profile. Please try again."); + } }; const activePasses = mockPasses.filter(pass => pass.status === 'active'); const expiredPasses = mockPasses.filter(pass => pass.status === 'expired'); + if (isLoading) { + return ( +
+
+
+

Loading...

+
+
+ ); + } + return (
{/* Navbar */} - {}} + onCityChange={() => { }} onHomeClick={onHomeClick} onMelbourneClick={onMelbourneClick} onPassesClick={onPassesClick} @@ -312,7 +364,7 @@ export function ProfilePage({
- handleInputChange('country', value)}> @@ -326,15 +378,33 @@ export function ProfilePage({ India Japan - + */} + handleInputChange('country', e.target.value)} + className="mt-1 font-poppins font-light" + />
- + handleInputChange('address', e.target.value)} + id="address1" + value={formData.address1} + onChange={(e) => handleInputChange('address1', e.target.value)} + className="mt-1 font-poppins font-light mb-4" + /> + + + handleInputChange('address2', e.target.value)} className="mt-1 font-poppins font-light" />
@@ -362,7 +432,7 @@ export function ProfilePage({ @@ -384,7 +454,7 @@ export function ProfilePage({ // Determine which pass type to show const hasUnlimitedPass = activePasses.some(pass => pass.type === 'Unlimited Pass'); const hasSelectivePass = activePasses.some(pass => pass.type === 'Flexi Pass'); - + if (hasUnlimitedPass) { return ( <> @@ -394,7 +464,7 @@ export function ProfilePage({ Melbourne Unlimited Card

- Unlimited access to 25+ attractions. Visit as many places as you want with one simple card. + Unlimited access to 25+ attractions. Visit as many places as you want with one simple card. Save up to 40% compared to individual tickets.

@@ -423,13 +493,13 @@ export function ProfilePage({ {/* Purchase CTA */}
- -
@@ -478,13 +548,13 @@ export function ProfilePage({ {/* Purchase CTA */}
- -
@@ -535,13 +605,13 @@ export function ProfilePage({ {/* Purchase CTA */}
- -
- +
Attractions: @@ -616,10 +686,10 @@ export function ProfilePage({ ))}
- + {/* Offers Button */}
-
- +
Attractions visited: @@ -689,7 +759,7 @@ export function ProfilePage({ >

My Itineraries

-
- +
@@ -728,8 +798,8 @@ export function ProfilePage({
-