Разработана первая версия приложений

This commit is contained in:
mi
2026-07-10 18:06:14 +03:00
parent aa8761d1b3
commit 8c7b4074c4
162 changed files with 12178 additions and 16 deletions
@@ -0,0 +1,63 @@
import { useQuery } from "@tanstack/react-query";
import { Link } from "expo-router";
import React, { useState } from "react";
import { ScrollView, Text, View } from "react-native";
import { useApp } from "../src/app-context";
import { profileApi } from "../src/services";
import { Button, ErrorNotice, Header, Loading, styles } from "../src/ui";
export default function ProfileScreen() {
const app = useApp();
const enabled = app.authStatus === "authenticated";
const profile = useQuery({ queryKey: ["profile"], queryFn: profileApi.me, enabled });
const documents = useQuery({ queryKey: ["documents"], queryFn: profileApi.documents, enabled });
const [downloadError, setDownloadError] = useState<unknown>();
const download = async (id: string) => {
try {
const result = await profileApi.documentUrl(id);
if (typeof window !== "undefined") window.location.assign(result.download_url);
} catch (error) { setDownloadError(error); }
};
if (!enabled) return <ScrollView contentContainerStyle={styles.page}>
<Header status={app.authStatus} realtime={app.realtimeState} />
<Text accessibilityRole="header" style={styles.title}>Профиль</Text>
<Text style={styles.text}>Профиль доступен после авторизации.</Text>
<Link href="/" style={styles.link}>Перейти в чат для входа</Link>
</ScrollView>;
const personal = profile.data?.profile.personal_data;
return <ScrollView contentContainerStyle={styles.page}>
<Header status={app.authStatus} realtime={app.realtimeState} onLogout={() => void app.signOut()} />
<Text accessibilityRole="header" style={styles.title}>Профиль</Text>
{(profile.isLoading || documents.isLoading) && <Loading />}
{(profile.error || documents.error) && <ErrorNotice error={profile.error ?? documents.error} retry={() => { void profile.refetch(); void documents.refetch(); }} />}
<View style={styles.card}>
<Text accessibilityRole="header" style={styles.heading}>Личные данные</Text>
<Row label="ФИО" value={personal?.full_name} />
<Row label="Гражданство" value={personal?.citizenship} />
<Row label="Телефон в РФ" value={personal?.russian_phone} />
<Row label="Зарубежный телефон" value={personal?.foreign_phone} />
<Row label="Email" value={personal?.email} />
<Text style={styles.muted}>Редактирование профиля недоступно. Для изменения данных напишите оператору.</Text>
<Link href="/" style={styles.link}>Написать оператору</Link>
</View>
<View style={styles.card}>
<Text accessibilityRole="header" style={styles.heading}>Документы</Text>
{!documents.data?.items.length && <Text style={styles.muted}>Документов пока нет.</Text>}
{documents.data?.items.map((document) => <View key={document.document_id} style={styles.row}>
<View style={{ flex: 1 }}>
<Text style={styles.text}>{document.name}</Text>
<Text style={styles.muted}>{new Date(document.sent_at).toLocaleDateString("ru-RU")}</Text>
</View>
<Button title="Скачать" secondary onPress={() => void download(document.document_id)} />
</View>)}
{downloadError && <ErrorNotice error={downloadError} />}
</View>
</ScrollView>;
}
function Row({ label, value }: { label: string; value: string | null | undefined }) {
return <View><Text style={styles.muted}>{label}</Text><Text style={styles.text}>{value || "Не указано"}</Text></View>;
}