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
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:
107
frontend/components/CreateFolderModal.tsx
Normal file
107
frontend/components/CreateFolderModal.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import React, { useState, FormEvent, useEffect } from 'react';
|
||||
import { X, FolderPlus, LoaderCircle } from 'lucide-react';
|
||||
|
||||
interface CreateFolderModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onSubmit: (folderName: string) => void;
|
||||
isCreating: boolean;
|
||||
}
|
||||
|
||||
const CreateFolderModal: React.FC<CreateFolderModalProps> = ({ isOpen, onClose, onSubmit, isCreating }) => {
|
||||
const [folderName, setFolderName] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
// Reset form state when modal is closed or opened
|
||||
if (isOpen) {
|
||||
setFolderName('');
|
||||
setError('');
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
const handleSubmit = (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!folderName.trim()) {
|
||||
setError('Folder name cannot be empty.');
|
||||
return;
|
||||
}
|
||||
// Basic validation for folder name characters could be added here
|
||||
onSubmit(folderName.trim());
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 bg-black bg-opacity-60 flex justify-center items-center z-50 p-4"
|
||||
onClick={onClose}
|
||||
aria-modal="true"
|
||||
role="dialog"
|
||||
>
|
||||
<div
|
||||
className="bg-white dark:bg-slate-800 rounded-lg shadow-2xl w-full max-w-md flex flex-col overflow-hidden"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="flex justify-between items-center p-4 border-b border-slate-200 dark:border-slate-700">
|
||||
<h2 className="text-lg font-semibold text-slate-800 dark:text-slate-200 flex items-center gap-2">
|
||||
<FolderPlus className="w-6 h-6 text-primary" />
|
||||
Create New Folder
|
||||
</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-1 rounded-full text-slate-500 hover:bg-slate-200 dark:hover:bg-slate-700 transition-colors"
|
||||
aria-label="Close modal"
|
||||
>
|
||||
<X className="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="p-6">
|
||||
<label htmlFor="folderName" className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
Folder Name
|
||||
</label>
|
||||
<input
|
||||
id="folderName"
|
||||
type="text"
|
||||
value={folderName}
|
||||
onChange={(e) => {
|
||||
setFolderName(e.target.value);
|
||||
if (error) setError('');
|
||||
}}
|
||||
placeholder="e.g., 'Project Alpha'"
|
||||
className="w-full px-3 py-2 border border-slate-300 dark:border-slate-600 rounded-md bg-slate-50 dark:bg-slate-700 text-slate-800 dark:text-slate-200 focus:ring-2 focus:ring-primary focus:border-primary outline-none transition"
|
||||
autoFocus
|
||||
/>
|
||||
{error && <p className="text-sm text-red-500 mt-2">{error}</p>}
|
||||
</div>
|
||||
<div className="flex justify-end items-center gap-3 p-4 bg-slate-50 dark:bg-slate-800/50 border-t border-slate-200 dark:border-slate-700">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="px-4 py-2 text-sm font-semibold bg-white dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-md hover:bg-slate-100 dark:hover:bg-slate-600 transition-colors"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isCreating}
|
||||
className="flex items-center justify-center gap-2 w-40 px-4 py-2 text-sm font-semibold bg-primary text-white rounded-md hover:bg-blue-600 transition-colors disabled:bg-slate-400 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isCreating ? (
|
||||
<>
|
||||
<LoaderCircle className="w-4 h-4 animate-spin" />
|
||||
Creating...
|
||||
</>
|
||||
) : (
|
||||
'Create Folder'
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateFolderModal;
|
||||
Reference in New Issue
Block a user