feat: implement cover image upload with canvas compression and db storage in RIT-EMS-main

This commit is contained in:
2026-06-19 09:37:29 +05:30
parent 91842646f0
commit 785fe05902
17 changed files with 1217 additions and 453 deletions

View File

@@ -267,10 +267,69 @@ const App: React.FC = () => {
profile = externalStudent;
finalRole = 'STUDENT';
} else {
// FALLBACK: Auto-sync profile from metadata
// FALLBACK: Auto-sync profile from metadata or auto-register from Google email format
const meta = user.user_metadata;
// ... (rest of metadata sync logic)
if (meta && (meta.role === 'STUDENT' || meta.regNo)) {
const emailLower = (user.email || '').trim().toLowerCase();
const studentMatch = emailLower.match(/^student\.(\d{6})@([a-zA-Z0-9&-_]+)\.ritchennai\.edu\.in$/);
if (studentMatch) {
const rollNo = studentMatch[1];
const rawDept = studentMatch[2].toLowerCase();
// Calculate joining year and academic year (current local time is 2026-06-19)
const joinYear = 2000 + parseInt(rollNo.substring(0, 2));
const currentYear = new Date().getFullYear();
const currentMonth = new Date().getMonth();
const academicYearOffset = currentMonth >= 5 ? 1 : 0;
const yearIndex = currentYear - joinYear + academicYearOffset;
const years = ["1st Year", "2nd Year", "3rd Year", "4th Year"];
const calculatedYear = years[yearIndex - 1] || "N/A";
// Map department
let dept = rawDept.toUpperCase();
if (dept === 'AIDS') dept = 'AI&DS';
else if (dept === 'AIML') dept = 'AI&ML';
else if (dept === 'VLSI') dept = 'EE(VLSI)';
else if (dept === 'BIOTECH' || dept === 'BIO-TECH') dept = 'BIOTECH';
else if (dept === 'H&S') dept = 'H&S Dept';
const syncData = {
id: user.id,
name: meta?.name || `Student ${rollNo}`,
email: emailLower,
reg_no: rollNo,
phone: '',
department: dept,
year: calculatedYear,
section: 'A',
college_name: 'Rajalakshmi Institute of Technology',
updated_at: new Date().toISOString()
};
const { data: synced } = await supabase.from('Studentusers').upsert(syncData).select().single();
profile = synced || syncData;
finalRole = 'STUDENT';
} else if (emailLower && !emailLower.endsWith('@ritchennai.edu.in') && !emailLower.endsWith('@rit.edu') && !HIGH_AUTH_ADMINS.includes(emailLower)) {
// Auto-register external user if signing in via Google with a non-campus email
const syncData = {
id: user.id,
name: meta?.name || emailLower.split('@')[0],
email: emailLower,
reg_no: 'EXT-' + Math.floor(Math.random() * 100000),
phone: '',
department: 'Others',
year: 'N/A',
section: 'N/A',
college: 'External Institution',
college_location: 'N/A',
gender: 'Male',
updated_at: new Date().toISOString()
};
const { data: synced } = await supabase.from('externalusers').upsert(syncData).select().single();
profile = synced || syncData;
finalRole = 'STUDENT';
} else if (meta && (meta.role === 'STUDENT' || meta.regNo)) {
const isExternal = meta.signUpType === 'EXTERNAL';
const table = isExternal ? 'externalusers' : 'Studentusers';
@@ -303,7 +362,7 @@ const App: React.FC = () => {
finalRole = 'STUDENT';
} else {
console.warn("Auto-sync profile failed:", syncError?.message);
profile = syncData; // Use metadata-based object as semi-functional fallback
profile = syncData;
finalRole = 'STUDENT';
}
} else if (meta && (meta.role === 'ADMIN' || meta.role === 'COORDINATOR')) {
@@ -430,8 +489,36 @@ const App: React.FC = () => {
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
handleAuthChange(session);
});
return () => subscription.unsubscribe();
}, [handleAuthChange]);
// 3. Real-time Database Subscriptions
const eventsChannel = supabase
.channel('events-sync')
.on('postgres_changes', { event: '*', schema: 'public', table: 'events' }, () => {
fetchAllRegistrations();
})
.subscribe();
const specialEventsChannel = supabase
.channel('special-events-sync')
.on('postgres_changes', { event: '*', schema: 'public', table: 'special_events' }, () => {
fetchSpecialEvents();
})
.subscribe();
const announcementsChannel = supabase
.channel('announcements-sync')
.on('postgres_changes', { event: '*', schema: 'public', table: 'announcements' }, () => {
fetchAnnouncements();
})
.subscribe();
return () => {
subscription.unsubscribe();
supabase.removeChannel(eventsChannel);
supabase.removeChannel(specialEventsChannel);
supabase.removeChannel(announcementsChannel);
};
}, [handleAuthChange, fetchAllRegistrations, fetchSpecialEvents, fetchAnnouncements]);
// NOTE: CreateEventForm already handles the Supabase insert.
// This callback only refreshes the local events list.