feat: Complete Smart Resume Formatter with R2 and Gemini AI integration
Some checks failed
Profile Linker Docker Build / Build and push Docker image (push) Failing after 3s

- Integrated Cloudflare R2 for template storage and converted file management
- Added Google Gemini AI for resume parsing and HTML generation
- Created backend API endpoints for templates, conversion, and history
- Refactored frontend to use real API instead of mock data
- Fixed Docker networking issues (IPv6/IPv4) for R2 connectivity
- Added resumeService.ts for frontend API integration
- Updated Vite configuration for proper asset serving in Docker
- Successfully tested with 13 templates from R2 bucket
This commit is contained in:
Laxmi Khilnani
2025-10-14 21:43:41 +05:30
parent ee030b70bc
commit cda50356b4
34 changed files with 2604 additions and 360 deletions

View File

@@ -0,0 +1,60 @@
import React from 'react';
import { FileText, FileCode, Download, Eye } from 'lucide-react';
import { FileData } from '../types';
import { formatBytes, formatDate } from '../utils/formatters';
interface FileItemProps {
file: FileData;
onPreview: (url: string) => void;
}
const FileItem: React.FC<FileItemProps> = ({ file, onPreview }) => {
const getFileIcon = () => {
switch (file.type) {
case 'pdf':
return <FileText className="w-5 h-5 text-red-500" />;
case 'html':
return <FileCode className="w-5 h-5 text-blue-500" />;
default:
return <FileText className="w-5 h-5 text-slate-500" />;
}
};
return (
<div className="group grid grid-cols-1 md:grid-cols-[2fr,1fr,1.5fr,1.5fr] gap-4 items-center p-3 border-b border-slate-200 dark:border-slate-700 last:border-b-0 hover:bg-slate-50 dark:hover:bg-slate-800/50 transition-colors">
<div className="flex items-center gap-3 truncate">
{getFileIcon()}
<span className="font-medium text-slate-700 dark:text-slate-300 truncate group-hover:text-primary transition-colors" title={file.name}>{file.name}</span>
</div>
<div className="text-sm text-slate-500 dark:text-slate-400">
{formatBytes(file.size)}
</div>
<div className="text-sm text-slate-500 dark:text-slate-400 hidden md:block">
{formatDate(file.lastModified)}
</div>
<div className="flex items-center justify-start md:justify-end gap-2">
{file.type === 'html' && (
<button
onClick={() => onPreview(file.url)}
className="flex items-center gap-1.5 text-sm bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-300 hover:bg-slate-300 dark:hover:bg-slate-600 px-3 py-1.5 rounded-md transition-colors font-semibold"
>
<Eye className="w-4 h-4" />
Preview
</button>
)}
<a
href={file.url}
target="_blank"
rel="noopener noreferrer"
download={file.name}
className="flex items-center gap-1.5 text-sm bg-primary hover:bg-blue-600 text-white px-3 py-1.5 rounded-md transition-colors font-semibold"
>
<Download className="w-4 h-4" />
Download
</a>
</div>
</div>
);
};
export default FileItem;