Skip to content

Commit a3db5dc

Browse files
committed
Replace all files except .github/workflows
1 parent 970f7ea commit a3db5dc

File tree

9 files changed

+227
-1023
lines changed

9 files changed

+227
-1023
lines changed

README.md

-3
This file was deleted.

package-lock.json

+9-928
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
"react-dom": "^18.2.0",
1616
"react-router-dom": "^6.20.0",
1717
"react-markdown": "^8.0.7",
18-
"firebase": "^10.7.1",
1918
"react-hot-toast": "^2.4.1"
2019
},
2120
"devDependencies": {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react';
2+
import { Download, FileText } from 'lucide-react';
3+
import { Document } from '../../types/document';
4+
5+
interface DocumentListProps {
6+
documents: Document[];
7+
}
8+
9+
const DocumentList: React.FC<DocumentListProps> = ({ documents }) => {
10+
if (documents.length === 0) {
11+
return (
12+
<div className="text-center py-12">
13+
<FileText className="mx-auto h-12 w-12 text-gray-400" />
14+
<h3 className="mt-2 text-sm font-medium text-gray-900">No documents found</h3>
15+
<p className="mt-1 text-sm text-gray-500">
16+
Documents will appear here once added
17+
</p>
18+
</div>
19+
);
20+
}
21+
22+
return (
23+
<div className="grid gap-6">
24+
{documents.map((doc) => (
25+
<div key={doc.id} className="bg-white p-6 rounded-lg shadow-md">
26+
<div className="flex items-start justify-between">
27+
<div className="flex-1">
28+
<h3 className="text-xl font-semibold mb-2">{doc.title}</h3>
29+
<p className="text-gray-600 mb-4">{doc.brief}</p>
30+
<p className="text-sm text-gray-500">
31+
Uploaded on {new Date(doc.uploadDate).toLocaleDateString()}
32+
</p>
33+
</div>
34+
<a
35+
href={doc.fileUrl}
36+
download={doc.fileName}
37+
className="inline-flex items-center text-blue-600 hover:text-blue-700"
38+
title="Download document"
39+
>
40+
<Download className="h-5 w-5" />
41+
</a>
42+
</div>
43+
</div>
44+
))}
45+
</div>
46+
);
47+
};
48+
49+
export default DocumentList;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React, { useState } from 'react';
2+
import { Upload } from 'lucide-react';
3+
4+
interface DocumentUploadProps {
5+
onUpload: (title: string, brief: string, file: File) => Promise<void>;
6+
isUploading: boolean;
7+
}
8+
9+
const DocumentUpload: React.FC<DocumentUploadProps> = ({ onUpload, isUploading }) => {
10+
const [title, setTitle] = useState('');
11+
const [brief, setBrief] = useState('');
12+
const [file, setFile] = useState<File | null>(null);
13+
14+
const handleSubmit = async (e: React.FormEvent) => {
15+
e.preventDefault();
16+
if (!file || !title || !brief) return;
17+
18+
if (!file.type.includes('pdf')) {
19+
alert('Please upload a PDF file');
20+
return;
21+
}
22+
23+
await onUpload(title, brief, file);
24+
setTitle('');
25+
setBrief('');
26+
setFile(null);
27+
28+
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
29+
if (fileInput) fileInput.value = '';
30+
};
31+
32+
return (
33+
<form onSubmit={handleSubmit} className="bg-white p-6 rounded-lg shadow-md mb-8">
34+
<h2 className="text-2xl font-bold mb-6">Upload New Document</h2>
35+
<div className="space-y-4">
36+
<div>
37+
<label className="block text-sm font-medium text-gray-700">Title</label>
38+
<input
39+
type="text"
40+
value={title}
41+
onChange={(e) => setTitle(e.target.value)}
42+
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
43+
required
44+
/>
45+
</div>
46+
<div>
47+
<label className="block text-sm font-medium text-gray-700">Brief Description</label>
48+
<textarea
49+
value={brief}
50+
onChange={(e) => setBrief(e.target.value)}
51+
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
52+
rows={3}
53+
required
54+
/>
55+
</div>
56+
<div>
57+
<label className="block text-sm font-medium text-gray-700">PDF File</label>
58+
<input
59+
type="file"
60+
accept=".pdf"
61+
onChange={(e) => e.target.files && setFile(e.target.files[0])}
62+
className="mt-1 block w-full"
63+
required
64+
/>
65+
</div>
66+
<button
67+
type="submit"
68+
disabled={isUploading}
69+
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
70+
>
71+
<Upload className="h-4 w-4 mr-2" />
72+
{isUploading ? 'Uploading...' : 'Upload Document'}
73+
</button>
74+
</div>
75+
</form>
76+
);
77+
};
78+
79+
export default DocumentUpload;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React from 'react';
2+
import { Lock, FileText } from 'lucide-react';
3+
import { useNavigate } from 'react-router-dom';
4+
5+
const LoginPrompt = () => {
6+
const navigate = useNavigate();
7+
8+
return (
9+
<div className="min-h-screen bg-gradient-to-r from-blue-600 to-blue-800">
10+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20">
11+
<div className="max-w-md mx-auto bg-white rounded-lg shadow-xl overflow-hidden">
12+
<div className="px-6 py-8">
13+
<div className="text-center">
14+
<FileText className="mx-auto h-12 w-12 text-blue-600" />
15+
<h2 className="mt-4 text-3xl font-bold text-gray-900">Knowledge Base</h2>
16+
<p className="mt-2 text-gray-600">
17+
Access our comprehensive collection of technical documentation, guides, and resources.
18+
</p>
19+
</div>
20+
21+
<div className="mt-8 bg-gray-50 p-4 rounded-lg border border-gray-200">
22+
<div className="flex items-center">
23+
<Lock className="h-5 w-5 text-gray-400" />
24+
<p className="ml-2 text-sm text-gray-600">
25+
Use your partner's Login Credentials to Access the Knowledge base
26+
</p>
27+
</div>
28+
</div>
29+
30+
<div className="mt-8">
31+
<button
32+
onClick={() => navigate('/login')}
33+
className="w-full flex items-center justify-center px-4 py-2 border border-transparent text-base font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
34+
>
35+
Login to Access
36+
</button>
37+
</div>
38+
39+
<div className="mt-6 text-center">
40+
<p className="text-sm text-gray-600">
41+
Contact your account manager if you need access credentials.
42+
</p>
43+
</div>
44+
</div>
45+
46+
<div className="px-6 py-4 bg-gray-50 border-t border-gray-200">
47+
<div className="text-center text-sm text-gray-600">
48+
<p>Protected documents include:</p>
49+
<ul className="mt-2 space-y-1">
50+
<li>Technical Documentation</li>
51+
<li>Integration Guides</li>
52+
<li>API References</li>
53+
<li>Best Practices</li>
54+
<li>Case Studies</li>
55+
</ul>
56+
</div>
57+
</div>
58+
</div>
59+
</div>
60+
</div>
61+
);
62+
};
63+
64+
export default LoginPrompt;

src/pages/KnowledgeBase.tsx

+21-80
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,50 @@
11
import React, { useState, useEffect } from 'react';
22
import { useAuth } from '../contexts/AuthContext';
3-
import { Search } from 'lucide-react';
4-
import { Toaster, toast } from 'react-hot-toast';
5-
import DocumentUploadForm from '../components/DocumentUploadForm';
6-
import DocumentList from '../components/DocumentList';
7-
import { saveDocument, getDocuments, deleteDocument } from '../utils/documentStorage';
3+
import LoginPrompt from '../components/knowledge-base/LoginPrompt';
4+
import DocumentList from '../components/knowledge-base/DocumentList';
5+
import DocumentUpload from '../components/knowledge-base/DocumentUpload';
6+
import { saveDocument, getDocuments } from '../utils/documentStorage';
87
import type { Document } from '../types/document';
98

109
const KnowledgeBase = () => {
1110
const { isAuthenticated } = useAuth();
1211
const [documents, setDocuments] = useState<Document[]>([]);
13-
const [searchQuery, setSearchQuery] = useState('');
1412
const [isUploading, setIsUploading] = useState(false);
1513

1614
useEffect(() => {
17-
loadDocuments();
15+
setDocuments(getDocuments());
1816
}, []);
1917

20-
const loadDocuments = () => {
21-
const docs = getDocuments();
22-
setDocuments(docs);
23-
};
24-
2518
const handleUpload = async (title: string, brief: string, file: File) => {
2619
setIsUploading(true);
2720
try {
2821
await saveDocument(title, brief, file);
29-
loadDocuments();
30-
toast.success('Document uploaded successfully!');
22+
setDocuments(getDocuments());
3123
} catch (error) {
3224
console.error('Error uploading document:', error);
33-
toast.error('Failed to upload document. Please try again.');
3425
} finally {
3526
setIsUploading(false);
3627
}
3728
};
3829

39-
const handleDelete = (docId: string) => {
40-
const confirmed = window.confirm('Are you sure you want to delete this document?');
41-
if (!confirmed) return;
42-
43-
try {
44-
deleteDocument(docId);
45-
loadDocuments();
46-
toast.success('Document deleted successfully!');
47-
} catch (error) {
48-
console.error('Error deleting document:', error);
49-
toast.error('Failed to delete document. Please try again.');
50-
}
51-
};
52-
53-
const filteredDocuments = documents.filter(doc =>
54-
doc.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
55-
doc.brief.toLowerCase().includes(searchQuery.toLowerCase())
56-
);
30+
if (!isAuthenticated) {
31+
return <LoginPrompt />;
32+
}
5733

5834
return (
59-
<div>
60-
<Toaster position="top-right" />
61-
62-
{/* Hero Section */}
63-
<section className="bg-gradient-to-r from-blue-600 to-blue-800 text-white py-20">
64-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
65-
<div className="max-w-3xl">
66-
<h1 className="text-4xl font-bold mb-4">Document Repository</h1>
67-
<p className="text-xl opacity-90">Access and manage our collection of documents and resources</p>
68-
</div>
69-
</div>
70-
</section>
71-
72-
{/* Upload Form - Only visible when authenticated */}
73-
{isAuthenticated && (
74-
<section className="py-8 bg-gray-50">
75-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
76-
<DocumentUploadForm onUpload={handleUpload} isUploading={isUploading} />
77-
</div>
78-
</section>
79-
)}
80-
81-
{/* Search Section */}
82-
<section className="py-8">
83-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
84-
<div className="relative w-full md:w-96 mx-auto">
85-
<input
86-
type="text"
87-
placeholder="Search documents..."
88-
value={searchQuery}
89-
onChange={(e) => setSearchQuery(e.target.value)}
90-
className="w-full pl-10 pr-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500"
91-
/>
92-
<Search className="absolute left-3 top-2.5 h-5 w-5 text-gray-400" />
93-
</div>
94-
</div>
95-
</section>
96-
97-
{/* Documents List */}
98-
<section className="py-12">
99-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
100-
<DocumentList
101-
documents={filteredDocuments}
102-
isAuthenticated={isAuthenticated}
103-
onDelete={handleDelete}
35+
<div className="min-h-screen bg-gray-50 py-12">
36+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
37+
<h1 className="text-3xl font-bold text-gray-900 mb-8">Knowledge Base</h1>
38+
39+
{isAuthenticated && (
40+
<DocumentUpload
41+
onUpload={handleUpload}
42+
isUploading={isUploading}
10443
/>
105-
</div>
106-
</section>
44+
)}
45+
46+
<DocumentList documents={documents} />
47+
</div>
10748
</div>
10849
);
10950
};

src/types/document.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export interface Document {
33
title: string;
44
brief: string;
55
fileName: string;
6+
fileUrl: string;
67
uploadDate: string;
78
uploadedBy: string;
89
}

src/utils/documentStorage.ts

+4-11
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@ export const saveDocument = async (title: string, brief: string, file: File): Pr
1515
title,
1616
brief,
1717
fileName: file.name,
18+
fileUrl,
1819
uploadDate: timestamp,
1920
uploadedBy: 'admin'
2021
};
21-
22-
// Store the blob URL in sessionStorage to persist across page reloads
23-
sessionStorage.setItem(`file_${id}`, fileUrl);
2422

2523
documents.push(newDocument);
2624
localStorage.setItem(STORAGE_KEY, JSON.stringify(documents));
@@ -36,13 +34,8 @@ export const deleteDocument = (id: string): void => {
3634
localStorage.setItem(STORAGE_KEY, JSON.stringify(documents));
3735

3836
// Clean up the blob URL
39-
const fileUrl = sessionStorage.getItem(`file_${id}`);
40-
if (fileUrl) {
41-
URL.revokeObjectURL(fileUrl);
42-
sessionStorage.removeItem(`file_${id}`);
37+
const doc = getDocuments().find(d => d.id === id);
38+
if (doc?.fileUrl) {
39+
URL.revokeObjectURL(doc.fileUrl);
4340
}
44-
};
45-
46-
export const getDocumentUrl = (id: string): string | null => {
47-
return sessionStorage.getItem(`file_${id}`);
4841
};

0 commit comments

Comments
 (0)