fix issues

This commit is contained in:
priyanshuvish
2025-10-31 13:51:16 +05:30
parent a574f8a40e
commit bb3c138c25
19 changed files with 211 additions and 178 deletions

View File

@@ -1,3 +1,4 @@
// In App.tsx - FIXED VERSION
import React, { useState, useEffect } from "react";
import { Login } from "./components/auth/Login";
import { ForgotPassword } from "./components/auth/ForgotPassword";
@@ -18,7 +19,6 @@ import { ProfilerBuilder } from "./components/pages/ProfilerBuilder";
import { ProfilerMaster } from "./components/pages/ProfilerMaster";
import { ProfilerPreview } from "./components/pages/ProfilerPreview";
import { ProfilerApproval } from "./components/pages/ProfilerApproval";
import { LandingPages } from "./components/pages/LandingPagesNew";
import { HomeEditor } from "./components/pages/HomeEditor";
import { ServicesEditor } from "./components/pages/ServicesEditor";
@@ -38,13 +38,12 @@ import { Roles } from "./components/pages/Roles";
import { Analytics } from "./components/pages/Analytics";
import { Toaster } from "./components/ui/sonner";
import { SESSION_CONFIG, AutoSaveData, mockNotifications, Notification, mockApprovalTasks, ApprovalTask } from "./data/mockData";
import { Route } from "./types/routes";
import { ViewFAQ } from "./components/pages/ViewFAQ";
import { ViewBlog } from "./components/pages/ViewBlog";
import { EditFAQ } from "./components/pages/EditFAQ";
import { EditBlog } from "./components/pages/EditBlog";
import { EditWebcast, WebcastEditPage } from "./components/pages/EditWebcast";
import { EditWebcast } from "./components/pages/EditWebcast";
import { EditTrainingMaterial } from "./components/pages/EditTrainingMaterial";
import { EditReadingMaterial } from "./components/pages/EditReadingMaterial";
import { EditPodcast } from "./components/pages/EditPodcast";
@@ -62,14 +61,10 @@ export default function App() {
lastLogin: "2024-01-15 14:30",
});
// Auto-save state management
const [autoSaveData, setAutoSaveData] = useState<{ [key: string]: any }>({});
// Notification state management
const [notifications, setNotifications] = useState<Notification[]>(mockNotifications);
const [approvalTasks, setApprovalTasks] = useState<ApprovalTask[]>(mockApprovalTasks);
// Simulate authentication check
useEffect(() => {
const authToken = localStorage.getItem("klc_auth_token");
if (authToken) {
@@ -80,7 +75,6 @@ export default function App() {
}
}, []);
// Auto-save functionality
const handleAutoSave = (formData: any) => {
const routeKey = `${currentRoute}_${user.email}`;
setAutoSaveData(prev => ({
@@ -88,7 +82,6 @@ export default function App() {
[routeKey]: formData
}));
// Persist to localStorage
const autoSaveData: AutoSaveData = {
userId: user.email,
route: currentRoute,
@@ -100,13 +93,11 @@ export default function App() {
localStorage.setItem(`autosave_${routeKey}`, JSON.stringify(autoSaveData));
};
// Get auto-saved data for current route
const getAutoSavedData = () => {
const routeKey = `${currentRoute}_${user.email}`;
return autoSaveData[routeKey] || null;
};
// Clear auto-saved data
const clearAutoSavedData = (route?: string) => {
const routeKey = route ? `${route}_${user.email}` : `${currentRoute}_${user.email}`;
setAutoSaveData(prev => {
@@ -117,7 +108,6 @@ export default function App() {
localStorage.removeItem(`autosave_${routeKey}`);
};
// Notification handlers
const handleMarkNotificationAsRead = (notificationId: string) => {
setNotifications(prev =>
prev.map(n => n.id === notificationId ? { ...n, read: true } : n)
@@ -132,14 +122,12 @@ export default function App() {
setNotifications(prev => prev.filter(n => n.id !== notificationId));
};
// Approval handlers
const handleApproveTask = (taskId: string, comment: string) => {
setApprovalTasks(prev =>
prev.map(task =>
task.id === taskId ? { ...task, status: 'approved' as const } : task
)
);
// Add success notification
const task = approvalTasks.find(t => t.id === taskId);
if (task) {
const newNotification: Notification = {
@@ -166,7 +154,6 @@ export default function App() {
task.id === taskId ? { ...task, status: 'rejected' as const } : task
)
);
// Add notification
const task = approvalTasks.find(t => t.id === taskId);
if (task) {
const newNotification: Notification = {
@@ -193,7 +180,6 @@ export default function App() {
task.id === taskId ? { ...task, status: 'changes_requested' as const } : task
)
);
// Add notification
const task = approvalTasks.find(t => t.id === taskId);
if (task) {
const newNotification: Notification = {
@@ -215,12 +201,12 @@ export default function App() {
};
const navigate = (route: Route) => {
console.log('🧭 Navigating to:', route);
setCurrentRoute(route);
};
const login = () => {
localStorage.setItem("klc_auth_token", "mock_token");
// Set longer session timeout
const expirationTime = Date.now() + SESSION_CONFIG.LOGOUT_TIMEOUT;
localStorage.setItem("klc_auth_expiration", expirationTime.toString());
@@ -232,7 +218,6 @@ export default function App() {
localStorage.removeItem("klc_auth_token");
localStorage.removeItem("klc_auth_expiration");
// Clear all auto-saved data for this user
Object.keys(localStorage).forEach(key => {
if (key.startsWith(`autosave_`) && key.includes(user.email)) {
localStorage.removeItem(key);
@@ -244,9 +229,9 @@ export default function App() {
navigate("/login");
};
// In your App.tsx, update the renderPage function:
const renderPage = () => {
console.log('🏠 App.tsx - Current route:', currentRoute);
if (!isAuthenticated && !currentRoute.startsWith("/login")) {
return <Login onLogin={login} onNavigate={navigate} />;
}
@@ -261,7 +246,8 @@ export default function App() {
notifications,
onMarkNotificationAsRead: handleMarkNotificationAsRead,
onMarkAllNotificationsAsRead: handleMarkAllNotificationsAsRead,
onDeleteNotification: handleDeleteNotification
onDeleteNotification: handleDeleteNotification,
currentRoute
};
switch (currentRoute) {
@@ -284,27 +270,20 @@ export default function App() {
case "/users/organizations/new":
return <NewOrganization {...commonProps} />;
case "/content":
case "/content/blogs":
case "/content/faqs":
case "/content/webcasts":
case "/content/training-materials":
case "/content/reading-materials":
case "/content/podcasts":
case "/content/case-studies":
case "/content/klc-content-archive":
console.log('🏠 App.tsx - Rendering ContentManager with route:', currentRoute);
return <ContentManager {...commonProps} />;
case "/content/blogs/new":
return <NewBlog {...commonProps} />;
case "/content/faqs/new":
return <NewFAQ {...commonProps} />;
case "/content/faqs":
return <ContentManager {...commonProps} />;
case "/content/blogs":
return <ContentManager {...commonProps} />;
// ADD THESE ROUTES FOR WEBCASTS AND TRAINING MATERIALS
case "/content/webcasts":
return <ContentManager {...commonProps} />;
case "/content/training-materials":
return <ContentManager {...commonProps} />;
case "/content/reading-materials":
return <ContentManager {...commonProps} />;
case "/content/podcasts":
return <ContentManager {...commonProps} />;
case "/courses":
return <Courses {...commonProps} />;
case "/courses/course-builder":
@@ -361,15 +340,12 @@ export default function App() {
case "/admin/analytics":
return <Analytics {...commonProps} />;
default:
// Handle dynamic routes - UPDATE THIS SECTION:
if (currentRoute.startsWith("/content/faqs/view/")) {
const faqId = currentRoute.split("/").pop();
console.log('🔄 Rendering ViewFAQ with ID:', faqId);
return <ViewFAQ {...commonProps} faqId={faqId} />;
}
if (currentRoute.startsWith("/content/blogs/view/")) {
const blogId = currentRoute.split("/").pop();
console.log('🔄 Rendering ViewBlog with ID:', blogId);
return <ViewBlog {...commonProps} blogId={blogId} />;
}
if (currentRoute.startsWith("/content/faqs/edit/")) {
@@ -380,17 +356,14 @@ export default function App() {
const blogId = currentRoute.split("/").pop();
return <EditBlog {...commonProps} blogId={blogId} />;
}
if (currentRoute.startsWith("/content/case-studies/edit/")) {
const caseStudyId = currentRoute.split("/").pop();
return <EditCaseStudy {...commonProps} caseStudyId={caseStudyId} />;
}
if (currentRoute.startsWith("/content/klc-archive/edit/")) {
const archiveId = currentRoute.split("/").pop();
return <EditKlcArchiveContent {...commonProps} archiveId={archiveId} />;
}
if (currentRoute.startsWith("/content/webcasts/edit/")) {
const webcastId = currentRoute.split("/").pop();
return <EditWebcast {...commonProps} webcastId={webcastId} />;
@@ -407,16 +380,6 @@ export default function App() {
const readingMaterialId = currentRoute.split("/").pop();
return <EditReadingMaterial {...commonProps} readingMaterialId={readingMaterialId} />;
}
if (currentRoute.startsWith("/content/faqs/edit/")) {
const faqId = currentRoute.split("/").pop();
return <NewFAQ {...commonProps} formData={{ editMode: true, faqId }} />;
}
if (currentRoute.startsWith("/content/blogs/edit/")) {
const blogId = currentRoute.split("/").pop();
return <NewBlog {...commonProps} formData={{ editMode: true, blogId }} />;
}
if (currentRoute.startsWith("/programmes/") && currentRoute.endsWith("/assign")) {
const programmeId = currentRoute.split("/")[2];
return <ProgrammeAssignment programmeId={programmeId} {...commonProps} />;

View File

@@ -23,6 +23,11 @@ export function TwoFactorAuth({ onLogin, onNavigate }: TwoFactorAuthProps) {
const otpRefs = useRef<(HTMLInputElement | null)[]>([]);
// Initialize refs array
useEffect(() => {
otpRefs.current = otpRefs.current.slice(0, 6);
}, []);
// Get masked email from login context
useEffect(() => {
const loginContext = sessionStorage.getItem('login_context');
@@ -30,7 +35,6 @@ export function TwoFactorAuth({ onLogin, onNavigate }: TwoFactorAuthProps) {
const { email } = JSON.parse(loginContext);
setMaskedEmail(email);
} else {
// Fallback masked email if no context
setMaskedEmail('ad***@klc.edu');
}
}, []);
@@ -43,11 +47,14 @@ export function TwoFactorAuth({ onLogin, onNavigate }: TwoFactorAuthProps) {
}
}, [resendCooldown]);
// Focus management - focus first input on mount
// Focus first input on mount
useEffect(() => {
if (otpRefs.current[0]) {
otpRefs.current[0].focus();
}
const timer = setTimeout(() => {
if (otpRefs.current[0]) {
otpRefs.current[0].focus();
}
}, 100);
return () => clearTimeout(timer);
}, []);
const handleVerifyCode = async (e: React.FormEvent) => {
@@ -62,21 +69,15 @@ export function TwoFactorAuth({ onLogin, onNavigate }: TwoFactorAuthProps) {
setIsLoading(true);
// Simulate API call with different scenarios
setTimeout(() => {
if (code === '000000') {
// Simulate expired code
setError('Code expired. Request a new one.');
} else if (code === '999999') {
// Simulate too many attempts
setError('Too many attempts. Please wait before retrying.');
} else if (code === '123456') {
// Successful verification
// Clear session storage and redirect to dashboard
sessionStorage.removeItem('login_context');
onLogin();
} else {
// Incorrect code
const newAttempts = attempts + 1;
setAttempts(newAttempts);
@@ -86,7 +87,6 @@ export function TwoFactorAuth({ onLogin, onNavigate }: TwoFactorAuthProps) {
setError('Incorrect code.');
}
// Clear the code inputs and focus first input
setVerificationCode(['', '', '', '', '', '']);
if (otpRefs.current[0]) {
otpRefs.current[0].focus();
@@ -96,53 +96,85 @@ export function TwoFactorAuth({ onLogin, onNavigate }: TwoFactorAuthProps) {
}, 1200);
};
const handleCodeInput = (index: number, value: string) => {
const handleCodeChange = (index: number, value: string) => {
// Clear errors when user starts typing
if (error) {
setError('');
}
// Handle paste - distribute "123456" across all inputs
if (value.length > 1) {
const pastedCode = value.slice(0, 6).split('');
const newCode = [...verificationCode];
pastedCode.forEach((char, i) => {
if (index + i < 6 && /^\d$/.test(char)) {
newCode[index + i] = char;
}
});
setVerificationCode(newCode);
// Focus the last filled input or the next empty one
const lastIndex = Math.min(index + pastedCode.length - 1, 5);
const nextEmptyIndex = newCode.findIndex((char, i) => i > lastIndex && char === '');
const focusIndex = nextEmptyIndex !== -1 ? nextEmptyIndex : lastIndex;
if (otpRefs.current[focusIndex]) {
otpRefs.current[focusIndex]?.focus();
}
// Only allow digits
if (value && !/^\d+$/.test(value)) {
return;
}
// Handle single character input (digits only)
if (/^\d$/.test(value) || value === '') {
// Handle single digit input
if (value.length <= 1) {
const newCode = [...verificationCode];
newCode[index] = value;
setVerificationCode(newCode);
// Auto-advance to next input
if (value && index < 5 && otpRefs.current[index + 1]) {
otpRefs.current[index + 1]?.focus();
// Auto-focus next input if a digit was entered
if (value && index < 5) {
const nextInput = otpRefs.current[index + 1];
if (nextInput) {
// Use setTimeout to ensure the state update has happened
setTimeout(() => {
nextInput.focus();
}, 10);
}
}
}
};
const handleCodeKeyDown = (index: number, e: React.KeyboardEvent) => {
// Backspace navigation
if (e.key === 'Backspace' && !verificationCode[index] && index > 0) {
otpRefs.current[index - 1]?.focus();
const handleKeyDown = (index: number, e: React.KeyboardEvent<HTMLInputElement>) => {
// Handle backspace
if (e.key === 'Backspace') {
if (!verificationCode[index] && index > 0) {
// Move to previous input if current is empty
const prevInput = otpRefs.current[index - 1];
if (prevInput) {
prevInput.focus();
}
} else if (verificationCode[index]) {
// Clear current input but stay focused
const newCode = [...verificationCode];
newCode[index] = '';
setVerificationCode(newCode);
}
}
// Handle arrow keys
else if (e.key === 'ArrowLeft' && index > 0) {
const prevInput = otpRefs.current[index - 1];
if (prevInput) {
prevInput.focus();
}
} else if (e.key === 'ArrowRight' && index < 5) {
const nextInput = otpRefs.current[index + 1];
if (nextInput) {
nextInput.focus();
}
}
};
const handlePaste = (e: React.ClipboardEvent<HTMLInputElement>) => {
e.preventDefault();
const pastedData = e.clipboardData.getData('text');
const digits = pastedData.replace(/\D/g, '').slice(0, 6).split('');
if (digits.length === 6) {
const newCode = [...verificationCode];
digits.forEach((digit, i) => {
newCode[i] = digit;
});
setVerificationCode(newCode);
// Focus the last input after paste
setTimeout(() => {
if (otpRefs.current[5]) {
otpRefs.current[5].focus();
}
}, 10);
}
};
@@ -154,25 +186,11 @@ export function TwoFactorAuth({ onLogin, onNavigate }: TwoFactorAuthProps) {
setVerificationCode(['', '', '', '', '', '']);
// Focus first input after resend
if (otpRefs.current[0]) {
otpRefs.current[0].focus();
}
// Simulate API call
setTimeout(() => {
// Success handling would go here
}, 1000);
}
};
const handleFirstInputFocus = () => {
// Announce "6 fields" when first input is focused
const announcement = document.getElementById('otp-announcement');
if (announcement) {
announcement.textContent = '6 digit verification code input fields';
setTimeout(() => {
announcement.textContent = '';
}, 2000);
if (otpRefs.current[0]) {
otpRefs.current[0].focus();
}
}, 100);
}
};
@@ -220,19 +238,23 @@ export function TwoFactorAuth({ onLogin, onNavigate }: TwoFactorAuthProps) {
{verificationCode.map((digit, index) => (
<Input
key={index}
ref={(el) => (otpRefs.current[index] = el)}
ref={(el) => {
otpRefs.current[index] = el;
}}
type="text"
inputMode="numeric"
maxLength={6}
pattern="[0-9]*"
maxLength={1}
value={digit}
onChange={(e) => handleCodeInput(index, e.target.value)}
onKeyDown={(e) => handleCodeKeyDown(index, e)}
onFocus={index === 0 ? handleFirstInputFocus : undefined}
onChange={(e) => handleCodeChange(index, e.target.value)}
onKeyDown={(e) => handleKeyDown(index, e)}
onPaste={index === 0 ? handlePaste : undefined}
className="w-12 h-12 text-center font-mono text-lg focus-visible:ring-2 focus-visible:ring-[var(--color-brand-primary)] focus-visible:ring-opacity-50"
aria-label={`Digit ${index + 1} of 6`}
aria-describedby={error ? "code-error" : undefined}
aria-invalid={!!error}
disabled={tooManyAttempts}
autoComplete="one-time-code"
/>
))}
</div>
@@ -327,26 +349,6 @@ export function TwoFactorAuth({ onLogin, onNavigate }: TwoFactorAuthProps) {
</div>
</div>
</footer>
{/* Screen reader announcements */}
<div
id="otp-announcement"
role="status"
aria-live="polite"
aria-label="OTP field information"
className="sr-only"
/>
<div
role="status"
aria-live="polite"
aria-label="Form status"
className="sr-only"
>
{isLoading && "Verifying code, please wait"}
{error && `Error: ${error}`}
{resendCooldown > 0 && `Resend available in ${resendCooldown} seconds`}
</div>
</div>
);
}

View File

@@ -1,4 +1,5 @@
import React, { useState } from "react";
// In ContentManager.tsx - FIXED VERSION
import React, { useState, useEffect } from "react";
import { AuthenticatedLayout } from "../layout/AuthenticatedLayout";
import { Card, CardContent } from "../ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
@@ -20,11 +21,13 @@ import { ReadingMaterialsTab } from "./tabs/ReadingMaterialsTab";
import { KLCContentArchiveTab } from "./tabs/KLCContentArchiveTab";
import { CaseStudiesTab } from "./tabs/CaseStudiesTab";
import { PodcastsTab } from "./tabs/PodcastsTab";
import { Route } from "../../types/routes";
interface ContentManagerProps {
onNavigate: (route: string) => void;
onNavigate: (route: Route) => void;
onLogout: () => void;
user: any;
currentRoute?: Route;
}
const contentTabs = [
@@ -43,7 +46,7 @@ const contentTabs = [
primaryAction: "New Blog"
},
{
id: "faq",
id: "faq", // This is the tab ID - note it's "faq" without 's'
label: "FAQ",
icon: HelpCircle,
canCreate: true,
@@ -110,13 +113,79 @@ export function ContentManager({
onNavigate,
onLogout,
user,
currentRoute = "/content",
}: ContentManagerProps) {
const [activeTab, setActiveTab] = useState("profiler");
console.log('📦 ContentManager received currentRoute:', currentRoute);
const getInitialTab = () => {
console.log('🔄 getInitialTab called with currentRoute:', currentRoute);
// Map routes to tab IDs correctly
if (currentRoute.includes('/content/blogs')) return 'blogs';
if (currentRoute.includes('/content/faqs')) return 'faq'; // This should be 'faq' to match the tab ID
if (currentRoute.includes('/content/webcasts')) return 'webcasts';
if (currentRoute.includes('/content/training-materials')) return 'training-materials';
if (currentRoute.includes('/content/reading-materials')) return 'reading-materials';
if (currentRoute.includes('/content/podcasts')) return 'podcasts';
if (currentRoute.includes('/content/case-studies')) return 'case-studies';
if (currentRoute.includes('/content/klc-content-archive')) return 'klc-content-archive';
console.log('📌 Defaulting to profiler tab');
return 'profiler';
};
const [activeTab, setActiveTab] = useState(getInitialTab());
const [activeInnerTab, setActiveInnerTab] = useState<{ [key: string]: string }>({
"training-materials": "Facilitator Manual",
"klc-content-archive": "Leadership Lego Blocks"
});
useEffect(() => {
console.log('🔄 Route changed, updating active tab. Current route:', currentRoute);
const newTab = getInitialTab();
console.log('📌 Setting active tab to:', newTab);
setActiveTab(newTab);
}, [currentRoute]);
const handleTabChange = (tabId: string) => {
console.log('🔄 Tab changed to:', tabId);
setActiveTab(tabId);
// Navigate to specific routes when tabs are clicked
switch (tabId) {
case 'blogs':
onNavigate('/content/blogs');
break;
case 'faq': // This should be 'faq' to match the tab ID
onNavigate('/content/faqs');
break;
case 'webcasts':
onNavigate('/content/webcasts');
break;
case 'training-materials':
onNavigate('/content/training-materials');
break;
case 'reading-materials':
onNavigate('/content/reading-materials');
break;
case 'podcasts':
onNavigate('/content/podcasts');
break;
case 'case-studies':
onNavigate('/content/case-studies');
break;
case 'klc-content-archive':
onNavigate('/content/klc-content-archive');
break;
default:
onNavigate('/content');
}
};
useEffect(() => {
console.log('📌 Current active tab:', activeTab);
}, [activeTab]);
const breadcrumbs = [
{ label: "Content" }
];
@@ -132,7 +201,6 @@ export function ContentManager({
breadcrumbs={breadcrumbs}
>
<div className="p-6 space-y-6 max-w-[1440px] mx-auto">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h1>Content Manager</h1>
@@ -142,9 +210,7 @@ export function ContentManager({
</div>
</div>
{/* Main Content */}
<Tabs value={activeTab} onValueChange={setActiveTab}>
<Tabs value={activeTab} onValueChange={handleTabChange}>
<TabsList className="grid w-full grid-cols-9 h-auto p-1">
{contentTabs.map((tab) => {
const Icon = tab.icon;
@@ -162,27 +228,22 @@ export function ContentManager({
</TabsList>
<Card>
<CardContent className="p-6">
{/* Profiler Tab */}
<TabsContent value="profiler">
<ProfilerTab onNavigate={onNavigate} user={user} />
</TabsContent>
{/* Blogs Tab */}
<TabsContent value="blogs">
<BlogsTab onNavigate={onNavigate} user={user} />
</TabsContent>
{/* FAQ Tab */}
<TabsContent value="faq">
<TabsContent value="faq"> {/* This matches the tab ID */}
<FAQTab onNavigate={onNavigate} user={user} />
</TabsContent>
{/* Webcasts Tab */}
<TabsContent value="webcasts">
<WebcastsTab onNavigate={onNavigate} user={user} />
</TabsContent>
{/* Training Materials Tab */}
<TabsContent value="training-materials">
<TrainingMaterialsTab
onNavigate={onNavigate}
@@ -192,22 +253,18 @@ export function ContentManager({
/>
</TabsContent>
{/* Reading Materials Tab */}
<TabsContent value="reading-materials">
<ReadingMaterialsTab onNavigate={onNavigate} user={user} />
</TabsContent>
{/* Podcasts Tab */}
<TabsContent value="podcasts">
<PodcastsTab onNavigate={onNavigate} user={user} />
</TabsContent>
{/* Case Studies Tab */}
<TabsContent value="case-studies">
<CaseStudiesTab onNavigate={onNavigate} user={user} />
</TabsContent>
{/* KLC Content Archive Tab */}
<TabsContent value="klc-content-archive">
<KLCContentArchiveTab
onNavigate={onNavigate}
@@ -216,7 +273,6 @@ export function ContentManager({
setActiveInnerTab={setActiveInnerTab}
/>
</TabsContent>
</CardContent>
</Card>
</Tabs>

View File

@@ -214,7 +214,7 @@ export function EditBlog({
}
toast.success(`Blog ${status === 'draft' ? 'updated' : 'published'} successfully`);
onNavigate('/content');
onNavigate('/content/blogs');
} catch (error: any) {
console.error('Error updating blog:', error);
toast.error(error.data?.message || 'Failed to update blog. Please try again.');

View File

@@ -134,7 +134,7 @@ export function EditCaseStudy({
}
toast.success('Case study updated successfully');
onNavigate('/content');
onNavigate('/content/case-studies');
} catch (error: any) {
console.error('Error updating case study:', error);
toast.error(error.data?.message || 'Failed to update case study. Please try again.');

View File

@@ -157,7 +157,7 @@ export function EditFAQ({
}
toast.success('FAQ updated successfully');
onNavigate('/content');
onNavigate('/content/faqs');
} catch (error: any) {
console.error('Error updating FAQ:', error);
toast.error(error.data?.message || 'Failed to update FAQ. Please try again.');

View File

@@ -145,7 +145,7 @@ export function EditKlcArchiveContent({
}
toast.success('Archive content updated successfully');
onNavigate('/content');
onNavigate('/content/klc-content-archive');
} catch (error: any) {
console.error('Error updating archive content:', error);
toast.error(error.data?.message || 'Failed to update archive content. Please try again.');

View File

@@ -134,7 +134,7 @@ export function EditPodcast({
}
toast.success('Podcast updated successfully');
onNavigate('/content');
onNavigate('/content/podcasts');
} catch (error: any) {
console.error('Error updating podcast:', error);
toast.error(error.data?.message || 'Failed to update podcast. Please try again.');

View File

@@ -136,7 +136,7 @@ export function EditReadingMaterial({
}
toast.success('Reading material updated successfully');
onNavigate('/content');
onNavigate('/content/reading-materials');
} catch (error: any) {
console.error('Error updating reading material:', error);
toast.error(error.data?.message || 'Failed to update reading material. Please try again.');

View File

@@ -142,7 +142,7 @@ export function EditTrainingMaterial({
}
toast.success('Training Material updated successfully');
onNavigate('/content');
onNavigate('/content/training-materials');
} catch (error: any) {
console.error('Error updating training material:', error);
toast.error(error.data?.message || 'Failed to update training material. Please try again.');

View File

@@ -140,7 +140,7 @@ export function EditWebcast({
}
toast.success('Webcast updated successfully');
onNavigate('/content');
onNavigate('/content/webcasts');
} catch (error: any) {
console.error('Error updating webcast:', error);
toast.error(error.data?.message || 'Failed to update webcast. Please try again.');

View File

@@ -150,7 +150,7 @@ export function NewBlog({
}
toast.success(`Blog ${status === 'draft' ? 'saved as draft' : 'published'} successfully`);
onNavigate('/content');
onNavigate('/content/blogs');
} catch (error: any) {
console.error('Error creating blog:', error);
@@ -179,7 +179,7 @@ export function NewBlog({
<div className="flex items-center gap-4">
<Button
variant="ghost"
onClick={() => onNavigate('/content')}
onClick={() => onNavigate('/content/blogs')}
className="min-h-[44px] focus-visible:ring-2 focus-visible:ring-[var(--color-brand-primary)] focus-visible:ring-opacity-50"
disabled={isSubmitting}
>

View File

@@ -188,7 +188,7 @@ export function NewFAQ({
}
toast.success(`${faqs.length} FAQ(s) created successfully`);
onNavigate('/content');
onNavigate('/content/faqs');
} catch (error: any) {
console.error('Error creating FAQs:', error);
@@ -242,7 +242,7 @@ export function NewFAQ({
}
toast.success(`${faqs.length} FAQ(s) created successfully`);
onNavigate('/content');
onNavigate('/content/faqs');
} catch (error: any) {
console.error('Error creating FAQs:', error);
toast.error(error.data?.message || 'Failed to save FAQs. Please try again.');

View File

@@ -136,7 +136,7 @@ export function CaseStudiesTab({ onNavigate, user }: CaseStudiesTabProps) {
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span>
Showing {enhancedCaseStudies.length} of {paginationMeta?.total || 0} items
{/* Showing {enhancedCaseStudies.length} of {paginationMeta?.total || 0} items */}
{paginationMeta && paginationMeta.totalPages > 1 && (
<span> (Page {currentPage} of {paginationMeta.totalPages})</span>
)}

View File

@@ -112,7 +112,6 @@ export function KLCContentArchiveTab({
setSelectedItems([]);
};
// REMOVED: Filter by category since API data doesn't have category field
// Use all data instead of filtering by category
const filteredArchive = archiveContent.filter((archive: any) =>
archive.title?.toLowerCase().includes(searchTerm.toLowerCase()) ||
@@ -192,7 +191,7 @@ export function KLCContentArchiveTab({
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span>
Showing {enhancedArchive.length} of {paginationMeta?.total || 0} items
{/* Showing {enhancedArchive.length} of {paginationMeta?.total || 0} items */}
{paginationMeta && paginationMeta.totalPages > 1 && (
<span> (Page {currentPage} of {paginationMeta.totalPages})</span>
)}

View File

@@ -136,7 +136,7 @@ export function PodcastsTab({ onNavigate, user }: PodcastsTabProps) {
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span>
Showing {enhancedPodcasts.length} of {paginationMeta?.total || 0} items
{/* Showing {enhancedPodcasts.length} of {paginationMeta?.total || 0} items */}
{paginationMeta && paginationMeta.totalPages > 1 && (
<span> (Page {currentPage} of {paginationMeta.totalPages})</span>
)}

View File

@@ -133,7 +133,7 @@ export function ReadingMaterialsTab({ onNavigate, user }: ReadingMaterialsTabPro
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span>
Showing {enhancedReadingMaterials.length} of {paginationMeta?.total || 0} items
{/* Showing {enhancedReadingMaterials.length} of {paginationMeta?.total || 0} items */}
{paginationMeta && paginationMeta.totalPages > 1 && (
<span> (Page {currentPage} of {paginationMeta.totalPages})</span>
)}

View File

@@ -211,7 +211,7 @@ export function TrainingMaterialsTab({
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span>
Showing {enhancedMaterials.length} of {paginationMeta?.total || 0} items
{/* Showing {enhancedMaterials.length} of {paginationMeta?.total || 0} items */}
{paginationMeta && paginationMeta.totalPages > 1 && (
<span> (Page {currentPage} of {paginationMeta.totalPages})</span>
)}

View File

@@ -1,3 +1,4 @@
// In types/routes.ts
export type Route =
| "/login"
| "/login/forget-password"
@@ -12,11 +13,23 @@ export type Route =
| "/content/blogs"
| "/content/blogs/new"
| `/content/blogs/edit/${string}`
| `/content/blogs/view/${string}` // Add blog view route
| `/content/blogs/view/${string}`
| "/content/faqs"
| "/content/faqs/new"
| `/content/faqs/edit/${string}`
| `/content/faqs/view/${string}` // Add FAQ view route
| `/content/faqs/view/${string}`
| "/content/webcasts"
| "/content/training-materials"
| "/content/reading-materials"
| "/content/podcasts"
| "/content/case-studies"
| "/content/klc-content-archive"
| `/content/webcasts/edit/${string}`
| `/content/training-materials/edit/${string}`
| `/content/reading-materials/edit/${string}`
| `/content/podcasts/edit/${string}`
| `/content/case-studies/edit/${string}`
| `/content/klc-archive/edit/${string}`
| "/courses"
| "/courses/course-builder"
| "/courses/new"