Convert backends to Firebase and combine projects

This commit is contained in:
2026-06-18 14:07:24 +05:30
commit 0a76feafc5
147 changed files with 35104 additions and 0 deletions

View File

@@ -0,0 +1,142 @@
import React, { useState } from 'react';
import { supabase, uploadImageToSupabase } from '../supabase';
interface CreateDomainViewProps {
onShowToast: (msg: string, type: 'success' | 'delete') => void;
onBack: () => void;
}
const CreateDomainView: React.FC<CreateDomainViewProps> = ({ onShowToast, onBack }) => {
const [formData, setFormData] = useState({
name: '',
description: '',
category: 'TECHNICAL',
});
const [imageFile, setImageFile] = useState<File | null>(null);
const [imagePreview, setImagePreview] = useState<string | null>(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
if (file.size > 2 * 1024 * 1024) {
alert("Image must be less than 2MB");
return;
}
setImageFile(file);
const reader = new FileReader();
reader.onloadend = () => {
setImagePreview(reader.result as string);
};
reader.readAsDataURL(file);
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!imagePreview) {
alert("Please upload a cover image for the domain.");
return;
}
setIsSubmitting(true);
try {
const { data: { user } } = await supabase.auth.getUser();
if (!user) throw new Error("Authentication required");
const imagePath = `domain_covers/${Date.now()}_${formData.name.replace(/\s+/g, '_')}`;
const imageUrl = await uploadImageToSupabase(imagePreview, imagePath, 'domains');
const { error } = await supabase.from('domains').insert({
name: formData.name,
description: formData.description,
category: formData.category,
image: imageUrl,
status: formData.category === 'CENTRE-ACTIVITY' ? 'APPROVED' : 'PENDING',
created_by: user.id
});
if (error) throw error;
onShowToast("Domain verification requested successfully!", "success");
onBack();
} catch (error: any) {
console.error("Domain Request Error:", error);
alert(`Request failed: ${error.message}`);
setIsSubmitting(false);
}
};
return (
<div className="w-full max-w-4xl mx-auto bg-white rounded-[3rem] p-8 md:p-12 shadow-[0_20px_50px_rgba(0,0,0,0.05)] border border-slate-100">
<div className="flex items-center justify-between mb-10">
<div>
<h2 className="text-4xl font-black text-slate-900 uppercase tracking-tighter">Propose Domain</h2>
<p className="text-slate-400 font-bold uppercase tracking-widest text-[10px] mt-1">Submit a new domain for verification</p>
</div>
<button
type="button"
onClick={onBack}
className="w-12 h-12 bg-slate-50 text-slate-400 rounded-full flex items-center justify-center hover:bg-slate-100 hover:text-slate-600 transition-all border border-slate-200"
>
<i className="fas fa-times"></i>
</button>
</div>
<form onSubmit={handleSubmit} className="space-y-8">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div className="space-y-6">
<div>
<label className="block text-[10px] font-black text-slate-400 uppercase tracking-widest mb-3 ml-2">Domain Name *</label>
<input required name="name" placeholder="e.g. Artificial Intelligence" className="w-full bg-slate-50 border-none rounded-2xl px-6 py-4 text-xs font-bold outline-none focus:ring-2 focus:ring-[#004a99] transition-all" value={formData.name} onChange={handleInputChange} />
</div>
<div>
<label className="block text-[10px] font-black text-slate-400 uppercase tracking-widest mb-3 ml-2">Category *</label>
<select required name="category" className="w-full bg-slate-50 border-none rounded-2xl px-6 py-4 text-xs font-bold outline-none focus:ring-2 focus:ring-[#004a99] transition-all" value={formData.category} onChange={handleInputChange}>
<option value="TECHNICAL">Technical</option>
<option value="NON-TECHNICAL">Non-Technical</option>
<option value="WORKSHOP">Workshop</option>
<option value="CENTRE-ACTIVITY">Centre Activity</option>
</select>
</div>
<div>
<label className="block text-[10px] font-black text-slate-400 uppercase tracking-widest mb-3 ml-2">Description</label>
<textarea name="description" placeholder="Brief description of the domain..." rows={4} className="w-full bg-slate-50 border-none rounded-3xl px-6 py-5 text-xs font-medium outline-none focus:ring-2 focus:ring-[#004a99] transition-all resize-none" value={formData.description} onChange={handleInputChange}></textarea>
</div>
</div>
<div>
<label className="block text-[10px] font-black text-slate-400 uppercase tracking-widest mb-3 ml-2">Cover Image *</label>
<div className="relative w-full h-64 bg-slate-50 border-2 border-dashed border-slate-200 rounded-[2rem] overflow-hidden group hover:border-[#004a99] transition-colors cursor-pointer flex flex-col items-center justify-center">
<input type="file" accept="image/*" onChange={handleImageChange} className="absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10" required />
{imagePreview ? (
<img src={imagePreview} alt="Preview" className="w-full h-full object-cover" />
) : (
<div className="text-center p-6">
<div className="w-16 h-16 bg-white rounded-full flex items-center justify-center mx-auto mb-4 shadow-sm text-slate-300 group-hover:text-[#004a99] transition-colors">
<i className="fas fa-image text-xl"></i>
</div>
<span className="block text-xs font-black text-slate-500 uppercase tracking-widest">Upload Cover</span>
<span className="block text-[10px] font-medium text-slate-400 mt-2">Max. 2MB (16:9 Recommended)</span>
</div>
)}
</div>
</div>
</div>
<button type="submit" disabled={isSubmitting} className="w-full py-5 bg-orange-500 text-white rounded-2xl font-black uppercase text-xs tracking-[0.2em] hover:bg-orange-600 transition-all shadow-xl shadow-orange-500/20 active:scale-95 disabled:opacity-70 disabled:cursor-not-allowed">
{isSubmitting ? 'Submitting Request...' : 'Submit Domain for Verification'}
</button>
</form>
</div>
);
};
export default CreateDomainView;