DRP_Sajidaat/DRP-App/app/add_review.tsx

313 lines
8.8 KiB
TypeScript

// app/add_review.tsx
import React, { useState } from 'react';
import {
View,
Text,
TextInput,
Button,
StyleSheet,
ScrollView,
Alert,
TouchableOpacity,
} from 'react-native';
import { Picker } from '@react-native-picker/picker'; // If you were using a picker
import { useRouter, useLocalSearchParams } from 'expo-router'; // Import useRouter and useLocalSearchParams
// Ensure interfaces match your PrayerSpacesListPage.tsx and backend expectations
interface ReviewPayload {
user: string;
place: string; // Backend expects place NAME string for lookup
quiet: number | null;
clean: number | null;
private: number | null;
cleanWudu: number | null;
childFriendly: number | null;
safe: number | null;
notes?: string; // Corresponds to comment in your frontend if added
}
interface AddReviewResponse {
message: string;
reviewId?: string;
}
const BACKEND_URL = 'http://132.145.65.145:8080'; // Your backend URL
const HARDCODED_USERNAME = 'testuser'; // Hardcoded username string, matching your seed user
// --- Emoji Rating Helpers (copied from PrayerSpacesListPage.tsx) ---
// This ensures the new page has these functions available
function averageRatingToEmoji(avg: number) {
if (avg < 1.66) {
return "😞";
} else if (avg < 2.33) {
return "😐";
} else {
return "😊";
}
}
interface EmojiRatingSelectorProps {
label: string;
value: number | null;
onSelect: (value: number) => void;
style?: object;
}
const EmojiRatingSelector: React.FC<EmojiRatingSelectorProps> = ({ label, value, onSelect, style }) => {
const emojis = [
{ emoji: "😞", value: 1, label: "Poor" },
{ emoji: "😐", value: 2, label: "Okay" },
{ emoji: "😊", value: 3, label: "Great" }
];
return (
<View style={[addReviewStyles.ratingContainer, style]}>
<Text style={addReviewStyles.ratingLabel}>{label}</Text>
<View style={addReviewStyles.emojiRow}>
{emojis.map((item) => (
<TouchableOpacity
key={item.value}
style={[
addReviewStyles.emojiButton,
value === item.value && addReviewStyles.selectedEmoji
]}
onPress={() => onSelect(item.value)}
>
<Text style={addReviewStyles.emojiText}>{item.emoji}</Text>
<Text style={addReviewStyles.emojiLabel}>{item.label}</Text>
</TouchableOpacity>
))}
</View>
</View>
);
};
// --- End Emoji Rating Helpers ---
export default function AddReviewScreen() {
const router = useRouter();
const params = useLocalSearchParams(); // Get params passed from navigation
const placeName = typeof params.placeName === 'string' ? params.placeName : 'Unknown Place';
const placeId = typeof params.placeId === 'string' ? params.placeId : ''; // Place ID for potential future use or debugging
const [quiet, setQuiet] = useState<number | null>(null);
const [clean, setClean] = useState<number | null>(null);
const [privacy, setPrivacy] = useState<number | null>(null);
const [cleanWudu, setCleanWudu] = useState<number | null>(null);
const [childFriendly, setChildFriendly] = useState<number | null>(null);
const [safe, setSafe] = useState<number | null>(null);
const [notes, setNotes] = useState(''); // Changed from comment to notes to match backend model name
const isValidRating = (val: number | null): boolean => {
return val !== null && val >= 1 && val <= 3;
};
const handleSubmit = async () => {
// Validate all rating fields
if (!quiet || !clean || !privacy || !cleanWudu || !childFriendly || !safe) {
Alert.alert('Missing Info', 'Please fill in all rating fields.');
return;
}
if (![quiet, clean, privacy, cleanWudu, childFriendly, safe].every(isValidRating)) {
Alert.alert('Invalid Input', 'Please select a rating for each category (1-3).');
return;
}
// Prepare payload for backend - sending place NAME as string
const payload: ReviewPayload = {
user: HARDCODED_USERNAME,
place: placeName, // IMPORTANT: Sending place NAME, not ID, as per your backend's SaveReview
quiet: quiet,
clean: clean,
private: privacy,
cleanWudu: cleanWudu,
childFriendly: childFriendly,
safe: safe,
notes: notes, // Sending notes field
};
console.log("Sending review payload from AddReviewScreen:", payload);
try {
const response = await fetch(`${BACKEND_URL}/reviews/new`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
console.error("Backend error response:", errorData);
throw new Error(errorData.message || `HTTP error! Status: ${response.status}`);
}
const data: AddReviewResponse = await response.json();
Alert.alert('Success', data.message || 'Review submitted!');
// Clear form and navigate back
setQuiet(null);
setClean(null);
setPrivacy(null);
setCleanWudu(null);
setChildFriendly(null);
setSafe(null);
setNotes(''); // Clear notes field
router.back(); // Go back to the previous screen (PrayerSpacesListPage)
} catch (error: any) {
Alert.alert('Error', `Could not send review: ${error.message || error}`);
console.error("Review submission error:", error);
}
};
return (
<ScrollView style={addReviewStyles.container} contentContainerStyle={addReviewStyles.contentContainer}>
<Text style={addReviewStyles.title}>Submit a Review</Text>
<Text style={addReviewStyles.subtitle}>For: {placeName}</Text>
{/* Emoji Rating Selectors */}
<EmojiRatingSelector
label="Cleanliness Rating"
value={clean}
onSelect={setClean}
/>
<EmojiRatingSelector
label="Wudu Cleanliness Rating"
value={cleanWudu}
onSelect={setCleanWudu}
/>
<EmojiRatingSelector
label="Quietness Rating"
value={quiet}
onSelect={setQuiet}
/>
<EmojiRatingSelector
label="Privacy Rating"
value={privacy}
onSelect={setPrivacy}
/>
<EmojiRatingSelector
label="Child Friendliness Rating"
value={childFriendly}
onSelect={setChildFriendly}
/>
<EmojiRatingSelector
label="Safety Rating"
value={safe}
onSelect={setSafe}
/>
<Text style={addReviewStyles.label}>Your Comments (optional)</Text>
<TextInput
style={[addReviewStyles.input, addReviewStyles.notesInput]}
placeholder="Add your thoughts about this place..."
value={notes}
onChangeText={setNotes}
multiline
numberOfLines={4}
textAlignVertical="top"
/>
<Button title="Submit Review" onPress={handleSubmit} />
<TouchableOpacity onPress={() => router.back()} style={addReviewStyles.cancelButton}>
<Text style={addReviewStyles.cancelButtonText}>Cancel</Text>
</TouchableOpacity>
</ScrollView>
);
}
const addReviewStyles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f8f9fa',
},
contentContainer: {
padding: 20,
paddingBottom: 40,
},
title: {
fontSize: 26,
fontWeight: 'bold',
marginBottom: 10,
textAlign: 'center',
color: '#333',
},
subtitle: {
fontSize: 18,
marginBottom: 25,
textAlign: 'center',
color: '#555',
fontWeight: '600',
},
label: {
fontSize: 16,
fontWeight: '600',
marginBottom: 8,
color: '#333',
marginTop: 10, // Add some top margin for spacing
},
input: {
backgroundColor: '#fff',
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 8,
paddingHorizontal: 15,
paddingVertical: 12,
fontSize: 16,
marginBottom: 15,
},
notesInput: {
height: 100,
paddingTop: 12,
},
// Styles for EmojiRatingSelector (copied from PrayerSpacesListPage)
ratingContainer: {
marginBottom: 15,
alignItems: 'center',
backgroundColor: '#fff', // Added background for better visibility
borderRadius: 8,
borderWidth: 1,
borderColor: '#ddd',
paddingVertical: 12,
},
ratingLabel: {
fontSize: 16,
fontWeight: '600',
marginBottom: 8,
color: '#333',
},
emojiRow: {
flexDirection: 'row',
justifyContent: 'space-around',
width: '90%',
},
emojiButton: {
padding: 8, // Slightly less padding for touch area
borderRadius: 5,
alignItems: 'center',
},
selectedEmoji: {
backgroundColor: '#e3f2fd',
borderColor: '#007AFF',
borderWidth: 1,
},
emojiText: {
fontSize: 30,
},
emojiLabel: {
fontSize: 12,
color: '#666',
marginTop: 5,
},
cancelButton: {
marginTop: 15,
paddingVertical: 10,
alignItems: 'center',
},
cancelButtonText: {
color: '#dc3545',
fontSize: 16,
fontWeight: '600',
},
});