158 lines
6.0 KiB
TypeScript
158 lines
6.0 KiB
TypeScript
import { useState } from "react";
|
||
import { View, Text, Pressable, Alert, ScrollView } from "react-native";
|
||
import { useLocalSearchParams, Stack, useRouter } from "expo-router";
|
||
import { Ionicons } from "@expo/vector-icons";
|
||
import { useQuery, useMutation } from "convex/react";
|
||
import { api } from "../../convex/_generated/api";
|
||
import { useAuth } from "../_layout";
|
||
import { useTheme } from "../../components/theme";
|
||
import { Button } from "../../components/ui/button";
|
||
import { Input } from "../../components/ui/input";
|
||
import { Loading } from "../../components/ui/loading";
|
||
|
||
const STAR_LABELS = ["", "Многу лошо", "Лошо", "Просечно", "Добро", "Одлично"];
|
||
|
||
export default function CreateReviewScreen() {
|
||
const { adId } = useLocalSearchParams<{ adId: string }>();
|
||
const theme = useTheme();
|
||
const router = useRouter();
|
||
const { token, isAuthenticated, userId } = useAuth();
|
||
|
||
const ad = useQuery(api.ads.getById, adId ? { id: adId as any } : "skip");
|
||
const handyman = useQuery(
|
||
api.users.getById,
|
||
ad ? { id: ad.handymanId } : "skip"
|
||
);
|
||
|
||
const [rating, setRating] = useState(0);
|
||
const [comment, setComment] = useState("");
|
||
const [submitting, setSubmitting] = useState(false);
|
||
|
||
const createReview = useMutation(api.reviews.create);
|
||
|
||
if (!isAuthenticated) {
|
||
return (
|
||
<>
|
||
<Stack.Screen options={{ title: "Оценка", headerShown: true, headerBackButtonDisplayMode: "minimal" }} />
|
||
<View style={{ flex: 1, justifyContent: "center", alignItems: "center", backgroundColor: theme.colors.background, padding: theme.spacing.lg }}>
|
||
<Text style={{ ...theme.typography.body, color: theme.colors.textSecondary, textAlign: "center" }}>
|
||
Најавете се за да напишете оценка.
|
||
</Text>
|
||
<View style={{ marginTop: theme.spacing.md }}>
|
||
<Button onPress={() => router.push("/(auth)/login")}>Најави се</Button>
|
||
</View>
|
||
</View>
|
||
</>
|
||
);
|
||
}
|
||
|
||
async function handleSubmit() {
|
||
if (rating === 0) {
|
||
Alert.alert("Грешка", "Одберете оценка (1-5 ѕвезди)");
|
||
return;
|
||
}
|
||
if (!token || !adId) return;
|
||
|
||
setSubmitting(true);
|
||
try {
|
||
await createReview({ token, adId: adId as any, rating, comment: comment.trim() || undefined });
|
||
router.back();
|
||
} catch (e: any) {
|
||
Alert.alert("Грешка", e.message || "Неуспешно креирање оценка");
|
||
} finally {
|
||
setSubmitting(false);
|
||
}
|
||
}
|
||
|
||
if (!ad) {
|
||
return (
|
||
<>
|
||
<Stack.Screen options={{ title: "Оценка", headerShown: true, headerBackButtonDisplayMode: "minimal" }} />
|
||
<View style={{ flex: 1, justifyContent: "center", alignItems: "center", backgroundColor: theme.colors.background }}>
|
||
<Loading />
|
||
</View>
|
||
</>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<Stack.Screen options={{ title: "Оценка", headerShown: true, headerBackButtonDisplayMode: "minimal" }} />
|
||
<ScrollView
|
||
contentInsetAdjustmentBehavior="automatic"
|
||
contentContainerStyle={{ padding: theme.spacing.lg, gap: theme.spacing.xl }}
|
||
>
|
||
<View style={{ backgroundColor: theme.colors.card, borderRadius: theme.radius.lg, padding: theme.spacing.lg, ...theme.shadows.sm, borderWidth: 1, borderColor: theme.colors.border }}>
|
||
<Text style={{ ...theme.typography.h3, color: theme.colors.text, letterSpacing: -0.3 }}>
|
||
{ad.title}
|
||
</Text>
|
||
{handyman && (
|
||
<View style={{ flexDirection: "row", alignItems: "center", gap: theme.spacing.sm, marginTop: theme.spacing.sm }}>
|
||
<Ionicons name="construct-outline" size={18} color={theme.colors.primary} />
|
||
<Text style={{ ...theme.typography.body, color: theme.colors.textSecondary }}>
|
||
Мајстор: {handyman.name}
|
||
</Text>
|
||
</View>
|
||
)}
|
||
</View>
|
||
|
||
<View style={{ gap: theme.spacing.md, alignItems: "center" }}>
|
||
<Text style={{ ...theme.typography.h2, color: theme.colors.text, letterSpacing: -0.3 }}>
|
||
Оценка
|
||
</Text>
|
||
<View style={{ flexDirection: "row", gap: theme.spacing.sm }}>
|
||
{[1, 2, 3, 4, 5].map((star) => (
|
||
<Pressable
|
||
key={star}
|
||
accessible
|
||
accessibilityLabel={`${star} ${star === 1 ? "ѕвезда" : "ѕвезди"}`}
|
||
accessibilityRole="button"
|
||
onPress={() => setRating(star)}
|
||
style={{ padding: 4 }}
|
||
>
|
||
<Ionicons
|
||
name={star <= rating ? "star" : "star-outline"}
|
||
size={44}
|
||
color={star <= rating ? theme.colors.star : theme.colors.border}
|
||
/>
|
||
</Pressable>
|
||
))}
|
||
</View>
|
||
{rating > 0 && (
|
||
<Text style={{ ...theme.typography.bodyBold, color: theme.colors.primary }}>
|
||
{STAR_LABELS[rating]}
|
||
</Text>
|
||
)}
|
||
</View>
|
||
|
||
<View style={{ gap: theme.spacing.sm }}>
|
||
<Text style={{ ...theme.typography.h3, color: theme.colors.text, letterSpacing: -0.3 }}>
|
||
Коментар (опционално)
|
||
</Text>
|
||
<Input
|
||
value={comment}
|
||
onChangeText={setComment}
|
||
placeholder="Споделете го вашето искуство…"
|
||
multiline
|
||
numberOfLines={4}
|
||
style={{ minHeight: 120, textAlignVertical: "top" }}
|
||
accessibilityLabel="Коментар"
|
||
/>
|
||
</View>
|
||
|
||
<Button
|
||
loading={submitting}
|
||
disabled={rating === 0}
|
||
onPress={handleSubmit}
|
||
accessibilityLabel="Испрати оценка"
|
||
size="lg"
|
||
fullWidth
|
||
>
|
||
<Ionicons name="star" size={18} color={theme.colors.textInverse} style={{ marginRight: 4 }} />
|
||
Испрати оценка
|
||
</Button>
|
||
</ScrollView>
|
||
</>
|
||
);
|
||
}
|