From b907162457a180971c1e09145f8c40f57d4c4b2a Mon Sep 17 00:00:00 2001 From: priyanshuvish Date: Fri, 27 Mar 2026 12:43:34 +0530 Subject: [PATCH] working left on homepage blog --- src/components/AboutUs.tsx | 259 ++-- src/components/CTABannerSection.tsx | 47 +- src/components/CourseCard.tsx | 6 +- src/components/KautilyaFacility.tsx | 1078 ++++++++--------- src/components/LearningOnline.tsx | 28 +- src/components/ProgrammeDetail.tsx | 981 +++++++++++---- src/components/TestimonialsSection.tsx | 73 +- src/components/WebinarDetail.tsx | 2 +- src/components/Webinars.tsx | 624 ++++------ src/components/services/CultureCompetence.tsx | 542 +++++---- src/components/services/ExecutiveCoaching.tsx | 542 +++++---- .../services/LeadershipDevelopment.tsx | 94 +- .../LeadershipPipelineDevelopment.tsx | 80 +- .../services/ManagementDevelopment.tsx | 80 +- src/components/ui/dialog.tsx | 4 +- src/pages/HomePage.tsx | 23 +- src/redux/services/aboutUsApi.ts | 11 + src/redux/services/courseApi.ts | 204 +++- src/redux/services/homepageApi.ts | 28 + src/redux/services/learningFacilityApi.ts | 122 ++ src/redux/services/webinarApi.ts | 128 ++ src/redux/store/Store.tsx | 7 + src/styles/globals.css | 40 +- 23 files changed, 2973 insertions(+), 2030 deletions(-) create mode 100644 src/redux/services/learningFacilityApi.ts create mode 100644 src/redux/services/webinarApi.ts diff --git a/src/components/AboutUs.tsx b/src/components/AboutUs.tsx index a335788..682af19 100644 --- a/src/components/AboutUs.tsx +++ b/src/components/AboutUs.tsx @@ -30,56 +30,10 @@ import { TestimonialsSection } from './TestimonialsSection'; import { Button } from './ui/button'; import { FullScreenLoader } from './FullScreenLoader'; -// Leadership Orientations Data -const leadershipOrientations = [ - { name: 'Thinking', icon: Brain, description: 'Strategic and analytical mindset' }, - { name: 'Risk Appetite', icon: TrendingUp, description: 'Calculated risk-taking approach' }, - { name: 'Power', icon: Shield, description: 'Authority and influence dynamics' }, - { name: 'Interpersonal/Political', icon: Users, description: 'Relationship and network building' }, - { name: 'Ambition', icon: Target, description: 'Drive for achievement and growth' }, - { name: 'Trust', icon: Heart, description: 'Building confidence and reliability' }, - { name: 'Learning', icon: BookOpen, description: 'Continuous development mindset' }, - { name: 'Nurturance', icon: Heart, description: 'Supporting and developing others' }, - { name: 'Result/Closure', icon: CheckCircle, description: 'Focus on outcomes and completion' } -]; -// Our Uniqueness Data -const uniquenessPoints = [ - { - icon: Target, - title: 'Context & Strategy Alignment', - description: 'We align our work to the client\'s specific context & strategy' - }, - { - icon: BookOpen, - title: 'Research-Anchored Approach', - description: 'Our work is anchored on research and work of scholars' - }, - { - icon: Users, - title: 'Client-Specific Needs', - description: 'We blend this with the specific needs of the client' - }, - { - icon: Puzzle, - title: 'Co-Creation Process', - description: 'We co-create the design with our clients' - } -]; - -// Benefits Data -const benefits = [ - 'We use proprietary exercises, custom written cases, curated films and proprietary tools', - 'Facilitate insights on the connect between one\'s leadership orientations and their leadership abilities', - 'We create learning at an individual level and at a group level', - 'Our designs focus on application and practice', - 'We bring in the connect of the learning to the Business contexts', - 'We recommend that the Leadership intervention is designed for a period of 12-15 months with multiple touch points which can constitute a combination of classroom, fire side chats, one-on-one sessions, address by an expert, use of profilers, accessing online content on concepts and accomplished leaders\' experiences' -]; - -// Team Members Data with Full Profiles (Static - can be kept or also fetched from API if needed) -const staticTeamMembers = [ - { +// Static detailed team member data for modal +const staticTeamMembersDetails = { + 'Mr. K Ramkumar': { name: 'Mr. K Ramkumar', role: 'Managing Director', image: Ramkumar, @@ -102,12 +56,12 @@ He co-created the ICICI Manipal Academy for Banking and Insurance, which inducte 'Executive Director on ICICI Bank Board', 'Created ICICI Manipal Academy (12,000 leaders trained)', 'Founded ICICI Academy for Skills (35,000+ youth skilled)', - 'Author of “Leveraging Human Capital” (McGraw Hill)' + 'Author of "Leveraging Human Capital" (McGraw Hill)' ], clientWork: 'Guided leadership development across ICICI Group and worked with Manipal Global Education to groom future banking leaders.', boardRoles: 'Former Board Member of ICICI Prudential Life, ICICI Ventures; served on CSR and leadership committees.' }, - { + 'Mr. R. Muralidharan': { name: 'Mr. R. Muralidharan', role: 'Practice Head – Leadership Development', image: Muralidharan, @@ -133,7 +87,7 @@ At ICICI Bank, he was part of the founding team in 1994 and rose to become GM clientWork: 'Worked with public and private banks, financial services firms, and non-profits on leadership and customer service transformation.', boardRoles: 'Held board positions in business and non-profits; Vice-Chair, Customer Service Excellence Foundation.' }, - { + 'Ms. Aparna Nair': { name: 'Ms. Aparna Nair', role: 'Practice Head – Leadership Development', image: Aparna, @@ -159,7 +113,7 @@ She is certified in MBTI and OPQ, has applied Balanced Scorecard frameworks, and clientWork: 'Worked with Godrej & Boyce, ICICI Prudential, Citi WAI, WNS, ThyssenKrupp, and others across pharma, BFSI, retail, auto, and private equity.', boardRoles: 'Independent Woman Director; held leadership positions at ICICI Bank and Blue Dart-FedEx.' }, - { + 'Mr. V. Swaminathan': { name: 'Mr. V. Swaminathan', role: 'Practice Head – Leadership Development', image: Swaminathan, @@ -185,7 +139,7 @@ He stepped down as Joint President of Kotak Mahindra Bank in 2021 before joining clientWork: 'Extensive work with BFSI organizations and leadership development initiatives at scale.', boardRoles: 'Key member of Kotak’s Management Committee; contributor to strategic boards within Kotak divisions.' }, - { + 'Mr. Balaji Chandrakumar': { name: 'Mr. Balaji Chandrakumar', role: 'Practice Head – Leadership Development', image: Balaji, @@ -211,7 +165,7 @@ Earlier, he worked in consulting with top Indian firms and began his HR journey clientWork: 'Worked with leading companies in telecom, food, and HR consulting sectors across India and SE Asia.', boardRoles: 'Advisor in HR capability building across organizations.' }, - { + 'Mr. Ramesh Padmanabhan': { name: 'Mr. Ramesh Padmanabhan', role: 'Practice Head – Leadership Development', image: Ramesh, @@ -237,7 +191,7 @@ He has consistently worked on capability building and leadership development alo clientWork: 'Significant work in BFSI sector; tailored leadership development for managers and executives.', boardRoles: 'Served on MANCOM and strategic boards in ICICI, Dhanlaxmi, and ADCB India.' }, - { + 'Ms. Diju S': { name: 'Ms. Diju S', role: 'Practice Head – Leadership Development', image: Diju, @@ -263,35 +217,19 @@ After a career break, she joined KLC as Practice Head. She now co-creates leader clientWork: 'Worked with BFSI clients and KLC partners to create custom leadership programs.', boardRoles: 'Active in leadership forums and project management at KLC.' } -]; +}; - -// Loading Skeleton Component -const AboutUsSkeleton = () => ( -
- {/* Hero Section Skeleton */} -
-
-
-
-
-
-
-
-
-
-
-
- - {/* Add more skeleton sections as needed */} -
Loading...
-
-); +// Helper function to get member details by name +const getMemberDetails = (nameRole: string) => { + // Extract the name from "Name - Role" format + const name = nameRole.split(' - ')[0]; + return staticTeamMembersDetails[name as keyof typeof staticTeamMembersDetails] || null; +}; export function AboutUs() { const [isVisible, setIsVisible] = useState(false); const [expandedValue, setExpandedValue] = useState('context'); - const [selectedMember, setSelectedMember] = useState(null); + const [selectedMember, setSelectedMember] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); // Fetch About Us data from API @@ -304,13 +242,13 @@ export function AboutUs() { id: testimonial.id || index, name: testimonial.name || "Anonymous", role: testimonial.designation || "Client", - company: undefined, // Company not provided in API response - avatar: testimonial.profile_photo_url || undefined, // If you have profile photo in API + company: undefined, + avatar: testimonial.profile_photo_url || undefined, image: testimonial.profile_photo_url || undefined, quote: testimonial.content || "", - rating: 5, // Default rating since API doesn't provide rating + rating: 5, isVideo: !!testimonial.video_url, - videoThumbnail: testimonial.video_thumbnail_url || testimonial.profile_photo_url, // If you have thumbnail + videoThumbnail: testimonial.video_thumbnail_url || testimonial.profile_photo_url, videoUrl: testimonial.video_url || undefined })); }; @@ -318,8 +256,29 @@ export function AboutUs() { // Transform the testimonials const testimonialsData = transformTestimonials(aboutUsData?.testimonials || []); - const handleMemberClick = (member: typeof staticTeamMembers[0]) => { - setSelectedMember(member); + // Get team members from API + const apiTeamMembers = aboutUsData?.our_team || []; + + const handleMemberClick = (member: any) => { + // Get detailed static data for the clicked member + const memberDetails = getMemberDetails(member.name_role); + if (memberDetails) { + setSelectedMember(memberDetails); + } else { + // Fallback to API data if no static details found + setSelectedMember({ + name: member.name_role.split(' - ')[0], + role: member.name_role.split(' - ')[1] || 'Team Member', + image: member.photo_url, + experience: member.bio, + fullBio: member.bio, + expertise: [], + education: '', + achievements: [], + clientWork: '', + boardRoles: '' + }); + } setIsModalOpen(true); }; @@ -376,8 +335,6 @@ export function AboutUs() { }; }, []); - // Show loading skeleton while fetching data - if (isLoading) { return (
@@ -386,7 +343,6 @@ export function AboutUs() { ); } - // Show error state if API call fails if (isError) { return (
@@ -480,7 +436,6 @@ export function AboutUs() {

{aboutUsData?.how_we_work_title || "How We Work"}

- {/* Four Key Points Grid - Using API data if available, otherwise fallback to static */}
{(aboutUsData?.how_we_work && aboutUsData.how_we_work.length > 0) ? ( aboutUsData.how_we_work.map((item, index) => ( @@ -512,7 +467,6 @@ export function AboutUs() { )) ) : ( - // Fallback to static data if API data is not available <> - {/* Split Layout - Left: Eyebrow Text, Right: Main Heading */}
- {/* Left Side - Eyebrow Text */}
@@ -632,7 +584,6 @@ export function AboutUs() {
- {/* Right Side - Main Heading */}

- {/* Updated Statistics Grid - Dynamic from API */}
{(aboutUsData?.stat_section && aboutUsData.stat_section.length > 0) ? ( aboutUsData.stat_section.map((stat, index) => ( @@ -670,7 +620,6 @@ export function AboutUs() { )) ) : ( - // Fallback to static statistics if API data is not available <> - {/* Section 4: Our Team - Dynamic from API */} + {/* Section 4: Our Team - Dynamic from API (outer grid from API, modal from static) */}
- {/* Centered Header Section */} - {/* Team Members Grid - Using static team members with full profiles */} + {/* Team Members Grid - Using API data for outer display */}
- {staticTeamMembers.map((member, index) => ( - handleMemberClick(member)} - > -
-
- {member.name} -
+ {apiTeamMembers.map((member, index) => { + const name = member.name_role.split(' - ')[0]; + const role = member.name_role.split(' - ')[1] || 'Team Member'; - {/* Hover Overlay */} -
-
-
handleMemberClick(member)} + > +
+
+ {member.alt_text { + (e.target as HTMLImageElement).src = 'https://ui-avatars.com/api/?name=' + encodeURIComponent(name) + '&background=04045B&color=fff&size=200'; }} - > - View Profile + /> +
+ +
+
+
+ View Profile +
-
-
-

{member.name}

-

- {member.role} -

-
- - ))} +
+

{name}

+

+ {role} +

+ {/* Bio Section */} +

+ {member.bio || "No bio available"} +

+
+ + ); + })}
@@ -849,9 +808,7 @@ export function AboutUs() { )}
- {/* Vertical Timeline Container */}
- {/* Vertical Line Background - Gray */}
- {/* Vertical Line Fill - Blue - Animated on Scroll */}
- {/* Map through phases from API - Create a copy before sorting */} {[...(aboutUsData.methodology.phases || [])] .sort((a, b) => (a.display_order || 0) - (b.display_order || 0)) .map((phase, phaseIndex) => (
- {/* Phase dot positioned absolutely */}
- {/* Column 1: Phase Label */}
@@ -894,7 +847,6 @@ export function AboutUs() {
- {/* Column 2: Main Heading */}
- {/* Column 3: Content - Description and Bullet Points */}
))} - {/* Our Philosophy - Dynamic from API */} {aboutUsData?.philosophy && (
- {/* Phase dot positioned absolutely */}
- {/* Left Section: Heading */}

{aboutUsData.philosophy.title || "Our Philosophy"}

- {/* Right Section: Content */}
- {/* Philosophy Description */}

{aboutUsData.philosophy.description}

- {/* Philosophy Points */} {aboutUsData.philosophy.points && aboutUsData.philosophy.points.length > 0 && (
{aboutUsData.philosophy.points.map((point, pointIndex) => ( @@ -1041,14 +986,10 @@ export function AboutUs() { tagText="Client Success Stories" /> - {/* CTA Banner Section */} - - - {/* Team Member Modal */} -
); diff --git a/src/components/CTABannerSection.tsx b/src/components/CTABannerSection.tsx index 5f995ca..f1c6dd9 100644 --- a/src/components/CTABannerSection.tsx +++ b/src/components/CTABannerSection.tsx @@ -5,21 +5,20 @@ import { PrimaryCTAButton } from "./PrimaryCTAButton"; import { navigateTo } from "./Router"; interface CTABannerSectionProps { - ctaBands?: Array<{ + ctaSection?: { id: string; background_image_url: string; - background_image_alt_text: string; text: string; cta_text: string; cta_destination: string; - }>; + description: string; + landing_page_type: string; + service_type: string | null; + }; isLoading?: boolean; } -export function CTABannerSection({ ctaBands = [], isLoading }: CTABannerSectionProps) { - // Get the first CTA band or use default values - const ctaBand = ctaBands && ctaBands.length > 0 ? ctaBands[0] : null; - +export function CTABannerSection({ ctaSection, isLoading }: CTABannerSectionProps) { if (isLoading) { return (
@@ -31,8 +30,8 @@ export function CTABannerSection({ ctaBands = [], isLoading }: CTABannerSectionP ); } - // If no CTA band is available, don't render anything - if (!ctaBand) { + // If no CTA section data is available, don't render anything + if (!ctaSection) { return null; } @@ -41,8 +40,8 @@ export function CTABannerSection({ ctaBands = [], isLoading }: CTABannerSectionP {/* Background Image */}
@@ -65,11 +64,11 @@ export function CTABannerSection({ ctaBands = [], isLoading }: CTABannerSectionP {/* Branded Tag */} - {/* Main Headline - Use API text or fallback */} + {/* Main Headline */}

- {ctaBand.text || "Ready to transform your leadership?"} + {ctaSection.text || "Ready to transform your leadership?"} + {/* Description */} + {ctaSection.description && ( +

+ {ctaSection.description} +

+ )} + {/* CTA Button */} navigateTo(ctaBand.cta_destination || '/contact?topic=consulting')} + text={ctaSection.cta_text || "Schedule a Consultation"} + onClick={() => navigateTo(ctaSection.cta_destination || '/contact?topic=consulting')} ariaLabel="Schedule a consultation with our leadership experts" className="cta-banner-yellow" /> - - {/* Supporting Text */} -

- Connect with our leadership experts to discuss your organization's specific development needs. -

diff --git a/src/components/CourseCard.tsx b/src/components/CourseCard.tsx index a6c06d9..42def13 100644 --- a/src/components/CourseCard.tsx +++ b/src/components/CourseCard.tsx @@ -22,7 +22,7 @@ export interface Course { level: string; format: string; rating: number; - participants: string; + reviews: string; category: string; description: string; price: string; @@ -147,7 +147,7 @@ export function CourseCard({ course, onClick, className, onAddToCart }: CourseCa color: 'var(--color-gray-muted)', fontWeight: '500' }}> - {course.participants} + {course.reviews}
@@ -265,4 +265,4 @@ export function CourseCard({ course, onClick, className, onAddToCart }: CourseCa
); -} \ No newline at end of file +} diff --git a/src/components/KautilyaFacility.tsx b/src/components/KautilyaFacility.tsx index 9e5f968..307aeea 100644 --- a/src/components/KautilyaFacility.tsx +++ b/src/components/KautilyaFacility.tsx @@ -43,111 +43,263 @@ import { Wifi } from 'lucide-react'; import { TestimonialsSection } from './TestimonialsSection'; +import { FullScreenLoader } from './FullScreenLoader'; +import { useGetServiceListQuery } from '../redux/services/sercicesApi'; -const targetAudience = [ - { - title: "Corporate Training Teams", - description: "Organizations seeking premium residential learning experiences for their leadership development programs", - icon: Building, - challenges: ["Facility booking complexity", "Quality accommodation needs", "Program logistics", "Cost management"] - }, - { - title: "Leadership Development Providers", - description: "Training organizations and consultancies requiring world-class facilities for executive programs", - icon: Users, - challenges: ["Facility availability", "Technology requirements", "Catering quality", "Professional environment"] - }, - { - title: "Executive Teams & Boards", - description: "Senior leadership teams planning strategic retreats and intensive development programs", - icon: Target, - challenges: ["Privacy requirements", "Executive-level facilities", "Strategic planning spaces", "Convenience needs"] - } -]; +// Types based on API response (same as LeadershipDevelopment) +interface ServicePageData { + hero_section: { + id: string; + landing_page_type: string; + background_image_url: string; + background_image_alt_text: string; + headline: string; + subtext: string; + cta_text: string; + cta_destination: string; + }; + overview: { + id: string; + title: string; + description: string; + highlight_text: string; + overview_cards: Array<{ + id: string; + title: string; + description: string; + icon_url: string; + accessible_label: string; + }>; + }; + audience_section: { + id: string; + title: string; + description: string; + audience_cards: Array<{ + id: string; + title: string; + description: string; + icon_url: string; + accessible_label: string; + challenges: string[]; + }>; + }; + use_case_section: { + id: string; + title: string; + description: string; + use_case_cards: Array<{ + id: string; + title: string; + description: string; + icon_url: string; + accessible_label: string; + highlight_text: string; + }>; + }; + approach_section: { + id: string; + title: string; + description: string; + approach_cards: Array<{ + id: string; + title: string; + description: string; + icon_url: string; + accessible_label: string; + bullets: string[]; + }>; + outcomes: Array<{ + id: string; + title: string; + description: string; + icon_url: string; + accessible_label: string; + bullets: string[]; + }>; + }; + stats_section: { + id: string; + title: string; + description: string; + stat_cards: Array<{ + id: string; + value: string; + label: string; + icon_url: string; + accessible_label: string; + }>; + }; + program_section: { + id: string; + title: string; + description: string; + program_phases: Array<{ + phase: { + id: string; + phase_number: number; + title: string; + duration: string; + }; + activities: Array<{ + id: string; + phase_id: string; + text: string; + }>; + outcomes: Array<{ + id: string; + phase_id: string; + text: string; + }>; + }>; + }; + impact_section: { + id: string; + title: string; + description: string; + impact_stats: Array<{ + id: string; + value: string; + description: string; + label: string; + icon_url: string; + accessible_label: string; + }>; + impact_benefits: Array<{ + id: string; + title: string; + description: string; + icon_url: string; + accessible_label: string; + }>; + }; + testimonial_section: Array<{ + id: string; + profile_xid: string; + name: string; + designation: string; + content: string; + video_url: string | null; + display_order: number; + }>; + cta_section: { + id: string; + background_image_url: string; + text: string; + cta_text: string; + cta_destination: string; + description: string; + landing_page_type: string; + service_type: string; + }; +} -const useCases = [ - { - title: "Leadership Residential Programs", - description: "When organizations need premium facilities for multi-day leadership development programs", - icon: Home, - scenario: "Executive development programs requiring 2-7 day residential experiences" - }, - { - title: "Strategic Planning Retreats", - description: "When leadership teams need focused environments for strategic planning and decision-making", - icon: Target, - scenario: "Board meetings, strategic sessions, or executive team planning retreats" - }, - { - title: "Learning & Development Events", - description: "When organizations require professional venues for training, workshops, and development events", - icon: BookOpen, - scenario: "Corporate training programs, workshops, or learning conferences" - }, - { - title: "Team Building & Culture Events", - description: "When teams need inspiring environments for team building and cultural development activities", - icon: Heart, - scenario: "Team building events, culture workshops, or organizational celebrations" - } -]; +// Map API icons to Lucide icons (same mapping as LeadershipDevelopment) +const getIconComponent = (iconUrl: string) => { + const iconMap: Record = { + '/icons/building.svg': Building, + '/icons/home.svg': Home, + '/icons/hotel.svg': Building, + '/icons/coffee.svg': Coffee, + '/icons/wifi.svg': Wifi, + '/icons/settings.svg': Settings, + '/icons/user-check.svg': UserCheck, + '/icons/heart.svg': Heart, + '/icons/trending-up.svg': TrendingUp, + '/icons/users.svg': Users, + '/icons/target.svg': Target, + '/icons/star.svg': Star, + '/icons/compass.svg': Compass, + '/icons/book-open.svg': BookOpen, + '/icons/message-circle.svg': MessageCircle, + '/icons/clock.svg': Clock, + }; -const facilityFeatures = [ - { - phase: "Premium Accommodations", - duration: "World-Class Comfort", - activities: ["Luxury single and double rooms", "Executive suites", "24/7 concierge service", "High-speed internet throughout"], - deliverables: ["Comfortable stay experience", "Professional environment", "Seamless connectivity", "Executive-level service"] - }, - { - phase: "Learning & Meeting Spaces", - duration: "State-of-the-Art Facilities", - activities: ["Modern conference rooms", "Interactive learning spaces", "Breakout areas", "Outdoor meeting spaces"], - deliverables: ["Flexible learning environments", "Technology-enabled spaces", "Collaborative areas", "Natural settings"] - }, - { - phase: "Dining & Recreation", - duration: "Complete Experience", - activities: ["Gourmet dining options", "Healthy meal programs", "Recreation facilities", "Wellness amenities"], - deliverables: ["Nutritious meal programs", "Networking opportunities", "Physical wellness", "Stress relief activities"] - } -]; - -const expectedOutcomes = [ - { - metric: "96%", - description: "Client satisfaction with facility quality and service", - icon: Heart, - category: "Satisfaction" - }, - { - metric: "87%", - description: "Improvement in program engagement in residential setting", - icon: TrendingUp, - category: "Engagement" - }, - { - metric: "92%", - description: "Would recommend Kautilya Facility to other organizations", - icon: Star, - category: "Recommendation" - }, - { - metric: "78%", - description: "Return rate for repeat bookings and programs", - icon: Building, - category: "Loyalty" - } -]; + const IconComponent = iconMap[iconUrl] || Building; + return IconComponent; +}; export function KautilyaFacility() { const [expandedUseCase, setExpandedUseCase] = useState(null); const [expandedFeature, setExpandedFeature] = useState(0); + // API call with service_type = 'kautilya_facility' + const { data: apiResponse, isLoading, error } = useGetServiceListQuery({ + service_type: 'kautilya_facility' + }); + + const apiData = apiResponse?.data as ServicePageData | undefined; + useEffect(() => { window.scrollTo(0, 0); }, []); + if (isLoading) { + return ( +
+ +
+ ); + } + + if (error || !apiData) { + return ( +
+
+

Error loading content. Please try again later.

+ +
+
+ ); + } + + // Transform data for UI (using API data with fallbacks to static data) + const targetAudience = apiData.audience_section?.audience_cards.map(card => ({ + title: card.title, + description: card.description, + icon: getIconComponent(card.icon_url), + challenges: card.challenges || [] + })) || []; + + const useCases = apiData.use_case_section?.use_case_cards.map(card => ({ + title: card.title, + description: card.description, + icon: getIconComponent(card.icon_url), + scenario: card.highlight_text + })) || []; + + const facilityFeatures = apiData.program_section?.program_phases.map(phase => ({ + phase: phase.phase.title, + duration: phase.phase.duration, + activities: phase.activities.map(activity => activity.text), + deliverables: phase.outcomes.map(outcome => outcome.text) + })) || []; + + const expectedOutcomes = apiData.impact_section?.impact_benefits.map(benefit => ({ + category: benefit.title, + description: benefit.description, + icon: getIconComponent(benefit.icon_url) + })) || []; + + const testimonials = apiData.testimonial_section?.map(testimonial => { + const designationParts = testimonial.designation.split(','); + const role = designationParts[0]?.trim() || ''; + const company = designationParts[1]?.trim() || ''; + + return { + id: parseInt(testimonial.id) || 0, + name: testimonial.name, + role: role, + company: company, + avatar: `https://ui-avatars.com/api/?name=${encodeURIComponent(testimonial.name)}&background=04045B&color=fff&size=128`, + quote: testimonial.content, + rating: 5, + isVideo: !!testimonial.video_url, + videoThumbnail: testimonial.video_url ? `/images/testimonials/thumbnails/${testimonial.id}.jpg` : undefined, + videoUrl: testimonial.video_url || undefined + }; + }) || []; + return (
{/* Hero Section */} @@ -156,7 +308,7 @@ export function KautilyaFacility() {
@@ -179,19 +331,19 @@ export function KautilyaFacility() {

- Kautilya Facility + {apiData.hero_section.headline}

- Experience world-class residential learning at our premium campus with 96% client satisfaction and exceptional facilities designed for leadership excellence. + {apiData.hero_section.subtext}

navigateTo('/contact?topic=kautilya-facility')} - ariaLabel="Book a consultation for Kautilya Facility" + text={apiData.hero_section.cta_text} + onClick={() => navigateTo(apiData.hero_section.cta_destination)} + ariaLabel={apiData.hero_section.cta_text} className="primary-cta-button-blue cta-text-white" />
@@ -206,70 +358,41 @@ export function KautilyaFacility() {
-

Premium Learning Campus & Residential Programs

+

{apiData.overview.title}

- Kautilya Facility is a world-class residential learning campus designed specifically for executive education and leadership development programs. Our premium facility combines luxury accommodations, state-of-the-art learning spaces, and comprehensive amenities to create an immersive environment that maximizes learning outcomes and program engagement. + {apiData.overview.description}

- The Business Problem It Solves: Many organizations struggle to find appropriate venues that combine professional learning environments with quality accommodations for residential programs. Standard hotels lack the specialized learning infrastructure, while conference centers often compromise on accommodation quality. Our facility eliminates these compromises by providing an integrated solution designed specifically for executive learning. + The Business Problem It Solves: {apiData.overview.highlight_text}

-
-
-
- + {apiData.overview.overview_cards.map((card, index) => { + const IconComponent = getIconComponent(card.icon_url); + return ( +
+
+
+ +
+

+ {card.title} +

+

+ {card.description} +

+
-

- Premium Campus -

-

- World-class residential learning campus with luxury amenities and sophisticated infrastructure -

-
-
- -
-
-
- -
-

- Learning-Focused Design -

-

- Specialized spaces designed for optimal learning and development with cutting-edge technology -

-
-
- -
-
-
- -
-

- 96% Satisfaction Rate -

-

- Exceptional client satisfaction with facility quality, service excellence, and learning outcomes -

-
-
+ ); + })}
@@ -281,9 +404,9 @@ export function KautilyaFacility() {
-

Target Audience

+

{apiData.audience_section.title}

- Designed for organizations and teams seeking premium residential learning and strategic planning experiences. + {apiData.audience_section.description}

@@ -326,9 +449,9 @@ export function KautilyaFacility() {
-

When Organizations Need Premium Learning Facilities

+

{apiData.use_case_section.title}

- Ideal for organizations seeking world-class residential learning experiences and strategic planning sessions. + {apiData.use_case_section.description}

@@ -338,7 +461,6 @@ export function KautilyaFacility() { key={index} className="bg-white rounded-xl border border-gray-200 p-6 hover:border-[#04045B] hover:shadow-lg transition-all duration-300" > - {/* Icon and Title */}
- {/* Ideal For Indicator */}
@@ -377,9 +498,9 @@ export function KautilyaFacility() {
-

Integrated Learning Campus Experience

+

{apiData.approach_section.title}

- Our comprehensive approach combines premium accommodations, state-of-the-art learning facilities, and exceptional service delivery. + {apiData.approach_section.description}

@@ -388,85 +509,41 @@ export function KautilyaFacility() { {/* Desktop: Horizontal Flowchart */}
- {/* Row 1: Facilities, Services, Technology */} + {/* Row 1: First 3 approach cards from API */}
- {/* Facilities */} -
-
- -
-

Premium Facilities

-

- World-class accommodations and learning environments -

-
-
- Luxury Accommodations + {apiData.approach_section.approach_cards.slice(0, 3).map((card, idx) => { + const IconComponent = getIconComponent(card.icon_url); + return ( +
+
+ +
+

{card.title}

+

{card.description}

+
+ {card.bullets.slice(0, 3).map((bullet, bulletIdx) => ( +
+ {bullet} +
+ ))} +
-
- Learning Spaces -
-
- Wellness Facilities -
-
-
+ ); + })} - {/* Arrow 1→2 */} -
-
- -
- - {/* Services */} -
-
- + {/* Arrows between first 3 cards */} + {apiData.approach_section.approach_cards.length >= 2 && ( +
+
+
-

Service Excellence

-

- Exceptional hospitality and dining experiences -

-
-
- Gourmet Catering -
-
- 24/7 Concierge -
-
- Event Management -
+ )} + {apiData.approach_section.approach_cards.length >= 3 && ( +
+
+
-
- - {/* Arrow 2→3 */} -
-
- -
- - {/* Technology */} -
-
- -
-

Technology Infrastructure

-

- Advanced technology for seamless learning delivery -

-
-
- High-Speed Internet -
-
- AV Equipment -
-
- Tech Support -
-
-
+ )}
{/* Vertical Connector - Center Flow Down */} @@ -477,58 +554,39 @@ export function KautilyaFacility() {
- {/* Row 2: Customization, Support */} -
- {/* Customization */} -
-
- -
-

Flexible Customization

-

- Adaptable spaces configured to your program needs -

-
-
- Room Configurations -
-
- Custom Setups -
-
- Branding Options -
-
-
+ {/* Row 2: Next 2 approach cards (if available) */} + {apiData.approach_section.approach_cards.length >= 4 && ( +
+ {apiData.approach_section.approach_cards.slice(3, 5).map((card, idx) => { + const IconComponent = getIconComponent(card.icon_url); + const isFirstOfPair = idx === 0; + return ( +
+
+ +
+

{card.title}

+

{card.description}

+
+ {card.bullets.slice(0, 3).map((bullet, bulletIdx) => ( +
+ {bullet} +
+ ))} +
+
+ ); + })} - {/* Arrow 4→5 */} -
-
- + {/* Arrow between the two cards */} + {apiData.approach_section.approach_cards.length >= 5 && ( +
+
+ +
+ )}
- - {/* Dedicated Support */} -
-
- -
-

Dedicated Support

-

- Expert team ensuring flawless program execution -

-
-
- Event Coordinators -
-
- Facility Staff -
-
- Technical Team -
-
-
-
+ )} {/* Final Vertical Connector - Center Flow Down to Outcome */}
@@ -538,19 +596,35 @@ export function KautilyaFacility() {
- {/* Row 3: Expected Outcome - Centered */} + {/* Row 3: Expected Outcome - Use API outcomes data */}
- -

Expected Outcome

+ {apiData.approach_section.outcomes && apiData.approach_section.outcomes[0] && (() => { + const OutcomeIcon = getIconComponent(apiData.approach_section.outcomes[0].icon_url); + return ; + })() || } +

+ {apiData.approach_section.outcomes?.[0]?.title || "Expected Outcome"} +

- An immersive learning environment that enhances focus, engagement, and program effectiveness for transformational results. + {apiData.approach_section.outcomes?.[0]?.description || "Transformational executive leaders with strategic capability, executive presence, and proven business impact."}

-
- - Exceptional Learning Experience +
+ {apiData.approach_section.outcomes?.[0]?.bullets?.slice(0, 2).map((bullet, idx) => ( +
+ + {bullet} +
+ )) || ( + <> +
+ + Exceptional Learning Experience +
+ + )}
@@ -559,198 +633,95 @@ export function KautilyaFacility() { {/* Tablet & Mobile: Vertical Flowchart */}
- {/* Facilities */} -
-
-
- + {/* Map all approach cards vertically */} + {apiData.approach_section.approach_cards.map((card, idx) => { + const IconComponent = getIconComponent(card.icon_url); + const isEven = idx % 2 === 0; + return ( +
+
+
+ +
+

{card.title}

+

{card.description}

+
+ {card.bullets.map((bullet, bulletIdx) => ( +
+ {bullet} +
+ ))} +
+
+ {/* Connector Arrow */} + {idx < apiData.approach_section.approach_cards.length - 1 && ( +
+ +
+ )}
-

Premium Facilities

-

- World-class accommodations and learning environments -

-
-
- Luxury Accommodations -
-
- Learning Spaces -
-
- Wellness Facilities -
-
-
- {/* Connector Arrow */} -
- -
-
+ ); + })} - {/* Services */} -
-
-
- -
-

Service Excellence

-

- Exceptional hospitality and dining experiences -

-
-
- Gourmet Catering -
-
- 24/7 Concierge -
-
- Event Management -
-
-
- {/* Connector Arrow */} -
- -
-
- - {/* Technology */} -
-
-
- -
-

Technology Infrastructure

-

- Advanced technology for seamless learning delivery -

-
-
- High-Speed Internet -
-
- AV Equipment -
-
- Tech Support -
-
-
- {/* Connector Arrow */} -
- -
-
- - {/* Customization */} -
-
-
- -
-

Flexible Customization

-

- Adaptable spaces configured to your program needs -

-
-
- Room Configurations -
-
- Custom Setups -
-
- Branding Options -
-
-
- {/* Connector Arrow */} -
- -
-
- - {/* Dedicated Support */} -
-
-
- -
-

Dedicated Support

-

- Expert team ensuring flawless program execution -

-
-
- Event Coordinators -
-
- Facility Staff -
-
- Technical Team -
-
-
- {/* Connector Arrow */} -
- -
-
- - {/* Expected Outcome */} + {/* Expected Outcome - Use API outcomes data */}
- -

Expected Outcome

+ {apiData.approach_section.outcomes && apiData.approach_section.outcomes[0] && (() => { + const OutcomeIcon = getIconComponent(apiData.approach_section.outcomes[0].icon_url); + return ; + })() || } +

+ {apiData.approach_section.outcomes?.[0]?.title || "Expected Outcome"} +

- An immersive learning environment that enhances focus, engagement, and program effectiveness for transformational results. + {apiData.approach_section.outcomes?.[0]?.description || "Transformational executive leaders with strategic capability, executive presence, and proven business impact."}

-
- - Exceptional Learning Experience +
+ {apiData.approach_section.outcomes?.[0]?.bullets?.slice(0, 2).map((bullet, idx) => ( +
+ + {bullet} +
+ )) || ( + <> +
+ + Exceptional Learning Experience +
+ + )}
- {/* Framework Effectiveness */} - {/*
-
-

Facility Excellence Metrics

-

- Our integrated campus approach delivers superior learning outcomes through exceptional environments. -

-
- -
-
-
- -
-
96%
-

Guest Satisfaction Rating

+ {/* Framework Effectiveness - Stats Section */} + {apiData.stats_section && ( +
+
+

{apiData.stats_section.title}

+

+ {apiData.stats_section.description} +

-
-
- -
-
92%
-

Program Effectiveness Increase

-
- -
-
- -
-
89%
-

Repeat Booking Rate

+
+ {apiData.stats_section.stat_cards.map((stat) => { + const IconComponent = getIconComponent(stat.icon_url); + return ( +
+
+ +
+
{stat.value}
+

{stat.label}

+
+ ); + })}
-
*/} + )}
@@ -762,9 +733,9 @@ export function KautilyaFacility() {
-

Complete Campus Experience

+

{apiData.program_section.title}

- A comprehensive facility experience designed to maximize learning outcomes and participant satisfaction. + {apiData.program_section.description}

@@ -845,119 +816,104 @@ export function KautilyaFacility() {
-

Measurable Facility Outcomes

+

{apiData.impact_section.title}

- Organizations consistently report high satisfaction and improved program outcomes when using our premium facility. + {apiData.impact_section.description}

- {/* Outcomes Grid */} -
- {expectedOutcomes.map((outcome, index) => ( - - -
- -
- {/*
- {outcome.metric} -
*/} -

{outcome.category}

- -

{outcome.description}

- {/*

{outcome.category}

*/} -
-
- ))} +
+ {apiData.impact_section.impact_stats.map((stat) => { + const IconComponent = getIconComponent(stat.icon_url); + return ( + + +
+ +
+
+ {stat.value} +
+

{stat.description}

+

{stat.label}

+
+
+ ); + })}
-
+

Additional Facility Benefits

-
- -

Premium Environment

-

World-class facilities that enhance learning and networking

-
-
- -

Exceptional Service

-

Dedicated support staff and personalized service excellence

-
-
- -

Strategic Location

-

Convenient location with peaceful, focused learning environment

-
+ {apiData.impact_section.impact_benefits.map((benefit) => { + const IconComponent = getIconComponent(benefit.icon_url); + return ( +
+
+ +
+

{benefit.title}

+

{benefit.description}

+
+ ); + })}
- {/* 7. Client Examples / Testimonials - Hero Section Design */} + {/* 7. Client Examples / Testimonials */} - {/* 8. CTA Section - Hero Section Design */} -
- {/* Background Image */} -
- - - {/* Subtle dark overlay for overall image */} -
- - {/* Gradient overlay for better text readability */} -
-
- - {/* Content Container */} -
- {/* CTA Content Block */} -
- {/* Branded Tag */} - - - {/* Main Headline */} -

- Ready to experience Kautilya Facility? - - {" "}Get in touch{" "} - - for world-class learning spaces. -

- - {/* CTA Button */} - navigateTo('/contact?topic=kautilya-facility')} - ariaLabel="Schedule a Kautilya Facility tour" + {/* 8. CTA Section */} + {apiData.cta_section && ( +
+
+ - - {/* Supporting Text */} -

- Connect with our facility experts to discuss hosting your next leadership program or strategic retreat at our world-class residential learning campus. -

+
+
-
-
+ +
+
+ +

+ {apiData.cta_section.text} + + {" "}Get in touch{" "} + + to schedule your facility tour. +

+ navigateTo(apiData.cta_section.cta_destination)} + ariaLabel={apiData.cta_section.cta_text} + /> + {apiData.cta_section.description && ( +

+ {apiData.cta_section.description} +

+ )} +
+
+
+ )}
); } \ No newline at end of file diff --git a/src/components/LearningOnline.tsx b/src/components/LearningOnline.tsx index 46f94d7..558cedb 100644 --- a/src/components/LearningOnline.tsx +++ b/src/components/LearningOnline.tsx @@ -23,7 +23,14 @@ import { Button } from './ui/button'; import { Card } from './ui/card'; import { Input } from './ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select'; -import { useGetCoursesQuery, Course, GetCoursesParams, useGetCourseCategoriesQuery, CourseCategory } from '../redux/services/courseApi'; +import { + courseApi, + useGetCoursesQuery, + Course, + GetCoursesParams, + useGetCourseCategoriesQuery, + CourseCategory +} from '../redux/services/courseApi'; import { useDebounce } from '../redux/hooks/useDebounce'; // Helper function to parse rupee price from string (keep as is) @@ -50,6 +57,7 @@ export function LearningOnline() { const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid'); const [currentPage, setCurrentPage] = useState(1); const coursesPerPage = 9; + const prefetchCourseById = courseApi.usePrefetch('getcoursebyid'); // Debounced search term to avoid too many API calls const debouncedSearchTerm = useDebounce(searchTerm, 500); @@ -260,12 +268,12 @@ export function LearningOnline() { level: 'Intermediate', format: course.retail_type === 'public' ? 'Cohort-based' : 'Self-paced', rating: course.avg_rating || 4.5, - participants: `${Math.floor(Math.random() * 5000) + 100}+`, + reviews: `${course.total_reviews || 0} review${(course.total_reviews || 0) === 1 ? '' : 's'}`, category: course.course_category_name || 'General', categoryId: course.course_category_xid || '', description: course.course_desc || `Master ${course.course_name} with our comprehensive program.`, - price: formatPrice(course.price), - originalPrice: formatPrice(course.price * 1.25), + price: formatPrice(course.best_value || 0), + originalPrice: formatPrice(course.price || 0), course_status: course.course_status })); }, [coursesData]); @@ -321,6 +329,11 @@ export function LearningOnline() { setRecentlyAddedItem(null); }; + const handleCourseClick = useCallback((courseId: string) => { + prefetchCourseById(courseId, { force: true }); + navigateTo(`/course/${courseId}`); + }, [prefetchCourseById]); + // Show loading state if (coursesLoading || categoriesLoading) { return ( @@ -595,6 +608,7 @@ export function LearningOnline() { handleCourseClick(course.id)} onAddToCart={handleAddToCart} />
@@ -609,7 +623,7 @@ export function LearningOnline() { navigateTo(`/course/${course.id}`)} + onClick={() => handleCourseClick(course.id)} >
@@ -665,7 +679,7 @@ export function LearningOnline() {
- {course.participants} + {course.reviews}
@@ -761,4 +775,4 @@ export function LearningOnline() { />
); -} \ No newline at end of file +} diff --git a/src/components/ProgrammeDetail.tsx b/src/components/ProgrammeDetail.tsx index 69c20cc..23e33f4 100644 --- a/src/components/ProgrammeDetail.tsx +++ b/src/components/ProgrammeDetail.tsx @@ -1,48 +1,43 @@ -import React, { useState, useEffect, useRef } from 'react'; -import { Button } from './ui/button'; -import { Card, CardContent, CardHeader, CardTitle } from './ui/card'; -import { Badge } from './ui/badge'; -import { Input } from './ui/input'; -import { Label } from './ui/label'; -import { Textarea } from './ui/textarea'; -import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './ui/accordion'; -import { Tabs, TabsContent, TabsList, TabsTrigger } from './ui/tabs'; -import { Separator } from './ui/separator'; -import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; -import { - Clock, - Users, - Award, - Play, - Download, - ChevronRight, - ChevronLeft, - Star, - Calendar, - Globe, - Building2, - User, - Mail, - Phone, - MessageCircle, - CheckCircle, +import { + Award, BookOpen, + CheckCircle, + Clock, + Download, + ExternalLink, + Lightbulb, + MessageCircle, + Play, + Star, Target, TrendingUp, - Lightbulb, - ArrowRight, - ExternalLink, - Quote, - X, - AlertCircle + User, + Users, + X } from 'lucide-react'; import { motion } from 'motion/react'; -import { navigateTo } from './Router'; -import { ImageWithFallback } from './figma/ImageWithFallback'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import { toast } from 'sonner'; +import { useGetcoursebyidQuery } from '../redux/services/courseApi'; import { BrandedTag } from './about/BrandedTag'; -import { PrimaryCTAButton } from './PrimaryCTAButton'; import { useCart } from './CartContext'; -import { toast } from 'sonner@2.0.3'; +import { ImageWithFallback } from './figma/ImageWithFallback'; +import { PrimaryCTAButton } from './PrimaryCTAButton'; +import { navigateTo } from './Router'; +import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; +import { Badge } from './ui/badge'; +import { Button } from './ui/button'; +import { Card, CardContent, CardHeader, CardTitle } from './ui/card'; +import { + Dialog, + DialogContent, + DialogOverlay, + DialogPortal +} from './ui/dialog'; +import { Input } from './ui/input'; +import { Label } from './ui/label'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from './ui/tabs'; // Mock data structure matching API contracts const mockProgrammeData = { @@ -54,6 +49,9 @@ const mockProgrammeData = { format: 'Hybrid', price: '₹2,50,000', originalPrice: '₹3,00,000', + methodologyDesc: 'Formulating Strategy is a theme that requires the exercise of leadership. Thus, the course starts with offering you an opportunity to review your lens to leadership and provides alternate perspectives to leadership', + reviewCount: 24, + rating: 4.8, currency: 'INR', published: true, enrollmentStatus: 'open', // open, closed, enrolled, waitlist @@ -350,11 +348,18 @@ const mockRelatedProgrammes = [ } ]; +const formatIndianPrice = (value: string | number | null | undefined) => { + const amount = Number(value ?? 0); + return `₹${amount.toLocaleString('en-IN')}`; +}; + interface ProgrammeDetailProps { slug?: string; } export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { + const params = useParams<{ slug: string }>(); + const courseId = slug || params.slug || ''; const [activeTab, setActiveTab] = useState('overview'); const [selectedFaculty, setSelectedFaculty] = useState(0); const [showVideoModal, setShowVideoModal] = useState(false); @@ -370,8 +375,28 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { designation: '' }); + const navigate = useNavigate(); + const heroRef = useRef(null); const { addToCart } = useCart(); + const { + data: courseDetailResponse, + isLoading, + isError + } = useGetcoursebyidQuery(courseId, { + skip: !courseId + }); + const courseDetail = courseDetailResponse?.data; + + const handleCourseClick = (courseId: string) => { + navigate(`/course/${courseId}`); + // Optionally scroll to top + window.scrollTo(0, 0); + }; + + + // Add this with your other useState declarations + const [showCertificatePreview, setShowCertificatePreview] = useState(false); // Sticky CTA logic useEffect(() => { @@ -386,15 +411,140 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { return () => window.removeEventListener('scroll', handleScroll); }, []); - // Mock API calls (replace with real API calls) - const programme = mockProgrammeData; - const outcomes = mockOutcomes; - const curriculum = mockCurriculum; - const faculty = mockFaculty; - const testimonials = mockTestimonials; - const faqs = mockFAQs; + const programme = useMemo(() => { + if (!courseDetail) return mockProgrammeData; + + const bestValue = Number(courseDetail.best_value ?? 0); + const originalValue = Number(courseDetail.price ?? 0); + const computedPrice = formatIndianPrice(bestValue); + const computedOriginalPrice = + originalValue > 0 && originalValue !== bestValue + ? formatIndianPrice(originalValue) + : undefined; + + return { + ...mockProgrammeData, + id: courseDetail.id, + title: courseDetail.course_name || mockProgrammeData.title, + subtitle: courseDetail.course_desc || mockProgrammeData.subtitle, + duration: courseDetail.duration || mockProgrammeData.duration, + // level: courseDetail.retail_type === 'public' ? 'Public' : 'Private', + // format: courseDetail.retail_type === 'public' ? 'Cohort-based' : 'Self-paced', + price: computedPrice, + originalPrice: computedOriginalPrice, + methodologyDesc: courseDetail.our_methodology_desc, + reviewCount: courseDetail.total_reviews || 0, + rating: Number(courseDetail.avg_rating ?? 0), + published: courseDetail.course_status === 'publish', + spotsLeft: courseDetail.total_lessons || mockProgrammeData.spotsLeft, + maxCapacity: Math.max(courseDetail.total_lessons || 0, mockProgrammeData.maxCapacity), + thumbnail: courseDetail.thumbnail_img || mockProgrammeData.thumbnail, + badges: [ + courseDetail.course_category_name, + courseDetail.retail_type === 'public' ? 'Public' : 'Private', + courseDetail.is_certificate_available ? 'Certified' : 'Non-Certified' + ].filter(Boolean), + previewVideoUrl: + courseDetail.reviews.find((review) => review.video_url)?.video_url || + mockProgrammeData.previewVideoUrl, + highlights: + courseDetail.course_learning_outcomes.slice(0, 5).map((item) => item.title) || + mockProgrammeData.highlights, + deliveryMethods: courseDetail.modules.length + ? courseDetail.modules.map((module) => module.module_name) + : mockProgrammeData.deliveryMethods, + credentials: + courseDetail.course_certificate?.program_title || + courseDetail.course_certificate?.institution_name || + mockProgrammeData.credentials, + targetROI: courseDetail.our_methodology_desc || mockProgrammeData.targetROI + }; + }, [courseDetail]); + + const outcomes = useMemo(() => { + if (!courseDetail?.course_learning_outcomes?.length) return mockOutcomes; + + return courseDetail.course_learning_outcomes.map((item) => ({ + title: item.title, + description: item.description + })); + }, [courseDetail]); + + const curriculum = useMemo(() => { + if (!courseDetail?.modules?.length) return mockCurriculum; + + return courseDetail.modules.map((module, index) => ({ + moduleNumber: index + 1, + title: module.module_name, + duration: `${module.lessons.length} lesson${module.lessons.length === 1 ? '' : 's'}`, + deliveryStyle: module.lessons.some((lesson) => !lesson.is_lock_lesson) ? 'Self-Paced' : 'Locked', + topics: module.lessons.map((lesson) => lesson.lesson_title) + })); + }, [courseDetail]); + + const faculty = useMemo(() => { + if (!courseDetail?.course_facilities?.length) return mockFaculty; + + return courseDetail.course_facilities.map((member) => ({ + id: member.id, + name: member.faculty_name, + title: member.faculty_title, + organization: member.faculty_organization_name, + bio: member.faculty_biography, + image: '', + linkedinUrl: '', + credentials: member.credentials.map((credential) => credential.credential_name), + expertise: member.expertises || [] + })); + }, [courseDetail]); + + const testimonials = useMemo(() => { + if (!courseDetail?.reviews?.length) return mockTestimonials; + + return courseDetail.reviews.map((review) => ({ + id: review.id, + type: review.video_url ? 'video' : 'text', + name: review.reviewer_name, + title: review.bio || 'Learner Review', + company: courseDetail.course_category_name, + content: review.comment, + videoThumbnail: programme.thumbnail, + videoUrl: review.video_url || '', + rating: review.rating, + programmeCompleted: courseDetail.course_name + })); + }, [courseDetail, programme.thumbnail]); + + const faqs = useMemo(() => { + if (!courseDetail?.course_faqs?.length) return mockFAQs; + return courseDetail.course_faqs; + }, [courseDetail]); + + const audienceSegments = useMemo(() => { + if (!courseDetail?.course_target_audiences?.length) return mockAudienceSegments; + + return courseDetail.course_target_audiences.map((segment, index) => ({ + title: segment.title, + description: segment.description, + icon: index % 3 === 0 + ? + : index % 3 === 1 + ? + : + })); + }, [courseDetail]); + + const useCases = useMemo(() => { + if (!courseDetail?.modules?.length) return mockUseCases; + return courseDetail.modules.flatMap((module) => module.lessons.map((lesson) => lesson.lesson_title)).slice(0, 6); + }, [courseDetail]); + const relatedProgrammes = mockRelatedProgrammes; + useEffect(() => { + setSelectedFaculty(0); + }, [courseId]); + // Handle enrollment based on status const handleEnrollment = (type: string = 'individual') => { if (programme.enrollmentStatus === 'enrolled') { @@ -437,10 +587,10 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { // method: 'POST', // body: JSON.stringify(brochureFormData) // }); - + // Simulate API delay await new Promise(resolve => setTimeout(resolve, 1000)); - + toast.success('Brochure download started! Check your email for additional resources.'); setShowBrochureForm(false); setBrochureFormData({ name: '', email: '', phone: '', company: '', designation: '' }); @@ -451,6 +601,33 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { } }; + if (isLoading) { + return ( +
+
+
+

Loading programme details...

+
+
+ ); + } + + if (isError || !courseDetail) { + return ( +
+
+

Programme Not Found

+

+ We couldn't load the programme details right now. +

+ +
+
+ ); + } + // Handle 404 for unpublished programmes if (!programme.published) { return ( @@ -472,7 +649,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {
{/* Enhanced Sticky CTA Bar */} {isSticky && ( - {/* Programme Thumbnail */}
-
{/* Quality Badge */} -
- + {/* Programme Details */}

@@ -533,8 +710,12 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { {programme.spotsLeft} spots left

+
+ + {programme.reviewCount} reviews +
- + {/* Price Display */}
{programme.price} @@ -561,18 +742,18 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { Brochure - + {/* Primary CTA Button - No Shadow */}
handleEnrollment()} className="cta-text-black h-12 px-8 transition-all duration-200" /> {/* Urgency Indicator */} {programme.spotsLeft <= 5 && programme.spotsLeft > 0 && ( -
@@ -584,9 +765,9 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {
- + {/* Subtle Bottom Accent Line */} -
- + {/* Left: Programme Info - REDESIGNED */}
{/* Keep as requested: BrandedTag (eyebrow text) */} - + {/* Keep as requested: Title */}

{programme.title}

- + {/* Keep as requested: Subtitle */}

{programme.subtitle}

@@ -618,18 +799,22 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { Duration: {programme.duration} - + {/* Level: {programme.level} Format: {programme.format} - + */} Spots Left: {programme.spotsLeft} + + + Reviews: {programme.reviewCount} +
{/* REDESIGNED: Professional Badges Section */} @@ -637,9 +822,9 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {

Programme Features

{programme.badges.map((badge, index) => ( - @@ -676,8 +861,8 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { {/* REDESIGNED: Professional CTA Buttons Layout */}
handleEnrollment()} className="cta-text-black flex-1 justify-center" /> @@ -748,8 +933,213 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { {/* Credentials */}

Certification

-

{programme.credentials}

+ {courseDetail?.course_certificate ? ( +
+ {/* Certificate Available Message */} +

+ Certificate Available upon completion +

+
+ {/* Certificate Preview */} +
Certificate Preview:
+ + {/* Certificate Card - Exact design from image */} +
+
setShowCertificatePreview(true)} + > +
+ {/* Title */} +

Certificate of Completion

+ + {/* Body Text */} +

This is to certify that

+ + [Learner Name] + +

has successfully completed

+

+ {courseDetail.course_certificate.program_title || programme.title} +

+

offered by

+

+ {courseDetail.course_certificate.institution_name || "Kautilya Leadership Centre"} +

+ + {/* Footer with Signature and Date */} +
+
+
+ {courseDetail.course_certificate.digital_signature_url ? ( + Signature + ) : ( +
+ )} +
+

Signature

+
+
+

Date

+

+ {new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })} +

+
+
+
+
+
+
+
+ ) : ( +

{programme.credentials}

+ )}
+ + {/* Certificate Preview Modal - Full View */} + {courseDetail?.course_certificate && ( + + + + +
+ {/* + + */} + + {/* Certificate Card - Authentic Certificate Style */} +
+ {/* Decorative Border */} +
+
+ {/* Inner Border */} +
+ {/* Certificate Content */} +
+ {/* Decorative Top Border */} +
+
+
+ + {/* Certificate Title */} +

+ Certificate of Completion +

+ + {/* Decorative Line */} +
+ + {/* Body Text */} +

This is to certify that

+ + {/* Learner Name */} +

+ [Learner Name] +

+ +

has successfully completed

+ + {/* Program Title */} +

+ {courseDetail.course_certificate.program_title || programme.title} +

+ +

offered by

+ + {/* Institution Name */} +

+ {courseDetail.course_certificate.institution_name || "Kautilya Leadership Centre"} +

+ + {/* Certificate ID */} + {courseDetail.course_certificate.id && ( +
+

+ Certificate ID: {courseDetail.course_certificate.id} +

+
+ )} + + {/* Footer with Signature and Date */} +
+ {/* Signature Section */} +
+ {courseDetail.course_certificate.digital_signature_url ? ( +
+ Signature +
+
+ ) : ( +
+
+
+ )} +

Authorized Signature

+ {courseDetail.course_certificate.signatory_name && ( +

{courseDetail.course_certificate.signatory_name}

+ )} + {courseDetail.course_certificate.signatory_title && ( +

{courseDetail.course_certificate.signatory_title}

+ )} +
+ + {/* Date Section */} +
+

Date of Issue

+

+ {new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })} +

+
+ + {/* Seal/Logo Section */} +
+ {courseDetail.course_certificate.company_logo_url ? ( + Institution Logo + ) : ( +
+ 🎓 +
+ )} +
+
+ + {/* Decorative Bottom Border */} +
+
+
+ + {/* Verification Note */} +

+ This certificate is digitally verified and can be authenticated online +

+
+
+
+
+
+
+
+
+
+ )}
@@ -765,32 +1155,32 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { {/* Enhanced Tabs List */} - Overview - Curriculum - Faculty - Reviews - FAQ @@ -808,7 +1198,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { This programme is designed for leaders at various stages of their career journey.

- +
@@ -822,9 +1212,9 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {

- +
- {mockAudienceSegments.map((segment, index) => ( + {audienceSegments.map((segment, index) => (
@@ -853,7 +1243,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { This course will help you understand the role of leadership in shaping strategy.

- +
@@ -867,7 +1257,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {

- +
{outcomes.map((outcome, index) => (
@@ -888,7 +1278,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { This course is designed to help you uncover dimensions through bite-size, easy to consume learning units.

- +
@@ -910,7 +1300,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {
- + {/* Learning Structure Visual */}
@@ -954,7 +1344,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { A comprehensive curriculum designed to build strategic leadership capabilities through progressive modules.

- +
{curriculum.map((module, index) => ( @@ -1002,7 +1392,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { Formulating Strategy is a theme that requires the exercise of leadership.

- +
@@ -1013,19 +1403,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {

Our Methodology

- Formulating Strategy is a theme that requires the exercise of leadership. Thus, the course starts with offering you an opportunity to review your lens to leadership and provides alternate perspectives to leadership. -

-

- You will be effective in the exercise of leadership based the leadership resources you possess and your ability to apply those resources to suit the situation. We refer to these leadership resources as Leadership Orientations. Orientations are characteristics or traits. In this course you will learn the leadership orientations that have an impact on Formulating Strategies. -

-

- The course will help you be self-aware and gain insights on your leadership orientations. You will learn the leadership abilities that have an impact on strategy formulation. Leadership abilities require the combined applying of the leadership orientations learnt. -

-

- Developing these leadership orientations and leadership abilities will help you think strategically. These include thinking orientation, offering, drawing and managing of perspectives, the understanding of risk, its assessment, management and mitigation and your orientation to learn. Applying thinking, perspectives, risk appetite and learning appropriately will enable you to spot opportunities and make judgement calls with limited information. All these ingredients come together to help you think through strategy from an outside in perspective and helps in formulating strategies. -

-

- This course will conclude offering you the perspectives and experiences of leaders when engaging with strategy and their learnings from it. + {programme.methodologyDesc}

@@ -1042,7 +1420,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { Learn from industry leaders and renowned academics with decades of executive experience.

- +
{faculty.map((member, index) => ( @@ -1053,12 +1431,12 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { {member.name.split(' ').map(n => n[0]).join('')} - +

{member.name}

{member.title}

{member.organization}

{member.bio}

- +
{member.credentials.map((credential, credIndex) => ( @@ -1101,7 +1479,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { Hear from leaders who have transformed their careers through our programme.

- + {/* Landing Page Testimonials Design */}
{/* Testimonials Cards Container */} @@ -1111,7 +1489,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { {testimonial.type === 'video' ? ( -
{ setSelectedVideo(testimonial.videoUrl!); @@ -1137,10 +1515,10 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { alt={`${testimonial.name} video testimonial`} className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105" /> - + {/* Video Overlay with Gradient */}
- + {/* Play Button - Compact Design */}
- @@ -1177,7 +1555,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { {testimonial.company && ` • ${testimonial.company}`}

- + {/* Star Rating */}
{[1, 2, 3, 4, 5].map((star) => ( @@ -1214,7 +1592,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { )}
- + {/* Star Rating - Top Right */}
{[1, 2, 3, 4, 5].map((star) => ( @@ -1265,7 +1643,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { Find answers to common questions about the programme structure, requirements, and enrollment process.

- +
{faqs.map((faq, index) => ( @@ -1299,126 +1677,267 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { {/* Enhanced Related Programmes */} -
-
-
-
-

You Might Also Like

-

- Explore related programmes to continue your leadership journey and expand your expertise across different domains. -

-
- -
- {relatedProgrammes.map((related, index) => ( - -
- -
- - {/* Top Badges */} -
- - {related.category} - - - {related.level} - -
-
- - -

- {related.title} -

-

{related.description}

- - {/* Metadata Section */} -
-
- - - {related.duration} - - - - 1,500+ - -
-
- {[1, 2, 3, 4, 5].map((star) => ( - - ))} - 4.8 -
-
- - {/* Pricing Section */} -
-
- {related.price} - ₹49,999 - Save 25% -
-
- - {/* Action Buttons */} -
- - -
-
- - ))} +
+ +
+ + {/* Top Badges */} +
+ + {course.course_category_name || "Course"} + + + {course.duration || "Self-Paced"} Hours + +
+
+ + +

+ {course.course_name} +

+

+ {course.course_desc || "Discover new skills and advance your career with this comprehensive course."} +

+ + {/* Metadata Section */} +
+
+ + + {course.duration + ? `${course.duration} ${course.duration === 1 ? "Hour" : "Hours"}` + : "20 hours"} + + + + {course.total_lessons || 1500}+ + {/* lessons */} + +
+
+ {[1, 2, 3, 4, 5].map((star) => ( + + ))} + {avgRating.toFixed(1)} +
+
+ + {/* Pricing Section */} +
+
+ {formattedPrice} + {originalPrice && originalPrice !== formattedPrice && ( + {originalPrice} + )} + {originalPrice && originalPrice !== formattedPrice && ( + + Save {Math.round(((parseFloat(course.price) - parseFloat(course.best_value)) / parseFloat(course.price)) * 100)}% + + )} +
+
+ + {/* Action Buttons */} +
+ + +
+
+ + ); + })} +
+ ) : ( + // Fallback to mock data if no recommended courses +
+ {mockRelatedProgrammes.map((related, index) => ( + handleCourseClick(related.id)} + > +
+ +
+ + {/* Top Badges */} +
+ + {related.category} + + + {related.level} + +
+
+ + +

+ {related.title} +

+

{related.description}

+ + {/* Metadata Section */} +
+
+ + + {related.duration} + + + + 1,500+ + +
+
+ {[1, 2, 3, 4, 5].map((star) => ( + + ))} + 4.8 +
+
+ + {/* Pricing Section */} +
+
+ {related.price} + ₹49,999 + Save 25% +
+
+ + {/* Action Buttons */} +
+ + +
+
+ + ))} +
+ )}
-
-
- + + )} + {/* Focused CTA Banner - Blue Box Design */}
{/* Background Image */} -
- +
- + {/* Blue Content Box */} -
{/* Badge */}
-
- + {/* Headline */}

Ready to Lead?{' '} Join Today

- + {/* Description */}

Transform your leadership potential with expert guidance and proven frameworks.

- + {/* CTA Button */}
- + {/* Support Text */}

Speak with our experts • Free consultation • Custom solutions @@ -1483,7 +2002,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {

- +
@@ -1491,7 +2010,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { id="name" required value={brochureFormData.name} - onChange={(e) => setBrochureFormData({...brochureFormData, name: e.target.value})} + onChange={(e) => setBrochureFormData({ ...brochureFormData, name: e.target.value })} />
@@ -1501,7 +2020,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { type="email" required value={brochureFormData.email} - onChange={(e) => setBrochureFormData({...brochureFormData, email: e.target.value})} + onChange={(e) => setBrochureFormData({ ...brochureFormData, email: e.target.value })} />
@@ -1510,7 +2029,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { id="phone" type="tel" value={brochureFormData.phone} - onChange={(e) => setBrochureFormData({...brochureFormData, phone: e.target.value})} + onChange={(e) => setBrochureFormData({ ...brochureFormData, phone: e.target.value })} />
@@ -1518,7 +2037,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { setBrochureFormData({...brochureFormData, company: e.target.value})} + onChange={(e) => setBrochureFormData({ ...brochureFormData, company: e.target.value })} />
@@ -1526,10 +2045,10 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) { setBrochureFormData({...brochureFormData, designation: e.target.value})} + onChange={(e) => setBrochureFormData({ ...brochureFormData, designation: e.target.value })} />
- +
diff --git a/src/components/WebinarDetail.tsx b/src/components/WebinarDetail.tsx index 197cbbf..ff176b3 100644 --- a/src/components/WebinarDetail.tsx +++ b/src/components/WebinarDetail.tsx @@ -44,7 +44,7 @@ import { navigateTo } from './Router'; import { ImageWithFallback } from './figma/ImageWithFallback'; import { BrandedTag } from './about/BrandedTag'; import { PrimaryCTAButton } from './PrimaryCTAButton'; -import { toast } from 'sonner@2.0.3'; +import { toast } from 'sonner'; import { getWebinarBySlug, sharedWebinarsData, type WebinarData } from '../data/webinarsData'; interface WebinarDetailProps { diff --git a/src/components/Webinars.tsx b/src/components/Webinars.tsx index e30eeed..e723506 100644 --- a/src/components/Webinars.tsx +++ b/src/components/Webinars.tsx @@ -1,151 +1,100 @@ -import React, { useState, useRef, useEffect } from 'react'; -import { Button } from './ui/button'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/card'; -import { Badge } from './ui/badge'; -import { Input } from './ui/input'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select'; -import { Slider } from './ui/slider'; -import { ImageWithFallback } from './figma/ImageWithFallback'; -import { PrimaryCTAButton } from './PrimaryCTAButton'; -import { navigateTo } from './Router'; -import { sharedWebinarsData, type WebinarData } from '../data/webinarsData'; -import { WebcastCTABanner } from './WebcastCTABanner'; import { - Search, - Calendar, - Clock, - Users, - Play, ArrowRight, + ChevronLeft, + ChevronRight, + Clock, + Eye, Filter, Grid, List, - SortAsc, - Eye, + Play, + Search, Star, - ChevronLeft, - ChevronRight, + Users, X } from 'lucide-react'; +import { useEffect, useRef, useState } from 'react'; +import { useWebinarListQuery, type WebinarItem } from '../redux/services/webinarApi'; +import { ImageWithFallback } from './figma/ImageWithFallback'; +import { FullScreenLoader } from './FullScreenLoader'; +import { navigateTo } from './Router'; +import { Badge } from './ui/badge'; +import { Button } from './ui/button'; +import { Card, CardContent } from './ui/card'; +import { Input } from './ui/input'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select'; +import { Slider } from './ui/slider'; +import { WebcastCTABanner } from './WebcastCTABanner'; + +// Status options with proper mapping to API values +const statusOptions = [ + { value: 'scheduled', label: '📅 Scheduled', color: 'bg-blue-100 text-blue-800 border-blue-200' }, + { value: 'live', label: '🔴 Live', color: 'bg-red-100 text-red-800 border-red-200' }, + { value: 'ended', label: '✅ Ended', color: 'bg-gray-100 text-gray-800 border-gray-200' }, + { value: 'cancelled', label: '❌ Cancelled', color: 'bg-red-50 text-red-600 border-red-200' } +]; + +const sortOptions = [ + { value: 'most_popular', label: 'Most Popular' }, + { value: 'newest', label: 'Newest First' }, + { value: 'oldest', label: 'Oldest First' }, + { value: 'title', label: 'Title A-Z' }, + { value: 'duration', label: 'Duration' } +]; + +// Static tags for all webinars +const staticTags = ['Leadership', 'Executive Development', 'Strategy', 'Innovation', 'Change Management', 'Business Growth', 'Team Building', 'Digital Transformation']; export function Webinars() { const [searchTerm, setSearchTerm] = useState(''); const [selectedCategory, setSelectedCategory] = useState('All Categories'); - const [selectedFormat, setSelectedFormat] = useState('All Formats'); - const [selectedLevel, setSelectedLevel] = useState('All Levels'); - - // Updated state for multi-select status pills const [selectedStatuses, setSelectedStatuses] = useState([]); - - // Updated state for duration slider (min, max in minutes) const [durationRange, setDurationRange] = useState([0, 120]); - - // Attendee range slider state const [attendeeRange, setAttendeeRange] = useState([0, 5000]); - - const [sortBy, setSortBy] = useState('Most Popular'); + const [sortBy, setSortBy] = useState('most_popular'); const [viewType, setViewType] = useState<'grid' | 'list'>('grid'); const [currentPage, setCurrentPage] = useState(1); const webinarsPerPage = 6; const containerRef = useRef(null); - // Use shared webinars data instead of local mock data - const webinars = sharedWebinarsData; - - // Get unique values for filters from shared data - const categories = ['All Categories', ...Array.from(new Set(webinars.map(webinar => webinar.category)))]; - const formats = ['All Formats', ...Array.from(new Set(webinars.map(webinar => webinar.format)))]; - const levels = ['All Levels', ...Array.from(new Set(webinars.map(webinar => webinar.level)))]; - - // Status options for pills - updated to match shared data structure - const statusOptions = [ - { value: 'upcoming', label: '📅 Upcoming', color: 'bg-blue-100 text-blue-800 border-blue-200' }, - { value: 'live', label: '🔴 Live', color: 'bg-red-100 text-red-800 border-red-200' }, - { value: 'recorded', label: '▶️ Recorded', color: 'bg-green-100 text-green-800 border-green-200' }, - { value: 'featured', label: '⭐ Featured', color: 'bg-yellow-100 text-yellow-800 border-yellow-200' } - ]; - - const sortOptions = [ - { value: 'Most Popular', label: 'Most Popular' }, - { value: 'newest', label: 'Newest First' }, - { value: 'oldest', label: 'Oldest First' }, - { value: 'title', label: 'Title A-Z' }, - { value: 'duration', label: 'Duration' } - ]; - - // Helper function to convert attendees string to number - const parseAttendees = (attendeesStr: string): number => { - const numStr = attendeesStr.replace(/[^\d]/g, ''); - return parseInt(numStr) || 0; - }; - - // Helper function to convert duration string to minutes - const parseDuration = (durationStr: string): number => { - const numStr = durationStr.replace(/[^\d]/g, ''); - return parseInt(numStr) || 0; - }; - - // Filter and sort webinars - const filteredWebinars = webinars.filter(webinar => { - const matchesSearch = webinar.title.toLowerCase().includes(searchTerm.toLowerCase()) || - webinar.description.toLowerCase().includes(searchTerm.toLowerCase()) || - webinar.presenter.toLowerCase().includes(searchTerm.toLowerCase()) || - webinar.tags.some(tag => tag.toLowerCase().includes(searchTerm.toLowerCase())); - const matchesCategory = selectedCategory === 'All Categories' || webinar.category === selectedCategory; - const matchesFormat = selectedFormat === 'All Formats' || webinar.format === selectedFormat; - const matchesLevel = selectedLevel === 'All Levels' || webinar.level === selectedLevel; - - const matchesStatus = selectedStatuses.length === 0 || - selectedStatuses.some(status => { - if (status === 'featured') return webinar.featured; - return webinar.status === status; - }); - - const durationMinutes = parseDuration(webinar.duration); - const matchesDuration = durationMinutes >= durationRange[0] && durationMinutes <= durationRange[1]; - - const attendeeCount = parseAttendees(webinar.attendees); - const matchesAttendees = attendeeCount >= attendeeRange[0] && attendeeCount <= attendeeRange[1]; - - return matchesSearch && matchesCategory && matchesFormat && matchesLevel && matchesStatus && matchesDuration && matchesAttendees; - }).sort((a, b) => { - switch (sortBy) { - case 'Most Popular': - // Add logic for "Most Popular" - you might want to use views, attendees, or featured status - return (b.featured ? 1 : 0) - (a.featured ? 1 : 0) || - parseAttendees(b.attendees) - parseAttendees(a.attendees); - case 'newest': - return new Date(b.date).getTime() - new Date(a.date).getTime(); - case 'oldest': - return new Date(a.date).getTime() - new Date(b.date).getTime(); - case 'title': - return a.title.localeCompare(b.title); - case 'duration': - return parseDuration(b.duration) - parseDuration(a.duration); - default: - return 0; - } + // Fetch webinars from API + const { + data: webinarResponse, + isLoading, + isError, + } = useWebinarListQuery({ + limit: 100, + offset: 0, + search: searchTerm || undefined, + status: selectedStatuses.length > 0 ? selectedStatuses : undefined, + minDuration: durationRange[0] > 0 ? durationRange[0] : undefined, + maxDuration: durationRange[1] < 120 ? durationRange[1] : undefined, + minAttendees: attendeeRange[0] > 0 ? attendeeRange[0] : undefined, + maxAttendees: attendeeRange[1] < 5000 ? attendeeRange[1] : undefined, + sortBy: sortBy as any, }); - // Statistics - const stats = { - total: webinars.length, - upcoming: webinars.filter(w => w.status === 'upcoming').length, - live: webinars.filter(w => w.status === 'live').length, - recorded: webinars.filter(w => w.status === 'recorded').length, - featured: webinars.filter(w => w.featured).length, - categories: new Set(webinars.map(w => w.category)).size + const webinars = webinarResponse?.data?.items || []; + + // Get random tags for each webinar (3 random tags from staticTags) + const getRandomTags = (seed: string) => { + // Use the webinar ID as seed to get consistent tags for each webinar + const hash = seed.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0); + const shuffled = [...staticTags]; + for (let i = shuffled.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; + } + return shuffled.slice(0, 3); }; - // Paginate results - const totalPages = Math.ceil(filteredWebinars.length / webinarsPerPage); - const currentWebinars = filteredWebinars.slice((currentPage - 1) * webinarsPerPage, currentPage * webinarsPerPage); - - console.log('Filtered webinars:', filteredWebinars.length); -console.log('Total pages:', totalPages); -console.log('Current page:', currentPage); -console.log('Current webinars count:', currentWebinars.length); + // Get unique categories from API data + const categories = [ + 'All Categories', + ...Array.from(new Set(webinars.map(webinar => webinar.session_title?.split(' ')[0] || 'General'))) + ]; + // Helper functions const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString('en-US', { year: 'numeric', @@ -154,26 +103,81 @@ console.log('Current webinars count:', currentWebinars.length); }); }; + const formatDuration = (minutes: number) => { + if (minutes >= 60) { + const hours = Math.floor(minutes / 60); + const remainingMinutes = minutes % 60; + return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}m` : `${hours}h`; + } + return `${minutes}min`; + }; + + const getStatusBadge = (status: string) => { + switch (status) { + case 'live': + return LIVE NOW; + case 'scheduled': + return SCHEDULED; + case 'ended': + return ENDED; + case 'cancelled': + return CANCELLED; + default: + return null; + } + }; + + const getActionText = (status: string) => { + switch (status) { + case 'live': + return 'Join Now'; + case 'scheduled': + return 'Register'; + case 'ended': + return 'Watch Recording'; + case 'cancelled': + return 'Cancelled'; + default: + return 'Learn More'; + } + }; + + // Statistics + const stats = { + total: webinars.length, + scheduled: webinars.filter(w => w.webinar_status === 'scheduled').length, + live: webinars.filter(w => w.webinar_status === 'live').length, + ended: webinars.filter(w => w.webinar_status === 'ended').length, + cancelled: webinars.filter(w => w.webinar_status === 'cancelled').length, + categories: categories.length - 1 + }; + + // Filter webinars + const filteredWebinars = webinars.filter(webinar => { + const matchesCategory = selectedCategory === 'All Categories' || + (webinar.session_title && webinar.session_title.toLowerCase().includes(selectedCategory.toLowerCase())); + return matchesCategory; + }); + + // Paginate results + const totalPages = Math.ceil(filteredWebinars.length / webinarsPerPage); + const currentWebinars = filteredWebinars.slice((currentPage - 1) * webinarsPerPage, currentPage * webinarsPerPage); + const clearAllFilters = () => { setSearchTerm(''); setSelectedCategory('All Categories'); - setSelectedFormat('All Formats'); - setSelectedLevel('All Levels'); setSelectedStatuses([]); setDurationRange([0, 120]); setAttendeeRange([0, 5000]); - setSortBy('Most Popular'); + setSortBy('most_popular'); }; const hasActiveFilters = searchTerm || selectedCategory !== 'All Categories' || - selectedFormat !== 'All Formats' || - selectedLevel !== 'All Levels' || selectedStatuses.length > 0 || durationRange[0] !== 0 || durationRange[1] !== 120 || attendeeRange[0] !== 0 || attendeeRange[1] !== 5000; - // Status pill toggle function const toggleStatus = (status: string) => { setSelectedStatuses(prev => prev.includes(status) @@ -182,95 +186,78 @@ console.log('Current webinars count:', currentWebinars.length); ); }; - // Reset to page 1 when filters change useEffect(() => { setCurrentPage(1); - }, [searchTerm, selectedCategory, selectedFormat, selectedLevel, selectedStatuses, durationRange, attendeeRange, sortBy]); + }, [searchTerm, selectedCategory, selectedStatuses, durationRange, attendeeRange, sortBy]); - // Updated WebinarCard component that navigates to consistent route - const WebinarCard = ({ webinar }: { webinar: WebinarData }) => { + const WebinarCard = ({ webinar }: { webinar: WebinarItem }) => { const handleCardClick = () => { - // Navigate to consistent webinar detail route - navigateTo(`/webinar/${webinar.slug}`); - }; - - const getStatusBadge = () => { - switch (webinar.status) { - case 'live': - return LIVE; - case 'upcoming': - return UPCOMING; - case 'recorded': - return RECORDED; - default: - return null; + if (webinar.webinar_status !== 'cancelled') { + navigateTo(`/webinar/${webinar.id}`); } }; - const getActionText = () => { - switch (webinar.status) { - case 'live': - return 'Join Now'; - case 'upcoming': - return 'Register'; - case 'recorded': - return 'Watch Recording'; - default: - return 'Learn More'; - } - }; + const isCancelled = webinar.webinar_status === 'cancelled'; + const webinarTags = getRandomTags(webinar.id); if (viewType === 'list') { return (
{/* Thumbnail */} -
- +
+
{/* Content */}
- {getStatusBadge()} - {webinar.featured && ( - Featured - )} + {getStatusBadge(webinar.webinar_status)}
- {formatDate(webinar.date)} + {formatDate(webinar.session_datetime)}
-

{webinar.title}

-

{webinar.description}

+

{webinar.session_title}

+

+ {webinar.description || 'No description available'} +

+ + {/* Tags */} +
+ {webinarTags.map((tag, idx) => ( + + {tag} + + ))} +
- {webinar.presenter} + {webinar.owner || 'Kautilya Leadership'} - {webinar.duration} + {formatDuration(webinar.duration_minutes)} - {webinar.attendees} + Max {webinar.max_attendee.toLocaleString()}
-
- {getActionText()} - -
+ {!isCancelled && ( +
+ {getActionText(webinar.webinar_status)} + +
+ )}
@@ -279,100 +266,122 @@ console.log('Current webinars count:', currentWebinars.length); ); } + // Grid View return ( {/* Image */} -
- +
+
+ +
{/* Status Badge */}
- {getStatusBadge()} + {getStatusBadge(webinar.webinar_status)}
- {/* Featured Badge */} - {webinar.featured && ( -
- - - Featured - -
- )} - {/* Play Icon Overlay */} -
-
- + {!isCancelled && ( +
+
+ +
-
+ )}
{/* Content */}
- {webinar.category} + {webinar.recurring_webinar ? 'Recurring' : 'One-time'} - {formatDate(webinar.date)} + {formatDate(webinar.session_datetime)}

- {webinar.title} + {webinar.session_title}

- {webinar.description} + {webinar.description || 'No description available'}

+ {/* Tags */} +
+ {webinarTags.slice(0, 2).map((tag, idx) => ( + + {tag} + + ))} +
+
- {webinar.presenter} + {webinar.owner || 'Kautilya Leadership'}
- {webinar.duration} + {formatDuration(webinar.duration_minutes)}
- {webinar.attendees} + Max {webinar.max_attendee.toLocaleString()}
-
-
- {webinar.tags.slice(0, 2).map((tag, index) => ( - - {tag} - - ))} + {!isCancelled && ( +
+
+ {webinar.require_registration && ( + <> + + Registration Required + + )} +
+
+ {getActionText(webinar.webinar_status)} + +
-
- {getActionText()} - -
-
+ )} ); }; + if (isLoading) { + return ( +
+ +
+ ); + } + + if (isError) { + return ( +
+
+

Error loading webinars. Please try again later.

+ +
+
+ ); + } + return (
- {/* Hero Section with Background Image */} + {/* Hero Section */}
- {/* Background Image */}
- {/* Hero Content */}

Leadership Webcasts &
Expert Insights

-

Explore our comprehensive collection of expert insights, research, and practical guidance to elevate your leadership journey and drive organizational excellence. @@ -397,8 +404,7 @@ console.log('Current webinars count:', currentWebinars.length);

- {/* Statistics Strip at Bottom */} -
+
@@ -424,12 +430,11 @@ console.log('Current webinars count:', currentWebinars.length);
- {/* Search Bar */}
setSearchTerm(e.target.value)} className="pl-10 pr-4 py-3 text-body rounded-lg border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 transition-all duration-200 w-full bg-gray-50" @@ -441,7 +446,6 @@ console.log('Current webinars count:', currentWebinars.length); />
- {/* View Toggle and Sort */}
- {/* Main Content Section with Sidebar */} + {/* Main Content Section */}
- {/* Left Sidebar - Sticky Filters */} + {/* Left Sidebar Filters */}
- {/* Filter Header */}
- +
-

- Filters -

+

Filters

{hasActiveFilters && (
- {/* Filter Content */}
- {/* Category Filter */} -
- - -
- - {/* Format Filter */} -
- - -
- - {/* Level Filter */} -
- - -
- - {/* Status Filter - Multi-select Pills */} + {/* Status Filter */}
- {/* Duration Filter - Slider */} + {/* Duration Filter */}
{durationRange[0]} min {durationRange[1]} min
-
- {durationRange[0] === 0 && durationRange[1] === 120 - ? 'All durations' - : `${durationRange[0]}-${durationRange[1]} minutes` - } -
- {/* Attendee Count Filter - Slider */} + {/* Attendee Filter */}
{attendeeRange[0].toLocaleString()} {attendeeRange[1].toLocaleString()}+
-
- {attendeeRange[0] === 0 && attendeeRange[1] === 5000 - ? 'Any size' - : `${attendeeRange[0].toLocaleString()}-${attendeeRange[1].toLocaleString()}+` - } -
@@ -672,24 +603,22 @@ console.log('Current webinars count:', currentWebinars.length); {/* Right Main Content */}
- {/* Results Header */}
- Showing {currentWebinars.length} of {filteredWebinars.length} webcasts + Showing {currentWebinars.length} of {filteredWebinars.length} webinars
Page {currentPage} of {totalPages}
- {/* Content Area */}
{currentWebinars.length === 0 ? (
-

No webcasts found

+

No webinars found

Try adjusting your filters or search terms

@@ -701,7 +630,6 @@ console.log('Current webinars count:', currentWebinars.length);
) : ( <> - {/* Grid View */} {viewType === 'grid' ? (
{currentWebinars.map((webinar) => ( @@ -709,7 +637,6 @@ console.log('Current webinars count:', currentWebinars.length); ))}
) : ( - /* List View */
{currentWebinars.map((webinar) => ( @@ -723,64 +650,46 @@ console.log('Current webinars count:', currentWebinars.length); -
- {Array.from({ length: totalPages }, (_, i) => { + {Array.from({ length: Math.min(totalPages, 5) }, (_, i) => { const page = i + 1; - // Show limited pages for better UX - if (totalPages > 7) { - const showPage = - page === 1 || - page === totalPages || - (page >= currentPage - 1 && page <= currentPage + 1); - - if (!showPage) { - if (page === currentPage - 2 || page === currentPage + 2) { - return ...; - } - return null; - } - } - return ( ); })} + {totalPages > 5 && ...} + {totalPages > 5 && ( + + )}
-
- {/* Webcast CTA Banner */}
); diff --git a/src/components/services/CultureCompetence.tsx b/src/components/services/CultureCompetence.tsx index 08f678b..2188be5 100644 --- a/src/components/services/CultureCompetence.tsx +++ b/src/components/services/CultureCompetence.tsx @@ -166,6 +166,16 @@ interface ServicePageData { video_url: string | null; display_order: number; }>; + cta_section: { + id: string; + background_image_url: string; + text: string; + cta_text: string; + cta_destination: string; + description: string; + landing_page_type: string; + service_type: string; + }; } // Map API icons to Lucide icons @@ -189,17 +199,17 @@ const getIconComponent = (iconUrl: string) => { '/icons/coaching.svg': MessageCircle, '/icons/compass.svg': Compass, }; - + return iconMap[iconUrl] || Target; }; export function CultureCompetence() { const [expandedPhase, setExpandedPhase] = useState(0); - - const { data: apiResponse, isLoading, error } = useGetServiceListQuery({ - service_type: 'culture_and_competence_consulting' + + const { data: apiResponse, isLoading, error } = useGetServiceListQuery({ + service_type: 'culture_and_competence_consulting' }); - + const apiData = apiResponse?.data as ServicePageData | undefined; useEffect(() => { @@ -207,13 +217,13 @@ export function CultureCompetence() { }, []); // Loading state - if (isLoading) { - return ( -
- -
- ); - } + if (isLoading) { + return ( +
+ +
+ ); + } // Error state if (error) { @@ -266,7 +276,7 @@ export function CultureCompetence() { const designationParts = testimonial.designation?.split(',') || []; const role = designationParts[0]?.trim() || ''; const company = designationParts[1]?.trim() || ''; - + return { id: parseInt(testimonial.id) || 0, name: testimonial.name || '', @@ -473,254 +483,254 @@ export function CultureCompetence() { {/* 4. Our Approach */}
-
-
-
-
- -

- {apiData?.approach_section?.title || "Our Approach to Leadership Development"} -

-

- {apiData?.approach_section?.description || "A systematic, research-backed methodology that transforms leadership potential into measurable business impact."} -

-
+
+
+
+
+ +

+ {apiData?.approach_section?.title || "Our Approach to Leadership Development"} +

+

+ {apiData?.approach_section?.description || "A systematic, research-backed methodology that transforms leadership potential into measurable business impact."} +

+
- {/* Flowchart Container with Connecting Lines */} -
- {/* Only render if approach_cards exist and have items */} - {apiData?.approach_section?.approach_cards && apiData.approach_section.approach_cards.length > 0 && ( - <> - {/* Desktop: Horizontal Flowchart */} -
-
- {/* Row 1: First 3 approach cards from API */} -
- {apiData.approach_section.approach_cards.slice(0, 3).map((card, idx) => { - const IconComponent = getIconComponent(card.icon_url); - return ( -
-
- {IconComponent ? : } -
-

{card.title}

-

{card.description}

- {card.bullets && card.bullets.length > 0 && ( -
- {card.bullets.slice(0, 3).map((bullet, bulletIdx) => ( -
- {bullet} + {/* Flowchart Container with Connecting Lines */} +
+ {/* Only render if approach_cards exist and have items */} + {apiData?.approach_section?.approach_cards && apiData.approach_section.approach_cards.length > 0 && ( + <> + {/* Desktop: Horizontal Flowchart */} +
+
+ {/* Row 1: First 3 approach cards from API */} +
+ {apiData.approach_section.approach_cards.slice(0, 3).map((card, idx) => { + const IconComponent = getIconComponent(card.icon_url); + return ( +
+
+ {IconComponent ? : }
- ))} +

{card.title}

+

{card.description}

+ {card.bullets && card.bullets.length > 0 && ( +
+ {card.bullets.slice(0, 3).map((bullet, bulletIdx) => ( +
+ {bullet} +
+ ))} +
+ )} +
+ ); + })} + + {/* Arrows between first 3 cards */} + {apiData.approach_section.approach_cards.length >= 2 && ( +
+
+ +
+ )} + {apiData.approach_section.approach_cards.length >= 3 && ( +
+
+
)}
- ); - })} - {/* Arrows between first 3 cards */} - {apiData.approach_section.approach_cards.length >= 2 && ( -
-
- -
- )} - {apiData.approach_section.approach_cards.length >= 3 && ( -
-
- -
- )} -
+ {/* Vertical Connector - Center Flow Down */} + {apiData.approach_section.approach_cards.length > 3 && ( +
+
+
+ +
+
+ )} - {/* Vertical Connector - Center Flow Down */} - {apiData.approach_section.approach_cards.length > 3 && ( -
-
-
- + {/* Row 2: Next 2 approach cards (if available) */} + {apiData.approach_section.approach_cards.length >= 4 && ( +
+ {apiData.approach_section.approach_cards.slice(3, 5).map((card, idx) => { + const IconComponent = getIconComponent(card.icon_url); + const isFirstOfPair = idx === 0; + return ( +
+
+ {IconComponent ? : } +
+

{card.title}

+

{card.description}

+ {card.bullets && card.bullets.length > 0 && ( +
+ {card.bullets.slice(0, 3).map((bullet, bulletIdx) => ( +
+ {bullet} +
+ ))} +
+ )} +
+ ); + })} + + {/* Arrow between the two cards */} + {apiData.approach_section.approach_cards.length >= 5 && ( +
+
+ +
+ )} +
+ )} + + {/* Final Vertical Connector - Center Flow Down to Outcome */} +
+
+
+ +
+
+ + {/* Row 3: Expected Outcome - Use API outcomes data */} +
+
+
+ {apiData.approach_section.outcomes && apiData.approach_section.outcomes[0] ? (() => { + const OutcomeIcon = getIconComponent(apiData.approach_section.outcomes[0].icon_url); + return OutcomeIcon ? : ; + })() : } +

+ {apiData.approach_section.outcomes?.[0]?.title || "Expected Outcome"} +

+
+

+ {apiData.approach_section.outcomes?.[0]?.description || "A systematic, measurable leadership pipeline that accelerates talent development and succession readiness."} +

+
+ {apiData.approach_section.outcomes?.[0]?.bullets && apiData.approach_section.outcomes[0].bullets.length > 0 ? ( + apiData.approach_section.outcomes[0].bullets.slice(0, 2).map((bullet, idx) => ( +
+ + {bullet} +
+ )) + ) : ( +
+ + Proven ROI on Leadership Investment +
+ )} +
+
+
- )} - {/* Row 2: Next 2 approach cards (if available) */} - {apiData.approach_section.approach_cards.length >= 4 && ( -
- {apiData.approach_section.approach_cards.slice(3, 5).map((card, idx) => { + {/* Tablet & Mobile: Vertical Flowchart */} +
+ {/* Map all approach cards vertically */} + {apiData.approach_section.approach_cards.map((card, idx) => { const IconComponent = getIconComponent(card.icon_url); - const isFirstOfPair = idx === 0; + const isEven = idx % 2 === 0; return ( -
-
- {IconComponent ? : } +
+
+
+ {IconComponent ? : } +
+

{card.title}

+

{card.description}

+ {card.bullets && card.bullets.length > 0 && ( +
+ {card.bullets.map((bullet, bulletIdx) => ( +
+ {bullet} +
+ ))} +
+ )}
-

{card.title}

-

{card.description}

- {card.bullets && card.bullets.length > 0 && ( -
- {card.bullets.slice(0, 3).map((bullet, bulletIdx) => ( -
- {bullet} -
- ))} + {/* Connector Arrow */} + {idx < apiData.approach_section.approach_cards.length - 1 && ( +
+
)}
); })} - {/* Arrow between the two cards */} - {apiData.approach_section.approach_cards.length >= 5 && ( -
-
- + {/* Expected Outcome - Use API outcomes data */} +
+
+ {apiData.approach_section.outcomes && apiData.approach_section.outcomes[0] ? (() => { + const OutcomeIcon = getIconComponent(apiData.approach_section.outcomes[0].icon_url); + return OutcomeIcon ? : ; + })() : } +

+ {apiData.approach_section.outcomes?.[0]?.title || "Expected Outcome"} +

- )} -
- )} - - {/* Final Vertical Connector - Center Flow Down to Outcome */} -
-
-
- -
-
- - {/* Row 3: Expected Outcome - Use API outcomes data */} -
-
-
- {apiData.approach_section.outcomes && apiData.approach_section.outcomes[0] ? (() => { - const OutcomeIcon = getIconComponent(apiData.approach_section.outcomes[0].icon_url); - return OutcomeIcon ? : ; - })() : } -

- {apiData.approach_section.outcomes?.[0]?.title || "Expected Outcome"} -

-
-

- {apiData.approach_section.outcomes?.[0]?.description || "A systematic, measurable leadership pipeline that accelerates talent development and succession readiness."} -

-
- {apiData.approach_section.outcomes?.[0]?.bullets && apiData.approach_section.outcomes[0].bullets.length > 0 ? ( - apiData.approach_section.outcomes[0].bullets.slice(0, 2).map((bullet, idx) => ( -
- - {bullet} -
- )) - ) : ( -
- - Proven ROI on Leadership Investment -
- )} -
-
-
-
-
- - {/* Tablet & Mobile: Vertical Flowchart */} -
- {/* Map all approach cards vertically */} - {apiData.approach_section.approach_cards.map((card, idx) => { - const IconComponent = getIconComponent(card.icon_url); - const isEven = idx % 2 === 0; - return ( -
-
-
- {IconComponent ? : } -
-

{card.title}

-

{card.description}

- {card.bullets && card.bullets.length > 0 && ( -
- {card.bullets.map((bullet, bulletIdx) => ( -
- {bullet} +

+ {apiData.approach_section.outcomes?.[0]?.description || "A systematic, measurable leadership pipeline that accelerates talent development and succession readiness."} +

+
+ {apiData.approach_section.outcomes?.[0]?.bullets && apiData.approach_section.outcomes[0].bullets.length > 0 ? ( + apiData.approach_section.outcomes[0].bullets.slice(0, 2).map((bullet, idx) => ( +
+ + {bullet}
- ))} -
- )} -
- {/* Connector Arrow */} - {idx < apiData.approach_section.approach_cards.length - 1 && ( -
- + )) + ) : ( +
+ + Proven ROI on Leadership Investment +
+ )}
- )} +
- ); - })} + + )} +
- {/* Expected Outcome - Use API outcomes data */} -
-
- {apiData.approach_section.outcomes && apiData.approach_section.outcomes[0] ? (() => { - const OutcomeIcon = getIconComponent(apiData.approach_section.outcomes[0].icon_url); - return OutcomeIcon ? : ; - })() : } -

- {apiData.approach_section.outcomes?.[0]?.title || "Expected Outcome"} -

+ {/* Framework Effectiveness - Stats Section */} + {apiData?.stats_section && apiData.stats_section.stat_cards && apiData.stats_section.stat_cards.length > 0 && ( +
+
+

{apiData.stats_section.title || "Framework Effectiveness"}

+

+ {apiData.stats_section.description || "Measurable results that demonstrate the impact of our leadership development approach."} +

-

- {apiData.approach_section.outcomes?.[0]?.description || "A systematic, measurable leadership pipeline that accelerates talent development and succession readiness."} -

-
- {apiData.approach_section.outcomes?.[0]?.bullets && apiData.approach_section.outcomes[0].bullets.length > 0 ? ( - apiData.approach_section.outcomes[0].bullets.slice(0, 2).map((bullet, idx) => ( -
- - {bullet} + +
+ {apiData.stats_section.stat_cards.map((stat) => { + const IconComponent = getIconComponent(stat.icon_url); + return ( +
+
+ {IconComponent ? : } +
+
{stat.value || "0"}
+

{stat.label || ""}

- )) - ) : ( -
- - Proven ROI on Leadership Investment -
- )} + ); + })}
-
- - )} -
- - {/* Framework Effectiveness - Stats Section */} - {apiData?.stats_section && apiData.stats_section.stat_cards && apiData.stats_section.stat_cards.length > 0 && ( -
-
-

{apiData.stats_section.title || "Framework Effectiveness"}

-

- {apiData.stats_section.description || "Measurable results that demonstrate the impact of our leadership development approach."} -

-
- -
- {apiData.stats_section.stat_cards.map((stat) => { - const IconComponent = getIconComponent(stat.icon_url); - return ( -
-
- {IconComponent ? : } -
-
{stat.value || "0"}
-

{stat.label || ""}

-
- ); - })} + )}
- )} -
-
-
-
+
+
{/* 5. Sample Program Format */}
@@ -870,41 +880,45 @@ export function CultureCompetence() { /> {/* 8. CTA Section */} -
-
- -
-
-
- -
-
- -

- Ready to transform your culture? - - {" "}Get in touch{" "} - - to align strategy and performance. -

- navigateTo('/contact?topic=culture-competence')} - ariaLabel="Schedule a culture and competence consultation" + {apiData.cta_section && ( +
+
+ -

- Connect with our culture transformation experts to discuss building a high-performance culture aligned with your business strategy. -

+
+
-
-
+ +
+
+ +

+ {apiData.cta_section.text} + + {" "}Get in touch{" "} + + to align strategy and performance. +

+ navigateTo(apiData.cta_section.cta_destination)} + ariaLabel={apiData.cta_section.cta_text} + /> + {apiData.cta_section.description && ( +

+ {apiData.cta_section.description} +

+ )} +
+
+
+ )}
); } \ No newline at end of file diff --git a/src/components/services/ExecutiveCoaching.tsx b/src/components/services/ExecutiveCoaching.tsx index c48845e..17c5917 100644 --- a/src/components/services/ExecutiveCoaching.tsx +++ b/src/components/services/ExecutiveCoaching.tsx @@ -169,6 +169,16 @@ interface ServicePageData { video_url: string | null; display_order: number; }>; + cta_section: { + id: string; + background_image_url: string; + text: string; + cta_text: string; + cta_destination: string; + description: string; + landing_page_type: string; + service_type: string; + }; } // Map API icons to Lucide icons @@ -191,18 +201,18 @@ const getIconComponent = (iconUrl: string) => { '/icons/network.svg': Network, '/icons/user.svg': User, }; - + return iconMap[iconUrl] || MessageCircle; }; export function ExecutiveCoaching() { const [expandedUseCase, setExpandedUseCase] = useState(null); const [expandedPhase, setExpandedPhase] = useState(0); - - const { data: apiResponse, isLoading, error } = useGetServiceListQuery({ - service_type: 'coaching_and_mentoring' + + const { data: apiResponse, isLoading, error } = useGetServiceListQuery({ + service_type: 'coaching_and_mentoring' }); - + const apiData = apiResponse?.data as ServicePageData | undefined; useEffect(() => { @@ -210,13 +220,13 @@ export function ExecutiveCoaching() { }, []); // Loading state - if (isLoading) { - return ( -
- -
- ); - } + if (isLoading) { + return ( +
+ +
+ ); + } // Error state if (error) { @@ -269,7 +279,7 @@ export function ExecutiveCoaching() { const designationParts = testimonial.designation?.split(',') || []; const role = designationParts[0]?.trim() || ''; const company = designationParts[1]?.trim() || ''; - + return { id: parseInt(testimonial.id) || 0, name: testimonial.name || '', @@ -482,254 +492,254 @@ export function ExecutiveCoaching() { {/* 4. Our Approach */}
-
-
-
-
- -

- {apiData?.approach_section?.title || "Our Approach to Leadership Development"} -

-

- {apiData?.approach_section?.description || "A systematic, research-backed methodology that transforms leadership potential into measurable business impact."} -

-
+
+
+
+
+ +

+ {apiData?.approach_section?.title || "Our Approach to Leadership Development"} +

+

+ {apiData?.approach_section?.description || "A systematic, research-backed methodology that transforms leadership potential into measurable business impact."} +

+
- {/* Flowchart Container with Connecting Lines */} -
- {/* Only render if approach_cards exist and have items */} - {apiData?.approach_section?.approach_cards && apiData.approach_section.approach_cards.length > 0 && ( - <> - {/* Desktop: Horizontal Flowchart */} -
-
- {/* Row 1: First 3 approach cards from API */} -
- {apiData.approach_section.approach_cards.slice(0, 3).map((card, idx) => { - const IconComponent = getIconComponent(card.icon_url); - return ( -
-
- {IconComponent ? : } -
-

{card.title}

-

{card.description}

- {card.bullets && card.bullets.length > 0 && ( -
- {card.bullets.slice(0, 3).map((bullet, bulletIdx) => ( -
- {bullet} + {/* Flowchart Container with Connecting Lines */} +
+ {/* Only render if approach_cards exist and have items */} + {apiData?.approach_section?.approach_cards && apiData.approach_section.approach_cards.length > 0 && ( + <> + {/* Desktop: Horizontal Flowchart */} +
+
+ {/* Row 1: First 3 approach cards from API */} +
+ {apiData.approach_section.approach_cards.slice(0, 3).map((card, idx) => { + const IconComponent = getIconComponent(card.icon_url); + return ( +
+
+ {IconComponent ? : }
- ))} +

{card.title}

+

{card.description}

+ {card.bullets && card.bullets.length > 0 && ( +
+ {card.bullets.slice(0, 3).map((bullet, bulletIdx) => ( +
+ {bullet} +
+ ))} +
+ )} +
+ ); + })} + + {/* Arrows between first 3 cards */} + {apiData.approach_section.approach_cards.length >= 2 && ( +
+
+ +
+ )} + {apiData.approach_section.approach_cards.length >= 3 && ( +
+
+
)}
- ); - })} - {/* Arrows between first 3 cards */} - {apiData.approach_section.approach_cards.length >= 2 && ( -
-
- -
- )} - {apiData.approach_section.approach_cards.length >= 3 && ( -
-
- -
- )} -
+ {/* Vertical Connector - Center Flow Down */} + {apiData.approach_section.approach_cards.length > 3 && ( +
+
+
+ +
+
+ )} - {/* Vertical Connector - Center Flow Down */} - {apiData.approach_section.approach_cards.length > 3 && ( -
-
-
- + {/* Row 2: Next 2 approach cards (if available) */} + {apiData.approach_section.approach_cards.length >= 4 && ( +
+ {apiData.approach_section.approach_cards.slice(3, 5).map((card, idx) => { + const IconComponent = getIconComponent(card.icon_url); + const isFirstOfPair = idx === 0; + return ( +
+
+ {IconComponent ? : } +
+

{card.title}

+

{card.description}

+ {card.bullets && card.bullets.length > 0 && ( +
+ {card.bullets.slice(0, 3).map((bullet, bulletIdx) => ( +
+ {bullet} +
+ ))} +
+ )} +
+ ); + })} + + {/* Arrow between the two cards */} + {apiData.approach_section.approach_cards.length >= 5 && ( +
+
+ +
+ )} +
+ )} + + {/* Final Vertical Connector - Center Flow Down to Outcome */} +
+
+
+ +
+
+ + {/* Row 3: Expected Outcome - Use API outcomes data */} +
+
+
+ {apiData.approach_section.outcomes && apiData.approach_section.outcomes[0] ? (() => { + const OutcomeIcon = getIconComponent(apiData.approach_section.outcomes[0].icon_url); + return OutcomeIcon ? : ; + })() : } +

+ {apiData.approach_section.outcomes?.[0]?.title || "Expected Outcome"} +

+
+

+ {apiData.approach_section.outcomes?.[0]?.description || "A systematic, measurable leadership pipeline that accelerates talent development and succession readiness."} +

+
+ {apiData.approach_section.outcomes?.[0]?.bullets && apiData.approach_section.outcomes[0].bullets.length > 0 ? ( + apiData.approach_section.outcomes[0].bullets.slice(0, 2).map((bullet, idx) => ( +
+ + {bullet} +
+ )) + ) : ( +
+ + Proven ROI on Leadership Investment +
+ )} +
+
+
- )} - {/* Row 2: Next 2 approach cards (if available) */} - {apiData.approach_section.approach_cards.length >= 4 && ( -
- {apiData.approach_section.approach_cards.slice(3, 5).map((card, idx) => { + {/* Tablet & Mobile: Vertical Flowchart */} +
+ {/* Map all approach cards vertically */} + {apiData.approach_section.approach_cards.map((card, idx) => { const IconComponent = getIconComponent(card.icon_url); - const isFirstOfPair = idx === 0; + const isEven = idx % 2 === 0; return ( -
-
- {IconComponent ? : } +
+
+
+ {IconComponent ? : } +
+

{card.title}

+

{card.description}

+ {card.bullets && card.bullets.length > 0 && ( +
+ {card.bullets.map((bullet, bulletIdx) => ( +
+ {bullet} +
+ ))} +
+ )}
-

{card.title}

-

{card.description}

- {card.bullets && card.bullets.length > 0 && ( -
- {card.bullets.slice(0, 3).map((bullet, bulletIdx) => ( -
- {bullet} -
- ))} + {/* Connector Arrow */} + {idx < apiData.approach_section.approach_cards.length - 1 && ( +
+
)}
); })} - {/* Arrow between the two cards */} - {apiData.approach_section.approach_cards.length >= 5 && ( -
-
- + {/* Expected Outcome - Use API outcomes data */} +
+
+ {apiData.approach_section.outcomes && apiData.approach_section.outcomes[0] ? (() => { + const OutcomeIcon = getIconComponent(apiData.approach_section.outcomes[0].icon_url); + return OutcomeIcon ? : ; + })() : } +

+ {apiData.approach_section.outcomes?.[0]?.title || "Expected Outcome"} +

- )} -
- )} - - {/* Final Vertical Connector - Center Flow Down to Outcome */} -
-
-
- -
-
- - {/* Row 3: Expected Outcome - Use API outcomes data */} -
-
-
- {apiData.approach_section.outcomes && apiData.approach_section.outcomes[0] ? (() => { - const OutcomeIcon = getIconComponent(apiData.approach_section.outcomes[0].icon_url); - return OutcomeIcon ? : ; - })() : } -

- {apiData.approach_section.outcomes?.[0]?.title || "Expected Outcome"} -

-
-

- {apiData.approach_section.outcomes?.[0]?.description || "A systematic, measurable leadership pipeline that accelerates talent development and succession readiness."} -

-
- {apiData.approach_section.outcomes?.[0]?.bullets && apiData.approach_section.outcomes[0].bullets.length > 0 ? ( - apiData.approach_section.outcomes[0].bullets.slice(0, 2).map((bullet, idx) => ( -
- - {bullet} -
- )) - ) : ( -
- - Proven ROI on Leadership Investment -
- )} -
-
-
-
-
- - {/* Tablet & Mobile: Vertical Flowchart */} -
- {/* Map all approach cards vertically */} - {apiData.approach_section.approach_cards.map((card, idx) => { - const IconComponent = getIconComponent(card.icon_url); - const isEven = idx % 2 === 0; - return ( -
-
-
- {IconComponent ? : } -
-

{card.title}

-

{card.description}

- {card.bullets && card.bullets.length > 0 && ( -
- {card.bullets.map((bullet, bulletIdx) => ( -
- {bullet} +

+ {apiData.approach_section.outcomes?.[0]?.description || "A systematic, measurable leadership pipeline that accelerates talent development and succession readiness."} +

+
+ {apiData.approach_section.outcomes?.[0]?.bullets && apiData.approach_section.outcomes[0].bullets.length > 0 ? ( + apiData.approach_section.outcomes[0].bullets.slice(0, 2).map((bullet, idx) => ( +
+ + {bullet}
- ))} -
- )} -
- {/* Connector Arrow */} - {idx < apiData.approach_section.approach_cards.length - 1 && ( -
- + )) + ) : ( +
+ + Proven ROI on Leadership Investment +
+ )}
- )} +
- ); - })} + + )} +
- {/* Expected Outcome - Use API outcomes data */} -
-
- {apiData.approach_section.outcomes && apiData.approach_section.outcomes[0] ? (() => { - const OutcomeIcon = getIconComponent(apiData.approach_section.outcomes[0].icon_url); - return OutcomeIcon ? : ; - })() : } -

- {apiData.approach_section.outcomes?.[0]?.title || "Expected Outcome"} -

+ {/* Framework Effectiveness - Stats Section */} + {apiData?.stats_section && apiData.stats_section.stat_cards && apiData.stats_section.stat_cards.length > 0 && ( +
+
+

{apiData.stats_section.title || "Framework Effectiveness"}

+

+ {apiData.stats_section.description || "Measurable results that demonstrate the impact of our leadership development approach."} +

-

- {apiData.approach_section.outcomes?.[0]?.description || "A systematic, measurable leadership pipeline that accelerates talent development and succession readiness."} -

-
- {apiData.approach_section.outcomes?.[0]?.bullets && apiData.approach_section.outcomes[0].bullets.length > 0 ? ( - apiData.approach_section.outcomes[0].bullets.slice(0, 2).map((bullet, idx) => ( -
- - {bullet} + +
+ {apiData.stats_section.stat_cards.map((stat) => { + const IconComponent = getIconComponent(stat.icon_url); + return ( +
+
+ {IconComponent ? : } +
+
{stat.value || "0"}
+

{stat.label || ""}

- )) - ) : ( -
- - Proven ROI on Leadership Investment -
- )} + ); + })}
-
- - )} -
- - {/* Framework Effectiveness - Stats Section */} - {apiData?.stats_section && apiData.stats_section.stat_cards && apiData.stats_section.stat_cards.length > 0 && ( -
-
-

{apiData.stats_section.title || "Framework Effectiveness"}

-

- {apiData.stats_section.description || "Measurable results that demonstrate the impact of our leadership development approach."} -

-
- -
- {apiData.stats_section.stat_cards.map((stat) => { - const IconComponent = getIconComponent(stat.icon_url); - return ( -
-
- {IconComponent ? : } -
-
{stat.value || "0"}
-

{stat.label || ""}

-
- ); - })} + )}
- )} -
-
-
-
+
+
{/* 5. Sample Program Format */}
@@ -879,41 +889,45 @@ export function ExecutiveCoaching() { /> {/* 8. CTA Section */} -
-
- -
-
-
- -
-
- -

- Ready to accelerate your leadership? - - {" "}Get in touch{" "} - - for personalized coaching now. -

- navigateTo('/contact?topic=coaching-mentoring')} - ariaLabel="Schedule a coaching and mentoring consultation" + {apiData.cta_section && ( +
+
+ -

- Connect with our executive coaching experts to discuss personalized leadership development that transforms your effectiveness and career trajectory. -

+
+
-
-
+ +
+
+ +

+ {apiData.cta_section.text} + + {" "}Get in touch{" "} + + for personalized coaching now. +

+ navigateTo(apiData.cta_section.cta_destination)} + ariaLabel={apiData.cta_section.cta_text} + /> + {apiData.cta_section.description && ( +

+ {apiData.cta_section.description} +

+ )} +
+
+
+ )}
); } \ No newline at end of file diff --git a/src/components/services/LeadershipDevelopment.tsx b/src/components/services/LeadershipDevelopment.tsx index b7e87e2..b634a16 100644 --- a/src/components/services/LeadershipDevelopment.tsx +++ b/src/components/services/LeadershipDevelopment.tsx @@ -178,6 +178,16 @@ interface ServicePageData { video_url: string | null; display_order: number; }>; + cta_section: { + id: string; + background_image_url: string; + text: string; + cta_text: string; + cta_destination: string; + description: string; + landing_page_type: string; + service_type: string; + }; } // Map API icons to Lucide icons @@ -217,13 +227,13 @@ export function LeadershipDevelopment() { window.scrollTo(0, 0); }, []); - if (isLoading) { - return ( -
- -
- ); - } + if (isLoading) { + return ( +
+ +
+ ); + } if (error || !apiData) { return ( @@ -858,41 +868,45 @@ export function LeadershipDevelopment() { /> {/* 8. CTA Section */} -
-
- -
-
-
- -
-
- -

- Ready to transform your leadership? - - {" "}Get in touch{" "} - - to drive exceptional strategic outcomes. -

- navigateTo('/contact?topic=leadership-development')} - ariaLabel="Schedule a leadership development consultation" + {apiData.cta_section && ( +
+
+ -

- Connect with our leadership development experts to discuss building visionary leadership capability in your organization. -

+
+
-
-
+ +
+
+ +

+ {apiData.cta_section.text} + + {" "}Get in touch{" "} + + to drive exceptional strategic outcomes. +

+ navigateTo(apiData.cta_section.cta_destination)} + ariaLabel={apiData.cta_section.cta_text} + /> + {apiData.cta_section.description && ( +

+ {apiData.cta_section.description} +

+ )} +
+
+
+ )}
); } \ No newline at end of file diff --git a/src/components/services/LeadershipPipelineDevelopment.tsx b/src/components/services/LeadershipPipelineDevelopment.tsx index 039f0fb..ebaf2b3 100644 --- a/src/components/services/LeadershipPipelineDevelopment.tsx +++ b/src/components/services/LeadershipPipelineDevelopment.tsx @@ -178,6 +178,16 @@ interface ServicePageData { video_url: string | null; display_order: number; }>; + cta_section: { + id: string; + background_image_url: string; + text: string; + cta_text: string; + cta_destination: string; + description: string; + landing_page_type: string; + service_type: string; + }; } // Map API icons to Lucide icons @@ -882,41 +892,45 @@ export function LeadershipPipelineDevelopment() { /> {/* 8. CTA Section */} -
-
- -
-
-
- -
-
- -

- Ready to build your leadership pipeline? - - {" "}Get in touch{" "} - - to eliminate succession gaps now. -

- navigateTo('/contact?topic=leadership-pipeline')} - ariaLabel="Schedule a leadership pipeline consultation" + {apiData.cta_section && ( +
+
+ -

- Connect with our pipeline development experts to discuss building sustainable leadership capability across your organization. -

+
+
-
-
+ +
+
+ +

+ {apiData.cta_section.text} + + {" "}Get in touch{" "} + + to eliminate succession gaps now. +

+ navigateTo(apiData.cta_section.cta_destination)} + ariaLabel={apiData.cta_section.cta_text} + /> + {apiData.cta_section.description && ( +

+ {apiData.cta_section.description} +

+ )} +
+
+
+ )}
); } \ No newline at end of file diff --git a/src/components/services/ManagementDevelopment.tsx b/src/components/services/ManagementDevelopment.tsx index 3b55592..c5bb963 100644 --- a/src/components/services/ManagementDevelopment.tsx +++ b/src/components/services/ManagementDevelopment.tsx @@ -165,6 +165,16 @@ interface ServicePageData { video_url: string | null; display_order: number; }>; + cta_section: { + id: string; + background_image_url: string; + text: string; + cta_text: string; + cta_destination: string; + description: string; + landing_page_type: string; + service_type: string; + }; } // Map API icons to Lucide icons @@ -868,41 +878,45 @@ export function ManagementDevelopment() { /> {/* 8. CTA Section */} -
-
- -
-
-
- -
-
- -

- Ready to build exceptional managers? - - {" "}Get in touch{" "} - - to drive team performance now. -

- navigateTo('/contact?topic=management-development')} - ariaLabel="Schedule a management development consultation" + {apiData.cta_section && ( +
+
+ -

- Connect with our management development experts to discuss building exceptional managers who drive team engagement and results. -

+
+
-
-
+ +
+
+ +

+ {apiData.cta_section.text} + + {" "}Get in touch{" "} + + to drive team performance now. +

+ navigateTo(apiData.cta_section.cta_destination)} + ariaLabel={apiData.cta_section.cta_text} + /> + {apiData.cta_section.description && ( +

+ {apiData.cta_section.description} +

+ )} +
+
+
+ )}
); } \ No newline at end of file diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx index 903d7cc..220677e 100644 --- a/src/components/ui/dialog.tsx +++ b/src/components/ui/dialog.tsx @@ -1,8 +1,8 @@ "use client"; import * as React from "react"; -import * as DialogPrimitive from "@radix-ui/react-dialog@1.1.6"; -import { XIcon } from "lucide-react@0.487.0"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { XIcon } from "lucide-react"; import { cn } from "./utils"; diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index 109c214..2ac17f1 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -25,6 +25,19 @@ const HomePage: React.FC = () => { const stats = data?.stats_sections ?? []; const highlightCards = data?.highlight_cards ?? []; const ctaBands = data?.cta_bands ?? []; + const ctaSection = data?.cta_section; + + // Transform testimonial section data to match Testimonial interface + const testimonialData = data?.testimonial_section?.map((item: any) => ({ + id: item.id, + name: item.name, + role: item.designation, + quote: item.content, + videoUrl: item.video_url, + isVideo: !!item.video_url, + rating: 5, // Default rating, can be updated from API if available + avatar: item.profile_xid ? `https://example.com/avatars/${item.profile_xid}.jpg` : undefined, + })) || []; if (isLoading) { return ( @@ -101,9 +114,15 @@ const HomePage: React.FC = () => {
- + {/* Pass testimonial data to the TestimonialsSection */} + - + ); }; diff --git a/src/redux/services/aboutUsApi.ts b/src/redux/services/aboutUsApi.ts index 965c225..93a0b18 100644 --- a/src/redux/services/aboutUsApi.ts +++ b/src/redux/services/aboutUsApi.ts @@ -47,6 +47,16 @@ export interface TeamMember { alt_text: string; bio: string; } +export interface CtaData { + id: string; + background_image_url: string; + text: string; + cta_text: string; + cta_destination: string; + description: string; + landing_page_type: string; + service_type: string | null; +} export interface AboutUsData { hero_section: HeroSection; @@ -61,6 +71,7 @@ export interface AboutUsData { methodology: Methodology; philosophy: Philosophy; testimonials: Testimonial[]; + cta_section: CtaData; } export interface Methodology { diff --git a/src/redux/services/courseApi.ts b/src/redux/services/courseApi.ts index c3b260e..490fac0 100644 --- a/src/redux/services/courseApi.ts +++ b/src/redux/services/courseApi.ts @@ -67,6 +67,196 @@ export interface CourseListResponse { }; } +export interface CourseReview { + id: string; + rating: number; + comment: string; + video_url: string | null; + reviewer_name: string; + profile_image: string | null; + bio: string | null; + created_at: string; +} + +export interface CourseFaq { + id: string; + question: string; + answer: string; +} + +export interface CourseTargetAudience { + id: string; + course_xid: string; + course_icon_xid: string; + title: string; + description: string; + display_order: number; +} + +export interface CourseLearningOutcome { + id: string; + course_xid: string; + title: string; + description: string; + display_order: number; +} + +export interface CourseLearningStructure { + id: string; + course_xid: string; + title: string; + description: string; + display_order: number; +} + +export interface CourseFacultyCredential { + id: string; + course_xid: string; + course_faculty_xid: string; + credential_name: string; + display_order: number; +} + +export interface CourseFaculty { + id: string; + course_xid: string; + faculty_name: string; + faculty_title: string; + faculty_organization_name: string; + faculty_biography: string; + display_order: number; + expertises: string[] | null; + credentials: CourseFacultyCredential[]; +} + +export interface CourseLessonResource { + id: string; + course_xid: string; + module_xid: string; + lesson_xid: string; + content_xid: string; + content_type_xid: string; + content_title: string; + total_duration: number | null; + content_type_name: string; + is_active: boolean; +} + +export interface CourseLesson { + id: string; + course_xid: string; + module_xid: string; + lesson_title: string; + lesson_description: string; + is_lock_lesson: boolean; + display_order: number; + lesson_resources: CourseLessonResource[]; +} + +export interface CourseModule { + id: string; + course_xid: string; + module_name: string; + display_order: number; + lessons: CourseLesson[]; +} + +export interface CourseResource { + id: string; + course_xid: string; + content_xid: string; + content_type_xid: string; + display_order: number | null; +} + +export interface CourseCertificateTemplate { + id: string; + template_name: string; + template_code: string; + display_order: number; + is_active: boolean; +} + +export interface CourseCertificate { + id: string; + course_xid: string; + certificate_template_xid: string; + company_logo_url: string | null; + institution_name: string; + program_title: string; + signatory_name: string; + signatory_title: string; + digital_signature_url: string | null; + minimum_pass_percentage: number; + complete_all_lesson_required: boolean; + certificate_template: CourseCertificateTemplate; +} + +export interface RecommendedCourse { + id: string; + course_name: string; + course_desc: string; + thumbnail_img: string; + price: string; + best_value: number; + duration: number; + recommended_course_reviews: { + id: string; + rating: number; + comment: string; + reviewer_name: string; + }[]; +} + +export interface CourseDetail { + id: string; + course_name: string; + course_desc: string; + thumbnail_img: string; + course_category_xid: string; + duration: number; + retail_type: string; + price: string | number; + best_value: number; + target_audience_desc: string | null; + learning_outcomes_desc: string | null; + learning_structure_desc: string | null; + our_methodology_desc: string | null; + is_certificate_available: boolean; + course_status: CourseStatus; + benefit_section: string | null; + learning_section: string | null; + structure_section: string | null; + approach_section: string | null; + faculty_section: string | null; + avg_rating: number; + total_reviews: number; + reviews: CourseReview[]; + course_faqs: CourseFaq[]; + total_modules: number; + total_lessons: number; + formatted_duration: string; + course_category_name: string; + course_language_xids: string[]; + course_target_audiences: CourseTargetAudience[]; + course_learning_outcomes: CourseLearningOutcome[]; + course_learning_structures: CourseLearningStructure[]; + course_facilities: CourseFaculty[]; + modules: CourseModule[]; + course_resources: CourseResource[]; + course_certificate: CourseCertificate | null; + recommended_courses: RecommendedCourse[]; +} + +export interface CourseDetailResponse { + success: boolean; + status: number; + message: string; + data: CourseDetail; + errors: unknown; + correlation_id: string; +} + /* ================= PREPOPULATE TYPES ================= */ export interface CourseCategory { @@ -163,7 +353,19 @@ export const courseApi = createApi({ }, providesTags: ["CourseCategories"], }), + + // GET Course By Id + getcoursebyid: builder.query({ + query: (course_id) => `admin/course/${course_id}`, + providesTags: (_result, _error, course_id) => [{ type: "Course", id: course_id }], + }), + + }), }); -export const { useGetCoursesQuery, useGetCourseCategoriesQuery } = courseApi; \ No newline at end of file +export const { + useGetCoursesQuery, + useGetCourseCategoriesQuery, + useGetcoursebyidQuery, +} = courseApi; diff --git a/src/redux/services/homepageApi.ts b/src/redux/services/homepageApi.ts index 817150e..3bf35b8 100644 --- a/src/redux/services/homepageApi.ts +++ b/src/redux/services/homepageApi.ts @@ -28,6 +28,7 @@ export interface StatItem { /* ================= HIGHLIGHT CARD ================= */ export interface HighlightCard { + id?: string; card_title: string; icon_url: string; accessible_label: string; @@ -46,6 +47,31 @@ export interface CtaBand { cta_destination: string; } +/* ================= TESTIMONIAL TYPES ================= */ + +export interface TestimonialItem { + id: string; + profile_xid: string; + name: string; + designation: string; + content: string; + video_url: string | null; + display_order: number; +} + +/* ================= CTA SECTION TYPES ================= */ + +export interface CtaSection { + id: string; + background_image_url: string; + text: string; + cta_text: string; + cta_destination: string; + description: string; + landing_page_type: string; + service_type: string | null; +} + /* ================= RESPONSE ================= */ export interface HomePageResponse { @@ -57,6 +83,8 @@ export interface HomePageResponse { stats_sections: StatItem[]; highlight_cards: HighlightCard[]; cta_bands: CtaBand[]; + cta_section: CtaSection; + testimonial_section: TestimonialItem[]; }; errors: any; correlation_id: string; diff --git a/src/redux/services/learningFacilityApi.ts b/src/redux/services/learningFacilityApi.ts new file mode 100644 index 0000000..aa9fbd5 --- /dev/null +++ b/src/redux/services/learningFacilityApi.ts @@ -0,0 +1,122 @@ +import { createApi } from "@reduxjs/toolkit/query/react"; +import baseQueryWithReauth from "./baseQuery"; + +export interface KautilyaPageResponse { + success: boolean; + status: number; + message: string; + data: { + hero_sections: { + id: string; + background_image_url: string; + background_image_alt_text: string; + headline: string; + subtext: string; + cta_text: string; + cta_destination: string; + }; + our_story: { + id: string; + tag: string; + title: string; + content: string; + image_url: string; + }; + why_choose_us: { + id: string; + tag: string; + title: string; + description: string; + cards: Array<{ + id: string; + title: string; + description: string; + image_url: string; + icon: string; + display_order: number; + bullets: Array<{ + id: string; + text: string; + }>; + }>; + }; + facility_features: { + id: string; + title: string; + description: string; + features: Array<{ + id: string; + title: string; + description: string; + image_url: string; + sub_title: string; + sub_description: string; + display_order: number; + points: Array<{ + id: string; + text: string; + }>; + }>; + }; + visual_tour: { + id: string; + title: string; + description: string; + categories: Array<{ + id: string; + name: string; + display_order: number; + images: Array<{ + id: string; + image_url: string; + title: string; + subtitle: string; + display_order: number; + }>; + }>; + }; + daily_experience: { + id: string; + title: string; + description: string; + items: Array<{ + id: string; + label: string; + title: string; + description: string; + image_url: string; + display_order: number; + }>; + }; + cta_section: { + id: string; + background_image_url: string; + text: string; + cta_text: string; + cta_destination: string; + description: string; + }; + }; + errors: any; + correlation_id: string; +} + +export const learningFacilityApi = createApi({ + reducerPath: "learningFacilityApi", + baseQuery: baseQueryWithReauth, + tagTypes: ["KautilyaPage"], + endpoints: (builder) => ({ + getKautilyaPage: builder.query< + KautilyaPageResponse["data"], + { } + >({ + query: ({ }) => ({ + url: "/admin/kautilya-page/get", + }), + transformResponse: (response: KautilyaPageResponse) => response.data, + providesTags: [{ type: "KautilyaPage", id: "LIST" }], + }), + }), +}); + +export const { useGetKautilyaPageQuery } = learningFacilityApi; \ No newline at end of file diff --git a/src/redux/services/webinarApi.ts b/src/redux/services/webinarApi.ts new file mode 100644 index 0000000..4aeb897 --- /dev/null +++ b/src/redux/services/webinarApi.ts @@ -0,0 +1,128 @@ +import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; +import baseQueryWithReauth from "./baseQuery"; + +/* ================= TYPES ================= */ + +export interface WebinarItem { + id: string; + session_title: string; + description: string | null; + session_datetime: string; + duration_minutes: number; + timezone_xid: string; + max_attendee: number; + passcode: string; + require_registration: boolean; + recurring_webinar: boolean; + webinar_status: "scheduled" | "live" | "ended" | "cancelled"; + owner?: string; +} + +export interface WebinarListData { + total: number; + limit: number; + offset: number; + items: WebinarItem[]; +} + +export interface WebinarListResponse { + success: boolean; + status: number; + message: string; + data: WebinarListData; + errors: any; + correlation_id: string; +} + +/* ================= QUERY PARAM TYPE ================= */ + +export interface WebinarListParams { + limit?: number; + offset?: number; + search?: string; + status?: string[]; // ✅ multiple status + fromDate?: string; + toDate?: string; + minDuration?: number; + maxDuration?: number; + minAttendees?: number; // ✅ NEW + maxAttendees?: number; // ✅ NEW + sortBy?: "most_popular" | "newest" | "oldest" | "title" | "duration"; +} + +/* ================= API ================= */ + +export const webinarApi = createApi({ + reducerPath: "webinarApi", + baseQuery: baseQueryWithReauth, + tagTypes: ["Webinar"], + + endpoints: (builder) => ({ + webinarList: builder.query({ + query: ({ + limit = 10, + offset = 0, + search, + status, + fromDate, + toDate, + minDuration, + maxDuration, + minAttendees, + maxAttendees, + sortBy, + }) => { + const params = new URLSearchParams(); + + params.append("limit", String(limit)); + params.append("offset", String(offset)); + + if (search) { + params.append("search_term", search); // ✅ FIXED NAME + } + + if (status && status.length > 0) { + status.forEach((s) => + params.append("session_status", s) // ✅ array support + ); + } + + if (fromDate) { + params.append("from_date", fromDate); + } + + if (toDate) { + params.append("to_date", toDate); + } + + if (minDuration !== undefined) { + params.append("min_duration", String(minDuration)); + } + + if (maxDuration !== undefined) { + params.append("max_duration", String(maxDuration)); + } + + if (minAttendees !== undefined) { + params.append("min_attendee", String(minAttendees)); // ✅ NEW + } + + if (maxAttendees !== undefined) { + params.append("max_attendee", String(maxAttendees)); // ✅ NEW + } + + if (sortBy) { + params.append("sort_by", sortBy); + } + + return `/admin/webinars/list?${params.toString()}`; + }, + + providesTags: ["Webinar"], + }), + }), +}); + +/* ================= EXPORT HOOK ================= */ + +export const { useWebinarListQuery } = webinarApi; \ No newline at end of file diff --git a/src/redux/store/Store.tsx b/src/redux/store/Store.tsx index 5478372..42dbeaf 100644 --- a/src/redux/store/Store.tsx +++ b/src/redux/store/Store.tsx @@ -6,6 +6,8 @@ import { blogApi } from "../services/blogApi"; import { aboutUsApi } from "../services/aboutUsApi"; import { sercicesApi } from "../services/sercicesApi"; import { courseApi } from "../services/courseApi"; +import { learningFacilityApi } from "../services/learningFacilityApi"; +import { webinarApi } from "../services/webinarApi"; export const store = configureStore({ reducer: { @@ -16,6 +18,9 @@ export const store = configureStore({ [aboutUsApi.reducerPath]: aboutUsApi.reducer, [sercicesApi.reducerPath]: sercicesApi.reducer, [courseApi.reducerPath]: courseApi.reducer, + [learningFacilityApi.reducerPath]: learningFacilityApi.reducer, + [webinarApi.reducerPath]: webinarApi.reducer, + }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat( @@ -26,6 +31,8 @@ export const store = configureStore({ aboutUsApi.middleware, sercicesApi.middleware, courseApi.middleware, + learningFacilityApi.middleware, + webinarApi.middleware, ), }); diff --git a/src/styles/globals.css b/src/styles/globals.css index 57e4aee..0fa769a 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -167,6 +167,9 @@ /* Small text */ --font-small: 0.875rem; /* 14px */ + /* Extra small text */ + --font-extra-small: 0.75rem; + /* 12px */ --line-height-small: 1.5; --font-weight-small: 400; @@ -601,6 +604,14 @@ html { color: var(--color-black); } + .text-small-extra { + font-size: var(--font-extra-small); + line-height: var(--line-height-small); + font-weight: var(--font-weight-small); + font-family: var(--font-family-base); + color: var(--color-black); + } + .text-eyebrow { font-size: var(--font-eyebrow); line-height: var(--line-height-eyebrow); @@ -5294,4 +5305,31 @@ html { font-size: calc(var(--font-h2) * 0.8); /* reduce by 20% */ line-height: calc(var(--line-height-h2) * 0.9); } -} \ No newline at end of file +} + + .custom-scrollbar { + scrollbar-width: thin; + scrollbar-color: transparent transparent; + } + + .custom-scrollbar::-webkit-scrollbar { + width: 6px; + } + + .custom-scrollbar::-webkit-scrollbar-track { + background: transparent; + } + + .custom-scrollbar::-webkit-scrollbar-thumb { + background-color: transparent; + border-radius: 20px; + } + + /* Optional: Show scrollbar only on hover */ + .custom-scrollbar:hover::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 0, 0.2); + } + + .custom-scrollbar:hover { + scrollbar-color: rgba(0, 0, 0, 0.2) transparent; + } \ No newline at end of file