164 lines
6.7 KiB
TypeScript
164 lines
6.7 KiB
TypeScript
import { View, Text, ScrollView, Alert, Pressable } from "react-native";
|
||
import { Stack, useRouter } from "expo-router";
|
||
import { useState } from "react";
|
||
import { Ionicons } from "@expo/vector-icons";
|
||
import { 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 { CATEGORIES } from "../../lib/constants";
|
||
|
||
export default function CreatePostScreen() {
|
||
const router = useRouter();
|
||
const theme = useTheme();
|
||
const { token, isAuthenticated } = useAuth();
|
||
|
||
const [title, setTitle] = useState("");
|
||
const [description, setDescription] = useState("");
|
||
const [category, setCategory] = useState<string | null>(null);
|
||
const [location, setLocation] = useState("");
|
||
const [budget, setBudget] = useState("");
|
||
const [submitting, setSubmitting] = useState(false);
|
||
|
||
const createPost = useMutation(api.posts.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 }}>
|
||
<View style={{ width: 88, height: 88, borderRadius: 44, backgroundColor: theme.colors.primaryLight, alignItems: "center", justifyContent: "center", marginBottom: 16, ...theme.shadows.sm }}>
|
||
<Ionicons name="lock-closed" size={38} color={theme.colors.primary} />
|
||
</View>
|
||
<Text style={{ ...theme.typography.h3, color: theme.colors.text, marginBottom: 8 }}>
|
||
Најавете се
|
||
</Text>
|
||
<Text style={{ ...theme.typography.body, color: theme.colors.textSecondary, textAlign: "center", marginBottom: theme.spacing.lg }}>
|
||
Треба да сте најавени за да креирате побарување.
|
||
</Text>
|
||
<Button onPress={() => router.push("/(auth)/login" as any)} accessibilityLabel="Најави се">Најави се</Button>
|
||
</View>
|
||
</>
|
||
);
|
||
}
|
||
|
||
async function handleSubmit() {
|
||
if (!title.trim()) {
|
||
Alert.alert("Грешка", "Внесете наслов");
|
||
return;
|
||
}
|
||
if (!description.trim()) {
|
||
Alert.alert("Грешка", "Внесете опис");
|
||
return;
|
||
}
|
||
|
||
setSubmitting(true);
|
||
try {
|
||
const postId = await createPost({
|
||
token: token!,
|
||
title: title.trim(),
|
||
description: description.trim(),
|
||
category: category ?? undefined,
|
||
location: location.trim() || undefined,
|
||
budget: budget.trim() || undefined,
|
||
});
|
||
router.replace(`/post/${postId}` as any);
|
||
} catch (e: any) {
|
||
Alert.alert("Грешка", e.message || "Неуспешно креирање");
|
||
} finally {
|
||
setSubmitting(false);
|
||
}
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<Stack.Screen options={{ title: "Ново побарување", headerShown: true, headerBackButtonDisplayMode: "minimal" }} />
|
||
<ScrollView contentInsetAdjustmentBehavior="automatic" contentContainerStyle={{ padding: theme.spacing.lg, gap: theme.spacing.md }}>
|
||
<Text style={{ ...theme.typography.h3, color: theme.colors.text, letterSpacing: -0.3 }}>Креирајте побарување</Text>
|
||
|
||
<View style={{ gap: theme.spacing.xs }}>
|
||
<Text style={{ ...theme.typography.captionBold, color: theme.colors.text, fontSize: 13 }}>Наслов *</Text>
|
||
<Input
|
||
placeholder="Што ви треба?"
|
||
value={title}
|
||
onChangeText={setTitle}
|
||
maxLength={100}
|
||
accessibilityLabel="Наслов на побарување"
|
||
/>
|
||
</View>
|
||
|
||
<View style={{ gap: theme.spacing.xs }}>
|
||
<Text style={{ ...theme.typography.captionBold, color: theme.colors.text, fontSize: 13 }}>Опис *</Text>
|
||
<Input
|
||
placeholder="Опишете го проблемот детално..."
|
||
value={description}
|
||
onChangeText={setDescription}
|
||
multiline
|
||
numberOfLines={4}
|
||
style={{ minHeight: 120, textAlignVertical: "top" }}
|
||
maxLength={2000}
|
||
accessibilityLabel="Опис на побарување"
|
||
/>
|
||
</View>
|
||
|
||
<View style={{ gap: theme.spacing.xs }}>
|
||
<Text style={{ ...theme.typography.captionBold, color: theme.colors.text, fontSize: 13 }}>Категорија</Text>
|
||
<View style={{ flexDirection: "row", flexWrap: "wrap", gap: theme.spacing.sm }}>
|
||
{CATEGORIES.map((cat) => (
|
||
<Pressable
|
||
key={cat.slug}
|
||
onPress={() => setCategory(category === cat.slug ? null : cat.slug)}
|
||
style={{
|
||
backgroundColor: category === cat.slug ? theme.colors.primary : theme.colors.surface,
|
||
borderRadius: theme.radius.full,
|
||
paddingHorizontal: 16,
|
||
paddingVertical: 10,
|
||
borderWidth: 1.5,
|
||
borderColor: category === cat.slug ? theme.colors.primary : theme.colors.border,
|
||
}}
|
||
>
|
||
<Text
|
||
style={{
|
||
color: category === cat.slug ? theme.colors.textInverse : theme.colors.text,
|
||
...theme.typography.captionBold,
|
||
}}
|
||
>
|
||
{cat.name}
|
||
</Text>
|
||
</Pressable>
|
||
))}
|
||
</View>
|
||
</View>
|
||
|
||
<View style={{ gap: theme.spacing.xs }}>
|
||
<Text style={{ ...theme.typography.captionBold, color: theme.colors.text, fontSize: 13 }}>Локација</Text>
|
||
<Input
|
||
placeholder="нр. Скопје, Битола..."
|
||
value={location}
|
||
onChangeText={setLocation}
|
||
maxLength={100}
|
||
accessibilityLabel="Локација"
|
||
/>
|
||
</View>
|
||
|
||
<View style={{ gap: theme.spacing.xs }}>
|
||
<Text style={{ ...theme.typography.captionBold, color: theme.colors.text, fontSize: 13 }}>Буџет</Text>
|
||
<Input
|
||
placeholder="нр. 5000 - 10000 денари"
|
||
value={budget}
|
||
onChangeText={setBudget}
|
||
maxLength={100}
|
||
accessibilityLabel="Буџет"
|
||
/>
|
||
</View>
|
||
|
||
<Button onPress={handleSubmit} loading={submitting} disabled={submitting} accessibilityLabel="Објави побарување" size="lg" fullWidth>
|
||
Објави побарување
|
||
</Button>
|
||
</ScrollView>
|
||
</>
|
||
);
|
||
}
|