Skip to content

Commit d39ce25

Browse files
committed
idk if this stuff works
1 parent 574459c commit d39ce25

16 files changed

Lines changed: 524 additions & 732 deletions

File tree

backend/controllers/teamController.ts

Lines changed: 92 additions & 241 deletions
Large diffs are not rendered by default.

backend/services/databaseService.ts

Lines changed: 0 additions & 219 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ export class DatabaseService {
1111
);
1212
}
1313

14-
getSupabaseClient() {
15-
return this.supabase;
16-
}
17-
1814
async requestLiveDemo(email: string) {
1915
return await this.supabase.from("live_demo_requests").insert({ email });
2016
}
@@ -220,171 +216,6 @@ export class DatabaseService {
220216
return await this.supabase.from("tenders").select("*");
221217
}
222218

223-
async getTendersPaginated(params: {
224-
offset: number;
225-
limit: number;
226-
search: string;
227-
sortBy: string;
228-
sortOrder: string;
229-
filters: {
230-
status?: string;
231-
category?: string;
232-
region?: string;
233-
entity?: string;
234-
};
235-
}) {
236-
let query = this.supabase.from("tenders").select("*", { count: "exact" });
237-
238-
// Apply search filter
239-
if (params.search) {
240-
query = query.or(
241-
`title.ilike.%${params.search}%,description.ilike.%${params.search}%,contracting_entity_name.ilike.%${params.search}%`
242-
);
243-
}
244-
245-
// Apply status filter
246-
if (params.filters.status) {
247-
query = query.eq("status", params.filters.status);
248-
}
249-
250-
// Apply category filter
251-
if (params.filters.category) {
252-
query = query.eq("category_primary", params.filters.category);
253-
}
254-
255-
// Apply region filter
256-
if (params.filters.region) {
257-
query = query.or(
258-
`contracting_entity_province.ilike.%${params.filters.region}%,contracting_entity_city.ilike.%${params.filters.region}%,delivery_location.ilike.%${params.filters.region}%`
259-
);
260-
}
261-
262-
// Apply entity filter
263-
if (params.filters.entity) {
264-
query = query.ilike(
265-
"contracting_entity_name",
266-
`%${params.filters.entity}%`
267-
);
268-
}
269-
270-
// Apply sorting
271-
query = query.order(params.sortBy, {
272-
ascending: params.sortOrder === "asc",
273-
});
274-
275-
// Apply pagination
276-
query = query.range(params.offset, params.offset + params.limit - 1);
277-
278-
const { data, error, count } = await query;
279-
280-
if (error) {
281-
return { data: null, error };
282-
}
283-
284-
return {
285-
data: {
286-
data: data || [],
287-
total: count || 0,
288-
},
289-
error: null,
290-
};
291-
}
292-
293-
async getTenderStatistics() {
294-
try {
295-
// Get total counts by source
296-
const { data: sourceStats, error: sourceError } = await this.supabase
297-
.from("tenders")
298-
.select("source")
299-
.then(async ({ data, error }) => {
300-
if (error) return { data: null, error };
301-
302-
// Group by source and count
303-
const sourceGroups =
304-
data?.reduce((acc: Record<string, number>, tender) => {
305-
const source = tender.source || "unknown";
306-
acc[source] = (acc[source] || 0) + 1;
307-
return acc;
308-
}, {}) || {};
309-
310-
return { data: sourceGroups, error: null };
311-
});
312-
313-
if (sourceError) {
314-
return { data: null, error: sourceError };
315-
}
316-
317-
// Get tenders added in last 24 hours by source
318-
const yesterday = new Date();
319-
yesterday.setDate(yesterday.getDate() - 1);
320-
321-
const { data: recentStats, error: recentError } = await this.supabase
322-
.from("tenders")
323-
.select("source, last_scraped_at")
324-
.gte("last_scraped_at", yesterday.toISOString())
325-
.then(async ({ data, error }) => {
326-
if (error) return { data: null, error };
327-
328-
// Group by source and count recent additions
329-
const recentGroups =
330-
data?.reduce((acc: Record<string, number>, tender) => {
331-
const source = tender.source || "unknown";
332-
acc[source] = (acc[source] || 0) + 1;
333-
return acc;
334-
}, {}) || {};
335-
336-
return { data: recentGroups, error: null };
337-
});
338-
339-
if (recentError) {
340-
return { data: null, error: recentError };
341-
}
342-
343-
// Map sources to display names
344-
const sourceMapping: Record<string, string> = {
345-
canadian: "Government of Canada",
346-
ontario: "Ontario Province",
347-
toronto: "City of Toronto",
348-
quebec: "Quebec Province",
349-
mississauga: "City of Mississauga",
350-
brampton: "City of Brampton",
351-
hamilton: "City of Hamilton",
352-
london: "City of London",
353-
unknown: "Other Sources",
354-
};
355-
356-
// Build statistics array from all sources that have data
357-
const allSources = new Set([
358-
...Object.keys(sourceStats || {}),
359-
...Object.keys(recentStats || {}),
360-
]);
361-
362-
const statistics = Array.from(allSources)
363-
.map((sourceKey) => {
364-
const displayName =
365-
sourceMapping[sourceKey] ||
366-
sourceKey.charAt(0).toUpperCase() + sourceKey.slice(1);
367-
const totalCount = sourceStats?.[sourceKey] || 0;
368-
const recentCount = recentStats?.[sourceKey] || 0;
369-
370-
return {
371-
source: displayName,
372-
numberOfTendersAddedDaily: recentCount,
373-
numberOfTendersAvailable: totalCount,
374-
};
375-
})
376-
.filter((stat) => stat.numberOfTendersAvailable > 0) // Only show sources with data
377-
.sort(
378-
(a, b) => b.numberOfTendersAvailable - a.numberOfTendersAvailable
379-
); // Sort by total count descending
380-
381-
return { data: statistics, error: null };
382-
} catch (error) {
383-
console.error("Error calculating tender statistics:", error);
384-
return { data: null, error };
385-
}
386-
}
387-
388219
async getTendersForAiFiltering(limit: number = 5) {
389220
return await this.supabase
390221
.from("tenders")
@@ -522,56 +353,6 @@ export class DatabaseService {
522353
}
523354
}
524355

525-
async changeUserPassword(accessToken: string, currentPassword: string, newPassword: string) {
526-
try {
527-
// Set the session with the access token first
528-
const { data: sessionData, error: sessionError } =
529-
await this.supabase.auth.setSession({
530-
access_token: accessToken,
531-
refresh_token: "", // Will be handled by Supabase
532-
});
533-
534-
if (sessionError) {
535-
console.error("Error setting session for password change:", sessionError);
536-
throw sessionError;
537-
}
538-
539-
// Get the current user
540-
const { data: user, error: userError } = await this.supabase.auth.getUser();
541-
542-
if (userError || !user.user) {
543-
console.error("Error getting user:", userError);
544-
throw new Error("User not found or session invalid");
545-
}
546-
547-
// Verify current password by attempting to sign in with it
548-
const { error: verifyError } = await this.supabase.auth.signInWithPassword({
549-
email: user.user.email!,
550-
password: currentPassword,
551-
});
552-
553-
if (verifyError) {
554-
console.error("Current password verification failed:", verifyError);
555-
throw new Error("Current password is incorrect");
556-
}
557-
558-
// Update the password
559-
const { data, error } = await this.supabase.auth.updateUser({
560-
password: newPassword,
561-
});
562-
563-
if (error) {
564-
console.error("Error changing password:", error);
565-
throw error;
566-
}
567-
568-
return data;
569-
} catch (error) {
570-
console.error("Failed to change password:", error);
571-
throw error;
572-
}
573-
}
574-
575356
// Profile methods
576357
async createOrUpdateProfile(
577358
profileData:

0 commit comments

Comments
 (0)