diff --git a/backend/pom.xml b/backend/pom.xml
index 6905d3aa..f690d539 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -29,6 +29,8 @@
21
+ 21
+ 21
@@ -149,7 +151,7 @@
false
100
- 1.7
+ 21
diff --git a/backend/src/main/java/br/com/servicemaker/controller/AgendaController.java b/backend/src/main/java/br/com/servicemaker/controller/AgendaController.java
index 10986c37..c0725812 100644
--- a/backend/src/main/java/br/com/servicemaker/controller/AgendaController.java
+++ b/backend/src/main/java/br/com/servicemaker/controller/AgendaController.java
@@ -10,7 +10,7 @@
@CrossOrigin("*")
@RestController
-@RequestMapping("/agenda")
+@RequestMapping("/api/agenda")
public class AgendaController extends AbstractController {
public AgendaController(AgendaService service) {
diff --git a/backend/src/main/java/br/com/servicemaker/controller/ServicoController.java b/backend/src/main/java/br/com/servicemaker/controller/ServicoController.java
index 1eb8beef..176ad25d 100644
--- a/backend/src/main/java/br/com/servicemaker/controller/ServicoController.java
+++ b/backend/src/main/java/br/com/servicemaker/controller/ServicoController.java
@@ -5,6 +5,10 @@
import br.com.servicemaker.domain.Servico;
import br.com.servicemaker.repository.ServicoRepository;
import br.com.servicemaker.service.ServicoService;
+import java.util.List;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -13,8 +17,16 @@
public class ServicoController extends
AbstractController {
+ private final ServicoService servicoService;
+
public ServicoController(ServicoService service) {
super(service);
+ this.servicoService = service;
}
+ @GetMapping("/prestador/{idPrestador}")
+ public ResponseEntity> findAllServicosPorPrestador(@PathVariable Long idPrestador) {
+ List servicosPorPrestador = servicoService.findAllServicosPorPrestador(idPrestador);
+ return ResponseEntity.ok(servicosPorPrestador);
+ }
}
diff --git a/backend/src/main/java/br/com/servicemaker/domain/Agenda.java b/backend/src/main/java/br/com/servicemaker/domain/Agenda.java
index e9ed76b0..7370cd94 100644
--- a/backend/src/main/java/br/com/servicemaker/domain/Agenda.java
+++ b/backend/src/main/java/br/com/servicemaker/domain/Agenda.java
@@ -23,11 +23,10 @@ public class Agenda extends AbstractEntity {
@OneToMany(mappedBy = "agenda", cascade = CascadeType.REMOVE)
- @JsonManagedReference
private List cronogramas;
@OneToMany(mappedBy = "agenda")
- @JsonManagedReference
+ @JsonManagedReference("agenda-reservas")
private List reservas;
}
\ No newline at end of file
diff --git a/backend/src/main/java/br/com/servicemaker/domain/Avaliacao.java b/backend/src/main/java/br/com/servicemaker/domain/Avaliacao.java
index 2b6f3c2b..99f21204 100644
--- a/backend/src/main/java/br/com/servicemaker/domain/Avaliacao.java
+++ b/backend/src/main/java/br/com/servicemaker/domain/Avaliacao.java
@@ -38,10 +38,5 @@ public class Avaliacao extends AbstractEntity {
@JsonBackReference
private Usuario cliente;
- @ManyToOne()
- @JoinColumn(name = "ID_PRESTADOR", nullable = false)
- @JsonBackReference
- private Prestador prestador;
-
}
diff --git a/backend/src/main/java/br/com/servicemaker/domain/Certificado.java b/backend/src/main/java/br/com/servicemaker/domain/Certificado.java
index 406fbc64..37427391 100644
--- a/backend/src/main/java/br/com/servicemaker/domain/Certificado.java
+++ b/backend/src/main/java/br/com/servicemaker/domain/Certificado.java
@@ -1,7 +1,7 @@
package br.com.servicemaker.domain;
import br.com.servicemaker.abstractcrud.AbstractEntity;
-import com.fasterxml.jackson.annotation.JsonManagedReference;
+import com.fasterxml.jackson.annotation.JsonBackReference;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
@@ -32,7 +32,7 @@ public class Certificado extends AbstractEntity {
@ManyToOne()
@JoinColumn(name = "ID_PRESTADOR", nullable = false)
- @JsonManagedReference
+ @JsonBackReference("prestador-certificados")
private Prestador prestador;
}
\ No newline at end of file
diff --git a/backend/src/main/java/br/com/servicemaker/domain/Prestador.java b/backend/src/main/java/br/com/servicemaker/domain/Prestador.java
index ac498cd3..d6b65c4a 100644
--- a/backend/src/main/java/br/com/servicemaker/domain/Prestador.java
+++ b/backend/src/main/java/br/com/servicemaker/domain/Prestador.java
@@ -6,6 +6,7 @@
import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import java.util.Collection;
@@ -14,6 +15,7 @@
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
+import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -23,23 +25,26 @@
@AllArgsConstructor
@NoArgsConstructor
@DiscriminatorValue("prestador")
+@ToString(exclude = "servicos")
public class Prestador extends Usuario {
-
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "id_agenda", nullable = false, referencedColumnName = "id")
- @JsonManagedReference
private Agenda agenda;
@OneToMany(mappedBy = "prestador", cascade = {CascadeType.REMOVE, CascadeType.MERGE})
- @JsonManagedReference
+ @JsonManagedReference("prestador-servico")
private List servicos;
@OneToMany(mappedBy = "prestador", cascade = {CascadeType.REMOVE,
CascadeType.MERGE}, orphanRemoval = true)
- @JsonManagedReference
+ @JsonManagedReference("prestador-certificados")
private List certificados;
+ @ManyToOne
+ @JoinColumn(name = "id_setor")
+ private Setor setor;
+
public Prestador(String nome, String cpf, String senha, Contato contato, Endereco endereco,
Roles role,
Agenda agenda) {
@@ -52,4 +57,6 @@ public Collection extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority(Roles.ROLE_PRESTADOR.getRole()),
new SimpleGrantedAuthority(Roles.ROLE_CLIENTE.getRole()));
}
+
+
}
\ No newline at end of file
diff --git a/backend/src/main/java/br/com/servicemaker/domain/Reserva.java b/backend/src/main/java/br/com/servicemaker/domain/Reserva.java
index dbb8967d..91f59c56 100644
--- a/backend/src/main/java/br/com/servicemaker/domain/Reserva.java
+++ b/backend/src/main/java/br/com/servicemaker/domain/Reserva.java
@@ -27,24 +27,19 @@ public class Reserva extends AbstractEntity {
@ManyToOne()
@JoinColumn(name = "ID_CLIENTE", nullable = false)
- @JsonBackReference
+ @JsonBackReference("clientes-reservas")
private Usuario cliente;
@ManyToOne()
@JoinColumn(name = "ID_AGENDA", nullable = false)
- @JsonBackReference
+ @JsonBackReference("agenda-reservas")
private Agenda agenda;
@ManyToOne()
@JoinColumn(name = "ID_SERVICO", nullable = false)
- @JsonBackReference
+ @JsonBackReference("reservas-servicos")
private Servico servico;
- @ManyToOne()
- @JoinColumn(name = "id_prestador", nullable = false)
- @JsonBackReference
- private Prestador prestador;
-
@Enumerated(EnumType.STRING)
private Status status;
diff --git a/backend/src/main/java/br/com/servicemaker/domain/Servico.java b/backend/src/main/java/br/com/servicemaker/domain/Servico.java
index a43040d4..c62541a2 100644
--- a/backend/src/main/java/br/com/servicemaker/domain/Servico.java
+++ b/backend/src/main/java/br/com/servicemaker/domain/Servico.java
@@ -15,6 +15,7 @@
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
+import lombok.ToString;
@EqualsAndHashCode(callSuper = false)
@Entity
@@ -22,13 +23,9 @@
@Data
@AllArgsConstructor
@NoArgsConstructor
+@ToString(exclude = "prestador")
public class Servico extends AbstractEntity {
- @ManyToOne
- @JoinColumn(name = "ID_SETOR", nullable = false)
- @JsonBackReference
- private Setor setor;
-
private String descricao;
@Column(name = "tempo_servico")
@@ -38,11 +35,11 @@ public class Servico extends AbstractEntity {
@ManyToOne
@JoinColumn(name = "ID_PRESTADOR", nullable = false)
- @JsonBackReference
+ @JsonBackReference("prestador-servico")
private Prestador prestador;
@OneToMany(mappedBy = "servico")
- @JsonManagedReference
+ @JsonManagedReference("reservas-servicos")
private List reservas;
}
\ No newline at end of file
diff --git a/backend/src/main/java/br/com/servicemaker/domain/Usuario.java b/backend/src/main/java/br/com/servicemaker/domain/Usuario.java
index eb68245b..09dbe3f8 100644
--- a/backend/src/main/java/br/com/servicemaker/domain/Usuario.java
+++ b/backend/src/main/java/br/com/servicemaker/domain/Usuario.java
@@ -60,13 +60,12 @@ public class Usuario extends AbstractEntity implements UserDetails {
@Enumerated(EnumType.STRING)
private Roles role;
- @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
+ @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "id_contato")
- @JsonManagedReference
private Contato contato;
@OneToMany(mappedBy = "cliente", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
- @JsonManagedReference
+ @JsonManagedReference("clientes-reservas")
private List reservas;
@OneToMany(mappedBy = "cliente", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
diff --git a/backend/src/main/java/br/com/servicemaker/repository/ServicoRepository.java b/backend/src/main/java/br/com/servicemaker/repository/ServicoRepository.java
index e8ad7c19..5dcc19d2 100644
--- a/backend/src/main/java/br/com/servicemaker/repository/ServicoRepository.java
+++ b/backend/src/main/java/br/com/servicemaker/repository/ServicoRepository.java
@@ -2,9 +2,14 @@
import br.com.servicemaker.abstractcrud.AbstractRepository;
import br.com.servicemaker.domain.Servico;
+import java.util.List;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface ServicoRepository extends AbstractRepository {
+ @Query("SELECT s FROM Servico s WHERE s.prestador.id = :idPrestador ")
+ List findAllServicosPorPrestador(@Param("idPrestador") Long idPrestador);
}
diff --git a/backend/src/main/java/br/com/servicemaker/service/ServicoService.java b/backend/src/main/java/br/com/servicemaker/service/ServicoService.java
index 1a3620a5..04a30837 100644
--- a/backend/src/main/java/br/com/servicemaker/service/ServicoService.java
+++ b/backend/src/main/java/br/com/servicemaker/service/ServicoService.java
@@ -4,15 +4,22 @@
import br.com.servicemaker.domain.Servico;
import br.com.servicemaker.repository.ServicoRepository;
import jakarta.persistence.EntityManager;
+import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ServicoService extends AbstractService {
+ private final ServicoRepository servicoRepository;
+
@Autowired
public ServicoService(ServicoRepository repository, EntityManager em) {
super(repository, em);
+ this.servicoRepository = repository;
}
+ public List findAllServicosPorPrestador(Long idPrestador) {
+ return servicoRepository.findAllServicosPorPrestador(idPrestador);
+ }
}
diff --git a/backend/src/main/resources/META-INF/MANIFEST.MF b/backend/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..387c0fd3
--- /dev/null
+++ b/backend/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: br.com.servicemaker.SerivceMakerApplication
+
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties
index 7ef10966..44316f00 100644
--- a/backend/src/main/resources/application.properties
+++ b/backend/src/main/resources/application.properties
@@ -1,7 +1,7 @@
spring.application.name=serivceMaker
-spring.datasource.url=jdbc:postgresql://localhost:5432/servicemaker
+spring.datasource.url=jdbc:postgresql://autorack.proxy.rlwy.net:44626/railway
spring.datasource.username=postgres
-spring.datasource.password=root
+spring.datasource.password=VkSHVJkKYqUAopijrQfXuNeAYnkygFLT
spring.datasource.driver-class-name=org.postgresql.Driver
api.security.token.secret=${JWT_SECRET:my-secret-key}
spring.jpa.show-sql=true
diff --git a/backend/src/main/resources/db/migration/V5__insert_setores.sql b/backend/src/main/resources/db/migration/V5__insert_setores.sql
index e8dacba8..3c7ed7f7 100644
--- a/backend/src/main/resources/db/migration/V5__insert_setores.sql
+++ b/backend/src/main/resources/db/migration/V5__insert_setores.sql
@@ -1,4 +1,4 @@
-INSERT INTO servicemaker.public.setor (DESCRICAO)
+INSERT INTO setor (DESCRICAO)
VALUES
('Encanador'),
('Eletricista'),
diff --git a/backend/src/main/resources/db/migration/V6__criar_coluna_idsetor.sql b/backend/src/main/resources/db/migration/V6__criar_coluna_idsetor.sql
new file mode 100644
index 00000000..59708494
--- /dev/null
+++ b/backend/src/main/resources/db/migration/V6__criar_coluna_idsetor.sql
@@ -0,0 +1,8 @@
+ALTER TABLE IF EXISTS usuario
+ ADD COLUMN IF NOT EXISTS id_setor bigint;
+
+ALTER TABLE IF EXISTS usuario
+ ADD CONSTRAINT usuario_setor_fk FOREIGN KEY (id_setor) REFERENCES setor (id);
+
+alter table if exists servico
+ drop column if exists id_setor
\ No newline at end of file
diff --git a/frontend/app/(agenda)/agendamento.tsx b/frontend/app/(agenda)/agendamento.tsx
index ced20ac7..7b396591 100644
--- a/frontend/app/(agenda)/agendamento.tsx
+++ b/frontend/app/(agenda)/agendamento.tsx
@@ -1,111 +1,132 @@
import React, { useEffect, useState } from 'react';
-import { ScrollView, StyleSheet, Text, View, Button, StatusBar, Alert, TextInput, Pressable } from 'react-native';
+import { StyleSheet, Text, View, StatusBar, Pressable } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
-import DateTimePicker, { DateTimePickerEvent } from '@react-native-community/datetimepicker';
import { Controller, useForm } from 'react-hook-form';
import { SafeAreaView } from 'react-native-safe-area-context';
-import { router } from 'expo-router';
-import { obterNomeUsuario } from '@/utils/storageUtils';
+import { router, useLocalSearchParams } from 'expo-router';
+import { DateInput } from '@/components/DateInput';
+import { TimeInput } from '@/components/HoraInput';
+import PrestadorService from '../../service/prestadorservice'
+import ServicoService from '../../service/ServicoService'
+import ReservaService from '../../service/ReservaService'
+import { AutocompleteInput } from '@/components/AutocompleteInput';
+import { useUser } from '@/components/contextoApi';
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
+type AgendamentoForm = {
+ servico: any;
+ prestador: any;
+ data: Date | null;
+ horaInicio: string;
+ horaFim: string;
+ status: any,
+ usuario: any
+};
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
+const calculateHoraFim = (horaInicio: string, tempoServico: string) => {
- carregarNomeUsuario();
-}, []);
+ if (!horaInicio || !tempoServico) {
+ return '';
+ }
+ const [hours, minutes] = horaInicio.split(':').map(Number);
+ const [serviceHours, serviceMinutes] = tempoServico.split(':').map(Number);
+ const totalMinutes = hours * 60 + minutes + serviceHours * 60 + serviceMinutes;
-type AgendamentoForm = {
- servico: string;
- prestador: string;
- localizacao: string;
- anotacao: string;
- data: string;
- hora: string;
- horaFim: string;
+ const finalHours = Math.floor(totalMinutes / 60) % 24;
+ const finalMinutes = totalMinutes % 60;
+
+ return `${finalHours.toString().padStart(2, '0')}:${finalMinutes.toString().padStart(2, '0')}`;
};
-const prestadorClick = ()=>{
- router.navigate('/(servico)/prestador')
-}
export default function Agendamento() {
- const { control, handleSubmit, formState: { errors, isValid } } = useForm({
- defaultValues: {
- servico: '',
- prestador: '',
- localizacao: '',
- anotacao: '',
- data: '',
- hora: '',
- },
- mode: 'onChange',
- });
- const [selectedDate, setSelectedDate] = useState(undefined);
- const [showDatePicker, setShowDatePicker] = useState(false);
- const [showTimePicker, setShowTimePicker] = useState(false);
- const [mode, setMode] = useState<'date' | 'time'>('date');
- const [show, setShow] = useState(false);
-
- const onChange = (event: DateTimePickerEvent, selectedValue?: Date) => {
- const currentDate = selectedValue || selectedDate;
- setShowDatePicker(false);
- setShowTimePicker(false);
- setSelectedDate(currentDate);
- };
+ const { nomeUsuario } = useUser();
+
+ const [prestadores, setPrestadores] = useState([]);
+ const [servicos, setServicos] = useState([]);
- const showMode = (currentMode: 'date' | 'time') => {
- setMode(currentMode);
- setShow(true);
+ const { idPrestador, idServico, dataAgendamento } = useLocalSearchParams();
+
+ const parsedDataAgendamento = dataAgendamento ? new Date(dataAgendamento.toString()) : null;
+ const parsedIdServico = idServico ? parseInt(idServico.toString()) : null
+ const parsedIdPrestador = idPrestador ? parseInt(idPrestador.toString()) : null
+
+ const agendaClick = () => {
+ router.navigate('/(tabs)/agenda');
};
- const addTask = async (data: AgendamentoForm) => {
- if (!selectedDate || !data.servico || !data.prestador || !data.localizacao || !data.anotacao) {
- Alert.alert('Erro', 'Por favor, preencha todos os campos e selecione uma data.');
- return;
+ const fetchPrestadores = async () => {
+ try {
+ const response = await PrestadorService.getAllPrestadores();
+ setPrestadores(response);
+ } catch (error) {
+ console.error('Erro ao buscar prestadores:', error);
}
- console.log('Agendamento adicionado:', { ...data, date: selectedDate });
- Alert.alert('Agendamento adicionado com sucesso!');
- router.push('/(tabs)/inicio');
};
- const formatTime = (value: string) => {
- const onlyNumbers = value.replace(/\D/g, '');
- let formattedValue = onlyNumbers.slice(0, 4);
+ const fetchDataFromUrl = async () => {
+ try {
+ if (parsedIdPrestador) {
+ const prestador = await PrestadorService.getPrestadorById(parsedIdPrestador);
+ setValue('prestador', prestador?.nome || '');
+ setServicos(prestador?.servicos || []);
+ }
+ if (parsedIdServico) {
+ const servico = await ServicoService.getServicoById(parsedIdServico);
+ setValue('servico', servico?.descricao || '');
+ }
+ } catch (error) {
+ console.error('Erro ao buscar dados da URL:', error);
+ }
+ };
- if (formattedValue.length >= 3) {
- formattedValue = `${formattedValue.slice(0, 2)}h:${formattedValue.slice(2)}m`;
- } else if (formattedValue.length >= 1) {
- formattedValue = `${formattedValue}h`;
+ useEffect(() => {
+ if (parsedIdPrestador || parsedIdServico) {
+ fetchDataFromUrl();
+ } else {
+ fetchPrestadores();
}
+ }, []);
- return formattedValue;
- };
+ const { control, handleSubmit, formState: { errors, isValid }, watch, setValue, getValues } = useForm({
+ defaultValues: {
+ prestador: '',
+ servico: '',
+ data: parsedDataAgendamento,
+ horaInicio: '',
+ horaFim: '',
+ },
+ mode: 'onChange',
+ });
- const formatDate = (value: string) => {
- const onlyNumbers = value.replace(/\D/g, '');
- let formattedValue = onlyNumbers.slice(0, 8);
- if (formattedValue.length >= 6) {
- formattedValue = `${formattedValue.slice(0, 2)}/${formattedValue.slice(2, 4)}/${formattedValue.slice(4)}`;
- } else if (formattedValue.length >= 4) {
- formattedValue = `${formattedValue.slice(0, 2)}/${formattedValue.slice(2)}`;
- } else if (formattedValue.length >= 2) {
- formattedValue = `${formattedValue.slice(0, 2)}`;
- }
+ const handleHoraFimUpdate = (horaInicio: any, servicoSelecionado: any) => {
+ const servicoEncontrado = servicos.find(s => s.descricao === servicoSelecionado);
+ const tempoServico = servicoEncontrado?.tempoServico ?? '';
- return formattedValue;
- };
+ const newHoraFim = calculateHoraFim(horaInicio, tempoServico);
+ console.log("Calculando horaFim: ", newHoraFim);
- const agendaClick =()=>{
- router.navigate('/(tabs)/agenda');
+ setValue('horaFim', newHoraFim, { shouldDirty: true, shouldTouch: true });
};
+ const saveReserva = async (reserva: AgendamentoForm) => {
+ reserva.usuario = { id: 2 };
+ reserva.status = "PENDENTE";
+ console.log(reserva);
+
+ try {
+ // await ReservaService.createReserva(reserva);
+ router.navigate("/agenda");
+
+ } catch (error) {
+ console.error('Erro ao cadastrar reserva:', error);
+
+ }
+
+ }
+
return (
@@ -120,109 +141,89 @@ export default function Agendamento() {
{nomeUsuario}
-
Agendamento
+ (
+ {
+ onChange(item);
+ setServicos(item.servicos || []);
+ }}
+ filterKey="nome"
+ />
+ )}
+ />
+ {errors.prestador && {errors.prestador.message?.toString()}}
-
- (
-
- )}
- />
- {errors.servico && {errors.servico.message}}
-
- (
-
- )}
- />
- {errors.prestador && {errors.prestador.message}}
+ (
+ {
+ console.log('onChange:', value);
+ onChange(value)
+ handleHoraFimUpdate(watch('horaInicio'), value);
+ console.log(formState.dirtyFields)
+ }}
+ onSelect={item => {
+ console.log('onSelect:', item.descricao);
+ onChange(item.descricao);
+ handleHoraFimUpdate(watch('horaInicio'), value);
+ }}
+ filterKey="descricao"
+ />
+ )}
+ />
+ {errors.servico && {errors.servico.message?.toString()}}
-
+ (
-
- )}
+ label="Data de Agendamento"
/>
- {errors.data && {errors.data.message}}
- (
- onChange(formatTime(text))}
- placeholder="Hora"
- keyboardType="numeric"
- maxLength={7}
- />
- )}
- />
- {errors.hora && {errors.hora.message}}
- (
-
- )}
+ {errors.data && {errors.data.message}}
+
+ {
+ setValue('horaInicio', value, { shouldDirty: true, shouldTouch: true });
+ handleHoraFimUpdate(value, watch('servico')); // Atualiza também horaFim
+ }}
/>
- {errors.localizacao && {errors.localizacao.message}}
- (
-
- )}
+ {errors.horaInicio && {errors.horaInicio.message}}
+
+
+
- router.push('/(tabs)/agenda')}>Adicionar Agendamento
+ Adicionar Agendamento
+
);
@@ -292,4 +293,8 @@ const styles = StyleSheet.create({
backIcon: {
paddingRight: 15,
},
+ dataTempo: {
+ paddingRight: 25,
+ paddingLeft: 3
+ }
});
diff --git a/frontend/app/(agenda)/cronograma.tsx b/frontend/app/(agenda)/cronograma.tsx
index 4610b371..a782c257 100644
--- a/frontend/app/(agenda)/cronograma.tsx
+++ b/frontend/app/(agenda)/cronograma.tsx
@@ -1,22 +1,12 @@
-import React, { useEffect, useState } from 'react';
+import React, { } from 'react';
import { View, Text, TextInput, StyleSheet, Button, Alert, Pressable, ScrollView, StatusBar } from 'react-native';
import { useForm, Controller, useFieldArray } from 'react-hook-form';
import { Ionicons } from '@expo/vector-icons';
import { SafeAreaView } from 'react-native-safe-area-context';
import MultiSelect from 'react-native-multiple-select';
import { router } from 'expo-router';
-import { obterNomeUsuario } from '@/utils/storageUtils';
+import { useUser } from '@/components/contextoApi';
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
-}, []);
type CronogramaForm = {
cronogramas: {
@@ -37,6 +27,8 @@ const diasSemana = [
];
export default function Cronograma() {
+ const { nomeUsuario } = useUser();
+
const { control, handleSubmit, formState: { errors } } = useForm({
defaultValues: {
cronogramas: [{
diff --git a/frontend/app/(auth)/login.tsx b/frontend/app/(auth)/login.tsx
index eab27218..fa3a6409 100644
--- a/frontend/app/(auth)/login.tsx
+++ b/frontend/app/(auth)/login.tsx
@@ -5,7 +5,7 @@ import { SafeAreaView } from 'react-native-safe-area-context';
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { router } from 'expo-router';
-import UsuarioService from '../../service/UsuarioService'
+import { useUser } from '../../components/contextoApi';
type LoginForm = {
email: string;
@@ -32,12 +32,10 @@ const storeToken = async (data: any) => {
if (typeof window !== 'undefined' && window.localStorage) {
// Ambiente navegador
window.localStorage.setItem('jwt_token', data.token);
- window.localStorage.setItem('nome_usuario', data.nome)
console.log('windows')
} else {
// Ambiente móvel
await AsyncStorage.setItem('jwt_token', data.token);
- await AsyncStorage.setItem('nome_usuario', data.nome);
console.log('movel')
}
} catch (error) {
@@ -45,12 +43,13 @@ const storeToken = async (data: any) => {
}
};
-async function handleLogin(requestData: LoginForm) {
+async function handleLogin(requestData: LoginForm, setNomeUsuario: (name: string) => void) {
try {
const responseData = await login(requestData);
-
+ console.log('Resposta do login:', responseData);
+ setNomeUsuario(responseData.nome)
await storeToken(responseData);
-
+
router.push("/(tabs)/inicio");
} catch (error) {
@@ -67,6 +66,8 @@ const LoginScreen = () => {
mode: "onChange"
});
+ const { setNomeUsuario } = useUser();
+
return (
{
/>
{{errors?.senha?.message}}
-
+ handleLogin(data, setNomeUsuario))}
+ disabled={!isValid} >
Continuar
diff --git a/frontend/app/(perfil)/avaliacao.tsx b/frontend/app/(perfil)/avaliacao.tsx
index 0da53af3..7d0aad41 100644
--- a/frontend/app/(perfil)/avaliacao.tsx
+++ b/frontend/app/(perfil)/avaliacao.tsx
@@ -1,20 +1,10 @@
+import { useUser } from '@/components/contextoApi';
import { Ionicons } from '@expo/vector-icons';
import { router } from 'expo-router';
-import React, { useEffect, useState } from 'react';
+import React, { useState } from 'react';
import { SafeAreaView, StyleSheet, View, Text, Pressable, Alert, TextInput, StatusBar } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
-import { obterNomeUsuario } from '@/utils/storageUtils';
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
-}, []);
const perfilClick = ()=>{
router.navigate('/(tabs)/perfil')
@@ -23,6 +13,7 @@ const perfilClick = ()=>{
export default function Avaliacao() {
const [rating, setRating] = useState(0);
const [feedback, setFeedback] = useState('');
+ const { nomeUsuario } = useUser();
const handleSubmit = () => {
if (rating === 0) {
diff --git a/frontend/app/(perfil)/compartilhe.tsx b/frontend/app/(perfil)/compartilhe.tsx
index 7fef06e5..4c86e710 100644
--- a/frontend/app/(perfil)/compartilhe.tsx
+++ b/frontend/app/(perfil)/compartilhe.tsx
@@ -1,26 +1,13 @@
-import React, { useEffect, useState } from 'react';
-import { Text, SafeAreaView, StyleSheet, View, StatusBar, Pressable } from 'react-native';
+import React from 'react';
+import { Text, SafeAreaView, StyleSheet, View, StatusBar, Pressable, Share } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
-import { Share } from 'react-native';
import { router } from 'expo-router';
-import { obterNomeUsuario } from '@/utils/storageUtils';
+import { useUser } from '@/components/contextoApi';
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
-}, []);
-
-const perfilClick = ()=>{
- router.navigate('/(tabs)/perfil')
-}
export default function Compartilhar() {
+ const { nomeUsuario } = useUser();
+
const onShare = async () => {
try {
await Share.share({
@@ -35,7 +22,7 @@ export default function Compartilhar() {
}
};
- const perfilClick =()=>{
+ const perfilClick = () => {
router.navigate('/(tabs)/perfil');
};
@@ -55,7 +42,7 @@ export default function Compartilhar() {
- Compartilhe
+ Compartilhe
Compartilhe nosso aplicativo com seus amigos e familiares!
diff --git a/frontend/app/(perfil)/criaservico.tsx b/frontend/app/(perfil)/criaservico.tsx
index e1dd40e1..72141728 100644
--- a/frontend/app/(perfil)/criaservico.tsx
+++ b/frontend/app/(perfil)/criaservico.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import React, { } from 'react';
import { SafeAreaView, Text, View, TextInput, StyleSheet, ScrollView, Pressable } from 'react-native';
import { useForm, Controller } from 'react-hook-form';
import { Ionicons } from '@expo/vector-icons';
@@ -6,28 +6,14 @@ import { Picker } from '@react-native-picker/picker';
import ServicoService from '../../service/ServicoService'
import { Setor } from '@/constants/SetorEnum';
import { router } from 'expo-router';
-import { obterNomeUsuario } from '@/utils/storageUtils';
+import { useUser } from '@/components/contextoApi';
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
-}, []);
-
-const usuarioLogado = { id: 1, nome: 'Usúario' };
+const usuarioLogado = { id: 1, nome: 'Usuário' };
const perfilClick =()=>{
router.navigate('/(tabs)/perfil');
};
-const salvarClick =()=>{
- router.navigate('/(servico)/prestador');
-};
type criarServicoForm = {
servico: string;
@@ -37,7 +23,9 @@ type criarServicoForm = {
setor: Setor;
}
-export default function criaServico() {
+export default function CriaServico() {
+ const { nomeUsuario } = useUser();
+
const { control, handleSubmit, formState: { errors } } = useForm({
defaultValues: {
descricao: '',
@@ -55,20 +43,19 @@ export default function criaServico() {
return parseFloat(preco);
}
const toDateTime = (tempo: string) => {
- const match = RegExp(/(\d+)h:(\d+)m/).exec(tempo);
-
+ const match = RegExp(/(\d+)h(?::(\d+)m)?/).exec(tempo);
+
if (!match) {
throw new Error("Formato de tempo inválido");
}
-
+
const hours = parseInt(match[1], 10);
- const minutes = parseInt(match[2], 10);
-
+ const minutes = parseInt(match[2] || "0", 10);
+
const date = new Date();
date.setHours(hours, minutes, 0, 0);
return date.toLocaleTimeString("pt-BR");
- }
-
+ };
const onSubmit = async (data: criarServicoForm) => {
@@ -126,7 +113,7 @@ export default function criaServico() {
/>
- Usuário
+ {nomeUsuario}
@@ -315,13 +302,4 @@ const styles = StyleSheet.create({
backIcon: {
paddingRight: 15,
},
- tituloContainer: {
- alignItems: 'center',
- marginBottom: 20,
- },
- titulo: {
- fontSize: 22,
- fontWeight: 'bold',
- color: '#333',
- },
});
\ No newline at end of file
diff --git a/frontend/app/(perfil)/edicaoperfil.tsx b/frontend/app/(perfil)/edicaoperfil.tsx
index f0bd4e7a..302f635f 100644
--- a/frontend/app/(perfil)/edicaoperfil.tsx
+++ b/frontend/app/(perfil)/edicaoperfil.tsx
@@ -7,28 +7,17 @@ import UsuarioService from '../../service/UsuarioService'
import ContatoService from '../../service/ContatoService'
import EnderecoService from '../../service/EnderecoService'
import AsyncStorage from '@react-native-async-storage/async-storage';
-import { obterNomeUsuario } from '@/utils/storageUtils';
+import { useUser } from '@/components/contextoApi';
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
-}, []);
-
-const perfilClick = ()=>{
- router.navigate('/(tabs)/perfil')
-}
export default function EdicaoPerfil() {
const [nome, setNome] = useState('');
const [email, setEmail] = useState('');
const [telefone, setTelefone] = useState('');
const [endereco, setEndereco] = useState('');
+ const { nomeUsuario } = useUser();
+
useEffect(() => {
const fetchData = async () => {
diff --git a/frontend/app/(perfil)/endereco.tsx b/frontend/app/(perfil)/endereco.tsx
index 6abb82e1..9e70e6d0 100644
--- a/frontend/app/(perfil)/endereco.tsx
+++ b/frontend/app/(perfil)/endereco.tsx
@@ -1,30 +1,17 @@
import { Ionicons } from '@expo/vector-icons';
-import React, { useEffect, useState } from 'react';
+import React, { useState } from 'react';
import { SafeAreaView, StyleSheet, View, Text, TextInput, Pressable, FlatList, StatusBar } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import { useForm, Controller } from 'react-hook-form';
import { router } from 'expo-router';
-import { obterNomeUsuario } from '@/utils/storageUtils';
+import { useUser } from '@/components/contextoApi';
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
-}, []);
-
-
-const perfilClick = ()=>{
- router.navigate('/(tabs)/perfil')
-}
export default function GerenciarEndereco() {
const { control, handleSubmit, reset } = useForm();
const [enderecos, setEnderecos] = useState([]);
+ const { nomeUsuario } = useUser();
+
const onSubmit = (data: { novoEndereco: string; }) => {
if (data.novoEndereco.trim()) {
diff --git a/frontend/app/(perfil)/historico.tsx b/frontend/app/(perfil)/historico.tsx
index c7de8acc..74a32ec8 100644
--- a/frontend/app/(perfil)/historico.tsx
+++ b/frontend/app/(perfil)/historico.tsx
@@ -1,22 +1,13 @@
+import { useUser } from '@/components/contextoApi';
import { Ionicons } from '@expo/vector-icons';
import { router } from 'expo-router';
-import React, { useEffect, useState } from 'react';
+import React from 'react';
import { View, Text, StyleSheet, SafeAreaView, StatusBar, Pressable } from 'react-native';
import { ScrollView } from 'react-native-gesture-handler';
-import { obterNomeUsuario } from '@/utils/storageUtils';
-
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
-}, []);
const ServicosLista = () => {
+ const { nomeUsuario } = useUser();
+
const servicos = [
{ titulo: 'Conserto de Ar-Condicionado', empresa: 'CoolTech', data: '03/05/2024', avaliacao: 4, custo: 250.0 },
diff --git a/frontend/app/(perfil)/sobre.tsx b/frontend/app/(perfil)/sobre.tsx
index c37a5fdc..25e1b3a4 100644
--- a/frontend/app/(perfil)/sobre.tsx
+++ b/frontend/app/(perfil)/sobre.tsx
@@ -1,30 +1,17 @@
+import { useUser } from '@/components/contextoApi';
import { Ionicons } from '@expo/vector-icons';
import { router } from 'expo-router';
-import React, { useEffect, useState } from 'react';
+import React from 'react';
import { SafeAreaView, StyleSheet, View, Text, ScrollView, StatusBar, Pressable } from 'react-native';
-import { obterNomeUsuario } from '@/utils/storageUtils';
-
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
-}, []);
-
-const perfilClick = ()=>{
- router.navigate('/(tabs)/perfil')
-}
export default function SobreNos() {
const perfilClick =()=>{
router.navigate('/(tabs)/perfil');
};
+ const { nomeUsuario } = useUser();
return (
+
diff --git a/frontend/app/(servico)/_layout.tsx b/frontend/app/(servico)/_layout.tsx
new file mode 100644
index 00000000..2a06bd41
--- /dev/null
+++ b/frontend/app/(servico)/_layout.tsx
@@ -0,0 +1,6 @@
+import React from 'react';
+import { Slot } from 'expo-router';
+
+export default function ServicoLayout() {
+ return ;
+}
diff --git a/frontend/app/(servico)/detalhaservicocliente.tsx b/frontend/app/(servico)/detalhaservicocliente.tsx
index 1d80dddb..da506677 100644
--- a/frontend/app/(servico)/detalhaservicocliente.tsx
+++ b/frontend/app/(servico)/detalhaservicocliente.tsx
@@ -1,23 +1,14 @@
-import React, { useEffect, useState } from 'react';
-import { View, Text, StyleSheet, TextInput, ScrollView, TouchableOpacity, StatusBar } from 'react-native';
+import React, { useState } from 'react';
+import { View, Text, StyleSheet, TextInput, ScrollView, StatusBar } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { SafeAreaView } from 'react-native-safe-area-context';
-import { obterNomeUsuario } from '@/utils/storageUtils';
-
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
-}, []);
+import { useUser } from '@/components/contextoApi';
const DetalhesServico = () => {
const [descricao, setDescricao] = useState('');
const descricaoMaxLength = 240;
+ const { nomeUsuario } = useUser();
+
return (
diff --git a/frontend/app/(servico)/editaservico.tsx b/frontend/app/(servico)/editaservico.tsx
index 75412b8f..d0faddf1 100644
--- a/frontend/app/(servico)/editaservico.tsx
+++ b/frontend/app/(servico)/editaservico.tsx
@@ -1,20 +1,9 @@
+import { useUser } from '@/components/contextoApi';
import { Ionicons } from '@expo/vector-icons';
import { router } from 'expo-router';
-import React, { useEffect, useState } from 'react';
+import React, { useState } from 'react';
import { Text, SafeAreaView, StyleSheet, View, TextInput, ScrollView, Pressable, StatusBar } from 'react-native';
import { TextInputMask } from 'react-native-masked-text';
-import { obterNomeUsuario } from '@/utils/storageUtils';
-
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
-}, []);
type editaServicoProps = {
nome: string;
@@ -39,6 +28,8 @@ export default function editaServico({
}: editaServicoProps) {
const [data, setData] = useState(initialData);
const [custo, setCusto] = useState(initialCusto);
+ const { nomeUsuario } = useUser();
+
const handleChange = (text: string) => {
setData(text);
diff --git a/frontend/app/(servico)/prestador.tsx b/frontend/app/(servico)/prestador.tsx
index a0de6b0f..c484052a 100644
--- a/frontend/app/(servico)/prestador.tsx
+++ b/frontend/app/(servico)/prestador.tsx
@@ -1,157 +1,149 @@
-import { View, Text, ScrollView, TouchableOpacity, StyleSheet, Image } from 'react-native';
+import { View, Text, ScrollView, TouchableOpacity, StyleSheet, Image, Pressable } from 'react-native';
import React, { useEffect, useState } from 'react';
import { Ionicons } from '@expo/vector-icons';
import { router } from 'expo-router';
-import SetorService from '../../service/SetorService';
-import UsuarioService from '../../service/UsuarioService';
+import UsuarioService from '../../service/UsuarioService'
+import { useUser } from '@/components/contextoApi';
-interface Setor {
- id_prestador: number;
- titulo: string;
-}
+const Prestadores = () => {
+ const [prestadores, setPrestadores] = useState([]);
+ const { nomeUsuario } = useUser();
-interface Prestador {
- id: number;
- nome: string;
-}
+ useEffect(() => {
-const Prestadores = () => {
- const [prestadores, setPrestadores] = useState([]);
- const [setores, setSetor] = useState([]);
+ const fetchData = async () => {
+ try {
+ const usuariosData = await UsuarioService.getAllUsuarios();
+ console.log('Dados de usuários:', usuariosData);
+ setPrestadores(usuariosData);
+ } catch (error) {
+ console.error('Erro ao buscar dados:', error);
+ }
+ };
+ fetchData();
+ }, []);
- useEffect(() => {
- const fetchData = async () => {
- try {
- const usuariosData = await UsuarioService.getAllUsuarios();
- console.log('Dados de usuários:', usuariosData);
- const setoresData = await SetorService.getAllSetores();
- console.log('Dados de setores:', setoresData);
- setPrestadores(usuariosData);
- setSetor(setoresData);
- } catch (error) {
- console.error('Erro ao buscar dados:', error);
- }
- };
- fetchData();
- }, []);
+ const servicoPrestadorClick = (prestador: any) => {
+ router.navigate('/(servico)/servicoprestador');
+ router.push({ pathname: "/(servico)/servicoprestador", params: { id: prestador.id } })
- const servicoPrestadorClick = (prestadorId: number) => {
- router.push(`/servico/${prestadorId}`);
};
- const inicioClick = () => {
- router.push('/(tabs)/inicio');
- };
+ const inicioClick = () => {
+ router.navigate('/(tabs)/inicio');
+ };
+ return (
+
+
+
+
+
+
+
+ {nomeUsuario}
+
+
- return (
-
-
-
-
-
-
-
- Prestadores
-
-
+ Prestador
-
- {prestadores.map(prestador => {
- const setorAssociado = setores.find(setor => setor.id_prestador === prestador.id);
- return (
-
-
-
-
- Nome: {prestador.nome}
-
- {setorAssociado ? setorAssociado.titulo : 'Setor não disponível'}
-
-
-
- servicoPrestadorClick(prestador.id)}>
-
- Serviços
-
-
-
- );
- })}
-
-
- );
+
+ {prestadores.map((prestador: any) => (
+
+
+
+
+ Nome: {prestador.nome}
+
+ {prestador.setor?.descricao}
+
+
+
+ servicoPrestadorClick(prestador)}>
+
+ Serviços
+
+
+
+ ))}
+
+
+ );
};
const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: 'white',
- },
- topoTela: {
- backgroundColor: '#FBCB1C',
- borderBottomLeftRadius: 20,
- borderBottomRightRadius: 20,
- padding: 25,
- marginBottom: 20,
- flexDirection: 'row',
- justifyContent: 'center',
- },
- userName: {
- color: 'white',
- fontSize: 20,
- fontWeight: 'bold',
- marginLeft: 15,
- },
- header: {
- backgroundColor: '#D9D9D9',
- flexDirection: 'column',
- justifyContent: 'space-around',
- padding: 19,
- height: 120,
- margin: 4,
- borderRadius: 10,
- },
- imagem: {
- flexDirection: 'row',
- width: 60,
- height: 60,
- borderWidth: 1,
- borderRadius: 10,
- },
- nomePrestador: {
- fontSize: 13,
- fontWeight: 'bold',
- },
- infoPrestador: {
- fontSize: 14,
- fontWeight: 'bold',
- },
- textoContainer: {
- justifyContent: 'flex-start',
- margin: 10,
- },
- posicao: {
- flexDirection: 'row',
- },
- textServicos: {
- fontSize: 12,
- fontWeight: 'bold',
- },
- botaoServicos: {
- backgroundColor: '#FFD700',
- borderRadius: 5,
- marginVertical: 10,
- borderColor: 'black',
- borderWidth: 1,
- alignItems: 'center',
- },
- centralTitulo: {
- margin: 'auto',
- flexDirection: 'row',
- },
+ container: {
+ flex: 1,
+ backgroundColor: '#f5f5f5',
+ },
+ topoTela: {
+ backgroundColor: '#FFD700',
+ borderBottomLeftRadius: 20,
+ borderBottomRightRadius: 20,
+ padding: 25,
+ marginBottom: 20,
+ },
+ userText: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ userName: {
+ color: 'white',
+ fontSize: 20,
+ fontWeight: 'bold',
+ marginLeft: 15,
+ },
+ header: {
+ backgroundColor: '#FBCB1C',
+ borderBottomLeftRadius: 20,
+ borderBottomRightRadius: 20,
+ padding: 25,
+ marginBottom: 20,
+ },
+ imagem: {
+ flexDirection: 'row',
+ width: 60,
+ height: 60,
+ borderWidth: 1,
+ borderRadius: 10
+ },
+ nomePrestador: {
+ fontSize: 13,
+ fontWeight: 'bold',
+ },
+ infoPrestador: {
+ fontSize: 14,
+ fontWeight: 'bold',
+ },
+ textoContainer: {
+ justifyContent: 'flex-start',
+ margin: 10
+ },
+ posicao: {
+ flexDirection: 'row'
+ },
+ textServicos: {
+ fontSize: 12,
+ fontWeight: 'bold',
+ },
+ botaoServicos: {
+ backgroundColor: '#FFD700',
+ borderRadius: 5,
+ marginVertical: 10,
+ borderColor: 'black',
+ borderWidth: 1,
+ alignItems: 'center'
+ },
+ backIcon: {
+ paddingRight: 15,
+ },
+ title: {
+ fontSize: 22,
+ fontWeight: 'bold',
+ alignSelf: 'center',
+ marginBottom: 20,
+ },
});
export default Prestadores;
diff --git a/frontend/app/(servico)/servicoprestador.tsx b/frontend/app/(servico)/servicoprestador.tsx
index ee40967d..69a2008a 100644
--- a/frontend/app/(servico)/servicoprestador.tsx
+++ b/frontend/app/(servico)/servicoprestador.tsx
@@ -1,61 +1,81 @@
import { Ionicons } from "@expo/vector-icons";
import { View, Text, TouchableOpacity, ScrollView, StyleSheet } from "react-native";
-import React from "react";
-import { SafeAreaView } from "react-native-safe-area-context";
-import { router } from 'expo-router';
+import React, { useEffect, useState } from "react";
+import { router, useLocalSearchParams } from 'expo-router';
+import ServicoService from "@/service/ServicoService";
+import { useUser } from "@/components/contextoApi";
+
const ServicoPrestador = () => {
+ const [servicos, setServicos] = useState([]);
+ const { nomeUsuario } = useUser();
+
+ const idPrestador: any = useLocalSearchParams();
- const prestadorClick = () => {
- router.navigate('/(servico)/prestador');
- }
+ useEffect(() => {
+ console.log(nomeUsuario)
- const agendamentoClick = () => {
- router.navigate('/(agenda)/agendamento');
- }
+ if (!idPrestador.id) {
+ console.warn('Nenhum idPrestador fornecido.');
+ return;
+ }
+
+ const fetchData = async () => {
+ try {
+ const usuariosData = await ServicoService.getServicosByPrestador(idPrestador.id);
+ setServicos(usuariosData);
+ } catch (error) {
+ console.error('Erro ao buscar dados:', error);
+ }
+ };
+ fetchData();
+ }, []);
- const tiposServicos = [
- { id: '1', servico: 'Manutenção Geral de Jardins' },
- { id: '2', servico: 'Paisagismo' },
- { id: '3', servico: 'Poda de Árvores e Arbustos' },
- { id: '4', servico: 'Instalação de Sistemas de Irrigação' },
- { id: '5', servico: 'Preparação do Solo' },
- { id: '6', servico: 'Instalação de Grama e Tapetes Verdes' },
- ];
- const nomePrestador = [
- { id: '1', nome: 'Pedro' },
- { id: '2', nome: 'Rafael' },
- ];
+ const servicoAgendaClick = (idServico: number) => {
+ router.push({ pathname: "/(tabs)/agenda", params: { idPrestador: idPrestador.id, idServico: idServico } })
+ };
+
+ const inicioClick = () => {
+ router.navigate('/(tabs)/inicio');
+ };
return (
-
-
-
-
-
-
-
- Serviços do Prestador
+
+
+
+
+
+
+ {nomeUsuario}
- {nomePrestador.map((nome) => (
-
- {nome.nome}
-
- ))}
+ Serviços do Prestador
- {tiposServicos.map((tipos, index) => (
-
-
-
- {index + 1} - Serviço {tipos.servico}
-
+ {servicos.map((servico: any) => (
+
+
+
+ Nome: {servico.descricao}
+
+ {servico.tempoServico}
+
+
+ {servico.preco}
+
+
-
+ servicoAgendaClick(servico.id)}>
+
+ Agendamento
+
+
+
))}
@@ -83,24 +103,66 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
},
+ userText: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
userName: {
color: 'white',
fontSize: 20,
fontWeight: 'bold',
marginLeft: 15,
},
- tipoServicos: {
- backgroundColor: '#f0f0f0',
- margin: 4,
- padding: 19,
+ header: {
+ backgroundColor: '#FBCB1C',
+ borderBottomLeftRadius: 20,
+ borderBottomRightRadius: 20,
+ padding: 25,
+ marginBottom: 20,
},
- textoServico: {
+ imagem: {
+ flexDirection: 'row',
+ width: 60,
+ height: 60,
+ borderWidth: 1,
+ borderRadius: 10
+ },
+ nomePrestador: {
+ fontSize: 13,
fontWeight: 'bold',
},
- titulo: {
+ infoPrestador: {
+ fontSize: 14,
fontWeight: 'bold',
- alignItems: 'center',
- fontSize: 20,
+ },
+ textoContainer: {
+ justifyContent: 'flex-start',
+ margin: 10
+ },
+ posicao: {
+ flexDirection: 'row'
+ },
+ textServicos: {
+ fontSize: 12,
+ fontWeight: 'bold',
+ },
+ botaoServicos: {
+ backgroundColor: '#FFD700',
+ borderRadius: 5,
+ marginVertical: 10,
+ borderColor: 'black',
+ borderWidth: 1,
+ alignItems: 'center'
+ },
+
+ backIcon: {
+ paddingRight: 15,
+ },
+ title: {
+ fontSize: 22,
+ fontWeight: 'bold',
+ alignSelf: 'center',
+ marginBottom: 20,
},
});
diff --git a/frontend/app/(tabs)/agenda.tsx b/frontend/app/(tabs)/agenda.tsx
index 7bf1aed4..7bcf98a5 100644
--- a/frontend/app/(tabs)/agenda.tsx
+++ b/frontend/app/(tabs)/agenda.tsx
@@ -4,19 +4,10 @@ import { Ionicons } from '@expo/vector-icons';
import { Calendar } from 'react-native-calendars';
import { useForm } from 'react-hook-form';
import { SafeAreaView } from 'react-native-safe-area-context';
-import { router } from 'expo-router';
+import { router, useLocalSearchParams } from 'expo-router';
import { obterNomeUsuario } from '@/utils/storageUtils';
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
-}, []);
type AgendamentoForm = {
servico: string;
@@ -25,11 +16,16 @@ type AgendamentoForm = {
anotacao: string;
};
-const prestadorClick = ()=>{
- router.navigate('/(servico)/prestador')
+const inicioClick = () => {
+ router.navigate('/(tabs)/inicio')
+
}
+
const AgendaScreen = () => {
+ const [nomeUsuario, setNomeUsuario] = useState('Usuário');
+
+
const { control, handleSubmit, formState: { errors, isValid } } = useForm({
defaultValues: {
servico: '',
@@ -40,6 +36,13 @@ const AgendaScreen = () => {
mode: 'onChange',
});
+ const { idPrestador, idServico } = useLocalSearchParams();
+
+
+ const agandamentoClick = (dataAgendamento: string) => {
+ router.push({ pathname: "/(agenda)/agendamento", params: { idPrestador: idPrestador, idServico: idServico, dataAgendamento: dataAgendamento } })
+ }
+
const [selectedDate, setSelectedDate] = useState('');
const handleDayPress = (day: { dateString: string }) => {
@@ -57,11 +60,11 @@ const AgendaScreen = () => {
};
return (
-
+
-
+
@@ -72,40 +75,40 @@ const AgendaScreen = () => {
- Agenda
-
-
-
- Aparar a grama - José - 7:00
- Consertar a pia - Rafael - 15:00
- Cortar o cabelo - Juliana - 14:00
-
-
- router.navigate('/(agenda)/agendamento')}>
-
-
-
- router.navigate('/(agenda)/cronograma')}>
-
-
+ Agenda
+
+
+
+ Aparar a grama - José - 7:00
+ Consertar a pia - Rafael - 15:00
+ Cortar o cabelo - Juliana - 14:00
+
+
+ agandamentoClick(selectedDate)}>
+
+
+
+ router.navigate('/(agenda)/cronograma')}>
+
+
);
diff --git a/frontend/app/(tabs)/inicio.tsx b/frontend/app/(tabs)/inicio.tsx
index 266344a4..b1d5c20b 100644
--- a/frontend/app/(tabs)/inicio.tsx
+++ b/frontend/app/(tabs)/inicio.tsx
@@ -1,14 +1,13 @@
-import React,{useEffect, useState} from 'react';
+import React,{useState} from 'react';
import { View, Text, ScrollView, StyleSheet, Pressable, TextInput } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { StatusBar } from 'expo-status-bar';
import { router } from 'expo-router';
-import Pesquisa from '../search/[query]';
-import { obterNomeUsuario } from '@/utils/storageUtils';
+import { useUser } from '@/components/contextoApi';
const Inicio = () => {
- const [nomeUsuario, setNomeUsuario] = useState('Usuário');
+ const { nomeUsuario } = useUser();
const [searchText, setSearchText] = useState('');
const promocoes = [
@@ -45,15 +44,6 @@ const Inicio = () => {
{ id: '12', nome: 'Sofia', icon: 'person-outline' },
];
- useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
-
- carregarNomeUsuario();
- }, []);
-
const profissionalClick = () => {
router.navigate('/(servico)/prestador');
};
diff --git a/frontend/app/(tabs)/perfil.tsx b/frontend/app/(tabs)/perfil.tsx
index a17dc67e..1ab972be 100644
--- a/frontend/app/(tabs)/perfil.tsx
+++ b/frontend/app/(tabs)/perfil.tsx
@@ -1,22 +1,19 @@
+import { useUser } from '@/components/contextoApi';
import { Ionicons } from '@expo/vector-icons';
import { router } from 'expo-router';
-import React, { useEffect, useState } from 'react';
+import React, { useEffect } from 'react';
import { Text, SafeAreaView, StyleSheet, View, Image, ScrollView, StatusBar, Pressable } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
-import { obterNomeUsuario } from '@/utils/storageUtils';
-const [nomeUsuario, setNomeUsuario] = useState('Usuário');
-useEffect(() => {
- const carregarNomeUsuario = async () => {
- const nome = await obterNomeUsuario();
- setNomeUsuario(nome);
- };
+const Perfil = () => {
+ const { nomeUsuario } = useUser();
- carregarNomeUsuario();
-}, []);
+
+useEffect(()=>{
+console.log(nomeUsuario)
+})
-const Perfil = () => {
return (
diff --git a/frontend/app/_layout.tsx b/frontend/app/_layout.tsx
index d31baa56..044b3b6c 100644
--- a/frontend/app/_layout.tsx
+++ b/frontend/app/_layout.tsx
@@ -5,6 +5,7 @@ import { useEffect } from 'react';
import 'react-native-reanimated';
import React from 'react';
+import { UserProvider } from '@/components/contextoApi';
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
@@ -25,8 +26,10 @@ export default function RootLayout() {
}
return (
+
+
);
}
diff --git a/frontend/app/index.tsx b/frontend/app/index.tsx
index f5c8dde2..4d10fef7 100644
--- a/frontend/app/index.tsx
+++ b/frontend/app/index.tsx
@@ -1,6 +1,6 @@
import { router } from 'expo-router';
import React from 'react';
-import { View, Text, Button, StyleSheet, Image, Pressable } from 'react-native';
+import { View, Text, StyleSheet, Image, Pressable } from 'react-native';
export default function InicioLogin() {
return (
diff --git a/frontend/components/AutocompleteInput.tsx b/frontend/components/AutocompleteInput.tsx
new file mode 100644
index 00000000..2bbe134e
--- /dev/null
+++ b/frontend/components/AutocompleteInput.tsx
@@ -0,0 +1,89 @@
+import React, { useState } from 'react';
+import {
+ View,
+ TextInput,
+ FlatList,
+ Text,
+ StyleSheet,
+ Pressable,
+} from 'react-native';
+
+type AutocompleteInputProps = {
+ placeholder: string;
+ data: any[];
+ value: string;
+ onChange: (text: string) => void;
+ onSelect: (item: any) => void;
+ filterKey: string;
+};
+
+export const AutocompleteInput: React.FC = ({
+ placeholder,
+ data,
+ value,
+ onChange,
+ onSelect,
+ filterKey,
+}) => {
+ const [showSuggestions, setShowSuggestions] = useState(false);
+
+ const filteredData = data.filter((item) =>
+ item[filterKey]?.toLowerCase().includes(value?.toLowerCase())
+ );
+
+ return (
+
+ {
+ onChange(text);
+ setShowSuggestions(true);
+ }}
+ onFocus={() => setShowSuggestions(true)}
+ onBlur={() => setTimeout(() => setShowSuggestions(false), 200)
+ }
+ />
+ {showSuggestions && filteredData.length > 0 && (
+ _item.id || index.toString()}
+ renderItem={({ item }) => (
+ {
+ console.log("AAAA", item)
+ onSelect(item);
+ setShowSuggestions(false);
+ }}
+ >
+ {item[filterKey]}
+
+ )}
+ />
+ )}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ input: {
+ height: 40,
+ borderColor: '#CCC',
+ borderWidth: 1,
+ borderRadius: 5,
+ marginBottom: 10,
+ paddingHorizontal: 10,
+ },
+ suggestionItem: {
+ padding: 10,
+ borderBottomWidth: 1,
+ borderColor: '#EEE',
+ backgroundColor: '#FFF',
+ },
+ posicao:{
+ paddingLeft:3,
+ paddingRight:5
+ }
+});
\ No newline at end of file
diff --git a/frontend/components/DateInput.tsx b/frontend/components/DateInput.tsx
new file mode 100644
index 00000000..f4d39a98
--- /dev/null
+++ b/frontend/components/DateInput.tsx
@@ -0,0 +1,66 @@
+import React, { useState } from 'react';
+import { View, Text, Platform, TouchableOpacity } from 'react-native';
+import { Controller } from 'react-hook-form';
+import DateTimePicker from '@react-native-community/datetimepicker';
+
+export const DateInput = ({ control, name, label }: any) => {
+ const [showPicker, setShowPicker] = useState(false);
+
+ return (
+
+ {label}
+ (
+ <>
+ {Platform.OS === 'web' ? (
+ onChange(e.target.value)}
+ style={{
+ borderWidth: 1,
+ padding: 10,
+ borderColor: '#ccc',
+ borderRadius: 5,
+ marginTop: 5,
+ width: '100%',
+ }}
+ />
+ ) : (
+ <>
+ setShowPicker(true)}
+ >
+ {value || 'Selecione uma data'}
+
+ {showPicker && (
+ {
+ setShowPicker(false);
+ if (selectedDate) {
+ onChange(selectedDate.toISOString());
+ }
+ }}
+ />
+ )}
+ >
+ )}
+ >
+ )}
+ />
+
+ );
+};
diff --git a/frontend/components/HoraInput.tsx b/frontend/components/HoraInput.tsx
new file mode 100644
index 00000000..6ddd6584
--- /dev/null
+++ b/frontend/components/HoraInput.tsx
@@ -0,0 +1,89 @@
+import React, { useState } from 'react';
+import { View, Text, Platform, Pressable } from 'react-native';
+import DateTimePicker from '@react-native-community/datetimepicker';
+
+
+type TimeInputProps = {
+ placeholder: string;
+ value: string;
+ disabled?: boolean;
+ onChange?: (text: string) => void;
+};
+
+export const TimeInput: React.FC = ({
+ placeholder,
+ value,
+ disabled = false,
+ onChange,
+}) => {
+ const [showPicker, setShowPicker] = useState(false);
+
+ return (
+
+ {placeholder}
+ <>
+ {Platform.OS === 'web' ? (
+ // Campo para Web
+ onChange(e.target.value)}
+ disabled={disabled}
+ style={{
+ borderWidth: 1,
+ padding: 10,
+ borderColor: '#ccc',
+ borderRadius: 5,
+ marginTop: 5,
+ width: '100%',
+ }}
+ />
+ ) : (
+ <>
+ {
+ if (!disabled) {
+ setShowPicker(true)
+ }
+ }}
+ >
+ {value || 'Selecione um horário'}
+
+ {showPicker && (
+ {
+ setShowPicker(false);
+ if (selectedTime) {
+ const hours = selectedTime.getHours()
+ .toString()
+ .padStart(2, '0');
+ const minutes = selectedTime.getMinutes()
+ .toString()
+ .padStart(2, '0');
+ onChange(`${hours}:${minutes}`);
+ }
+ }}
+ />
+ )}
+ >
+ )}
+ >
+
+ );
+};
diff --git a/frontend/components/contextoApi.tsx b/frontend/components/contextoApi.tsx
new file mode 100644
index 00000000..ba5686ef
--- /dev/null
+++ b/frontend/components/contextoApi.tsx
@@ -0,0 +1,26 @@
+import React, { createContext, useContext, useState, ReactNode } from 'react';
+
+interface UserContextProps {
+ nomeUsuario: string | null;
+ setNomeUsuario: (name: string) => void;
+}
+
+const UserContext = createContext(undefined);
+
+export const UserProvider = ({ children }: { children: ReactNode }) => {
+ const [nomeUsuario, setNomeUsuario] = useState(null);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useUser = () => {
+ const context = useContext(UserContext);
+ if (!context) {
+ throw new Error('useUser must be used within a UserProvider');
+ }
+ return context;
+};
diff --git a/frontend/service/ServicoService.js b/frontend/service/ServicoService.js
index 31ec7523..318247e2 100644
--- a/frontend/service/ServicoService.js
+++ b/frontend/service/ServicoService.js
@@ -45,7 +45,6 @@ axiosInstance.interceptors.request.use(
const createServico = async (servicos) => {
try {
- console.log(await axiosInstance.post('', servicos));
const response = await axiosInstance.post('', servicos);
console.log('criou serviço')
return response.data;
@@ -57,7 +56,7 @@ const createServico = async (servicos) => {
const getServicosByPrestador = async (idPrestador) => {
try {
- const response = await axiosInstance.get(`?id_prestador=${idPrestador}`);
+ const response = await axiosInstance.get(`/prestador/${idPrestador}`);
return response.data;
} catch (error) {
console.error('Erro ao buscar serviços do prestador:', error);
diff --git a/frontend/service/UsuarioService.js b/frontend/service/UsuarioService.js
index ad766d8a..e6896a91 100644
--- a/frontend/service/UsuarioService.js
+++ b/frontend/service/UsuarioService.js
@@ -1,7 +1,7 @@
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';
-const API_URL = 'http://localhost:8080/api/usuarios';
+const API_URL = 'http://46.202.144.47:8080/api/usuarios';
// Função para recuperar o token do AsyncStorage
const getAuthToken = async () => {
diff --git a/frontend/service/prestadorservice.js b/frontend/service/prestadorservice.js
index 93466722..a95ae853 100644
--- a/frontend/service/prestadorservice.js
+++ b/frontend/service/prestadorservice.js
@@ -1,7 +1,7 @@
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';
-const API_URL = 'http://localhost:8080/api/prestador';
+const API_URL = 'http://localhost:8080/api/prestadores';
// Função para recuperar o token do AsyncStorage
const getAuthToken = async () => {
@@ -42,7 +42,7 @@ axiosInstance.interceptors.request.use(
const getAllPrestadores = async () => {
try {
- const response = await axiosInstance.get('/');
+ const response = await axiosInstance.get('');
return response.data;
} catch (error) {
console.error('Erro ao buscar todos os prestadores:', error);
diff --git a/frontend/utils/storageUtils.ts b/frontend/utils/storageUtils.ts
index 90acf3b3..9a169565 100644
--- a/frontend/utils/storageUtils.ts
+++ b/frontend/utils/storageUtils.ts
@@ -21,4 +21,18 @@ export const obterNomeUsuario = async () => {
console.error('Erro ao recuperar o nome do usuário:', error);
return 'Usuário'; // Valor padrão em caso de erro
}
+};
+
+export const limparStorage = async () => {
+ try {
+ if (typeof window !== 'undefined' && window.localStorage) {
+ // Ambiente navegador
+ window.localStorage.clear();
+ } else {
+ // Ambiente móvel
+ await AsyncStorage.clear();
+ }
+ } catch (error) {
+ console.error('Erro ao limpar o armazenamento:', error);
+ }
};
\ No newline at end of file