main #6

Merged
PriyanshuVishwakarma merged 2 commits from main into testing 2026-04-22 07:47:44 +00:00
17 changed files with 2457 additions and 2441 deletions

View File

@@ -31,7 +31,6 @@ import { WebinarsPage } from "./components/WebinarsPage";
import HomePage from './pages/HomePage';
import { AboutUs } from './components/AboutUs';
import { Services } from './components/Services';
import { LearningFacilityNew } from './components/LearningFacilityNew';
import { FooterNew } from './components/FooterNew';
import { Privacy } from "./pages/Privacy";
import { TermsCondition } from "./pages/TermsCondition";
@@ -39,6 +38,8 @@ import { FAQ } from "./pages/FAQ";
import { LeadershipPipelineDevelopment } from "./components/services/LeadershipPipelineDevelopment";
import { LeadershipDevelopment } from "./components/services/LeadershipDevelopment";
import { KautilyaFacility } from "./components/KautilyaFacility";
import { LearningFacilityPage } from "./components/LearningFacilityPage";
import WebinarDetail from "./components/WebinarDetail";
// import EnrollPlaceholder from "./components/EnrollPlaceholder";
// import ForgotPasswordPlaceholder from "./components/ForgotPasswordPlaceholder";
// import DashboardPlaceholder from "./components/DashboardPlaceholder";
@@ -85,6 +86,7 @@ export default function App() {
{/* Webinars Pages */}
<Route path="/webinars" element={<WebinarsPage />} />
<Route path="/webinars/:webinar_id" element={<WebinarDetail />} />
<Route path="/webinars-legacy" element={<WebinarsListing />} />
{/* Learning Online */}
@@ -115,7 +117,7 @@ export default function App() {
<Route path="/programme/:slug" element={<ProgrammeDetail />} />
{/* Learning Facility */}
<Route path="/learning-facility" element={<LearningFacilityNew />} />
<Route path="/learning-facility" element={<LearningFacilityPage />} />
{/* Privacy policy */}
<Route path="/privacy-policy" element={<Privacy />} />
<Route path="/term-condition" element={<TermsCondition />} />

View File

@@ -12,8 +12,8 @@ interface CTABannerSectionProps {
cta_text: string;
cta_destination: string;
description: string;
landing_page_type: string;
service_type: string | null;
landing_page_type?: string;
service_type?: string | null;
};
isLoading?: boolean;
}

View File

@@ -104,7 +104,10 @@ export function CourseCard({ course, onClick, className, onAddToCart }: CourseCa
fontFamily: 'var(--font-family-base)'
}}
>
{course.title}
{course.title
?.split(' ')
.slice(0, 3)
.join(' ') + (course.title.split(' ').length > 3 ? '...' : '')}
</h3>
{/* Course Description - Limited to 2 lines with ellipsis */}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -445,13 +445,13 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {
courseDetail.is_certificate_available ? 'Certified' : 'Non-Certified'
].filter(Boolean),
previewVideoUrl:
courseDetail.reviews.find((review) => review.video_url)?.video_url ||
(courseDetail.reviews ?? []).find((review) => review.video_url)?.video_url ||
mockProgrammeData.previewVideoUrl,
highlights:
courseDetail.course_learning_outcomes.slice(0, 5).map((item) => item.title) ||
(courseDetail.course_learning_outcomes ?? []).slice(0, 5).map((item) => item.title) ||
mockProgrammeData.highlights,
deliveryMethods: courseDetail.modules.length
? courseDetail.modules.map((module) => module.module_name)
deliveryMethods: (courseDetail.modules ?? []).length
? (courseDetail.modules ?? []).map((module) => module.module_name)
: mockProgrammeData.deliveryMethods,
credentials:
courseDetail.course_certificate?.program_title ||
@@ -476,9 +476,9 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {
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)
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]);
@@ -493,7 +493,7 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {
bio: member.faculty_biography,
image: '',
linkedinUrl: '',
credentials: member.credentials.map((credential) => credential.credential_name),
credentials: (member.credentials ?? []).map((credential) => credential.credential_name),
expertise: member.expertises || []
}));
}, [courseDetail]);
@@ -536,7 +536,9 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {
const useCases = useMemo(() => {
if (!courseDetail?.modules?.length) return mockUseCases;
return courseDetail.modules.flatMap((module) => module.lessons.map((lesson) => lesson.lesson_title)).slice(0, 6);
return courseDetail.modules
.flatMap((module) => (module.lessons ?? []).map((lesson) => lesson.lesson_title))
.slice(0, 6);
}, [courseDetail]);
const relatedProgrammes = mockRelatedProgrammes;
@@ -1006,16 +1008,8 @@ export function ProgrammeDetail({ slug }: ProgrammeDetailProps) {
<Dialog open={showCertificatePreview} onOpenChange={setShowCertificatePreview}>
<DialogPortal>
<DialogOverlay className="fixed inset-0 bg-black/70 z-[9999]" />
<DialogContent className="fixed left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] w-full max-w-3xl z-[9999] focus:outline-none bg-transparent border-none shadow-none p-0">
<DialogContent className="fixed left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] w-full max-w-4xl z-[9999] focus:outline-none bg-transparent border-none shadow-none p-0">
<div className="relative">
{/* <DialogClose asChild>
<button
className="absolute -top-12 right-0 text-white hover:bg-white/20 rounded-full p-1 z-10 focus:outline-none"
aria-label="Close"
>
<X className="w-5 h-5" />
</button>
</DialogClose> */}
{/* Certificate Card - Authentic Certificate Style */}
<div className="bg-white rounded-lg shadow-2xl overflow-hidden max-h-[90vh] overflow-y-auto custom-scrollbar">

View File

@@ -41,19 +41,53 @@ import {
} from 'lucide-react';
import { motion, AnimatePresence } from 'motion/react';
import { navigateTo } from './Router';
import { useParams } from 'react-router-dom';
import { ImageWithFallback } from './figma/ImageWithFallback';
import { BrandedTag } from './about/BrandedTag';
import { PrimaryCTAButton } from './PrimaryCTAButton';
import { toast } from 'sonner';
import { getWebinarBySlug, sharedWebinarsData, type WebinarData } from '../data/webinarsData';
import { useGetWebinarByIdQuery } from '../redux/services/webinarApi';
interface WebinarDetailProps {
params: { slug: string };
params?: { webinar_id: string };
}
export default function WebinarDetail({ params }: WebinarDetailProps) {
// Get webinar data from shared data source
const [webinar, setWebinar] = useState<WebinarData | null>(null);
// Helper function to format date
const formatDate = (dateTimeString: string) => {
const date = new Date(dateTimeString);
return {
date: date.toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
}),
time: date.toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit',
hour12: true
}),
full: date
};
};
// Helper to get webinar status based on date and API status
const getWebinarStatus = (sessionDatetime: string, webinarStatus: string): 'upcoming' | 'live' | 'recorded' => {
const now = new Date();
const sessionDate = new Date(sessionDatetime);
if (webinarStatus === 'cancelled') return 'recorded';
if (webinarStatus === 'live') return 'live';
if (sessionDate > now) return 'upcoming';
return 'recorded';
};
export default function WebinarDetail({ params }: WebinarDetailProps = {}) {
const routeParams = useParams<{ webinar_id: string }>();
const webinarId = routeParams.webinar_id || params?.webinar_id;
const { data: webinarData, isLoading, error } = useGetWebinarByIdQuery(webinarId as string, {
skip: !webinarId
});
const [timeLeft, setTimeLeft] = useState({ days: 0, hours: 0, minutes: 0, seconds: 0 });
const [isRegistered, setIsRegistered] = useState(false);
const [showRegistrationForm, setShowRegistrationForm] = useState(false);
@@ -75,22 +109,76 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
const videoRef = useRef<HTMLVideoElement>(null);
const shareMenuRef = useRef<HTMLDivElement>(null);
// Load webinar data on component mount
useEffect(() => {
const webinarData = getWebinarBySlug(params.slug);
if (webinarData) {
setWebinar(webinarData);
} else {
// Fallback: redirect to webinars page if webinar not found
navigateTo('/webinars');
}
}, [params.slug]);
// Transform API data to match your component's expected format
const webinar = webinarData?.data ? {
id: webinarData.data.id,
title: webinarData.data.session_title,
description: webinarData.data.description || '',
thumbnail: webinarData.data.media?.file_name
? `/api/media/${webinarData.data.media.id}`
: '/images/default-webinar.jpg',
theme: webinarData.data.webinar_category_id || 'Webinar',
date: formatDate(webinarData.data.session_datetime).date,
time: formatDate(webinarData.data.session_datetime).time,
timezone: 'IST', // You might need to fetch timezone name from timezone_xid
duration: `${webinarData.data.duration_minutes} minutes`,
status: getWebinarStatus(webinarData.data.session_datetime, webinarData.data.webinar_status),
attendees: `${webinarData.data.max_attendee}`, // Max capacity or registered count
maxAttendees: webinarData.data.max_attendee,
registrationOpen: webinarData.data.require_registration && webinarData.data.webinar_status === 'scheduled',
recordingReady: webinarData.data.webinar_status === 'ended',
zoomUrl: '#', // Not provided in API, might need additional endpoint
recordingUrl: '#', // Not provided in API
price: 'Free', // Not in API, adjust as needed
format: 'Virtual Event',
host: {
name: webinarData.data.speakers?.[0]?.name || 'Host Name',
title: webinarData.data.speakers?.[0]?.designation || 'Host',
company: webinarData.data.speakers?.[0]?.company || '',
bio: webinarData.data.speakers?.[0]?.bio || '',
avatar: webinarData.data.speakers?.[0]?.image_url || '/images/default-avatar.jpg',
linkedin: '#'
},
panelists: webinarData.data.speakers?.filter(s => !s.is_host).map(speaker => ({
id: speaker.id,
name: speaker.name,
title: speaker.designation,
company: speaker.company,
bio: speaker.bio,
avatar: speaker.image_url || '/images/default-avatar.jpg',
linkedin: '#'
})) || [],
abstract: webinarData.data.about_this_session?.description || webinarData.data.description || '',
keyTakeaways: webinarData.data.about_this_session?.points?.map(p => p.point) || [],
agenda: webinarData.data.agenda_items?.map(item => ({
time: formatDate(item.start_time).time,
title: item.title,
description: item.description
})) || [],
faqs: [] as Array<{ question: string; answer: string }>, // Not in API response
tags: [] as string[], // Not in API response, derive from category or other fields
relatedProgrammes: webinarData.data.course_links?.map(courseLink => ({
id: courseLink.course.id,
slug: courseLink.course.course_name.toLowerCase().replace(/\s+/g, '-'),
title: courseLink.course.course_name,
description: courseLink.course.course_desc,
category: courseLink.course.course_category_name,
level: courseLink.course.retail_type === 'private' ? 'Private' : 'Public',
duration: courseLink.course.total_duration ? `${courseLink.course.total_duration} mins` : 'Self-paced',
participants: courseLink.course.total_reviews || 0,
rating: courseLink.course.avg_rating || 0,
price: courseLink.course.price ? `${courseLink.course.price}` : 'Free',
originalPrice: courseLink.course.best_value ? `${courseLink.course.best_value}` : `${courseLink.course.price}`,
image: courseLink.course.thumbnail_img || '/images/default-course.jpg',
bestValue: courseLink.course.best_value
})) || []
} : null;
// Countdown timer
useEffect(() => {
if (!webinar || webinar.status !== 'upcoming') return;
if (!webinar || webinar.status !== 'upcoming' || !webinarData?.data.session_datetime) return;
const targetDate = new Date(`${webinar.date}T${webinar.time}:00`);
const targetDate = new Date(webinarData.data.session_datetime);
const updateCountdown = () => {
const now = new Date().getTime();
@@ -110,7 +198,7 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
const interval = setInterval(updateCountdown, 1000);
return () => clearInterval(interval);
}, [webinar?.date, webinar?.time, webinar?.status]);
}, [webinar, webinarData?.data.session_datetime]);
// Close share menu when clicking outside
useEffect(() => {
@@ -129,7 +217,7 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
e.preventDefault();
setIsSubmittingRegistration(true);
// Simulate API call
// TODO: Integrate with your registration API endpoint
await new Promise(resolve => setTimeout(resolve, 2000));
setIsSubmittingRegistration(false);
@@ -163,7 +251,7 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
if (!webinar) return { text: 'Loading...', onClick: () => {}, disabled: true };
const now = new Date();
const webinarDate = new Date(`${webinar.date}T${webinar.time}:00`);
const webinarDate = webinarData?.data.session_datetime ? new Date(webinarData.data.session_datetime) : new Date();
const tenMinutesBefore = new Date(webinarDate.getTime() - 10 * 60 * 1000);
switch (webinar.status) {
@@ -177,7 +265,10 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
if (now >= tenMinutesBefore) {
return {
text: 'Launch in Zoom',
onClick: () => window.open(webinar.zoomUrl, '_blank'),
onClick: () => {
// You'll need to get the Zoom URL from a separate endpoint
toast.info('Zoom link would open here');
},
disabled: false
};
} else {
@@ -256,7 +347,7 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
};
// Show loading state while webinar data is loading
if (!webinar) {
if (isLoading) {
return (
<div className="min-h-screen flex items-center justify-center" style={{ backgroundColor: '#FFFFFF' }}>
<div className="text-center">
@@ -267,7 +358,26 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
);
}
// Show error state
if (error || !webinar) {
return (
<div className="min-h-screen flex items-center justify-center" style={{ backgroundColor: '#FFFFFF' }}>
<div className="text-center">
<AlertCircle className="w-12 h-12 text-red-500 mx-auto mb-4" />
<h2 className="text-h2 mb-2">Webinar Not Found</h2>
<p className="text-body text-gray-600 mb-6">The webinar you're looking for doesn't exist or has been removed.</p>
<PrimaryCTAButton
text="Browse Webinars"
onClick={() => navigateTo('/webinars')}
className="cta-text-black"
/>
</div>
</div>
);
}
const ctaProps = getCTAProps();
const sessionDateTime = webinarData?.data.session_datetime ? new Date(webinarData.data.session_datetime) : null;
return (
<div className="min-h-screen" style={{ backgroundColor: '#FFFFFF' }}>
@@ -298,7 +408,7 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
</p>
{/* Countdown Timer for Upcoming Webinars */}
{webinar.status === 'upcoming' && (
{webinar.status === 'upcoming' && sessionDateTime && (
<div className="mb-8">
<div className="grid grid-cols-4 gap-4 max-w-md mb-4">
{[
@@ -318,12 +428,7 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
))}
</div>
<div className="text-small-white opacity-80">
Starts {new Date(`${webinar.date}T${webinar.time}:00`).toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
})} at {webinar.time} {webinar.timezone}
Starts {webinar.date} at {webinar.time}
</div>
</div>
)}
@@ -337,11 +442,11 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
<span className="text-small font-medium">LIVE NOW</span>
</div>
<div className="text-small-white">
{webinar.attendees} people watching
Max capacity: {webinar.maxAttendees} attendees
</div>
</div>
<div className="text-body-lg-white">
Session in progress Ends at {webinar.endTime} {webinar.timezone}
Session in progress
</div>
</div>
)}
@@ -356,7 +461,7 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
)}
</div>
<div className="text-body-lg-white">
Session held on {new Date(`${webinar.date}T${webinar.time}:00`).toLocaleDateString('en-US', {
Session held on {sessionDateTime?.toLocaleDateString('en-US', {
month: 'long',
day: 'numeric',
year: 'numeric'
@@ -425,7 +530,7 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
<div className="flex items-center gap-2 text-muted">
<Users className="w-4 h-4" />
<span className="text-small">
{webinar.attendees} {webinar.status === 'live' ? 'watching' : 'registered'}
{webinar.attendees} {webinar.status === 'live' ? 'watching' : 'capacity'}
</span>
</div>
</div>
@@ -445,45 +550,49 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
{webinar.abstract}
</p>
<div>
<h3 className="text-h3 mb-4">What You'll Learn</h3>
<ul className="space-y-3">
{webinar.keyTakeaways.map((takeaway, index) => (
<li key={index} className="flex items-start gap-3">
<CheckCircle className="w-5 h-5 text-[#04045B] mt-0.5 flex-shrink-0" />
<span className="text-body">{takeaway}</span>
</li>
))}
</ul>
</div>
{webinar.keyTakeaways.length > 0 && (
<div>
<h3 className="text-h3 mb-4">What You'll Learn</h3>
<ul className="space-y-3">
{webinar.keyTakeaways.map((takeaway, index) => (
<li key={index} className="flex items-start gap-3">
<CheckCircle className="w-5 h-5 text-[#04045B] mt-0.5 flex-shrink-0" />
<span className="text-body">{takeaway}</span>
</li>
))}
</ul>
</div>
)}
</div>
</section>
{/* Agenda Timeline */}
<section>
<h2 className="text-h2 mb-6">Session Agenda</h2>
<div className="space-y-6">
{webinar.agenda.map((item, index) => (
<div key={index} className="flex gap-6">
<div className="flex flex-col items-center">
<div className="w-4 h-4 bg-[#04045B] rounded-full" />
{index < webinar.agenda.length - 1 && (
<div className="w-0.5 h-16 bg-gray-200 mt-2" />
)}
</div>
<div className="flex-1 pb-8">
<div className="flex flex-col sm:flex-row sm:items-center gap-2 mb-2">
<Badge variant="outline" className="w-fit text-[#04045B] border-[#04045B]">
{item.time}
</Badge>
<h3 className="text-h4">{item.title}</h3>
{webinar.agenda.length > 0 && (
<section>
<h2 className="text-h2 mb-6">Session Agenda</h2>
<div className="space-y-6">
{webinar.agenda.map((item, index) => (
<div key={index} className="flex gap-6">
<div className="flex flex-col items-center">
<div className="w-4 h-4 bg-[#04045B] rounded-full" />
{index < webinar.agenda.length - 1 && (
<div className="w-0.5 h-16 bg-gray-200 mt-2" />
)}
</div>
<div className="flex-1 pb-8">
<div className="flex flex-col sm:flex-row sm:items-center gap-2 mb-2">
<Badge variant="outline" className="w-fit text-[#04045B] border-[#04045B]">
{item.time}
</Badge>
<h3 className="text-h4">{item.title}</h3>
</div>
<p className="text-body text-muted">{item.description}</p>
</div>
<p className="text-body text-muted">{item.description}</p>
</div>
</div>
))}
</div>
</section>
))}
</div>
</section>
)}
{/* Host & Panelists */}
<section>
@@ -503,14 +612,16 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
<h3 className="text-h4 mb-1">{webinar.host.name}</h3>
<p className="text-small text-[#04045B] font-medium">HOST</p>
</div>
<Button
variant="ghost"
size="sm"
onClick={() => window.open(webinar.host.linkedin, '_blank')}
className="text-[#04045B] hover:bg-[#04045B] hover:text-white"
>
<ExternalLink className="w-4 h-4" />
</Button>
{webinar.host.linkedin !== '#' && (
<Button
variant="ghost"
size="sm"
onClick={() => window.open(webinar.host.linkedin, '_blank')}
className="text-[#04045B] hover:bg-[#04045B] hover:text-white"
>
<ExternalLink className="w-4 h-4" />
</Button>
)}
</div>
<p className="text-small text-muted mb-1">{webinar.host.title}</p>
<p className="text-small text-muted">{webinar.host.company}</p>
@@ -535,14 +646,16 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
<h3 className="text-h4 mb-1">{panelist.name}</h3>
<p className="text-small text-[#F8C301] font-medium">SPEAKER</p>
</div>
<Button
variant="ghost"
size="sm"
onClick={() => window.open(panelist.linkedin, '_blank')}
className="text-[#04045B] hover:bg-[#04045B] hover:text-white"
>
<ExternalLink className="w-4 h-4" />
</Button>
{panelist.linkedin !== '#' && (
<Button
variant="ghost"
size="sm"
onClick={() => window.open(panelist.linkedin, '_blank')}
className="text-[#04045B] hover:bg-[#04045B] hover:text-white"
>
<ExternalLink className="w-4 h-4" />
</Button>
)}
</div>
<p className="text-small text-muted mb-1">{panelist.title}</p>
<p className="text-small text-muted">{panelist.company}</p>
@@ -604,7 +717,7 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
<div className="text-center mb-6">
<div className="text-h3 mb-2">{webinar.price}</div>
<div className="text-small text-muted">
{webinar.maxAttendees - parseInt(webinar.attendees.replace(/\D/g, '')) || 0} spots remaining
{webinar.maxAttendees} spots available
</div>
</div>
@@ -612,15 +725,8 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
<div className="flex items-center gap-3">
<Calendar className="w-5 h-5 text-[#04045B]" />
<div>
<div className="text-body font-medium">
{new Date(`${webinar.date}T${webinar.time}:00`).toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
})}
</div>
<div className="text-small text-muted">{webinar.time} {webinar.timezone}</div>
<div className="text-body font-medium">{webinar.date}</div>
<div className="text-small text-muted">{webinar.time}</div>
</div>
</div>
@@ -636,7 +742,7 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
<div className="flex items-center gap-3">
<Users className="w-5 h-5 text-[#04045B]" />
<div className="text-body">{webinar.attendees} registered</div>
<div className="text-body">Capacity: {webinar.attendees} attendees</div>
</div>
</div>
@@ -863,9 +969,9 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
{/* Add to Cart Button - Outline Blue */}
<Button
variant="outline"
onClick={(e) => {
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
// Add to cart functionality would go here
toast.info('Add to cart functionality would go here');
}}
className="flex-1 flex items-center justify-center gap-2 h-11 rounded-lg transition-all duration-200 font-medium"
style={{
@@ -877,11 +983,11 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
fontWeight: '500',
borderWidth: '2px'
}}
onMouseEnter={(e) => {
onMouseEnter={(e: React.MouseEvent<HTMLButtonElement>) => {
e.currentTarget.style.backgroundColor = '#04045B';
e.currentTarget.style.color = 'white';
}}
onMouseLeave={(e) => {
onMouseLeave={(e: React.MouseEvent<HTMLButtonElement>) => {
e.currentTarget.style.backgroundColor = 'transparent';
e.currentTarget.style.color = '#04045B';
}}
@@ -901,10 +1007,10 @@ export default function WebinarDetail({ params }: WebinarDetailProps) {
fontWeight: '500',
border: 'none'
}}
onMouseEnter={(e) => {
onMouseEnter={(e: React.MouseEvent<HTMLButtonElement>) => {
e.currentTarget.style.backgroundColor = '#030359';
}}
onMouseLeave={(e) => {
onMouseLeave={(e: React.MouseEvent<HTMLButtonElement>) => {
e.currentTarget.style.backgroundColor = '#04045B';
}}
>

View File

@@ -193,7 +193,7 @@ export function Webinars() {
const WebinarCard = ({ webinar }: { webinar: WebinarItem }) => {
const handleCardClick = () => {
if (webinar.webinar_status !== 'cancelled') {
navigateTo(`/webinar/${webinar.id}`);
navigateTo(`/webinars/${webinar.id}`);
}
};

View File

@@ -111,7 +111,7 @@ export const aboutUsApi = createApi({
// ✅ GET About Us
getAboutUs: builder.query<AboutUsData, void>({
query: () => ({
url: "/admin/about-us",
url: "/guest/about-us",
method: "GET",
}),

View File

@@ -104,7 +104,7 @@ export const blogApi = createApi({
if (tag_id && tag_id !== "all") params.tag_id = tag_id;
return {
url: "/admin/blogs/list",
url: "/guest/blogs/list",
method: "GET",
params,
};
@@ -114,7 +114,7 @@ export const blogApi = createApi({
getBlogByID: builder.query<BlogItem, string>({
query: (id) => ({
url: `/admin/blogs/list/${id}`,
url: `/guest/blogs/list/${id}`,
method: "GET",
}),
transformResponse: (response: BlogByIdResponse) => response.data,

View File

@@ -10,7 +10,7 @@ export const contactUsApi = createApi({
// GET Lead Categories
getLeadCategories: builder.query({
query: ({ limit = 10, offset = 0, status = "active" }) => ({
url: "admin/prepopulate/lead-categories/list",
url: "guest/prepopulate/lead-categories/list",
params: {
limit,
offset,
@@ -23,7 +23,7 @@ export const contactUsApi = createApi({
// CREATE Lead
createLead: builder.mutation({
query: (body) => ({
url: "admin/leads/create",
url: "guest/leads/create",
method: "POST",
body,
}),

View File

@@ -321,8 +321,8 @@ export const courseApi = createApi({
const queryString = searchParams.toString();
return queryString
? `admin/course/public/list?${queryString}`
: `admin/course/public/list`;
? `guest/course/public/list?${queryString}`
: `guest/course/public/list`;
},
providesTags: (result) =>
@@ -348,15 +348,15 @@ export const courseApi = createApi({
}
const queryString = searchParams.toString();
return queryString
? `admin/prepopulate/course-categories/list?${queryString}`
: `admin/prepopulate/course-categories/list`;
? `guest/prepopulate/course-categories/list?${queryString}`
: `guest/prepopulate/course-categories/list`;
},
providesTags: ["CourseCategories"],
}),
// GET Course By Id
getcoursebyid: builder.query<CourseDetailResponse, string>({
query: (course_id) => `admin/course/${course_id}`,
query: (course_id) => `guest/course/${course_id}`,
providesTags: (_result, _error, course_id) => [{ type: "Course", id: course_id }],
}),
@@ -368,4 +368,5 @@ export const {
useGetCoursesQuery,
useGetCourseCategoriesQuery,
useGetcoursebyidQuery,
} = courseApi;

View File

@@ -10,7 +10,7 @@ export const faqApi = createApi({
// GET FAQs LIST
getFaqs: builder.query({
query: ({ limit = 10, offset = 0, search_term, content_status, content_category_xid }) => ({
url: "admin/faq/list",
url: "guest/faq/list",
params: {
limit,
offset,
@@ -25,7 +25,7 @@ export const faqApi = createApi({
// GET category TAGS LIST
getFaqCategories: builder.query({
query: ({ limit = 10, offset = 0, search_query }) => ({
url: "admin/prepopulate/content-categories/list",
url: "guest/prepopulate/content-categories/list",
params: {
limit,
offset,

View File

@@ -103,7 +103,7 @@ export const homepageApi = createApi({
{ landing_page_type: "home" | "services" | "about_us" }
>({
query: ({ landing_page_type }) => ({
url: "/admin/home-page/list",
url: "/guest/home-page/list",
params: { landing_page_type },
}),
@@ -114,7 +114,7 @@ export const homepageApi = createApi({
getFeaturedBlogs: builder.query({
query: ({ limit = 3 }) => ({
url: `/admin/blogs/featured?limit=${limit}`,
url: `/guest/blogs/featured?limit=${limit}`,
method: 'GET',
}),
transformResponse: (response: any) => {

View File

@@ -14,7 +14,15 @@ export interface KautilyaPageResponse {
subtext: string;
cta_text: string;
cta_destination: string;
images: Array<{ // ✅ FIX ADDED
id: string;
hero_section_xid: string;
image_url: string;
alt_text: string;
display_order: number;
}>;
};
our_story: {
id: string;
tag: string;
@@ -22,6 +30,7 @@ export interface KautilyaPageResponse {
content: string;
image_url: string;
};
why_choose_us: {
id: string;
tag: string;
@@ -40,6 +49,7 @@ export interface KautilyaPageResponse {
}>;
}>;
};
facility_features: {
id: string;
title: string;
@@ -58,6 +68,7 @@ export interface KautilyaPageResponse {
}>;
}>;
};
visual_tour: {
id: string;
title: string;
@@ -75,6 +86,7 @@ export interface KautilyaPageResponse {
}>;
}>;
};
daily_experience: {
id: string;
title: string;
@@ -88,6 +100,7 @@ export interface KautilyaPageResponse {
display_order: number;
}>;
};
cta_section: {
id: string;
background_image_url: string;
@@ -97,6 +110,7 @@ export interface KautilyaPageResponse {
description: string;
};
};
errors: any;
correlation_id: string;
}
@@ -111,7 +125,7 @@ export const learningFacilityApi = createApi({
{ }
>({
query: ({ }) => ({
url: "/admin/kautilya-page/get",
url: "/guest/kautilya-page/get",
}),
transformResponse: (response: KautilyaPageResponse) => response.data,
providesTags: [{ type: "KautilyaPage", id: "LIST" }],

View File

@@ -10,7 +10,7 @@ export const sercicesApi = createApi({
getServiceList: builder.query<any, { service_type: string }>({
query: ({ service_type }) => ({
url: `/admin/service-page/list`,
url: `/guest/service-page/list`,
params: { service_type },
}),
}),

View File

@@ -50,6 +50,92 @@ export interface WebinarListParams {
sortBy?: "most_popular" | "newest" | "oldest" | "title" | "duration";
}
export interface WebinarDetailResponse {
success: boolean;
status: number;
message: string;
data: {
id: string;
session_title: string;
description: string | null;
session_datetime: string;
duration_minutes: number;
timezone_xid: string;
webinar_category_id: string;
max_attendee: number;
passcode: string;
require_registration: boolean;
recurring_webinar: boolean;
webinar_status: "scheduled" | "live" | "ended" | "cancelled";
type: string;
media: {
id: string;
file_name: string;
file_type: string;
file_extension: string;
} | null;
about_this_session: {
description: string;
points: Array<{
id: string;
about_id: string;
point: string;
sort_order: number;
}>;
} | null;
agenda_items: Array<{
id: string;
webinar_xid: string;
start_time: string;
end_time: string;
title: string;
description: string;
}>;
speakers: Array<{
id: string;
webinar_xid: string;
name: string;
designation: string;
company: string;
bio: string;
image_url: string;
is_host: boolean;
}>;
faqs: any;
course_links: Array<{
id: string;
webinar_xid: string;
course_xid: string;
display_order: number;
course: {
id: string;
course_name: string;
course_desc: string;
thumbnail_img: string;
course_category_xid: string;
course_category_name: string;
best_value: number;
avg_rating: number;
total_reviews: number;
retail_type: string;
price: number;
is_certificate_available: boolean;
course_status: string;
updated_at: string;
total_duration: number | null;
no_of_modules: number;
media_id: string | null;
media_file_type: string | null;
media_file_extension: string | null;
media_file_name: string | null;
};
}>;
};
errors: any;
correlation_id: string;
}
/* ================= API ================= */
export const webinarApi = createApi({
@@ -115,14 +201,18 @@ export const webinarApi = createApi({
params.append("sort_by", sortBy);
}
return `/admin/webinars/list?${params.toString()}`;
return `/guest/webinars/list?${params.toString()}`;
},
providesTags: ["Webinar"],
}),
getWebinarById: builder.query<WebinarDetailResponse, string>({
query: (webinarId) => `/guest/webinars/${webinarId}`,
providesTags: (result, error, id) => [{ type: "Webinar", id }],
}),
}),
});
/* ================= EXPORT HOOK ================= */
export const { useWebinarListQuery } = webinarApi;
export const { useWebinarListQuery, useGetWebinarByIdQuery } = webinarApi;