diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx
index 514e602..5e4c871 100644
--- a/app/(tabs)/_layout.tsx
+++ b/app/(tabs)/_layout.tsx
@@ -1,4 +1,5 @@
import { HapticTab } from '@/components/HapticTab';
+import AskNavbar from '@/components/layout/ask';
import { TabBarIcon } from '@/components/navigation/TabBarIcon';
import { requestNotificationPermission } from '@/components/owner/utils';
import TabBarBackground from '@/components/ui/TabBarBackground';
@@ -7,14 +8,13 @@ import { useColorScheme } from '@/hooks/useColorScheme';
import { prefetchChats } from '@/lib/prefetch';
import { fetchApi } from '@/lib/server-api-util';
import { webSocketManager, WebSocketStatus } from '@/lib/websocket-util';
+import { TransitionPresets } from '@react-navigation/bottom-tabs';
import * as Notifications from 'expo-notifications';
import { Tabs } from 'expo-router';
import * as SecureStore from 'expo-secure-store';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Platform } from 'react-native';
-import { TransitionPresets } from '@react-navigation/bottom-tabs';
-import AskNavbar from '@/components/layout/ask';
interface PollingData {
title: string;
diff --git a/app/(tabs)/reset-password.tsx b/app/(tabs)/reset-password.tsx
index 3995603..598ad10 100644
--- a/app/(tabs)/reset-password.tsx
+++ b/app/(tabs)/reset-password.tsx
@@ -7,19 +7,19 @@ import { Ionicons } from '@expo/vector-icons';
import { useLocalSearchParams, useRouter } from 'expo-router';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { ActivityIndicator, KeyboardAvoidingView, Platform, ScrollView, TextInput, TouchableOpacity, View } from 'react-native';
+import { ActivityIndicator, KeyboardAvoidingView, Platform, ScrollView, StyleSheet, TextInput, TouchableOpacity, View } from 'react-native';
-const resetPassword = () => {
+const ResetPassword = () => {
const { t } = useTranslation();
const router = useRouter();
const { session_id: resetPasswordSessionId, token } = useLocalSearchParams<{ session_id: string; token: string }>();
- // 使用 auth context 登录
const { login } = useAuth();
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [loading, setLoading] = useState(false);
const [showPassword, setShowPassword] = useState(false);
+ const [showSecondPassword, setShowSecondPassword] = useState(false);
const [error, setError] = useState('');
const validatePassword = (pwd: string) => {
@@ -38,8 +38,8 @@ const resetPassword = () => {
return;
}
- if (!validatePassword(password)) {
- setError(t('auth.signup.passwordAuth', { ns: 'login' }));
+ if (password?.length < 6) {
+ setError(t('auth.signup.pwdLengthError', { ns: 'login' }));
return;
}
@@ -64,6 +64,7 @@ const resetPassword = () => {
if (login) {
login(response, response.access_token || '');
}
+ router.push('/ask');
} catch (error) {
console.error('Reset password error:', error);
setError(t('auth.resetPwd.error', { ns: 'login' }) || 'Failed to reset password');
@@ -75,80 +76,75 @@ const resetPassword = () => {
return (
-
-
-
+
+
+
{t('auth.resetPwd.title', { ns: 'login' })}
{error ? (
-
+
{error}
) : null}
-
-
+
+
{
+ setPassword(value)
+ }}
secureTextEntry={!showPassword}
- autoCapitalize="none"
- autoCorrect={false}
/>
setShowPassword(!showPassword)}
- className="p-2"
+ style={styles.eyeIcon}
>
-
-
-
+
{
+ setConfirmPassword(value)
+ }}
+ secureTextEntry={!showSecondPassword}
/>
setShowPassword(!showPassword)}
- className="p-2"
+ onPress={() => setShowSecondPassword(!showSecondPassword)}
+ style={styles.eyeIcon}
>
-
{loading ? (
) : (
-
+
{t('auth.resetPwd.resetButton', { ns: 'login' })}
)}
@@ -157,6 +153,87 @@ const resetPassword = () => {
);
-}
+};
-export default resetPassword
+const styles = StyleSheet.create({
+ passwordInputContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ borderRadius: 12,
+ backgroundColor: '#FFF8DE',
+ overflow: 'hidden',
+ },
+ container: {
+ flex: 1,
+ backgroundColor: '#fff',
+ },
+ scrollContainer: {
+ flexGrow: 1,
+ justifyContent: 'center',
+ padding: 20,
+ },
+ formContainer: {
+ width: '100%',
+ maxWidth: 400,
+ alignSelf: 'center',
+ padding: 20,
+ borderRadius: 12,
+ backgroundColor: '#fff',
+ },
+ title: {
+ fontSize: 24,
+ fontWeight: 'bold',
+ marginBottom: 24,
+ textAlign: 'center',
+ color: '#1f2937',
+ },
+ errorText: {
+ color: '#ef4444',
+ marginBottom: 16,
+ textAlign: 'center',
+ },
+ inputContainer: {
+ marginBottom: 24,
+ gap: 16
+ },
+ inputWrapper: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ borderWidth: 1,
+ borderColor: '#e5e7eb',
+ borderRadius: 8,
+ paddingHorizontal: 12,
+ },
+ confirmInput: {
+ marginTop: 16,
+ },
+ input: {
+ borderRadius: 12,
+ paddingHorizontal: 16,
+ paddingVertical: 12,
+ fontSize: 16,
+ textAlignVertical: 'center',
+ backgroundColor: '#FFF8DE'
+ },
+ eyeIcon: {
+ padding: 8,
+ },
+ submitButton: {
+ width: '100%',
+ paddingVertical: 12,
+ borderRadius: 8,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: '#E2793F',
+ },
+ submitButtonDisabled: {
+ backgroundColor: '#f59e0b',
+ },
+ submitButtonText: {
+ color: '#fff',
+ fontSize: 16,
+ fontWeight: '600',
+ },
+});
+
+export default ResetPassword;
diff --git a/components/ask/send.tsx b/components/ask/send.tsx
index b70c028..08effe9 100644
--- a/components/ask/send.tsx
+++ b/components/ask/send.tsx
@@ -12,12 +12,11 @@ import {
View
} from 'react-native';
+import { webSocketManager, WsMessage } from '@/lib/websocket-util';
import { Message } from '@/types/ask';
import { useTranslation } from 'react-i18next';
import { ThemedText } from '../ThemedText';
import { createNewConversation } from './utils';
-import { WsMessage } from '@/lib/websocket-util';
-import { webSocketManager } from '@/lib/websocket-util';
interface Props {
setIsHello: Dispatch>,
@@ -38,12 +37,12 @@ export default function SendMessage(props: Props) {
const [inputValue, setInputValue] = useState('');
// 添加一个ref来跟踪键盘状态
- const isKeyboardVisible = useRef(false);
+ const isKeyboardVisible = useRef(false);
const chunkQueue = useRef([]);
const renderInterval = useRef | null>(null);
useEffect(() => {
- const handleChatStream = (message: WsMessage) => {
+ const handleChatStream = (message: WsMessage) => {
if (message.type !== 'ChatStream' || !message.chunk) return;
chunkQueue.current.push(message.chunk);
@@ -76,7 +75,7 @@ export default function SendMessage(props: Props) {
}
};
- const handleChatStreamEnd = (message: WsMessage) => {
+ const handleChatStreamEnd = (message: WsMessage) => {
if (message.type !== 'ChatStreamEnd') return;
// Stop the timer and process any remaining chunks
@@ -129,7 +128,7 @@ export default function SendMessage(props: Props) {
webSocketManager.subscribe('ChatStreamEnd', typedHandleChatStreamEnd);
webSocketManager.subscribe('ChatResponse', typedHandleChatResponse);
- return () => {
+ return () => {
webSocketManager.unsubscribe('ChatStream', typedHandleChatStream);
webSocketManager.unsubscribe('ChatStreamEnd', typedHandleChatStreamEnd);
webSocketManager.unsubscribe('ChatResponse', typedHandleChatResponse);
@@ -194,6 +193,13 @@ export default function SendMessage(props: Props) {
if (!currentSessionId) {
currentSessionId = await createNewConversation(text);
setConversationId(currentSessionId);
+ webSocketManager.send({
+ type: 'Chat',
+ session_id: currentSessionId,
+ message: text,
+ image_material_ids: selectedImages.length > 0 ? selectedImages : undefined,
+ });
+ setSelectedImages([]);
}
// 通过 WebSocket 发送消息