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:
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user