feat: implement report submission with photo upload and map display

- Fix Prisma client generation and database schema sync issues
- Implement user auto-creation from Clerk authentication
- Add raw SQL queries to handle MySQL POINT spatial fields
- Make password_hash optional for Clerk-only authentication
- Update MapPage to fetch real reports from API
- Add photo display in map popups with full-size modal view
- Configure CORS and Helmet for cross-origin image loading
- Add cleanup tracking task to implementation plan

Fixes report submission 500 errors and enables end-to-end workflow from submission to map display.
This commit is contained in:
2025-11-16 20:01:26 +00:00
parent a58e8da0e1
commit 64fe312f01
7 changed files with 180 additions and 39 deletions

View File

@@ -20,27 +20,43 @@ export interface CreateReportData {
export class ReportService {
async createReport(data: CreateReportData) {
const report = await prisma.report.create({
data: {
userId: data.userId,
latitude: new Prisma.Decimal(data.latitude),
longitude: new Prisma.Decimal(data.longitude),
locationSource: data.locationSource,
photoUrls: data.photoUrls,
photoTimestamp: data.photoTimestamp,
litterType: data.litterType,
quantity: data.quantity,
description: data.description,
environmentalConcerns: data.environmentalConcerns
? {
create: data.environmentalConcerns.map((concern) => ({
concernType: concern.type,
severity: concern.severity,
description: concern.description,
})),
}
: undefined,
},
// Create report using raw SQL to handle the POINT field
const reportId = await prisma.$queryRaw<Array<{ id: string }>>`
INSERT INTO reports (
user_id, location, latitude, longitude, location_source,
photo_urls, photo_timestamp, litter_type, quantity, description
) VALUES (
${data.userId},
ST_GeomFromText(${`POINT(${data.longitude} ${data.latitude})`}, 4326),
${data.latitude},
${data.longitude},
${data.locationSource},
${JSON.stringify(data.photoUrls)},
${data.photoTimestamp || null},
${data.litterType},
${data.quantity},
${data.description || null}
)
`;
// Get the created report ID
const createdId = await prisma.$queryRaw<Array<{ id: string }>>`
SELECT id FROM reports ORDER BY created_at DESC LIMIT 1
`;
// Create environmental concerns if provided
if (data.environmentalConcerns && data.environmentalConcerns.length > 0) {
for (const concern of data.environmentalConcerns) {
await prisma.$queryRaw`
INSERT INTO environmental_concerns (report_id, concern_type, severity, description)
VALUES (${createdId[0].id}, ${concern.type}, ${concern.severity}, ${concern.description})
`;
}
}
// Fetch and return the complete report
const report = await prisma.report.findUnique({
where: { id: createdId[0].id },
include: {
user: {
select: {