feat(listings): add user-facing scam/abuse report flow (GOO-19)
- Add ListingFlag model with FlagReason enum (SCAM, DUPLICATE, WRONG_INFO, ALREADY_SOLD, INAPPROPRIATE) - Add POST /listings/:id/report endpoint with rate limiting and duplicate prevention - Auto-flag listings with ≥3 reports to PENDING_REVIEW for moderator review - Add GET /admin/flagged-listings endpoint for admin moderation queue - Add "Báo cáo" button + modal on listing detail page (Vietnamese UI) - Add Prisma migration for listing_flags table with unique constraint per user/listing Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -25,6 +25,16 @@ export type Direction =
|
||||
|
||||
export type Furnishing = 'FULLY_FURNISHED' | 'BASIC_FURNISHED' | 'UNFURNISHED';
|
||||
export type PropertyCondition = 'NEW' | 'LIKE_NEW' | 'RENOVATED' | 'USED';
|
||||
export type LegalStatus = 'SO_DO' | 'SO_HONG' | 'LAND_USE_RIGHT' | 'JOINT_USE_RIGHT' | 'AWAITING' | 'NO_CERTIFICATE';
|
||||
|
||||
export type FlagReason = 'SCAM' | 'DUPLICATE' | 'WRONG_INFO' | 'ALREADY_SOLD' | 'INAPPROPRIATE';
|
||||
|
||||
export interface ReportListingResult {
|
||||
flagId: string;
|
||||
listingId: string;
|
||||
totalReports: number;
|
||||
autoFlagged: boolean;
|
||||
}
|
||||
|
||||
// ─── Interfaces ──────────────────────────────────────────
|
||||
|
||||
@@ -99,7 +109,8 @@ export interface ListingDetail {
|
||||
totalFloors: number | null;
|
||||
direction: Direction | null;
|
||||
yearBuilt: number | null;
|
||||
legalStatus: string | null;
|
||||
legalStatus: LegalStatus | null;
|
||||
certificateVerified: boolean;
|
||||
amenities: string[] | null;
|
||||
nearbyPOIs: unknown;
|
||||
metroDistanceM: number | null;
|
||||
@@ -303,4 +314,7 @@ export const listingsApi = {
|
||||
`/analytics/neighborhoods/${encodeURIComponent(district)}/score?city=${encodeURIComponent(city)}`,
|
||||
)
|
||||
.then((res) => res.data),
|
||||
|
||||
reportListing: (listingId: string, reason: FlagReason, description?: string) =>
|
||||
apiClient.post<ReportListingResult>(`/listings/${listingId}/report`, { reason, description }),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user