File size: 2,826 Bytes
d99b1af | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
import path from 'path';
export type SavedFoodReview = {
id: string;
userEmail: string;
submissionId: string;
campaignSlug: string;
placeName: string;
dishName: string;
privacy: 'private' | 'public';
createdAt: number;
};
const LOCAL_DATA_DIR = path.join(process.cwd(), '.local-review-data');
const USER_REVIEWS_FILE = path.join(LOCAL_DATA_DIR, 'user-reviews.json');
function ensureLocalDir() {
mkdirSync(LOCAL_DATA_DIR, { recursive: true });
}
function readAllReviews(): SavedFoodReview[] {
if (!existsSync(USER_REVIEWS_FILE)) return [];
try {
const parsed = JSON.parse(readFileSync(USER_REVIEWS_FILE, 'utf8')) as unknown;
if (!Array.isArray(parsed)) return [];
return parsed.filter(isSavedReview);
} catch {
return [];
}
}
function writeAllReviews(reviews: SavedFoodReview[]) {
ensureLocalDir();
writeFileSync(USER_REVIEWS_FILE, `${JSON.stringify(reviews, null, 2)}\n`, 'utf8');
}
function isSavedReview(value: unknown): value is SavedFoodReview {
const maybe = value as Partial<SavedFoodReview>;
return (
typeof maybe.id === 'string' &&
typeof maybe.userEmail === 'string' &&
typeof maybe.submissionId === 'string' &&
typeof maybe.campaignSlug === 'string' &&
typeof maybe.placeName === 'string' &&
typeof maybe.dishName === 'string' &&
(maybe.privacy === 'private' || maybe.privacy === 'public') &&
typeof maybe.createdAt === 'number'
);
}
function reviewId(userEmail: string, submissionId: string) {
return `${userEmail.toLowerCase()}:${submissionId}`;
}
export function saveReviewForUser(input: {
userEmail: string;
submissionId: string;
campaignSlug: string;
placeName?: string | null;
dishName?: string | null;
}) {
const userEmail = input.userEmail.trim().toLowerCase();
if (!userEmail || !input.submissionId) return null;
const reviews = readAllReviews();
const id = reviewId(userEmail, input.submissionId);
const existingIndex = reviews.findIndex((review) => review.id === id);
const review: SavedFoodReview = {
id,
userEmail,
submissionId: input.submissionId,
campaignSlug: input.campaignSlug,
placeName: input.placeName?.trim() || 'Foodstar review',
dishName: input.dishName?.trim() || 'Micro food review',
privacy: 'private',
createdAt: existingIndex >= 0 ? reviews[existingIndex]!.createdAt : Date.now(),
};
if (existingIndex >= 0) reviews[existingIndex] = review;
else reviews.push(review);
writeAllReviews(reviews);
return review;
}
export function listReviewsForUser(userEmail: string) {
const normalized = userEmail.trim().toLowerCase();
return readAllReviews()
.filter((review) => review.userEmail === normalized)
.sort((a, b) => b.createdAt - a.createdAt);
}
|