Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"monochromeImage": "./assets/images/android-icon-monochrome.png"
},
"edgeToEdgeEnabled": true,
"softwareKeyboardLayoutMode": "resize",
"predictiveBackGestureEnabled": false
},
"web": {
Expand Down Expand Up @@ -49,4 +50,4 @@
"reactCompiler": true
}
}
}
}
39 changes: 39 additions & 0 deletions app/(mybusiness)/editStory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import AudioBox from '@/components/editStory/audioBox';
import Checklist from '@/components/editStory/checklist';
import InputBox from '@/components/editStory/inputBox';
import ToggleWrite from '@/components/editStory/toggleWrite';
import { Container } from '@/components/general/container';
import GeneralButton from '@/components/general/generalButton';
import { Header } from '@/components/general/header';
import { router } from 'expo-router';
import { useState } from 'react';
import { Text, View } from 'react-native';

export default function EditStory() {
const [toggle, setToggle] = useState<'WRITE' | 'AUDIO'>('WRITE')
const [text, setText] = useState('')
const [audio, setAudio] = useState('')

const handlePress = ()=> {
router.navigate('/(mybusiness)/manageImages')
}

return (
<Container>
<View className='gap-6'>
<Header title="Editar História" showBackButton showNotificationButton />
<Text className='pt-8 text-center text-lg font-semibold'>Conte sua história para nosso assistente, que vai resumir de uma forma objetiva e original.</Text>
<ToggleWrite toggle={toggle} setToggle={setToggle}/>
{toggle === 'WRITE' &&
<InputBox text={text} setText={setText}/>
}
{
toggle === 'AUDIO' &&
<AudioBox audio={audio} setAudio={setAudio}/>
}
<Checklist/>
<GeneralButton text='Salvar' handlePress={handlePress}/>
</View>
</Container>
);
}
17 changes: 17 additions & 0 deletions app/(mybusiness)/manageImages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Container } from '@/components/general/container';
import { Header } from '@/components/general/header';
import FileUpload from '@/components/manageImages/fileUpload';
import ImagesList from '@/components/manageImages/imagesList';
import { View } from 'react-native';

export default function ManageImages () {
return(
<Container>
<View className="gap-6">
<Header title="Editar Imagens" showBackButton showNotificationButton />
<FileUpload/>
<ImagesList/>
</View>
</Container>
)
}
3 changes: 3 additions & 0 deletions app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ export default function RootLayout() {
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="index" />
<Stack.Screen name="home" />
<Stack.Screen name="consultant" />
<Stack.Screen name="(mybusiness)/myBusiness" />
<Stack.Screen name="(mybusiness)/menu" />
<Stack.Screen name="(mybusiness)/reservations" />
<Stack.Screen name="(mybusiness)/reviews" />
<Stack.Screen name="(mybusiness)/schedule" />
<Stack.Screen name="(mybusiness)/businessOverview" />
<Stack.Screen name="(mybusiness)/editStory" />
<Stack.Screen name="(mybusiness)/manageImages" />
<Stack.Screen name="report" />
<Stack.Screen name="settings" />
<Stack.Screen name="help" />
Expand Down
196 changes: 196 additions & 0 deletions app/consultant.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import { ChatBubble } from '@/components/consultant/ChatBubble';
import { ChatInput } from '@/components/consultant/ChatInput';
import { CHATBOT_THEME } from '@/constants/theme';
import { ChatMessage } from '@/types';
import Ionicons from '@expo/vector-icons/Ionicons';
import axios from 'axios';
import { useEffect, useRef, useState } from 'react';
import {
ActivityIndicator,
FlatList,
KeyboardAvoidingView,
Platform,
Pressable,
Text,
View,
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';

const INITIAL_BOT_MESSAGE = `Olá! Sou seu consultor virtual.
Como posso ajudar com a gestão
do seu restaurante hoje?`;

export default function Consultant() {
const [messages, setMessages] = useState<ChatMessage[]>([
{
id: '1',
type: 'bot',
content: INITIAL_BOT_MESSAGE,
timestamp: new Date(),
contentType: 'text',
},
]);
const [isAwaitingResponse, setIsAwaitingResponse] = useState(false);
const [user, setUser] = useState<any>(null);

Check warning on line 34 in app/consultant.tsx

View workflow job for this annotation

GitHub Actions / Lint (Style Check)

Unexpected any. Specify a different type
const [showScrollButton, setShowScrollButton] = useState(false);
const flatListRef = useRef<FlatList>(null);

// Carrega dados do usuário sem bloquear a renderização inicial do chat
useEffect(() => {
const loadUser = async () => {
try {
const userId = '453df15b-61ce-4571-8bdb-cdbedf0ff041';

const responseUser = await axios.get(
`https://mandaca-backend.onrender.com/users/${userId}`,
{ timeout: 4000 },
);

setUser(responseUser.data);
} catch (error) {
console.error('Erro ao carregar usuário:', error);

Check warning on line 51 in app/consultant.tsx

View workflow job for this annotation

GitHub Actions / Lint (Style Check)

Unexpected console statement
}
};

loadUser();
}, []);

// Scroll automático para a última mensagem quando nova mensagem chega
useEffect(() => {
if (messages.length > 1) {
setTimeout(() => {
flatListRef.current?.scrollToEnd({ animated: true });
}, 100);
}
}, [messages]);


const handleSendMessage = async (content: string) => {
// Adiciona mensagem do usuário
const userMessage: ChatMessage = {
id: Date.now().toString(),
type: 'user',
content: content,
timestamp: new Date(),
contentType: 'text',
};

setMessages((prev) => [...prev, userMessage]);
setIsAwaitingResponse(true);

try {
// Requisição para buscar resposta do backend:

// Simulando delay de resposta (temporario)
await new Promise((resolve) => setTimeout(resolve, 800));

const botResponse: ChatMessage = {
id: (Date.now() + 1).toString(),
type: 'bot',
content:
'Entendo. Este é um exemplo de resposta do bot. Em produção, isso virá do backend com orientações específicas para seu restaurante.',
timestamp: new Date(),
contentType: 'text',
};

setMessages((prev) => [...prev, botResponse]);
} catch (error) {
console.error('Erro ao enviar mensagem:', error);

Check warning on line 98 in app/consultant.tsx

View workflow job for this annotation

GitHub Actions / Lint (Style Check)

Unexpected console statement

const errorMessage: ChatMessage = {
id: (Date.now() + 1).toString(),
type: 'bot',
content:
'Desculpe, houve um erro ao processar sua mensagem. Tente novamente.',
timestamp: new Date(),
contentType: 'text',
};

setMessages((prev) => [...prev, errorMessage]);
} finally {
setIsAwaitingResponse(false);
}
};

const handleScrollToBottom = () => {
flatListRef.current?.scrollToEnd({ animated: true });
setShowScrollButton(false);
};

const handleScroll = (event: any) => {

Check warning on line 120 in app/consultant.tsx

View workflow job for this annotation

GitHub Actions / Lint (Style Check)

Unexpected any. Specify a different type
const { contentOffset, contentSize, layoutMeasurement } = event.nativeEvent;
// Mostra botão se o usuário não está no final da lista
const isAtBottom =
contentOffset.y + layoutMeasurement.height >= contentSize.height - 100;
setShowScrollButton(!isAtBottom && messages.length > 3);
};

return (
<SafeAreaView className="flex-1" edges={['top', 'left', 'right']}>
{/* Main Content Container */}
<View className="flex-1 bg-background">
{/* Header */}
<View className="px-6 py-4 border-b border-gray-200">
<View className="flex flex-row justify-center">
<Text className="text-xl font-semibold text-gray-800">Consultor Virtual</Text>
</View>
</View>

{/* Messages List */}
<FlatList
ref={flatListRef}
data={messages}
renderItem={({ item }) => (
<ChatBubble
message={item}
userProfileUri={user?.url_foto_usuario}
userName={user?.nome}
/>
)}
keyExtractor={(item) => item.id}
contentContainerStyle={{
paddingVertical: 16,
paddingHorizontal: 12,
flexGrow: 1,
}}
keyboardDismissMode={Platform.OS === 'ios' ? 'interactive' : 'on-drag'}
showsVerticalScrollIndicator={false}
keyboardShouldPersistTaps="handled"
onScroll={handleScroll}
scrollEventThrottle={16}
ListFooterComponent={
isAwaitingResponse ? (
<View className="px-4 py-2">
<ActivityIndicator size="small" color="#C34342" />
</View>
) : null
}
/>

{/* Scroll to Bottom Button */}
{showScrollButton && (
<Pressable
className="absolute right-4 bottom-24 w-11 h-11 rounded-full justify-center items-center shadow-md"
style={{
backgroundColor: CHATBOT_THEME.input.bgColor,
elevation: 5,
}}
onPress={handleScrollToBottom}
>
<Ionicons name="arrow-down" size={16} color="#6B7280" />
</Pressable>
)}
</View>

<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'position'}
keyboardVerticalOffset={Platform.OS === 'ios' ? 8 : 0}
>
<ChatInput
onSendMessage={handleSendMessage}
isLoading={isAwaitingResponse}
/>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
6 changes: 3 additions & 3 deletions app/home.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Container } from '@/components/general/container';
import { CompleteProfile } from '@/components/Home/completeProfile/main';
import { Header } from '@/components/Home/header/main';
import { CompleteProfile } from '@/components/Home/completeProfile/completeProfile';
import { Header } from '@/components/Home/header/header';
import { RouteGrid } from '@/components/Home/routeGrid/main';

export default function Home() {
return (
<Container>
<Header />
<CompleteProfile prifileProgress={200} />
<CompleteProfile/>
<RouteGrid />
</Container>
);
Expand Down
17 changes: 12 additions & 5 deletions app/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { router } from 'expo-router';
import { useRouter } from 'expo-router';
import { Pressable, Text, View } from 'react-native';
import '../global.css';

export default function App() {
const router = useRouter(); // ✅ correto

return (
<View className="flex-1 items-center justify-center bg-white">
<Text className="text-xl font-bold text-blue-500">Hello Mandacá!</Text>
<Text className="text-xl font-bold text-blue-500">
Hello Mandacá!
</Text>

<Pressable
className="px-8 py-4 bg-primary rounded-lg"
onPress={() => router.navigate('/home')}
onPress={() => router.push('/home')} // ✅ usar push
>
<Text className="text-secondary font-semibold">ir para Home</Text>
<Text className="text-secondary font-semibold">
ir para Home
</Text>
</Pressable>
</View>
);
}
}
20 changes: 18 additions & 2 deletions app/report.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import { Container } from '@/components/general/container';
import { Header } from '@/components/general/header';
import { router } from 'expo-router';
import { Text, View } from 'react-native';

export default function Report() {
const handleConsultorPress = () => {
router.push('/consultant');
};

return (
<Container>
<View>
<Text>Relatórios</Text>
<Header
title="Seus Relatórios"
showBackButton={true}
showNotificationButton={true}
rightButtonIcon="chatbox-outline"
rightButtonColor="#FFFFFF"
rightButtonBgColor="#C34342"
onNotificationPress={handleConsultorPress}
/>
<View className="mt-6">
<Text className="text-lg">Conteúdo dos Relatórios</Text>
{/* Implementar conteúdo de relatórios */}
</View>
</Container>
);
Expand Down
Binary file added assets/images/profile-robot.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading