Первая версия мобильного приложения
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import * as Crypto from "expo-crypto";
|
||||
import { useRouter } from "expo-router";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Text, View } from "react-native";
|
||||
import { useApp } from "../../src/app-context";
|
||||
import { AppHeader } from "../../src/components/AppHeader";
|
||||
import { ChatScreenHeader } from "../../src/components/ChatScreenHeader";
|
||||
import { GuestAuthGate } from "../../src/components/GuestAuthGate";
|
||||
import { ScreenShell } from "../../src/components/ScreenShell";
|
||||
import {
|
||||
bindPendingFileIntent,
|
||||
bindPendingTextIntent,
|
||||
loadPendingTextIntent,
|
||||
pendingDialogKey,
|
||||
} from "../../src/pending-intent";
|
||||
import { dialogApi } from "../../src/services";
|
||||
import { ErrorNotice, Loading, styles } from "../../src/ui";
|
||||
import { spacing } from "../../src/theme";
|
||||
|
||||
export default function DialogsScreen() {
|
||||
const app = useApp();
|
||||
const router = useRouter();
|
||||
const [requestKey, setRequestKey] = useState<string>();
|
||||
const [bindError, setBindError] = useState<unknown>();
|
||||
const [bindAttempt, setBindAttempt] = useState(0);
|
||||
useEffect(() => {
|
||||
if (app.authStatus === "authenticated" && !requestKey) {
|
||||
setRequestKey(pendingDialogKey() ?? Crypto.randomUUID());
|
||||
}
|
||||
}, [app.authStatus, requestKey]);
|
||||
const chat = useQuery({
|
||||
queryKey: ["current-dialog", requestKey],
|
||||
queryFn: () => dialogApi.create(requestKey!),
|
||||
enabled: app.authStatus === "authenticated" && Boolean(requestKey),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (chat.data) {
|
||||
const bindAndOpen = async () => {
|
||||
const intent = loadPendingTextIntent();
|
||||
if (intent && !intent.dialogId) {
|
||||
await bindPendingTextIntent(intent, chat.data.dialog_id);
|
||||
}
|
||||
await bindPendingFileIntent(chat.data.dialog_id);
|
||||
router.replace(`/dialogs/${chat.data.dialog_id}`);
|
||||
};
|
||||
void bindAndOpen().catch(setBindError);
|
||||
}
|
||||
}, [bindAttempt, chat.data, router]);
|
||||
|
||||
if (app.authStatus !== "authenticated") {
|
||||
return (
|
||||
<ScreenShell>
|
||||
<ChatScreenHeader title="Чат" subtitle="Требуется вход" />
|
||||
<GuestAuthGate
|
||||
icon="message-circle"
|
||||
title="Чат доступен после входа"
|
||||
description="Авторизуйтесь, чтобы переписываться с оператором и получать ответы."
|
||||
/>
|
||||
</ScreenShell>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ScreenShell>
|
||||
<AppHeader />
|
||||
<View style={{ flex: 1, padding: spacing.lg, justifyContent: "center" }}>
|
||||
<Text accessibilityRole="header" style={styles.title}>Открываем чат…</Text>
|
||||
{chat.isLoading && <Loading />}
|
||||
{Boolean(chat.error || bindError) && (
|
||||
<ErrorNotice
|
||||
error={chat.error ?? bindError}
|
||||
retry={() => {
|
||||
setBindError(undefined);
|
||||
if (chat.error) void chat.refetch();
|
||||
else setBindAttempt((attempt) => attempt + 1);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</ScreenShell>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user