mojmajstor/app/(tabs)/(profile)/index.tsx
echo 5102ed23c1 feat: Phase 1 - project setup, auth, and base UI
Set up Expo SDK 56 project with TypeScript and Expo Router (file-based).

Backend:
- Full Convex schema (users, accounts, sessions, ads, categories,
  reviews, chats, messages, posts) deployed to self-hosted instance
- Custom email/password auth with SHA-256 hashing via Convex actions
- Query/mutation scaffolds for all domain tables
- Convex environment variables configured on backend

App structure:
- Root layout with ConvexProvider, ThemeProvider, AuthContext
- (auth) group: login and register screens (Macedonian UI)
  with role selection (handyman/customer)
- (tabs) group: 5 tabs (Home, Explore, Posts, Chat, Profile)
  each with nested Stack layouts
- Placeholder detail screens for ad, post, chat, review flows
- 404 not-found screen in Macedonian

UI primitives (components/ui/):
- Button (4 variants), Input, Card, Loading, Avatar, Rating, Badge
- ThemeProvider with light/dark palette via React context

All user-facing strings in Macedonian. Code identifiers in English.
TypeScript passes with zero errors.
2026-05-29 18:18:58 +02:00

81 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { View, Text, Pressable, ScrollView } from "react-native";
import { useRouter } from "expo-router";
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";
export default function ProfileScreen() {
const router = useRouter();
const theme = useTheme();
const { token, isAuthenticated, logout } = useAuth();
const user = useQuery(api.users.getCurrentUser, isAuthenticated ? { token: token! } : "skip");
const logoutMutation = useMutation(api.auth.logout);
async function handleLogout() {
if (token) {
try {
await logoutMutation({ token });
} catch {}
}
await logout();
router.replace("/(auth)/login");
}
if (!isAuthenticated) {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center", backgroundColor: theme.colors.background, padding: theme.spacing.lg }}>
<Text style={{ fontSize: 48, marginBottom: 16 }}>👤</Text>
<Text style={{ fontSize: 18, fontWeight: "600", color: theme.colors.text, marginBottom: 8 }}>
Најавете се
</Text>
<Text style={{ color: theme.colors.textSecondary, textAlign: "center", marginBottom: theme.spacing.lg }}>
За да ги видите вашиот профил и податоци.
</Text>
<Button onPress={() => router.push("/(auth)/login")}>Најави се</Button>
</View>
);
}
return (
<ScrollView contentInsetAdjustmentBehavior="automatic" contentContainerStyle={{ padding: theme.spacing.lg, gap: theme.spacing.md }}>
<View style={{ alignItems: "center", paddingVertical: theme.spacing.lg }}>
<View style={{
width: 80,
height: 80,
borderRadius: 40,
backgroundColor: theme.colors.primaryLight,
alignItems: "center",
justifyContent: "center",
}}>
<Text style={{ color: theme.colors.primary, fontWeight: "700", fontSize: 28 }}>
{user?.name?.charAt(0)?.toUpperCase() || "?"}
</Text>
</View>
<Text style={{ fontSize: 20, fontWeight: "700", color: theme.colors.text, marginTop: theme.spacing.md }}>
{user?.name || "Корисник"}
</Text>
<Text style={{ color: theme.colors.textSecondary }}>
{user?.role === "handyman" ? "Мајстор" : "Клиент"}
</Text>
</View>
<View style={{ backgroundColor: theme.colors.card, borderRadius: theme.radius.lg, padding: theme.spacing.md, gap: theme.spacing.sm }}>
<Pressable style={{ paddingVertical: theme.spacing.sm }}>
<Text style={{ color: theme.colors.text, fontSize: 16 }}>Мои огласи</Text>
</Pressable>
<Pressable style={{ paddingVertical: theme.spacing.sm }}>
<Text style={{ color: theme.colors.text, fontSize: 16 }}>Оцени</Text>
</Pressable>
<Pressable style={{ paddingVertical: theme.spacing.sm }}>
<Text style={{ color: theme.colors.text, fontSize: 16 }}>Поставки</Text>
</Pressable>
</View>
<Button variant="destructive" onPress={handleLogout}>
Одјави се
</Button>
</ScrollView>
);
}